From 249aba65cdffde577263ed63d29de6b9fcadc13e Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Wed, 19 Aug 2026 15:53:33 +0100 Subject: [PATCH] web/routes: load timeline in root when logged in Signed-off-by: oppiliappan --- .../timeline/Timeline.stories.svelte | 62 +------------ .../timeline/TimelineView.stories.svelte | 46 ++++++++++ .../components/timeline/TimelineView.svelte | 80 +++++++++++++++++ .../timeline/TrendingRepos.stories.svelte | 30 +------ web/src/lib/components/timeline/load.ts | 38 ++++++++ web/src/lib/components/timeline/mock.ts | 90 +++++++++++++++++++ web/src/routes/+page.svelte | 10 ++- web/src/routes/+page.ts | 23 +++-- web/src/routes/timeline/+page.svelte | 69 ++------------ web/src/routes/timeline/+page.ts | 32 +------ 10 files changed, 287 insertions(+), 193 deletions(-) create mode 100644 web/src/lib/components/timeline/TimelineView.stories.svelte create mode 100644 web/src/lib/components/timeline/TimelineView.svelte create mode 100644 web/src/lib/components/timeline/load.ts create mode 100644 web/src/lib/components/timeline/mock.ts diff --git a/web/src/lib/components/timeline/Timeline.stories.svelte b/web/src/lib/components/timeline/Timeline.stories.svelte index a2f3c6a0f..a71c2180d 100644 --- a/web/src/lib/components/timeline/Timeline.stories.svelte +++ b/web/src/lib/components/timeline/Timeline.stories.svelte @@ -1,68 +1,8 @@ + + +{#snippet template(args: ComponentProps)} + + + +{/snippet} + + + + + + + + + + + + + + + + diff --git a/web/src/lib/components/timeline/TimelineView.svelte b/web/src/lib/components/timeline/TimelineView.svelte new file mode 100644 index 000000000..7c874a695 --- /dev/null +++ b/web/src/lib/components/timeline/TimelineView.svelte @@ -0,0 +1,80 @@ + + +
+ + + +
+
+
+

+

+ {#if signedIn} + + + + + {/if} +
+ + +
+
+ + +
+ + + +
+
diff --git a/web/src/lib/components/timeline/TrendingRepos.stories.svelte b/web/src/lib/components/timeline/TrendingRepos.stories.svelte index e7e9721d9..a8102256c 100644 --- a/web/src/lib/components/timeline/TrendingRepos.stories.svelte +++ b/web/src/lib/components/timeline/TrendingRepos.stories.svelte @@ -1,39 +1,13 @@ diff --git a/web/src/lib/components/timeline/load.ts b/web/src/lib/components/timeline/load.ts new file mode 100644 index 000000000..72cae5ebc --- /dev/null +++ b/web/src/lib/components/timeline/load.ts @@ -0,0 +1,38 @@ +import { jsonGet } from "$lib/api/_request"; +import { toHttpError } from "$lib/api/load"; +import { getTrending } from "$lib/api/profile"; +import { toRepoCard } from "./mappers"; +import type { BobbinContext } from "$lib/api/client"; +import type * as ShTangledFeedGetTimeline from "$lib/api/lexicons/types/sh/tangled/feed/getTimeline"; + +const PAGE_LIMIT = 50; + +export interface LoadTimelineOptions { + ctx: BobbinContext; + viewer: string | undefined; + url: URL; +} + +// shared by /timeline and the signed-in homescreen at / +export const loadTimeline = async ({ ctx, viewer, url }: LoadTimelineOptions) => { + const followingOnly = url.searchParams.get("following") === "true" && viewer !== undefined; + + try { + const [{ feed }, trending] = await Promise.all([ + jsonGet(ctx, "sh.tangled.feed.getTimeline", { + viewer, + followingOnly, + limit: PAGE_LIMIT + }), + getTrending(ctx).catch(() => ({ people: [], repos: [] })) + ]); + return { + feed, + trending: trending.repos.map(toRepoCard), + followingOnly, + signedIn: viewer !== undefined + }; + } catch (cause) { + toHttpError(cause, "Could not load timeline"); + } +}; diff --git a/web/src/lib/components/timeline/mock.ts b/web/src/lib/components/timeline/mock.ts new file mode 100644 index 000000000..0c4bd159d --- /dev/null +++ b/web/src/lib/components/timeline/mock.ts @@ -0,0 +1,90 @@ +// fixture feed and rail data for the timeline stories + +import type { RepoCardData } from "$lib/components/profile/types"; +import type * as ShTangledFeedGetTimeline from "$lib/api/lexicons/types/sh/tangled/feed/getTimeline"; + +const owner = { did: "did:plc:3p7ejjxnufohsygt5vbyxb2i", handle: "tangled.org" }; +const alice = { did: "did:plc:oky5czdrnfjpqslsw2a5iclo", handle: "alice.tngl.sh" }; + +const repo = { + did: "did:plc:3p7ejjxnufohsygt5vbyxb2i", + slug: "core", + owner, + createdAt: "2025-06-01T10:30:00Z", + description: "The knot server, appview, and everything that makes tangled tick.", + starCount: 42 +}; + +export const feed = [ + { + event: { + $type: "sh.tangled.feed.getTimeline#repoEvent", + cid: "bafyreib1", + uri: "at://did:plc:3p7ejjxnufohsygt5vbyxb2i/sh.tangled.repo/core", + repo + }, + eventAt: "2025-06-04T09:00:00Z" + }, + { + event: { + $type: "sh.tangled.feed.getTimeline#starEvent", + cid: "bafyreib2", + uri: "at://did:plc:oky5czdrnfjpqslsw2a5iclo/sh.tangled.feed.star/3l", + actor: alice, + repo + }, + eventAt: "2025-06-03T18:20:00Z" + }, + { + event: { + $type: "sh.tangled.feed.getTimeline#followEvent", + cid: "bafyreib3", + uri: "at://did:plc:oky5czdrnfjpqslsw2a5iclo/sh.tangled.graph.follow/3l", + actor: alice, + subject: { + did: "did:plc:3p7ejjxnufohsygt5vbyxb2i", + handle: "joshka.net", + description: "Rust, TUIs, and the occasional git plumbing yak-shave.", + followersCount: 128, + followsCount: 87 + } + }, + eventAt: "2025-06-02T12:00:00Z" + }, + { + event: { + $type: "sh.tangled.feed.getTimeline#repoEvent", + cid: "bafyreib4", + uri: "at://did:plc:3p7ejjxnufohsygt5vbyxb2i/sh.tangled.repo/core-fork", + repo: { ...repo, slug: "core-fork" }, + source: repo + }, + eventAt: "2025-06-01T08:00:00Z" + } +] as unknown as ShTangledFeedGetTimeline.$output["feed"]; + +export const trending: RepoCardData[] = [ + { + name: "core", + repoDid: "did:plc:3p7ejjxnufohsygt5vbyxb2i", + ownerHandle: "tangled.org", + description: "The knot server, appview, and everything that makes tangled tick.", + createdAt: "2025-06-01T10:30:00Z", + stars: 1234 + }, + { + name: "spindle", + repoDid: "did:plc:oky5czdrnfjpqslsw2a5iclo", + ownerHandle: "alice.tngl.sh", + description: "A tiny CI runner that speaks the pipeline lexicon.", + createdAt: "2025-05-20T08:00:00Z", + stars: 87 + }, + { + name: "dotfiles", + repoDid: "did:plc:6qtmvlpvcgwuemcxjbfvnpxg", + ownerHandle: "someone-with-a-rather-long-handle.example.com", + createdAt: "2025-05-18T08:00:00Z", + stars: 9 + } +]; diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte index bf0d2e6b3..06d468c02 100644 --- a/web/src/routes/+page.svelte +++ b/web/src/routes/+page.svelte @@ -1,6 +1,10 @@ @@ -13,10 +17,8 @@ /> -{#if auth.currentUser} -
-

Home

-
+{#if auth.currentUser && data.timeline} + {:else} {/if} diff --git a/web/src/routes/+page.ts b/web/src/routes/+page.ts index 67e1b962f..dc06756bd 100644 --- a/web/src/routes/+page.ts +++ b/web/src/routes/+page.ts @@ -3,25 +3,30 @@ import { redirect } from "@sveltejs/kit"; import { createBobbinClient } from "$lib/api/client"; import { httpStatusFor, toHttpError } from "$lib/api/load"; import { getProfile } from "$lib/api/records"; +import { loadTimeline } from "$lib/components/timeline/load"; import type { PageLoad } from "./$types"; export const load: PageLoad = async (event) => { const parent = await event.parent(); const viewer = parent.auth?.did; - if (!viewer) return {}; - if (browser && sessionStorage.getItem("tangled.onboarding.profile") === viewer) return {}; + // signed out gets the marketing page, which needs no data + if (!viewer) return { timeline: null }; const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, fetch: event.fetch }); - try { - await getProfile(ctx, viewer); - if (browser) sessionStorage.removeItem("tangled.onboarding.profile"); - } catch (cause) { - if (httpStatusFor(cause) === 404) redirect(307, "/welcome"); - toHttpError(cause, "Could not load profile"); + + // onboarding already knows the profile exists; skip the round-trip + if (!(browser && sessionStorage.getItem("tangled.onboarding.profile") === viewer)) { + try { + await getProfile(ctx, viewer); + if (browser) sessionStorage.removeItem("tangled.onboarding.profile"); + } catch (cause) { + if (httpStatusFor(cause) === 404) redirect(307, "/welcome"); + toHttpError(cause, "Could not load profile"); + } } - return {}; + return { timeline: await loadTimeline({ ctx, viewer, url: event.url }) }; }; diff --git a/web/src/routes/timeline/+page.svelte b/web/src/routes/timeline/+page.svelte index 8e58d7d6d..c3580eab5 100644 --- a/web/src/routes/timeline/+page.svelte +++ b/web/src/routes/timeline/+page.svelte @@ -1,13 +1,5 @@