// BidaAngMamamayan desk registry — single source of truth for categories. // // A tribute site has fewer desks than a general paper, but each one is // deliberate: the "BAM" lead desk, his signature beats (education/college, // energy/electricity, gaming/esports, the Senate floor), and the PH + world // context he works inside. export const CATEGORIES = [ { key: "bam", label: "BAM Front", blurb: "Every story that names him" }, { key: "education", label: "Education", blurb: "College, scholarship, the classroom" }, { key: "energy", label: "Energy & Electricity", blurb: "The power bill fight" }, { key: "gaming", label: "Gamer's Corner", blurb: "Esports, gaming, the 2025 runner-up" }, { key: "politics", label: "The Senate Floor", blurb: "Bills, sessions, the chamber" }, { key: "ph", label: "The Philippines", blurb: "Home context, region by region" }, { key: "world", label: "World", blurb: "The rest of the wire" }, ]; export const CATEGORY_KEYS = new Set(CATEGORIES.map((c) => c.key)); export const CATEGORY_LABELS = Object.fromEntries(CATEGORIES.map((c) => [c.key, c.label])); // Anything that isn't a valid desk key falls back to the lead desk. The gate // (lib/crawl.js) already decided the story belongs on this site, so "bam" is // the honest default, not "world". export function normalizeCategory(c) { if (typeof c === "string" && CATEGORY_KEYS.has(c)) return c; return "bam"; } export function sectionName(c) { return CATEGORY_LABELS[normalizeCategory(c)] || "BAM Front"; } // The relevance gate lives in lib/crawl.js (it needs the description text); // this is just the desk classifier for rows that pass the gate but arrive // without a query tag. const CLASSIFIERS = [ ["gaming", /\besports?\b|\bgaming\b|\bvideo games?\b|\bsteam\b|\bplaystation\b|\bnintendo\b|\bxbox\b|\bconsole\b|\bgame (studio|developer|release)\b|\briot\b|\bvalorant\b|\blol\b|\bdota\b/i], ["education", /\beducation\b|\bschool(s|ing)?\b|\bcollege\b|\buniversity\b|\bscholarship\b|\bstudents?\b|\bclassroom\b|\bteachers?\b|\blearning\b|\bched\b|\bdeped\b/i], ["energy", /\bpower (outage|bill|rates?|grid)\b|\belectricity\b|\bbrownout\b|\bblackout\b|\bvat.*\bpower\b|\benergy\b|\bsystem loss\b|\belectric rate\b/i], ["politics", /\bsenate\b|\bbill\b|\bcongress\b|\bpresidenc?\b|\belection\b|\bparty\b|\bpolitical\b|\bimpeach\b|\bcommitte\w*\b/i], ["ph", /\bphilippines?\b|\bmanila\b|\bmarikina\b|\bquezon city\b|\bpampanga\b|\bc[eé]bu city\b|\bdavao\b|\bbaguio\b|\bpalawan\b|\bmindanao\b|\bvisayas\b|\bluzon\b|\bcalabarzon\b|\bbarangay\b|\bsenior citizen\b|\bprovincial\b|\bpeso\b/i], ]; export function classifyStory({ title, summary, source } = {}) { const text = `${title || ""} ${summary || ""} ${source || ""}`; if (!text.trim()) return "bam"; for (const [key, re] of CLASSIFIERS) { if (re.test(text)) return key; } return "bam"; }