import Link from "next/link"; import { badgeVariants } from "@/components/ui/badge"; import { fmtAgo } from "@/lib/format"; import type { ArticleRow } from "@/lib/articles/sites"; // One row per article: what it is, where it stands, what is waiting on it, // and where it came from. Server-rendered, zero JS -- the /browse idiom. const posterUrl = (a: ArticleRow) => `/api/sites/media?site=${encodeURIComponent(a.site)}&report=${encodeURIComponent(a.id)}&file=poster.jpg`; const baseName = (p: string) => p.split("/").pop() ?? p; export function articleHref(a: { site: string; id: string }) { return `/sites/${a.site}/${a.id}`; } export default function ArticleTable({ articles }: { articles: ArticleRow[] }) { if (articles.length === 0) return

no articles

; return ( {articles.map((a) => ( ))}
article status updated cites notes video project source
{a.hasPoster ? ( // eslint-disable-next-line @next/next/no-img-element ) : (
)}
{a.title}
{a.id} {a.series ? ` · ${a.series}` : ""} {a.problem ? · {a.problems} problem{a.problems === 1 ? "" : "s"} : null}
{a.status} {a.updated ?? (a.mtimeMs ? fmtAgo(a.mtimeMs) : "—")} {a.citations} {a.openNotes > 0 ? ( {a.openNotes} open ) : ( {a.notes || "—"} )} {a.projects.linked.map((p) => ( {p.id} ))} {a.projects.possible.map((p) => ( {p.id} (possible) ))} {a.projects.linked.length + a.projects.possible.length === 0 && —} {a.source?.draft ? baseName(a.source.draft) : a.source?.generator ? baseName(a.source.generator) : "—"}
); }