Add font import for Now, Gotham and Open Sauce One overrides; package fonts for Void
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.
This commit is contained in:
@@ -11,6 +11,11 @@ export interface TemplateCatalogEntry {
|
||||
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<TemplateCatalogEntry["family"], string> = {
|
||||
@@ -32,11 +37,11 @@ export const TEMPLATE_CATALOG: readonly TemplateCatalogEntry[] = [
|
||||
{ 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 },
|
||||
{ id: "citrus-split", name: "Citrus Split", family: "northline", thumbnail: "/templates/citrus-split.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 },
|
||||
{ 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 },
|
||||
];
|
||||
|
||||
|
||||
@@ -18,31 +18,32 @@ export const BAND_TO = "#ECEAEE";
|
||||
* Marble's type (docs/templates/01-marble.md): Lustria in tracked caps for the title, headings, table heads and the
|
||||
* amount due; "Now" (drawn in Jost, the bundled look-alike) for everything else. Jost sets about 12% narrower than Now,
|
||||
* so every Now role carries the tracking that restores the reference widths (0.10 to 0.13 em on top of the design's
|
||||
* 0.04 em). Lustria ascent 0.955, descent 0.327; Jost 1.07 / 0.375.
|
||||
* 0.04 em). A real Now imported by the user replaces Jost, so those roles take the design's 0.04 em back through
|
||||
* ownFont. Lustria ascent 0.955, descent 0.327; Jost 1.07 / 0.375.
|
||||
*/
|
||||
export const MARBLE_ROLES = defineRoles({
|
||||
/** "INVOICE" / "TAX INVOICE": 25.18 pt, tracked 0.192 em, shrunk to the room the stack has. */
|
||||
title: { face: L, weight: 400, size: 25.18, leading: 25.2, tracking: 0.192, caps: true, minSize: 13 },
|
||||
/** The vendor's name at the header's left (the design leaves it empty). */
|
||||
brand: { face: L, weight: 400, size: 12.65, leading: 18.2, tracking: 0.11, caps: true, minSize: 9 },
|
||||
meta: { face: N, weight: 400, size: 11.55, leading: 17.5, tracking: 0.105, minSize: 8 },
|
||||
meta: { face: N, weight: 400, size: 11.55, leading: 17.5, tracking: 0.105, ownFont: { tracking: 0.04 }, minSize: 8 },
|
||||
/** BILL TO:, PAYABLE TO:, SUPPLIER:. */
|
||||
heading: { face: L, weight: 400, size: 12.65, leading: 18.2, tracking: 0.11, caps: true },
|
||||
body: { face: N, weight: 400, size: 11.55, leading: 18.2, tracking: 0.105, minSize: 8 },
|
||||
body: { face: N, weight: 400, size: 11.55, leading: 18.2, tracking: 0.105, ownFont: { tracking: 0.04 }, minSize: 8 },
|
||||
tableHead: { face: L, weight: 400, size: 11.68, leading: 16, tracking: 0.192, caps: true },
|
||||
tableBody: { face: N, weight: 400, size: 10.57, leading: 17.4, tracking: 0.102 },
|
||||
tableSub: { face: N, weight: 400, size: 8.5, leading: 11.5, tracking: 0.1 },
|
||||
tableBody: { face: N, weight: 400, size: 10.57, leading: 17.4, tracking: 0.102, ownFont: { tracking: 0.04 } },
|
||||
tableSub: { face: N, weight: 400, size: 8.5, leading: 11.5, tracking: 0.1, ownFont: { tracking: 0.04 } },
|
||||
totalLabel: { face: L, weight: 400, size: 9, leading: 16, tracking: 0.192, caps: true },
|
||||
totalValue: { face: N, weight: 400, size: 10.57, leading: 16, tracking: 0.102 },
|
||||
totalValue: { face: N, weight: 400, size: 10.57, leading: 16, tracking: 0.102, ownFont: { tracking: 0.04 } },
|
||||
/** AMOUNT DUE: 14.6 pt, tracked 0.192 em. */
|
||||
due: { face: L, weight: 400, size: 14.6, leading: 20, tracking: 0.192, caps: true, minSize: 10 },
|
||||
small: { face: N, weight: 400, size: 9.6, leading: 15.3, tracking: 0.13 },
|
||||
small: { face: N, weight: 400, size: 9.6, leading: 15.3, tracking: 0.13, ownFont: { tracking: 0.04 } },
|
||||
smallLabel: { face: L, weight: 400, size: 9, leading: 15.3, tracking: 0.192, caps: true },
|
||||
signName: { face: N, weight: 400, size: 10.57, leading: 15, tracking: 0.102 },
|
||||
signDesignation: { face: N, weight: 400, size: 9.6, leading: 14, tracking: 0.13 },
|
||||
fine: { face: N, weight: 400, size: 8, leading: 11, tracking: 0.1 },
|
||||
signName: { face: N, weight: 400, size: 10.57, leading: 15, tracking: 0.102, ownFont: { tracking: 0.04 } },
|
||||
signDesignation: { face: N, weight: 400, size: 9.6, leading: 14, tracking: 0.13, ownFont: { tracking: 0.04 } },
|
||||
fine: { face: N, weight: 400, size: 8, leading: 11, tracking: 0.1, ownFont: { tracking: 0.04 } },
|
||||
/** The footer band's contact lines. */
|
||||
contact: { face: N, weight: 400, size: 9.6, leading: 15.3, tracking: 0.13, minSize: 7 },
|
||||
contact: { face: N, weight: 400, size: 9.6, leading: 15.3, tracking: 0.13, ownFont: { tracking: 0.04 }, minSize: 7 },
|
||||
footer: { face: N, weight: 400, size: 7 },
|
||||
});
|
||||
|
||||
|
||||
@@ -28,21 +28,21 @@ export const CITRUS_ROLES = defineRoles({
|
||||
metaStrong: { face: DM, weight: 700, size: 12.36, leading: 16, minSize: 8 },
|
||||
billedLabel: { face: DM, weight: 700, size: 12.4, leading: 17, caps: true },
|
||||
clientName: { face: DM, weight: 700, size: 14.87, leading: 19, caps: true },
|
||||
clientLine: { face: G, weight: 400, size: gotham(10.5), leading: 15.5 },
|
||||
headService: { face: G, weight: 700, size: gotham(15.17), leading: 18, tracking: 0.15, caps: true },
|
||||
headNum: { face: G, weight: 700, size: gotham(14.17), leading: 18, caps: true },
|
||||
tableBody: { face: G, weight: 400, size: gotham(12), leading: 15 },
|
||||
clientLine: { face: G, weight: 400, size: gotham(10.5), ownFont: { size: 10.5 }, leading: 15.5 },
|
||||
headService: { face: G, weight: 700, size: gotham(15.17), ownFont: { size: 15.17 }, leading: 18, tracking: 0.15, caps: true },
|
||||
headNum: { face: G, weight: 700, size: gotham(14.17), ownFont: { size: 14.17 }, leading: 18, caps: true },
|
||||
tableBody: { face: G, weight: 400, size: gotham(12), ownFont: { size: 12 }, leading: 15 },
|
||||
tableSub: { face: G, weight: 400, size: 9, leading: 11.5 },
|
||||
totalLabel: { face: G, weight: 700, size: gotham(12.5), leading: 17, caps: true },
|
||||
totalValue: { face: G, weight: 400, size: gotham(12.5), leading: 17 },
|
||||
grand: { face: G, weight: 700, size: gotham(14.7), leading: 18, caps: true },
|
||||
grandValue: { face: G, weight: 700, size: gotham(14.7), leading: 18 },
|
||||
totalLabel: { face: G, weight: 700, size: gotham(12.5), ownFont: { size: 12.5 }, leading: 17, caps: true },
|
||||
totalValue: { face: G, weight: 400, size: gotham(12.5), ownFont: { size: 12.5 }, leading: 17 },
|
||||
grand: { face: G, weight: 700, size: gotham(14.7), ownFont: { size: 14.7 }, leading: 18, caps: true },
|
||||
grandValue: { face: G, weight: 700, size: gotham(14.7), ownFont: { size: 14.7 }, leading: 18 },
|
||||
words: { face: DM, weight: 700, size: 11, leading: 14 },
|
||||
wordsLabel: { face: DM, weight: 700, size: 11, leading: 14 },
|
||||
sectionLabel: { face: DM, weight: 700, size: 12, leading: 16, caps: true },
|
||||
bank: { face: G, weight: 400, size: gotham(11), leading: 15 },
|
||||
bullet: { face: G, weight: 400, size: gotham(12), leading: 16.5 },
|
||||
contact: { face: G, weight: 400, size: gotham(12.77), leading: 18, minSize: 7 },
|
||||
bank: { face: G, weight: 400, size: gotham(11), ownFont: { size: 11 }, leading: 15 },
|
||||
bullet: { face: G, weight: 400, size: gotham(12), ownFont: { size: 12 }, leading: 16.5 },
|
||||
contact: { face: G, weight: 400, size: gotham(12.77), ownFont: { size: 12.77 }, leading: 18, minSize: 7 },
|
||||
small: { face: DM, weight: 400, size: 9, leading: 12 },
|
||||
fine: { face: DM, weight: 400, size: 7, leading: 10 },
|
||||
signName: { face: DM, weight: 700, size: 9.5, leading: 13 },
|
||||
|
||||
@@ -22,25 +22,25 @@ export const PURPLE_ROLES = defineRoles({
|
||||
wordmark: { face: "Open Sauce One", weight: 800, size: 94.07, leading: 84, tracking: -0.08, minSize: 48 },
|
||||
taxCaption: { face: DM, weight: 700, size: 14, leading: 18, tracking: 0.15, caps: true },
|
||||
brand: { face: DM, weight: 700, size: 17.77, leading: 21, minSize: 12 },
|
||||
pill: { face: G, weight: 700, size: gotham(13.39), leading: 17, tracking: 0.13, caps: true, minSize: 8.5 },
|
||||
label: { face: G, weight: 700, size: gotham(12), leading: 16, caps: true },
|
||||
clientName: { face: G, weight: 700, size: gotham(14.39), leading: 18, caps: true },
|
||||
clientLine: { face: G, weight: 400, size: gotham(10.16), leading: 15.5 },
|
||||
pill: { face: G, weight: 700, size: gotham(13.39), ownFont: { size: 13.39 }, leading: 17, tracking: 0.13, caps: true, minSize: 8.5 },
|
||||
label: { face: G, weight: 700, size: gotham(12), ownFont: { size: 12 }, leading: 16, caps: true },
|
||||
clientName: { face: G, weight: 700, size: gotham(14.39), ownFont: { size: 14.39 }, leading: 18, caps: true },
|
||||
clientLine: { face: G, weight: 400, size: gotham(10.16), ownFont: { size: 10.16 }, leading: 15.5 },
|
||||
amount: { face: DM, weight: 700, size: 32.74, leading: 36, minSize: 20, tnum: true },
|
||||
date: { face: DM, weight: 700, size: 14.05, leading: 19.5, caps: true, minSize: 10 },
|
||||
tableHead: { face: DM, weight: 700, size: 14, leading: 18, caps: true },
|
||||
tableBody: { face: DM, weight: 400, size: 11.83, leading: 15 },
|
||||
tableSub: { face: DM, weight: 400, size: 9, leading: 11.5 },
|
||||
totalLabel: { face: G, weight: 700, size: gotham(13), leading: 17, caps: true },
|
||||
totalValue: { face: G, weight: 400, size: gotham(13), leading: 17 },
|
||||
grand: { face: G, weight: 700, size: gotham(13), leading: 17, caps: true },
|
||||
grandValue: { face: G, weight: 700, size: gotham(13), leading: 17 },
|
||||
totalLabel: { face: G, weight: 700, size: gotham(13), ownFont: { size: 13 }, leading: 17, caps: true },
|
||||
totalValue: { face: G, weight: 400, size: gotham(13), ownFont: { size: 13 }, leading: 17 },
|
||||
grand: { face: G, weight: 700, size: gotham(13), ownFont: { size: 13 }, leading: 17, caps: true },
|
||||
grandValue: { face: G, weight: 700, size: gotham(13), ownFont: { size: 13 }, leading: 17 },
|
||||
words: { face: DM, weight: 400, size: 10, leading: 13 },
|
||||
wordsLabel: { face: DM, weight: 700, size: 10, leading: 13 },
|
||||
termsLabel: { face: DM, weight: 700, size: 13, leading: 17, caps: true },
|
||||
bullet: { face: DM, weight: 400, size: 11, leading: 14.2 },
|
||||
bank: { face: G, weight: 400, size: gotham(11), leading: 12.5 },
|
||||
contact: { face: G, weight: 400, size: gotham(10.14), leading: 15, minSize: 7 },
|
||||
bank: { face: G, weight: 400, size: gotham(11), ownFont: { size: 11 }, leading: 12.5 },
|
||||
contact: { face: G, weight: 400, size: gotham(10.14), ownFont: { size: 10.14 }, leading: 15, minSize: 7 },
|
||||
small: { face: DM, weight: 400, size: 9, leading: 12 },
|
||||
fine: { face: DM, weight: 400, size: 7, leading: 10 },
|
||||
signName: { face: DM, weight: 700, size: 9.5, leading: 13 },
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { GapRange } from "../neutral/variant";
|
||||
/**
|
||||
* Gotham (commercial) is drawn with Montserrat, which runs about 4% wider at the same size. Every Gotham-derived
|
||||
* size is multiplied by this when a token is defined, so the substitute takes the width the design has. A real
|
||||
* Gotham imported over the licensed name would need these tokens at factor 1.
|
||||
* Gotham imported over the licensed name takes the design size back: each such token carries it as `ownFont.size`.
|
||||
*/
|
||||
export const GOTHAM_SIZE = 0.96;
|
||||
const round2 = (n: number) => Math.round(n * 100) / 100;
|
||||
|
||||
Reference in New Issue
Block a user