diff --git a/site/src/components/ActivityDetail.svelte b/site/src/components/ActivityDetail.svelte index 5632622..e5cfd1f 100644 --- a/site/src/components/ActivityDetail.svelte +++ b/site/src/components/ActivityDetail.svelte @@ -41,7 +41,9 @@ localDescription = e.detail.description; } - $: trackUrl = activity.track_url ? `${base}data/${activity.track_url}` : null; + $: trackUrl = activity.track_url + ? (activity.track_url.startsWith('http') ? activity.track_url : `${base}data/${activity.track_url}`) + : null; $: color = sportColor(activity.sport); function lightboxPrev() { if (lightboxIndex !== null) lightboxIndex = (lightboxIndex - 1 + galleryImages.length) % galleryImages.length; } @@ -169,7 +171,7 @@ {/if} - {formatDate(activity.started_at)} · {formatTime(activity.started_at)} + {formatDate(activity.started_at)} · {formatTime(activity.started_at)}{#if activity.handle} · @{activity.handle}{/if}
diff --git a/site/src/components/ActivityFeed.svelte b/site/src/components/ActivityFeed.svelte index e941b8a..ffc330e 100644 --- a/site/src/components/ActivityFeed.svelte +++ b/site/src/components/ActivityFeed.svelte @@ -128,18 +128,23 @@ {:else}
{#each visible as a (a.id)} - + + diff --git a/site/src/lib/dataloader.ts b/site/src/lib/dataloader.ts index 53a3a0a..3933a59 100644 --- a/site/src/lib/dataloader.ts +++ b/site/src/lib/dataloader.ts @@ -79,14 +79,23 @@ async function resolveShards( const shardResults = await Promise.allSettled( index.shards.map(async shard => { const url = shard.url.startsWith('http') ? shard.url : `${base}${shard.url}`; + // Base URL of this shard's directory (e.g. "http://…/data/dave/_merged/") + const shardBase = url.substring(0, url.lastIndexOf('/') + 1); const sub = await fetchJSON(url); // Recursively resolve nested shards (e.g. user shard that itself paginates) const activities = await resolveShards(sub, url); - // Tag each activity with the handle declared in the shard entry - if (shard.handle) { - return activities.map(a => ({ ...a, handle: shard.handle })); - } - return activities; + // Rewrite relative detail_url / track_url to be absolute so they can be + // fetched correctly regardless of where the root index lives. + return activities.map(a => ({ + ...a, + ...(shard.handle ? { handle: shard.handle } : {}), + detail_url: a.detail_url && !a.detail_url.startsWith('http') + ? `${shardBase}${a.detail_url}` + : a.detail_url, + track_url: a.track_url && !a.track_url.startsWith('http') + ? `${shardBase}${a.track_url}` + : a.track_url, + })); }), ); @@ -152,7 +161,10 @@ export async function loadActivity( if (cached) return cached; try { - return await fetchJSON(`${baseUrl}data/${detailUrl}`); + const url = detailUrl.startsWith('http') + ? detailUrl + : `${baseUrl}data/${detailUrl}`; + return await fetchJSON(url); } catch { return null; } diff --git a/site/src/pages/activity/[id].astro b/site/src/pages/activity/[id].astro index d152a1e..36cb8d5 100644 --- a/site/src/pages/activity/[id].astro +++ b/site/src/pages/activity/[id].astro @@ -19,13 +19,26 @@ export async function getStaticPaths() { const root: BASIndex = JSON.parse(readFileSync(join(dataDir, 'index.json'), 'utf-8')); // Collect activities from root (single-user) or walk shards (multi-user) - function readActivities(indexPath: string): ActivitySummary[] { + function readActivities(indexPath: string, urlPrefix: string = ''): ActivitySummary[] { try { const idx: BASIndex = JSON.parse(readFileSync(indexPath, 'utf-8')); - const own = idx.activities ?? []; + const own = (idx.activities ?? []).map(a => + urlPrefix + ? { + ...a, + detail_url: a.detail_url && !a.detail_url.startsWith('http') ? `${urlPrefix}${a.detail_url}` : a.detail_url, + track_url: a.track_url && !a.track_url.startsWith('http') ? `${urlPrefix}${a.track_url}` : a.track_url, + } + : a + ); const fromShards = (idx.shards ?? []).flatMap(s => { const shardPath = join(dataDir, s.url); - return readActivities(shardPath); + // Prefix for activities read from this shard: path of the shard dir relative to dataDir + const shardDir = s.url.substring(0, s.url.lastIndexOf('/') + 1); + return readActivities(shardPath, shardDir).map(a => ({ + ...a, + ...(s.handle && !a.handle ? { handle: s.handle } : {}), + })); }); return [...own, ...fromShards]; } catch {