diff --git a/web/src/lib/components/timeline/TrendingRepos.svelte b/web/src/lib/components/timeline/TrendingRepos.svelte
index 383a3dbea..15e867f61 100644
--- a/web/src/lib/components/timeline/TrendingRepos.svelte
+++ b/web/src/lib/components/timeline/TrendingRepos.svelte
@@ -3,10 +3,27 @@
import type { RepoCardData } from "$lib/components/profile/types";
import PreviewCard from "$lib/components/timeline/PreviewCard.svelte";
import TrendingReposList from "$lib/components/timeline/TrendingReposList.svelte";
+ import Pending from "$lib/components/ui/Pending.svelte";
+ import Bones from "$lib/components/ui/Bones.svelte";
+ import timelineTrendingreposlistSkeletonFixture from "$lib/bones/timeline-trendingreposlist--skeleton-fixture.bones.json";
- let { repos }: { repos: RepoCardData[] } = $props();
+ let {
+ repos = []
+ }: {
+ repos?: RepoCardData[] | Promise
;
+ } = $props();
-
+ {#if repos instanceof Promise}
+
+ {#snippet skeleton()}
+
+ {/snippet}
+ {@const resolved = await repos}
+
+
+ {:else}
+
+ {/if}
diff --git a/web/src/lib/components/timeline/load.ts b/web/src/lib/components/timeline/load.ts
index e0b628a33..f65750d7c 100644
--- a/web/src/lib/components/timeline/load.ts
+++ b/web/src/lib/components/timeline/load.ts
@@ -13,15 +13,23 @@ export interface LoadFeedOptions {
// shared by /timeline and the signed-in homescreen at /
export const loadFeed = async ({ ctx, followingOnly }: LoadFeedOptions) => {
- const { feed } = await jsonGet(
- ctx,
- "sh.tangled.feed.getTimeline",
- { followingOnly, limit: PAGE_LIMIT }
- );
- return feed;
+ try {
+ const { feed } = await jsonGet(
+ ctx,
+ "sh.tangled.feed.getTimeline",
+ { followingOnly, limit: PAGE_LIMIT }
+ );
+ return feed;
+ } catch {
+ return [];
+ }
};
export const loadTrendingRepos = async (ctx: BobbinContext) => {
- const trending = await getTrending(ctx).catch(() => ({ people: [], repos: [] }));
- return trending.repos.map(toRepoCard);
+ try {
+ const trending = await getTrending(ctx);
+ return trending.repos.map(toRepoCard);
+ } catch {
+ return [];
+ }
};
diff --git a/web/src/lib/components/timeline/timelineFeed.svelte.ts b/web/src/lib/components/timeline/timelineFeed.svelte.ts
deleted file mode 100644
index a62d8babe..000000000
--- a/web/src/lib/components/timeline/timelineFeed.svelte.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import { createBobbinClient } from "$lib/api/client";
-import { getAuth } from "$lib/auth.svelte";
-import { loadFeed, loadTrendingRepos } from "$lib/components/timeline/load";
-import type * as ShTangledFeedGetTimeline from "$lib/api/lexicons/types/sh/tangled/feed/getTimeline";
-import type { RepoCardData } from "$lib/components/profile/types";
-
-export interface TimelineFeedOptions {
- followingOnly: () => boolean;
- /** set to `() => false` to skip fetching entirely (e.g. marketing page branch of `/`) */
- enabled?: () => boolean;
-}
-
-export const createTimelineFeed = (opts: TimelineFeedOptions) => {
- const auth = getAuth();
-
- let feed = $state([]);
- let trending = $state([]);
- let loading = $state(true);
- let trendingLoading = $state(true);
- let failed = $state(false);
-
- const signedIn = $derived(Boolean(auth.currentDid));
-
- $effect(() => {
- const isEnabled = opts.enabled ? opts.enabled() : true;
- if (!isEnabled || auth.agentPending) return;
-
- const agent = auth.agent ?? undefined;
- const wantFollowing = opts.followingOnly() && Boolean(auth.currentDid);
-
- loading = true;
- failed = false;
- let cancelled = false;
-
- const ctx = createBobbinClient({ serviceUrl: auth.bobbinUrl, agent });
- loadFeed({ ctx, followingOnly: wantFollowing })
- .then((result) => {
- if (cancelled) return;
- feed = result;
- loading = false;
- })
- .catch(() => {
- if (!cancelled) {
- loading = false;
- failed = true;
- }
- });
-
- return () => {
- cancelled = true;
- };
- });
-
- $effect(() => {
- const isEnabled = opts.enabled ? opts.enabled() : true;
- if (!isEnabled || auth.agentPending) return;
-
- const agent = auth.agent ?? undefined;
-
- trendingLoading = true;
- let cancelled = false;
-
- const ctx = createBobbinClient({ serviceUrl: auth.bobbinUrl, agent });
- loadTrendingRepos(ctx)
- .then((result) => {
- if (cancelled) return;
- trending = result;
- trendingLoading = false;
- })
- .catch(() => {
- if (!cancelled) {
- trendingLoading = false;
- }
- });
-
- return () => {
- cancelled = true;
- };
- });
-
- return {
- get feed() {
- return feed;
- },
- get trending() {
- return trending;
- },
- get loading() {
- return loading;
- },
- get trendingLoading() {
- return trendingLoading;
- },
- get failed() {
- return failed;
- },
- get signedIn() {
- return signedIn;
- }
- };
-};
diff --git a/web/src/lib/notifications.svelte.ts b/web/src/lib/notifications.svelte.ts
index 2c78b61b2..68bf65795 100644
--- a/web/src/lib/notifications.svelte.ts
+++ b/web/src/lib/notifications.svelte.ts
@@ -40,8 +40,10 @@ export const createNotifications = (
};
const preview = async (limit: number): Promise => {
- const agent = auth.agent;
- if (!agent || !deliberiUrl) return null;
+ const did = auth.currentDid;
+ if (!did || !deliberiUrl) return null;
+ const agent = auth.agent ?? (await auth.agentFor(did).catch(() => null));
+ if (!agent) return null;
const deliberi = createDeliberiClient({ deliberiUrl, agent });
const hydrate = (items: NotificationItem[]): Promise =>
hydrateNotifications(createBobbinClient({ serviceUrl: bobbinUrl }), items);
diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte
index 96c4af3ac..14d532697 100644
--- a/web/src/routes/+page.svelte
+++ b/web/src/routes/+page.svelte
@@ -3,15 +3,13 @@
import { getAuth } from "$lib/auth.svelte";
import MarketingHome from "$lib/components/home/MarketingHome.svelte";
import TimelineView from "$lib/components/timeline/TimelineView.svelte";
- import { createTimelineFeed } from "$lib/components/timeline/timelineFeed.svelte";
+ import type { PageData } from "./$types";
+
+ let { data }: { data: PageData } = $props();
const auth = getAuth();
const signedIn = $derived(Boolean(auth.currentUser));
const followingOnly = $derived(page.url.searchParams.get("following") === "true");
- const feedState = createTimelineFeed({
- followingOnly: () => followingOnly,
- enabled: () => signedIn
- });
@@ -21,12 +19,10 @@
{#if signedIn}
{:else}
diff --git a/web/src/routes/+page.ts b/web/src/routes/+page.ts
index 7a1c58061..376730c3f 100644
--- a/web/src/routes/+page.ts
+++ b/web/src/routes/+page.ts
@@ -3,6 +3,7 @@ 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 { loadFeed, loadTrendingRepos } from "$lib/components/timeline/load";
import type { PageLoad } from "./$types";
export const load: PageLoad = async (event) => {
@@ -27,5 +28,10 @@ export const load: PageLoad = async (event) => {
}
}
- return {};
+ const followingOnly = event.url.searchParams.get("following") === "true";
+
+ return {
+ feed: loadFeed({ ctx, followingOnly }),
+ trending: loadTrendingRepos(ctx)
+ };
};
diff --git a/web/src/routes/timeline/+page.svelte b/web/src/routes/timeline/+page.svelte
index 1c37a9c90..74aef253b 100644
--- a/web/src/routes/timeline/+page.svelte
+++ b/web/src/routes/timeline/+page.svelte
@@ -1,10 +1,14 @@
@@ -12,11 +16,9 @@
diff --git a/web/src/routes/timeline/+page.ts b/web/src/routes/timeline/+page.ts
new file mode 100644
index 000000000..2ce6bdd4a
--- /dev/null
+++ b/web/src/routes/timeline/+page.ts
@@ -0,0 +1,18 @@
+import { createBobbinClient } from "$lib/api/client";
+import { loadFeed, loadTrendingRepos } from "$lib/components/timeline/load";
+import type { PageLoad } from "./$types";
+
+export const load: PageLoad = async (event) => {
+ const parent = await event.parent();
+ const ctx = createBobbinClient({
+ serviceUrl: parent.publicConfig.bobbinUrl,
+ fetch: event.fetch
+ });
+
+ const followingOnly = event.url.searchParams.get("following") === "true";
+
+ return {
+ feed: loadFeed({ ctx, followingOnly }),
+ trending: loadTrendingRepos(ctx)
+ };
+};