From 5f809c4043635619bdd00d29b5e99683c7154d29 Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Thu, 30 Jul 2026 10:40:18 +0100 Subject: [PATCH] web/components: add components and stories for timeline also fix up timeline styles Signed-off-by: oppiliappan --- .../profile/FollowCard.stories.svelte | 45 ++++++++++ .../lib/components/profile/FollowCard.svelte | 79 ++++------------ .../profile/FollowCardContent.svelte | 65 ++++++++++++++ .../profile/StringCard.stories.svelte | 35 ++++++++ .../lib/components/profile/StringCard.svelte | 47 ++++------ .../profile/StringCardContent.svelte | 34 +++++++ .../components/profile/tabs/StarredTab.svelte | 7 +- .../components/repo/RepoCard.stories.svelte | 54 +++++++++++ web/src/lib/components/repo/RepoCard.svelte | 90 +++++-------------- .../components/repo/RepoCardContent.svelte | 75 ++++++++++++++++ .../lib/components/repo/RepoIndexView.svelte | 2 +- .../repo/issues/IssueCard.stories.svelte | 1 + .../components/repo/issues/IssueCard.svelte | 52 ++++------- .../repo/issues/IssueCardContent.svelte | 45 ++++++++++ .../settings/KeyCard.stories.svelte | 30 +++++++ .../lib/components/settings/KeyCard.svelte | 44 ++++----- .../components/settings/KeyCardContent.svelte | 38 ++++++++ .../components/timeline/TimelineCard.svelte | 17 ++++ .../TimelineFollowEvent.stories.svelte | 38 ++++++++ .../timeline/TimelineFollowEvent.svelte | 21 +++++ .../timeline/TimelineRepoEvent.stories.svelte | 56 ++++++++++++ .../timeline/TimelineRepoEvent.svelte | 34 +++++++ .../timeline/TimelineStarEvent.stories.svelte | 41 +++++++++ .../timeline/TimelineStarEvent.svelte | 29 ++++++ web/src/lib/components/timeline/mappers.ts | 26 ++++++ web/src/lib/components/ui/Card.stories.svelte | 39 ++++++++ web/src/lib/components/ui/Card.svelte | 66 ++++++++++++++ web/src/routes/timeline/+page.svelte | 73 +++------------ web/src/routes/timeline/+page.ts | 2 - 29 files changed, 890 insertions(+), 295 deletions(-) create mode 100644 web/src/lib/components/profile/FollowCard.stories.svelte create mode 100644 web/src/lib/components/profile/FollowCardContent.svelte create mode 100644 web/src/lib/components/profile/StringCard.stories.svelte create mode 100644 web/src/lib/components/profile/StringCardContent.svelte create mode 100644 web/src/lib/components/repo/RepoCard.stories.svelte create mode 100644 web/src/lib/components/repo/RepoCardContent.svelte create mode 100644 web/src/lib/components/repo/issues/IssueCardContent.svelte create mode 100644 web/src/lib/components/settings/KeyCard.stories.svelte create mode 100644 web/src/lib/components/settings/KeyCardContent.svelte create mode 100644 web/src/lib/components/timeline/TimelineCard.svelte create mode 100644 web/src/lib/components/timeline/TimelineFollowEvent.stories.svelte create mode 100644 web/src/lib/components/timeline/TimelineFollowEvent.svelte create mode 100644 web/src/lib/components/timeline/TimelineRepoEvent.stories.svelte create mode 100644 web/src/lib/components/timeline/TimelineRepoEvent.svelte create mode 100644 web/src/lib/components/timeline/TimelineStarEvent.stories.svelte create mode 100644 web/src/lib/components/timeline/TimelineStarEvent.svelte create mode 100644 web/src/lib/components/timeline/mappers.ts create mode 100644 web/src/lib/components/ui/Card.stories.svelte create mode 100644 web/src/lib/components/ui/Card.svelte diff --git a/web/src/lib/components/profile/FollowCard.stories.svelte b/web/src/lib/components/profile/FollowCard.stories.svelte new file mode 100644 index 00000000..58ee65e5 --- /dev/null +++ b/web/src/lib/components/profile/FollowCard.stories.svelte @@ -0,0 +1,45 @@ + + + + + + + + {#snippet template(args)} + + + + {/snippet} + diff --git a/web/src/lib/components/profile/FollowCard.svelte b/web/src/lib/components/profile/FollowCard.svelte index ba5e4df5..b3bec5ff 100644 --- a/web/src/lib/components/profile/FollowCard.svelte +++ b/web/src/lib/components/profile/FollowCard.svelte @@ -1,66 +1,21 @@ -
-
- -
- -
-
- - {person.handle} - - {#if person.description} -

{person.description}

- {/if} - -
- - {#if !person.isSelf} -
- -
- {/if} -
-
+ + + diff --git a/web/src/lib/components/profile/FollowCardContent.svelte b/web/src/lib/components/profile/FollowCardContent.svelte new file mode 100644 index 00000000..3d6fc6db --- /dev/null +++ b/web/src/lib/components/profile/FollowCardContent.svelte @@ -0,0 +1,65 @@ + + +
+
+
+ +
+ +
+ + {person.handle} + + {#if person.description} +

{person.description}

+ {/if} + +
+
+ + {#if !person.isSelf} +
+ +
+ {/if} +
diff --git a/web/src/lib/components/profile/StringCard.stories.svelte b/web/src/lib/components/profile/StringCard.stories.svelte new file mode 100644 index 00000000..d15fc862 --- /dev/null +++ b/web/src/lib/components/profile/StringCard.stories.svelte @@ -0,0 +1,35 @@ + + + + + diff --git a/web/src/lib/components/profile/StringCard.svelte b/web/src/lib/components/profile/StringCard.svelte index 2af23f25..6712aba4 100644 --- a/web/src/lib/components/profile/StringCard.svelte +++ b/web/src/lib/components/profile/StringCard.svelte @@ -1,36 +1,21 @@ -
- - - {#if entry.description} -

{entry.description}

- {/if} - -
- {entry.lines} line{entry.lines === 1 ? "" : "s"} · {compactRelativeTime( - entry.createdAt - )} -
-
+ + + diff --git a/web/src/lib/components/profile/StringCardContent.svelte b/web/src/lib/components/profile/StringCardContent.svelte new file mode 100644 index 00000000..83ab1245 --- /dev/null +++ b/web/src/lib/components/profile/StringCardContent.svelte @@ -0,0 +1,34 @@ + + +
+ + + {#if entry.description} +

{entry.description}

+ {/if} + +
+ {entry.lines} line{entry.lines === 1 ? "" : "s"} · {compactRelativeTime( + entry.createdAt + )} +
+
diff --git a/web/src/lib/components/profile/tabs/StarredTab.svelte b/web/src/lib/components/profile/tabs/StarredTab.svelte index ac2344af..01c9f3c3 100644 --- a/web/src/lib/components/profile/tabs/StarredTab.svelte +++ b/web/src/lib/components/profile/tabs/StarredTab.svelte @@ -1,6 +1,7 @@ + + + + + + + + {#snippet template(args)} + + + + {/snippet} + diff --git a/web/src/lib/components/repo/RepoCard.svelte b/web/src/lib/components/repo/RepoCard.svelte index a649b70f..07207416 100644 --- a/web/src/lib/components/repo/RepoCard.svelte +++ b/web/src/lib/components/repo/RepoCard.svelte @@ -1,77 +1,27 @@ -
- - - {#if repo.description} -

{repo.description}

- {/if} - - {#if repo.language !== undefined || stats.length > 0} -
- {#if repo.language} - - - {repo.language} - - {/if} - {#each stats as stat (stat.Icon)} - - - {/each} -
- {/if} -
+ + + diff --git a/web/src/lib/components/repo/RepoCardContent.svelte b/web/src/lib/components/repo/RepoCardContent.svelte new file mode 100644 index 00000000..743bcb26 --- /dev/null +++ b/web/src/lib/components/repo/RepoCardContent.svelte @@ -0,0 +1,75 @@ + + +
+ + + {#if repo.description} +

{repo.description}

+ {/if} + + {#if repo.language !== undefined || stats.length > 0} +
+ {#if repo.language} + + + {repo.language} + + {/if} + {#each stats as stat (stat.Icon)} + + + {/each} +
+ {/if} +
diff --git a/web/src/lib/components/repo/RepoIndexView.svelte b/web/src/lib/components/repo/RepoIndexView.svelte index fd7a3709..bbbcf18b 100644 --- a/web/src/lib/components/repo/RepoIndexView.svelte +++ b/web/src/lib/components/repo/RepoIndexView.svelte @@ -29,7 +29,7 @@ const refsCapped = $derived(data.refs.capped); - + {#if data.needsUpgrade}
diff --git a/web/src/lib/components/repo/issues/IssueCard.stories.svelte b/web/src/lib/components/repo/issues/IssueCard.stories.svelte index 3a462985..2191e863 100644 --- a/web/src/lib/components/repo/issues/IssueCard.stories.svelte +++ b/web/src/lib/components/repo/issues/IssueCard.stories.svelte @@ -29,3 +29,4 @@ + diff --git a/web/src/lib/components/repo/issues/IssueCard.svelte b/web/src/lib/components/repo/issues/IssueCard.svelte index a3617442..0df24590 100644 --- a/web/src/lib/components/repo/issues/IssueCard.svelte +++ b/web/src/lib/components/repo/issues/IssueCard.svelte @@ -1,47 +1,27 @@ - + + + diff --git a/web/src/lib/components/repo/issues/IssueCardContent.svelte b/web/src/lib/components/repo/issues/IssueCardContent.svelte new file mode 100644 index 00000000..1911d052 --- /dev/null +++ b/web/src/lib/components/repo/issues/IssueCardContent.svelte @@ -0,0 +1,45 @@ + + + + + diff --git a/web/src/lib/components/settings/KeyCard.stories.svelte b/web/src/lib/components/settings/KeyCard.stories.svelte new file mode 100644 index 00000000..95273e42 --- /dev/null +++ b/web/src/lib/components/settings/KeyCard.stories.svelte @@ -0,0 +1,30 @@ + + + + + diff --git a/web/src/lib/components/settings/KeyCard.svelte b/web/src/lib/components/settings/KeyCard.svelte index 87a0f7e8..befcc902 100644 --- a/web/src/lib/components/settings/KeyCard.svelte +++ b/web/src/lib/components/settings/KeyCard.svelte @@ -1,9 +1,6 @@ -
-
-
-
- {#if fingerprint} - {fingerprint} - {/if} - added {relativeTime(createdAt)} -
- -
+ + + diff --git a/web/src/lib/components/settings/KeyCardContent.svelte b/web/src/lib/components/settings/KeyCardContent.svelte new file mode 100644 index 00000000..e1e0d2de --- /dev/null +++ b/web/src/lib/components/settings/KeyCardContent.svelte @@ -0,0 +1,38 @@ + + +
+
+
+
+ {#if fingerprint} + {fingerprint} + {/if} + added {relativeTime(createdAt)} +
+ +
diff --git a/web/src/lib/components/timeline/TimelineCard.svelte b/web/src/lib/components/timeline/TimelineCard.svelte new file mode 100644 index 00000000..d5cf52d6 --- /dev/null +++ b/web/src/lib/components/timeline/TimelineCard.svelte @@ -0,0 +1,17 @@ + + + +
+ {@render header()} +
+
+ {@render children()} +
+
diff --git a/web/src/lib/components/timeline/TimelineFollowEvent.stories.svelte b/web/src/lib/components/timeline/TimelineFollowEvent.stories.svelte new file mode 100644 index 00000000..ffeed555 --- /dev/null +++ b/web/src/lib/components/timeline/TimelineFollowEvent.stories.svelte @@ -0,0 +1,38 @@ + + + + {#snippet template(args)} + + + + {/snippet} + diff --git a/web/src/lib/components/timeline/TimelineFollowEvent.svelte b/web/src/lib/components/timeline/TimelineFollowEvent.svelte new file mode 100644 index 00000000..54df1f63 --- /dev/null +++ b/web/src/lib/components/timeline/TimelineFollowEvent.svelte @@ -0,0 +1,21 @@ + + + + {#snippet header()} + + followed + + {relativeTime(eventAt)} + {/snippet} + + + diff --git a/web/src/lib/components/timeline/TimelineRepoEvent.stories.svelte b/web/src/lib/components/timeline/TimelineRepoEvent.stories.svelte new file mode 100644 index 00000000..2f81839e --- /dev/null +++ b/web/src/lib/components/timeline/TimelineRepoEvent.stories.svelte @@ -0,0 +1,56 @@ + + + + {#snippet template(args)} + + + + {/snippet} + + + + {#snippet template(args)} + + + + {/snippet} + diff --git a/web/src/lib/components/timeline/TimelineRepoEvent.svelte b/web/src/lib/components/timeline/TimelineRepoEvent.svelte new file mode 100644 index 00000000..fb35ab83 --- /dev/null +++ b/web/src/lib/components/timeline/TimelineRepoEvent.svelte @@ -0,0 +1,34 @@ + + + + {#snippet header()} + + {#if event.source} + forked + {event.source.owner.handle}/{event.source.slug} + to {event.repo.slug} + {:else} + created {event.repo.slug} + {/if} + {relativeTime(eventAt)} + {/snippet} + + + diff --git a/web/src/lib/components/timeline/TimelineStarEvent.stories.svelte b/web/src/lib/components/timeline/TimelineStarEvent.stories.svelte new file mode 100644 index 00000000..8264c528 --- /dev/null +++ b/web/src/lib/components/timeline/TimelineStarEvent.stories.svelte @@ -0,0 +1,41 @@ + + + + {#snippet template(args)} + + + + {/snippet} + diff --git a/web/src/lib/components/timeline/TimelineStarEvent.svelte b/web/src/lib/components/timeline/TimelineStarEvent.svelte new file mode 100644 index 00000000..66efda70 --- /dev/null +++ b/web/src/lib/components/timeline/TimelineStarEvent.svelte @@ -0,0 +1,29 @@ + + + + {#snippet header()} + + starred + {event.repo.owner.handle}/{event.repo.slug} + {relativeTime(eventAt)} + {/snippet} + + + diff --git a/web/src/lib/components/timeline/mappers.ts b/web/src/lib/components/timeline/mappers.ts new file mode 100644 index 00000000..ead8b47d --- /dev/null +++ b/web/src/lib/components/timeline/mappers.ts @@ -0,0 +1,26 @@ +import { resolve } from "$app/paths"; +import { rkeyFromUri } from "$lib/api/uri"; +import type { RepoCardData, PersonData } from "$lib/components/profile/types"; +import type * as ShTangledRepoDefs from "$lib/api/lexicons/types/sh/tangled/repo/defs"; +import type * as ShTangledActorDefs from "$lib/api/lexicons/types/sh/tangled/actor/defs"; + +export const toRepoCard = (repo: ShTangledRepoDefs.RepoViewBasic): RepoCardData => ({ + name: repo.slug, + repoDid: repo.did, + ownerHandle: repo.owner.handle, + description: repo.description, + createdAt: repo.createdAt, + stars: repo.starCount, + viewerStarRkey: repo.viewer?.star ? rkeyFromUri(repo.viewer.star) : null +}); + +export const toPerson = (profile: ShTangledActorDefs.ProfileViewDetailed): PersonData => ({ + did: profile.did, + handle: profile.handle, + followers: profile.followersCount, + following: profile.followsCount, + viewerFollowRkey: profile.viewer?.following ? rkeyFromUri(profile.viewer.following) : null +}); + +export const repoHref = (repo: ShTangledRepoDefs.RepoViewBasic) => + resolve(`/${repo.owner.handle}/${repo.slug}` as "/"); diff --git a/web/src/lib/components/ui/Card.stories.svelte b/web/src/lib/components/ui/Card.stories.svelte new file mode 100644 index 00000000..b131d615 --- /dev/null +++ b/web/src/lib/components/ui/Card.stories.svelte @@ -0,0 +1,39 @@ + + + +Card content +Bordered card with shadow + + Borderless, shadowless, background-less + + + +
+ Bordered, no shadow (profile / settings) + Bordered + shadow (elevated) + Plain (timeline) +
+
diff --git a/web/src/lib/components/ui/Card.svelte b/web/src/lib/components/ui/Card.svelte new file mode 100644 index 00000000..e11d37f0 --- /dev/null +++ b/web/src/lib/components/ui/Card.svelte @@ -0,0 +1,66 @@ + + + + +
+ {#if children} + {@render children()} + {/if} +
diff --git a/web/src/routes/timeline/+page.svelte b/web/src/routes/timeline/+page.svelte index 4cf45608..14b9507b 100644 --- a/web/src/routes/timeline/+page.svelte +++ b/web/src/routes/timeline/+page.svelte @@ -4,39 +4,12 @@ import Button from "$lib/components/ui/Button.svelte"; import ButtonGroup from "$lib/components/ui/ButtonGroup.svelte"; import EmptyState from "$lib/components/ui/EmptyState.svelte"; - import User from "$lib/components/ui/User.svelte"; - import RepoCard from "$lib/components/repo/RepoCard.svelte"; - import FollowCard from "$lib/components/profile/FollowCard.svelte"; - import { rkeyFromUri } from "$lib/api/uri"; - import { relativeTime } from "$lib/format"; - import type { RepoCardData, PersonData } from "$lib/components/profile/types"; - import type * as ShTangledRepoDefs from "$lib/api/lexicons/types/sh/tangled/repo/defs"; - import type * as ShTangledActorDefs from "$lib/api/lexicons/types/sh/tangled/actor/defs"; + import TimelineRepoEvent from "$lib/components/timeline/TimelineRepoEvent.svelte"; + import TimelineStarEvent from "$lib/components/timeline/TimelineStarEvent.svelte"; + import TimelineFollowEvent from "$lib/components/timeline/TimelineFollowEvent.svelte"; import type { PageData } from "./$types"; let { data }: { data: PageData } = $props(); - - const toRepoCard = (repo: ShTangledRepoDefs.RepoViewBasic): RepoCardData => ({ - name: repo.slug, - repoDid: repo.did, - ownerHandle: repo.owner.handle, - description: repo.description, - createdAt: repo.createdAt, - stars: repo.starCount, - viewerStarRkey: repo.viewer?.star ? rkeyFromUri(repo.viewer.star) : null - }); - - const toPerson = (profile: ShTangledActorDefs.ProfileViewDetailed): PersonData => ({ - did: profile.did, - handle: profile.handle, - avatar: profile.avatar, - followers: profile.followersCount, - following: profile.followsCount, - viewerFollowRkey: profile.viewer?.following ? rkeyFromUri(profile.viewer.following) : null - }); - - const repoHref = (repo: ShTangledRepoDefs.RepoViewBasic) => - resolve(`/${repo.owner.handle}/${repo.slug}` as "/"); @@ -65,39 +38,13 @@ {#each data.feed as item (item.event.uri)} {@const event = item.event} -
-
- {#if event.$type === "sh.tangled.feed.getTimeline#repoEvent"} - - {#if event.source} - forked - {event.source.owner.handle}/{event.source.slug} - to {event.repo.slug} - {:else} - created {event.repo.slug} - {/if} - {:else if event.$type === "sh.tangled.feed.getTimeline#starEvent"} - - starred - {event.repo.owner.handle}/{event.repo.slug} - {:else if event.$type === "sh.tangled.feed.getTimeline#followEvent"} - - followed - - {/if} - {relativeTime(item.eventAt)} -
- - {#if event.$type === "sh.tangled.feed.getTimeline#followEvent"} - - {:else} - - {/if} -
+ {#if event.$type === "sh.tangled.feed.getTimeline#repoEvent"} + + {:else if event.$type === "sh.tangled.feed.getTimeline#starEvent"} + + {:else if event.$type === "sh.tangled.feed.getTimeline#followEvent"} + + {/if} {:else} { const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, fetch: event.fetch }); const viewer = parent.auth?.did; - // the following feed needs a viewer to resolve the followed set; bobbin 400s without one const followingOnly = event.url.searchParams.get("following") === "true" && viewer !== undefined; try { - // output key is `feed`, not `items`, so the pagination.ts helpers don't apply const { feed } = await jsonGet( ctx, "sh.tangled.feed.getTimeline", -- 2.51.2