/* PAPERS VIEW — the real corpus from /papers, with per-paper figure counts from the figures index and a detail drawer. Only fields the API actually serves are shown (no fabricated authors/venue/citations). */ function PaperCard({ p, figCount, onOpen }) { return ( ); } /* First caption line, with internal [chunk_id] placeholders hidden — the Figures gallery cleans these the same way. */ function drawerCaption(raw) { const first = String(raw || "").split("\n")[0].trim(); return !first || /^\[[^\]]+\]$/.test(first) ? "No caption captured" : first; } function PaperDrawer({ p, figs, onClose }) { useEffect(() => { if (!p) return; const onEsc = (e) => { if (e.key === "Escape") onClose(); }; document.addEventListener("keydown", onEsc); return () => document.removeEventListener("keydown", onEsc); }, [p, onClose]); if (!p) return null; return (
e.stopPropagation()}>
{p.paper_id}

{p.title || p.paper_id}

{p.is_arxiv && p.arxiv_url && (
{p.arxiv_url}
)}
{p.page_count}pages
{figs.length}figures indexed
1024-dembeddings
{figs.length > 0 && (

Indexed figures

{figs.map((f) => (
p.{f.page_number} · {clip(drawerCaption(f.caption), 40)}
))}
)}
); } function PapersView({ setTab, papers, figures }) { const [q, setQ] = useState(""); const [filter, setFilter] = useState("all"); const [open, setOpen] = useState(null); const figByPaper = useMemo(() => { const m = {}; (figures || []).forEach((f) => { m[f.paper_id] = (m[f.paper_id] || 0) + 1; }); return m; }, [figures]); if (!papers || papers.length === 0) { return
Loading papers… If this doesn't resolve, the server may be unreachable or no corpus is indexed.
; } // Only offer source filters when the corpus actually mixes sources — a // permanently empty "other" chip reads as broken. const filters = papers.some((p) => !p.is_arxiv) ? ["all", "arxiv", "other"] : ["all"]; const filtered = papers.filter((p) => { const okF = filter === "all" || (filter === "arxiv" ? p.is_arxiv : !p.is_arxiv); const okQ = !q || ((p.title || "") + " " + p.paper_id).toLowerCase().includes(q.toLowerCase()); return okF && okQ; }); return (
setQ(e.target.value)} />
{filters.map((t) => ( ))}
{filtered.length} / {papers.length}
{filtered.map((p) => )}
f.paper_id === open.paper_id) : []} onClose={() => setOpen(null)} />
); } window.PapersView = PapersView;