ActivityFeed — replaced the <button> inside <a> (invalid HTML, unreliable) with the stretched-link pattern: the card is now a <div>, the title <a> carries a ::before pseudo-element

that covers the whole card making it clickable, and @handle is a proper <a> with z-index: 10 sitting above the stretched link. Clicking the handle navigates to /u/{handle}/; clicking
  anywhere else navigates to the activity.

  ActivityDetail — @handle link added in the date/time row of the header, linking to /u/{handle}/. Only shown when activity.handle is set (i.e. multi-user mode).
This commit is contained in:
Davide Scaini
2026-04-09 12:32:22 +02:00
parent 7dcb1e6dd0
commit 50cdeb3b6e
4 changed files with 50 additions and 18 deletions
+18 -6
View File
@@ -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<BASIndex>(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<ActivityDetail>(`${baseUrl}data/${detailUrl}`);
const url = detailUrl.startsWith('http')
? detailUrl
: `${baseUrl}data/${detailUrl}`;
return await fetchJSON<ActivityDetail>(url);
} catch {
return null;
}