| 1 | --- |
| 2 | export const prerender = false; |
| 3 | |
| 4 | import PageLayout from "@/layouts/Base.astro"; |
| 5 | import LinkCard from "@/components/page/LinkCard.astro"; |
| 6 | |
| 7 | type Link = { |
| 8 | id: number; |
| 9 | short_id: string; |
| 10 | title: string; |
| 11 | url: string; |
| 12 | category_id: number; |
| 13 | created_at: number; |
| 14 | favicon_url?: string | null; |
| 15 | }; |
| 16 | |
| 17 | const meta = { |
| 18 | title: "/bookmarks", |
| 19 | description: "Links I've saved and want to read", |
| 20 | }; |
| 21 | |
| 22 | let categories: [string, Link[]][] = []; |
| 23 | let error: string | null = null; |
| 24 | try { |
| 25 | const res = await fetch("https://bookmarks.stevedylan.dev/api/links"); |
| 26 | if (res.ok) { |
| 27 | const data: Record<string, Link[]> = await res.json(); |
| 28 | categories = Object.entries(data).filter(([, links]) => links.length > 0); |
| 29 | } else { |
| 30 | error = `API returned ${res.status}`; |
| 31 | } |
| 32 | } catch (e) { |
| 33 | error = e instanceof Error ? e.message : "Failed to reach bookmarks API"; |
| 34 | } |
| 35 | --- |
| 36 | |
| 37 | <PageLayout meta={meta}> |
| 38 | <div class="flex min-h-screen flex-col items-start justify-start gap-6"> |
| 39 | <h1 class="title">/bookmarks</h1> |
| 40 | {error ? ( |
| 41 | <p class="text-red-400 text-sm">Could not load bookmarks: {error}</p> |
| 42 | ) : categories.length === 0 ? ( |
| 43 | <p class="text-zinc-400 text-sm">no bookmarks yet</p> |
| 44 | ) : ( |
| 45 | <div class="flex flex-col w-full gap-8"> |
| 46 | {categories.map(([name, links]) => ( |
| 47 | <div class="flex flex-col w-full"> |
| 48 | <h2 class="text-sm font-semibold uppercase tracking-widest opacity-50 mb-2">{name}</h2> |
| 49 | {links.map((link) => ( |
| 50 | <LinkCard link={link} /> |
| 51 | ))} |
| 52 | </div> |
| 53 | ))} |
| 54 | </div> |
| 55 | )} |
| 56 | </div> |
| 57 | </PageLayout> |