import type { JSX } from "react" import { Link } from "react-router-dom" import { LoginButton } from "@/auth/LoginButton" import { SettingsMenu } from "@/components/settings-menu" import { Skeleton } from "@/components/ui/skeleton" import { useCatalog } from "@/lib/corpus" import type { Author, TextManifest } from "@/lib/schemas/model" import { AUTHOR_ORDER, LANG_LABEL, SCHEME_LABEL } from "@/read/labels" /** * The corpus index — entry point to the reader. Groups the catalog by author, * then by work, and links each text to `/read/:id`. Editorial colophon styling: * a Playfair masthead over the Noto-Sans body, warm paper ground. */ interface WorkGroup { work: string texts: TextManifest[] } interface AuthorGroup { author: Author lang: string works: WorkGroup[] count: number } function group(texts: readonly TextManifest[]): AuthorGroup[] { const byAuthor = new Map() for (const t of texts) { const list = byAuthor.get(t.author) if (list) list.push(t) else byAuthor.set(t.author, [t]) } const ordered = [...byAuthor.keys()].sort( (a, b) => AUTHOR_ORDER.indexOf(a) - AUTHOR_ORDER.indexOf(b) ) return ordered.map((author) => { const authorTexts = byAuthor.get(author) ?? [] const byWork = new Map() for (const t of authorTexts) { const list = byWork.get(t.work) if (list) list.push(t) else byWork.set(t.work, [t]) } const works: WorkGroup[] = [...byWork.entries()].map(([work, ts]) => ({ work, texts: ts, })) const lang = authorTexts[0] ? LANG_LABEL[authorTexts[0].lang] : "" return { author, lang, works, count: authorTexts.length } }) } function Masthead(): JSX.Element { return (

Original-language reader

lekterion

Husserl · Heidegger · Kant · Aristotle · Descartes — read closely, gloss any span, cite by locus.

) } function AuthorSection({ group: g }: { group: AuthorGroup }): JSX.Element { return (

{g.author}

{g.lang} · {g.count} {g.count === 1 ? "text" : "texts"}
{g.works.map((w) => (

{w.work}

    {w.texts.map((t) => (
  • {t.title}
  • ))}
))}
) } function LibrarySkeleton(): JSX.Element { return (
{Array.from({ length: 4 }).map((_, i) => (
{Array.from({ length: 4 }).map((__, j) => ( ))}
))}
) } export function Library(): JSX.Element { const resource = useCatalog() return (
{resource.status === "loading" && } {resource.status === "error" && (

The corpus catalog could not be loaded: {resource.error.message}

)} {resource.status === "ready" && (
{group(resource.data.texts).map((g) => ( ))}
)}
) }