| 1 | --- |
| 2 | export const prerender = false; |
| 3 | |
| 4 | import PageLayout from "@/layouts/Base.astro"; |
| 5 | import BookCard from "@/components/page/BookCard.astro"; |
| 6 | |
| 7 | type Book = { |
| 8 | id: number; |
| 9 | title: string; |
| 10 | authors: string; |
| 11 | cover_url: string | null; |
| 12 | notes: string | null; |
| 13 | status: "read" | "reading" | "want"; |
| 14 | }; |
| 15 | |
| 16 | const meta = { |
| 17 | title: "/library", |
| 18 | description: "Books I'm reading, have read, and want to read", |
| 19 | }; |
| 20 | |
| 21 | let books: Book[] = []; |
| 22 | let error: string | null = null; |
| 23 | try { |
| 24 | const res = await fetch( |
| 25 | "https://library.stevedylan.dev/api/books?status=all", |
| 26 | ); |
| 27 | if (res.ok) { |
| 28 | books = await res.json(); |
| 29 | } else { |
| 30 | error = `API returned ${res.status}`; |
| 31 | } |
| 32 | } catch (e) { |
| 33 | error = e instanceof Error ? e.message : "Failed to reach library API"; |
| 34 | } |
| 35 | |
| 36 | const reading = books.filter((b) => b.status === "reading"); |
| 37 | const read = books.filter((b) => b.status === "read"); |
| 38 | const want = books.filter((b) => b.status === "want"); |
| 39 | |
| 40 | const sections: { label: string; items: Book[] }[] = [ |
| 41 | { label: "Reading", items: reading }, |
| 42 | { label: "Read", items: read }, |
| 43 | { label: "Want to Read", items: want }, |
| 44 | ]; |
| 45 | --- |
| 46 | |
| 47 | <PageLayout meta={meta}> |
| 48 | <div class="flex min-h-screen flex-col items-start justify-start gap-6"> |
| 49 | <h1 class="title">/library</h1> |
| 50 | {error ? ( |
| 51 | <p class="text-red-400 text-sm">Could not load books: {error}</p> |
| 52 | ) : books.length === 0 ? ( |
| 53 | <p class="text-zinc-400 text-sm">no books yet</p> |
| 54 | ) : ( |
| 55 | <div class="flex flex-col w-full gap-8"> |
| 56 | {sections.filter((s) => s.items.length > 0).map((section) => ( |
| 57 | <div class="flex flex-col w-full"> |
| 58 | <h2 class="text-sm font-semibold uppercase tracking-widest opacity-50 mb-2">{section.label}</h2> |
| 59 | {section.items.map((book) => ( |
| 60 | <BookCard book={book} /> |
| 61 | ))} |
| 62 | </div> |
| 63 | ))} |
| 64 | </div> |
| 65 | )} |
| 66 | </div> |
| 67 | </PageLayout> |