/** * What the template picker shows about each template. Kept free of layout code so the UI can import it * without pulling react-pdf into the main bundle; every TemplateDefinition takes its identity from here. */ export interface TemplateCatalogEntry { id: string; name: string; family: "classic" | "neutral" | "ledger" | "band" | "northline" | "standalone"; /** Static PNG from /public, written by scripts/thumbnails.mjs (sample data, not the user's invoice). */ thumbnail: string; badge?: "Matches your original format"; /** No reference placeholder: the logo shows only when the user turns it on. */ logoOptIn?: boolean; /** * The licensed faces this template draws (a user-imported font may replace them). Mirrors the roles of the * template; a test keeps the two in step. */ faces?: readonly ("Now" | "Gotham" | "Open Sauce One")[]; } export const FAMILY_LABELS: Record = { classic: "Classic", neutral: "Neutral", ledger: "Ledger", band: "Band", northline: "Northline", standalone: "Standalone", }; /** Picker order: Classic first, Linea (the vendor's original format) second. */ export const TEMPLATE_CATALOG: readonly TemplateCatalogEntry[] = [ { id: "classic", name: "Voiced Standard", family: "classic", thumbnail: "/templates/classic.png" }, { id: "linea", name: "Linea", family: "neutral", thumbnail: "/templates/linea.png", badge: "Matches your original format", logoOptIn: true }, { id: "monogram", name: "Monogram", family: "neutral", thumbnail: "/templates/monogram.png" }, { id: "serenity", name: "Serenity", family: "neutral", thumbnail: "/templates/serenity.png" }, { id: "crimson-grid", name: "Crimson Grid", family: "ledger", thumbnail: "/templates/crimson-grid.png" }, { id: "tangerine-ledger", name: "Tangerine Ledger", family: "ledger", thumbnail: "/templates/tangerine-ledger.png" }, { id: "slate-band", name: "Slate Band", family: "band", thumbnail: "/templates/slate-band.png" }, { id: "teal-swoosh", name: "Teal Swoosh", family: "band", thumbnail: "/templates/teal-swoosh.png" }, { id: "purple-pop", name: "Purple Pop", family: "northline", thumbnail: "/templates/purple-pop.png", logoOptIn: true, faces: ["Gotham", "Open Sauce One"] }, { id: "citrus-split", name: "Citrus Split", family: "northline", thumbnail: "/templates/citrus-split.png", faces: ["Now", "Gotham"] }, { id: "monolith", name: "Monolith", family: "standalone", thumbnail: "/templates/monolith.png" }, { id: "cobalt-stripe", name: "Cobalt Stripe", family: "standalone", thumbnail: "/templates/cobalt-stripe.png" }, { id: "marble", name: "Marble", family: "standalone", thumbnail: "/templates/marble.png", logoOptIn: true, faces: ["Now"] }, { id: "highlighter", name: "Highlighter", family: "standalone", thumbnail: "/templates/highlighter.png", logoOptIn: true }, ]; /** The entry for an id; an unknown id falls back to Classic, like getTemplate. */ export function catalogEntry(id: string | undefined): TemplateCatalogEntry { return TEMPLATE_CATALOG.find((e) => e.id === id) ?? TEMPLATE_CATALOG[0]; }