This repository has no description
1<script lang="ts">
2 import { untrack } from "svelte";
3 import { resolve } from "$app/paths";
4 import { getAuth } from "$lib/auth.svelte";
5 import { createBobbinClient } from "$lib/api/client";
6 import { IdentityCache } from "$lib/api/identity";
7 import RepoCard from "$lib/components/repo/RepoCard.svelte";
8 import Card from "$lib/components/ui/Card.svelte";
9 import Section from "$lib/components/ui/Section.svelte";
10 import Pagination from "$lib/components/ui/Pagination.svelte";
11 import Error from "$lib/components/ui/Error.svelte";
12 import { createCursorPager, pageCount } from "../pagination.svelte";
13 import { PROFILE_PAGE_LIMIT, fetchStarredPage } from "../pages";
14 import type { StarData } from "../types";
15
16 interface Props {
17 initial: StarData[];
18 cursor?: string;
19 total: number;
20 did: string;
21 }
22
23 let { initial, cursor: initialCursor, total, did }: Props = $props();
24
25 const auth = getAuth();
26
27 // shared across pages so repeat repo owners only resolve once
28 let identityCache: IdentityCache | undefined;
29 const pager = createCursorPager(
30 { items: untrack(() => initial), cursor: untrack(() => initialCursor) },
31 (cursor) => {
32 const ctx = createBobbinClient({ serviceUrl: auth.bobbinUrl });
33 identityCache ??= new IdentityCache(ctx);
34 return fetchStarredPage(ctx, {
35 did,
36 viewerDid: auth.currentDid ?? undefined,
37 cursor,
38 cache: identityCache
39 });
40 }
41 );
42 const stars = $derived(pager.items);
43 const pages = $derived(pageCount(total, PROFILE_PAGE_LIMIT));
44</script>
45
46<Section title="Starred" empty={stars.length === 0} emptyMessage="No stars yet.">
47 {#each stars as star (star.uri)}
48 {#if star.kind === "repo"}
49 <RepoCard repo={star.repo} />
50 {:else}
51 <Card shadow={false} class="flex items-center gap-2">
52 <a
53 href={resolve(`/${star.ownerHandle}/strings/${star.rkey}` as "/")}
54 class="truncate font-bold text-foreground-default no-underline hover:underline"
55 >
56 {star.ownerHandle}/{star.rkey}
57 </a>
58 </Card>
59 {/if}
60 {/each}
61 {#snippet footer()}
62 {#if pages > 1}
63 <div class="mt-4 flex justify-center">
64 <Pagination
65 page={pager.state.page}
66 total={pages}
67 labels
68 disabled={pager.state.kind === "loading"}
69 onchange={pager.select}
70 class="gap-5"
71 />
72 </div>
73 {/if}
74 {#if pager.state.kind === "failed"}
75 <Error label="couldn't load that page. try again." class="mt-2" />
76 {/if}
77 {/snippet}
78</Section>