Font import: - Migration M6 adds user_fonts; files are stored content-addressed under the local data dir. New Rust commands inspect, import, list, read and remove fonts, refusing WOFF2, collections, variable fonts and restricted fsType, and unpacking WOFF1 to plain sfnt. - Imported fonts register in the render worker as user:<Face> families with an italic alias, and are pinned in the frozen render prefs so issued invoices can still re-render. Fonts referenced by issued invoices are hidden, never deleted. - Size and tracking compensations tuned for the substitutes apply only while the face is not overridden; default output and fingerprint goldens are unchanged. - Settings gets a Fonts section with a licence acknowledgement. Void packaging: - Install fonts to /usr/share/fonts/voiced with per-family OFL licences, set font_dirs, and add INSTALL/REMOVE scripts that run fc-cache. xbps-create carries both scripts (verified in a void-glibc container). - Fix xbps-create dependency specs in build-xbps.sh.
52 lines
3.0 KiB
TypeScript
52 lines
3.0 KiB
TypeScript
/**
|
|
* 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 Canva 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<TemplateCatalogEntry["family"], string> = {
|
|
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];
|
|
}
|