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.
170 lines
6.8 KiB
TypeScript
170 lines
6.8 KiB
TypeScript
import type { Sides } from "../../engine/geometry";
|
|
import type { TypeToken } from "../../fonts/roles";
|
|
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 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;
|
|
/** The size a Gotham design value takes in Montserrat. */
|
|
export const gotham = (designSize: number) => round2(designSize * GOTHAM_SIZE);
|
|
|
|
/** Type roles of Purple Pop (DM Sans, Gotham -> Montserrat, the wordmark in Poppins 800). */
|
|
export interface PurpleRoles {
|
|
/** The oversized "Invoice" wordmark. */
|
|
wordmark: TypeToken;
|
|
/** "TAX" above the wordmark on a tax invoice. */
|
|
taxCaption: TypeToken;
|
|
brand: TypeToken;
|
|
/** "INVOICE NO : 012345" in the grey pill. */
|
|
pill: TypeToken;
|
|
/** "BILLED TO:", "AMOUNT DUE:", "PAYMENT METHOD". */
|
|
label: TypeToken;
|
|
clientName: TypeToken;
|
|
clientLine: TypeToken;
|
|
amount: TypeToken;
|
|
date: TypeToken;
|
|
tableHead: TypeToken;
|
|
tableBody: TypeToken;
|
|
tableSub: TypeToken;
|
|
totalLabel: TypeToken;
|
|
totalValue: TypeToken;
|
|
grand: TypeToken;
|
|
grandValue: TypeToken;
|
|
words: TypeToken;
|
|
wordsLabel: TypeToken;
|
|
termsLabel: TypeToken;
|
|
bullet: TypeToken;
|
|
bank: TypeToken;
|
|
contact: TypeToken;
|
|
/** GSTIN and PAN under the vendor name. */
|
|
small: TypeToken;
|
|
fine: TypeToken;
|
|
signName: TypeToken;
|
|
footer: TypeToken;
|
|
}
|
|
|
|
/** Type roles of Citrus Split (Now -> Jost for the wordmark, DM Sans, Gotham -> Montserrat). */
|
|
export interface CitrusRoles {
|
|
title: TypeToken;
|
|
taxCaption: TypeToken;
|
|
brand: TypeToken;
|
|
metaLabel: TypeToken;
|
|
metaValue: TypeToken;
|
|
metaStrong: TypeToken;
|
|
billedLabel: TypeToken;
|
|
clientName: TypeToken;
|
|
clientLine: TypeToken;
|
|
headService: TypeToken;
|
|
headNum: TypeToken;
|
|
tableBody: TypeToken;
|
|
tableSub: TypeToken;
|
|
totalLabel: TypeToken;
|
|
totalValue: TypeToken;
|
|
grand: TypeToken;
|
|
grandValue: TypeToken;
|
|
words: TypeToken;
|
|
wordsLabel: TypeToken;
|
|
sectionLabel: TypeToken;
|
|
bank: TypeToken;
|
|
bullet: TypeToken;
|
|
contact: TypeToken;
|
|
small: TypeToken;
|
|
fine: TypeToken;
|
|
signName: TypeToken;
|
|
footer: TypeToken;
|
|
}
|
|
|
|
export type NorthlineId = "purple-pop" | "citrus-split";
|
|
|
|
interface Common {
|
|
margins: Sides;
|
|
marginFloor: Sides;
|
|
signatureImageH: number;
|
|
chromeLeftW: number;
|
|
}
|
|
|
|
/**
|
|
* Purple Pop: y values are design distances measured on the reference A4 page (docs/templates/12-purple-pop.md)
|
|
* converted to flow gaps; x values are relative to the content edge (the left margin, x 54.8), so the same
|
|
* tokens serve every margin preset and both page sizes.
|
|
*/
|
|
export interface PurpleVariant extends Common {
|
|
id: "purple-pop";
|
|
roles: PurpleRoles;
|
|
ink: string;
|
|
purple: string;
|
|
yellow: string;
|
|
grey: string;
|
|
/** Alternate item row fill (the grey at 68% on cream, flattened). */
|
|
rowGrey: string;
|
|
cream: string;
|
|
watermark: string;
|
|
/** Header: inset of the vendor name and of the pill's right edge from the content edges. */
|
|
head: { nameInset: number; pillInset: number; pillH: number; pillPadX: number; nameMaxW: number; minNameW: number };
|
|
/** Client column: label inset, pill padding, the column's width and the gap to the wordmark. */
|
|
client: { inset: number; pillH: number; pillPadX: number; colW: number; colGap: number; wordmarkInset: number };
|
|
rule: { w: number; left: number; right: number };
|
|
/** Amount due / dates band. */
|
|
band: { amountInset: number; datesInset: number; gap: number };
|
|
/** Table: left offset of the narrow variant, the right inset, the pill paddings and the column widths. */
|
|
table: { narrowLeft: number; fullLeft: number; right: number; inset: number; headH: number; rowH: number; radiusHead: number; radiusRow: number; cols: { qty: number; rate: number; amount: number }; narrowDescMin: number };
|
|
asterisk: { size: number; offsetX: number; offsetY: number };
|
|
dome: { x: number; w: number };
|
|
totals: { boxW: number; labelInset: number; valueInset: number; rowGap: number; pillH: number; pillValueInset: number; wordsGap: number };
|
|
terms: { labelInset: number; labelW: number; signW: number; besideMax: number };
|
|
footer: { ruleLeft: number; ruleRight: number; bankW: number; contactLeft: number; contactW: number; addressLeft: number; iconW: number; iconGap: number };
|
|
gaps: {
|
|
/** Header row (or its GSTIN/PAN lines) to the client row. */
|
|
client: GapRange;
|
|
rule: GapRange;
|
|
band: GapRange;
|
|
table: GapRange;
|
|
tail: GapRange;
|
|
termsAbove: number;
|
|
ruleGap: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Citrus Split (docs/templates/13-citrus-split.md). x values are relative to the content edge (the left
|
|
* margin, x 73.3 on the reference page); the grey stripe is anchored to the RIGHT margin, so on Letter the extra
|
|
* width goes to the left column.
|
|
*/
|
|
export interface CitrusVariant extends Common {
|
|
id: "citrus-split";
|
|
roles: CitrusRoles;
|
|
ink: string;
|
|
text: string;
|
|
blush: string;
|
|
panel: string;
|
|
orange: string;
|
|
label: string;
|
|
/** Orange of the icon glyphs. */
|
|
icon: string;
|
|
stripeW: number;
|
|
/** The header's panel cell: inset of the logo from the stripe's left edge, and the gap between a mark and the name. */
|
|
head: { panelInset: number; markGap: number };
|
|
/** Client block: inset of its text from the content edge and the gap to the stripe. */
|
|
client: { inset: number; gap: number; labelGap: number; nameGap: number };
|
|
/** Meta row: inset of the first cell, minimum cell widths, panel-side start, gap between a label and its value. */
|
|
meta: { inset: number; noMin: number; dateMin: number; dueW: number; panelInset: number; labelGap: number };
|
|
/** Table: left offset from the content edge, header height, the SERVICE text inset, body text inset and row padding, columns. */
|
|
table: { left: number; headH: number; headInset: number; bodyInset: number; padY: number; padYMin: number; descRight: number; cols: { qty: number; rate: number; amount: number } };
|
|
separator: { color: string; h: number };
|
|
totals: { labelInset: number; valueInset: number; rowGap: number; barH: number; barInset: number; barGap: number; sepGap: number; wordsGap: number };
|
|
closing: { methodInset: number; bankInset: number; bulletInset: number; bulletText: number; bulletGap: number; sectionGap: number; labelGap: number; iconSize: number; iconGap: number; iconInset: number; contactGap: number; signW: number; clientTop: number; termsBesideMax: number };
|
|
gaps: {
|
|
/** Client block above the table (only when the invoice is more than a page). */
|
|
client: GapRange;
|
|
meta: GapRange;
|
|
table: GapRange;
|
|
tail: GapRange;
|
|
};
|
|
}
|
|
|
|
export type NorthlineVariant = PurpleVariant | CitrusVariant;
|