TypeScript 97.6%
SQL 1.4%
JavaScript 0.5%
1import Link from "next/link";2import { AppShell } from "@/components/shell/app-shell";3import { SiteFooter } from "./site-footer";4import { cn } from "@/lib/utils";56/** Long-form page shell: eyebrow, title, lead, sectioned prose, footer. */7export function ProsePage({ eyebrow, title, lead, updated, children, toc }: { eyebrow: string; title: string; lead: string; updated?: string; children: React.ReactNode; toc?: { id: string; label: string }[] }) {8 return (9 <AppShell>10 <article className="mx-auto max-w-3xl">11 <header className="mb-10">12 <div className="eyebrow mb-2">{eyebrow}</div>13 <h1 className="text-4xl font-semibold tracking-[-0.03em] sm:text-5xl">{title}</h1>14 <p className="mt-4 text-lg leading-relaxed text-fg-2">{lead}</p>15 {updated ? <p className="mt-3 text-[12px] text-fg-4">Last updated {updated}</p> : null}16 </header>17 {toc?.length ? (18 <nav aria-label="On this page" className="mb-10 rounded-lg border border-line p-4">19 <div className="eyebrow mb-2">On this page</div>20 <ol className="grid gap-1.5 text-sm sm:grid-cols-2">21 {toc.map((t, i) => (22 <li key={t.id}>23 <Link href={`#${t.id}`} className="inline-flex items-baseline gap-2 text-fg-2 hover:text-fg">24 <span className="font-mono text-[11px] text-fg-4">{String(i + 1).padStart(2, "0")}</span> {t.label}25 </Link>26 </li>27 ))}28 </ol>29 </nav>30 ) : null}31 <div className="prose-spinza space-y-10">{children}</div>32 <SiteFooter className="mt-20" />33 </article>34 </AppShell>35 );36}3738export function Section({ id, title, children, className }: { id: string; title: string; children: React.ReactNode; className?: string }) {39 return (40 <section id={id} aria-labelledby={`${id}-h`} className={cn("scroll-mt-24", className)}>41 <h2 id={`${id}-h`} className="text-2xl font-semibold tracking-tight">42 {title}43 </h2>44 <div className="mt-3 space-y-3 text-[15px] leading-relaxed text-fg-2">{children}</div>45 </section>46 );47}4849export function Callout({ children, tone = "accent" }: { children: React.ReactNode; tone?: "accent" | "neutral" }) {50 return <div className={cn("rounded-md border p-4 text-[15px] leading-relaxed", tone === "accent" ? "border-accent/30 bg-accent-soft text-fg" : "border-line bg-surface text-fg-2")}>{children}</div>;51}5253export function Bullets({ items }: { items: React.ReactNode[] }) {54 return (55 <ul className="space-y-2">56 {items.map((it, i) => (57 <li key={i} className="flex gap-3">58 <span className="mt-[9px] h-1.5 w-1.5 shrink-0 rounded-full bg-accent" aria-hidden />59 <span>{it}</span>60 </li>61 ))}62 </ul>63 );64}65