/** * /e/[cls] — list page for an entity class (e.g. /e/people, /e/locations). * * Reads wiki/entities//*.md frontmatter on the server; renders a * paginated, searchable grid with mention counts. Click → /e//. */ import Link from "next/link"; import { notFound } from "next/navigation"; import fs from "node:fs/promises"; import path from "node:path"; import matter from "gray-matter"; import { AuthBar } from "@/components/auth-bar"; import { WIKI, classKeyToFolder, type EntityClass } from "@/lib/wiki"; import { EntityListFilter } from "@/components/entity-list-filter"; export const dynamic = "force-dynamic"; const CLASS_TITLE: Record = { people: "Pessoas", organizations: "Organizações", locations: "Locais", events: "Eventos", "uap-objects": "Objetos UAP", vehicles: "Veículos", operations: "Operações", concepts: "Conceitos", }; const CLASS_COLOR: Record = { people: "text-[#ff6ec7] border-[#ff6ec7]", organizations: "text-[#ff8a4d] border-[#ff8a4d]", locations: "text-[#3fde6a] border-[#3fde6a]", events: "text-[#ffa500] border-[#ffa500]", "uap-objects": "text-[#ff3344] border-[#ff3344]", vehicles: "text-[#5b9bd5] border-[#5b9bd5]", operations: "text-[#9b5de5] border-[#9b5de5]", concepts: "text-[#06d6a0] border-[#06d6a0]", }; interface EntityRow { id: string; canonical_name: string; aliases: string[]; total_mentions: number; documents_count: number; enrichment_status: string | null; } async function listEntities(cls: EntityClass): Promise { const dir = path.join(WIKI, "entities", cls); let files: string[] = []; try { files = (await fs.readdir(dir)).filter((f) => f.endsWith(".md")); } catch { return []; } const rows: EntityRow[] = []; for (const f of files) { try { const raw = await fs.readFile(path.join(dir, f), "utf-8"); const fm = matter(raw).data as Record; rows.push({ id: f.replace(/\.md$/, ""), canonical_name: String(fm.canonical_name ?? f.replace(/\.md$/, "")), aliases: Array.isArray(fm.aliases) ? (fm.aliases as string[]) : [], total_mentions: Number(fm.total_mentions ?? 0), documents_count: Number(fm.documents_count ?? 0), enrichment_status: (fm.enrichment_status as string | null) ?? null, }); } catch { /* skip malformed */ } } rows.sort((a, b) => b.total_mentions - a.total_mentions); return rows; } export default async function EntityListPage({ params, }: { params: Promise<{ cls: string }>; }) { const { cls } = await params; const folder = classKeyToFolder(cls); if (!folder) notFound(); const entities = await listEntities(folder as EntityClass); return (
← home
{folder} · {entities.length} entidades

▍ {CLASS_TITLE[folder as EntityClass]}

Ordenadas por número de menções no corpus. Filtre por nome/alias abaixo.

); }