Add the Northline template family: Purple Pop and Citrus Split

Purple Pop (cream page, purple pills, asterisk and dome decor, opt-in
logo) and Citrus Split (grey split panel, halftone chevrons, icon
contacts, logo in the measured slot) are rebuilt from the Canva PDFs on
the engine with A4/Letter support, GST slots and zero audit errors. Adds
static DM Sans, Jost and Poppins 800 as look-alikes for the commercial
fonts. The picker now lists ten templates.
This commit is contained in:
2026-10-04 09:56:56 +05:30
parent c95514ee8d
commit d82515feee
40 changed files with 3033 additions and 56 deletions
+19
View File
@@ -216,3 +216,22 @@ US Letter is 612 × 792.
Sibling of 13.pdf. They are from the same Canva family, with the same placeholder data ('Northline Group', 'Amy Fletcher', 'Intelligent Bank'), the same DM Sans plus Gotham type system, the same raster 30% shadow effects, and the same SERVICE/QTY/RATE/AMOUNT table with SUBTOTAL/TAX/TOTAL.
The composition is different: pills and asterisks on cream here, versus a split grey column on blush in 13. Keep both and share the data-mapping code. Not similar to 1–11, format.pdf or the in-app template.
## Implementation notes
Built as `src/pdf/templates/northline/` (the family component shared with Citrus Split: `Layout.tsx` dispatches to `PurpleLayout.tsx`, the plans live in `plan.ts`, tokens in `purple.tsx` and `variant.ts`) on the decor primitives in `src/pdf/decor/` (`Asterisk`, `Underlay`, `CircledIcon`). Measured against `12.pdf` with `npm run templates:compare -- purple-pop` (`/tmp/invoice-c5/compare-purple-pop.png`, left Canva, right ours; `--numbers` prints both sets of baselines).
**Matches the design (measured, A4):** wordmark x 238.8 and 291.6 pt wide (Canva 238.2 / 292.2), right edge on the design's 530.4; INVOICE NO pill right edge 530.9, grey, text tracked 0.13 em; client label, pill and lines at x 67.1; AMOUNT DUE at 71.8; table pills, 46.6 pt header (radius 23.3), 32.7 pt rows (radius 16.35), alternating #EDEDE8 / #FFD80B, flush; SUBTOTAL / TOTAL labels at x 192 and values ending at 522 / 529; the TOTAL pill 369.4 x 41 at x 173.4; rule 1 at 64.8..533.4; footer columns at x 67.4 / 218.5 / 380.7.
**Intentional deviations, and why:**
- **Fonts.** Open Sauce One is not bundled: the wordmark is Poppins 800 at -0.08 em. Gotham is Montserrat with every size multiplied by 0.96 at token definition (`gotham()` in `variant.ts`; a real Gotham imported over the licensed name would need the tokens at factor 1). DM Sans is bundled 400/700 and has the rupee sign; Montserrat and Poppins carry it too, so no amount depends on the Plex fallback.
- **Wordmark and 'Tax'.** The wordmark always reads "Invoice". A tax invoice adds a tracked 14 pt "TAX" above it (right-aligned), not a 61 pt "Tax Invoice". Negative tracking leaves the last glyph's ink 7.5 pt past the line end, so the wordmark Text carries that much right padding; the ink then ends on the design's edge and the overflow audit stays quiet.
- **Vertical rhythm.** The design is generous and a Voiced invoice has more lines (GSTIN, place of supply, tax rows, amount in words, signature, bank lines), so the gaps between blocks are elastic (client 35 to 10, rules 18 to 6, amount band 18 to 6, table 20 to 8, totals 14 to 6; Letter gives back its 49.9 pt from them first). A one-page invoice of two or three plain items fits A4; a tax invoice with a signature and notes puts items and totals on page 1 and the closing block (terms, signature, footer) alone at the foot of page 2, which is how the other families behave too. When the gaps can give back the whole overflow only to keep the totals with the items, the plan does exactly that.
- **Table width.** The narrow table beside the asterisk (x 176.9, the design) is used only for up to three items whose descriptions take at most two lines in its ~100 pt column; everything else uses the full width (x 59.5..539.4) on every page and drops the asterisk, as the spec recommends. The 71.5 pt asterisk is page 1 only and a child of `FirstPageHeader`, positioned from the plan; the dome sits in the left gutter of the totals block and travels with it.
- **Pills.** Header and rows are Views with a flat fill and a radius, laid out through `TableRows`'s `pill` option (cells inset 15 pt inside the pill, the pill indented from the container's left edge). No opacity, so text is never faded.
- **Watermarks.** The two pale asterisks are `decor.underlay` items (fixed, painted before the flow, anchored to the page corners; the off-page part is cut away by the Svg's viewBox so the box always lies on the page, Letter included). No keep-outs: nothing printed over them needs a clear ground. Canva's drop-shadow rasters are dropped.
- **Dates.** "INVOICE DATE : ..." and "DUE DATE : ..." are explicit right-aligned lines (a PO line is added when present); the size shrinks to 10 pt before the amount (32.74 pt, shrinking to 20) loses its 150 pt.
- **Supplier lines.** GSTIN and PAN sit under the vendor name (9 pt, through `Slot.Gstin`); phone, e-mail and address are footer columns B and C with icons (solid discs for phone and e-mail, a ring for the address). The website column has no Voiced data and is dropped; UPI is a bank line.
- **Signature and terms.** The signature takes the 29 pt asterisk's place at the right of the terms row (190 pt wide, so the computer-generated line fits in one line). Terms are one bullet per note line; with more than the signature's height they flow as their own block before the closing block, each bullet unbreakable and the label held with the first.
- **Logo.** No Canva placeholder: opt-in (picker toggle, `prefs.logo.show`), off by default, in the area left of the vendor name (at most 200 x 34 from `slots.optin.ts`). A mark shifts the name right; a wordmark replaces it. The no-logo fallback is the vendor name in DM Sans Bold.
- **Margins.** Top 70 (the design's pill starts at 77; 7 pt go to the page-2+ continuation band), bottom 40 plus the footer reserve, 54.8 left, 52.48 right; floors 36 / 36 / 24 / 36.
+18
View File
@@ -182,3 +182,21 @@ US Letter is 612 × 792.
## Similarity to other templates
Sibling of 12.pdf: the same Canva family, data and type system with a different layout. It is distinct from everything else in the set and from format.pdf and the in-app template; the split grey column is unique to it. It can share the 12/13 data-mapping code, though its pill and label components differ.
## Implementation notes
Built as `src/pdf/templates/northline/` (the family component shared with Purple Pop: `Layout.tsx` dispatches to `CitrusLayout.tsx`, the plans live in `plan.ts`, tokens in `citrus.tsx` and `variant.ts`) on the decor primitives in `src/pdf/decor/` (`Underlay`, `Halftone`, `CircledIcon`). Measured against `13.pdf` with `npm run templates:compare -- citrus-split` (`/tmp/invoice-c5/compare-citrus-split.png`, left Canva, right ours).
**Matches the design (measured, A4):** INVOICE at x 73.3 with its baseline at 109.3 (Canva 109.7); the stripe at x 298.8..535.6; meta labels at x 87.9 / 174.1 / 315.5 / 423.7; table header 47.2 pt, orange SERVICE cell x 84.2..298.6 with the text at 115.9, numeric headings on white; description text at x 99.9 (Canva 100.1); SUBTOTAL / TAX labels at x 320.9 with values ending at 505; TOTAL bar 235 x 47.2 with TOTAL at 316.5 and its value ending at 505; BILLED TO block at x 85.6 beside the totals; PAYMENT METHOD / TERMS at x 81.7, bullets at 89.2 / 102.1.
**Intentional deviations, and why:**
- **Fonts.** Now Bold is drawn in Jost 700 at -0.081 em (Jost has no rupee sign and is used for that one word only; 'INVOICE' comes out 176 pt wide against Canva's 189.7). Gotham is Montserrat at 0.96 of the design size (`gotham()`); DM Sans for labels, names and the words line.
- **The stripe.** A full-height fixed underlay on every page (not Canva's 547 pt rectangle plus a bottom block), anchored to the right margin: `x = page width - right margin - 236.8`. On Letter the extra 16.5 pt go to the left column; Narrow and Normal margins move it with the margin. The three halftone fields are anchored to their page corners and edges, drawn as Svg circles over the stripe, each dot already in the gradient's colour at its x (no gradient object), at 9% opacity.
- **Table.** The three numeric columns add up to exactly 236.8 pt (66.8 / 80 / 90), so every number is printed on the grey whatever the data; the description column takes the rest (214.6 on A4, 231 on Letter). RATE and AMOUNT are right-aligned (the design centres them), the rate's unit goes under it when the short form does not fit, HSN/SAC is a 9 pt line under the description. Zebra rows span the full row width and only show on the left.
- **BILLED TO.** Beside the totals (the design) when the whole invoice fits one page; above the table, under the title, when it does not, so page 1 always names the client. `planCitrus` decides from the nominal height against the page and the gaps' slack.
- **Totals.** 12.5 pt labels (Gotham 700, drawn 0.96) and values; each row is one line (the value column takes only the width the amounts need, so 'TAXABLE VALUE' and 'UTGST @ 14%' never wrap). Amount in words sits under the TOTAL bar in the design's tagline slot, right-aligned; the reverse-charge line follows it.
- **Contacts.** Phone, e-mail and address with icons (a solid orange disc for the phone, rings for e-mail and address), right-aligned with the icons at the stripe's right edge; GSTIN and PAN replace the web line, without an icon. The signature goes under them in the panel column (the design's empty bottom block).
- **Row pitch.** 12.15 pt padding gives the design's 39.3 pt row; on Letter (and when an invoice is a little over a page) the row padding is the elastic part, down to 8 pt, together with the gaps.
- **Header.** Logo in the measured slot (a mark keeps the name, a wordmark replaces the lockup), the name 2+ lines at 17.13 pt; with no logo the name stands at the logo's x, vertically centred on the title. A tax invoice puts a tracked orange "TAX" above the wordmark.
- **Margins.** Top 58, bottom 40 plus the footer reserve, 73.3 left, 59.68 right; floors 36 / 36 / 24 / 36. The standard footer sits over the bottom-left halftone and the stripe.
- **Terms.** Beside the bank lines in the closing block; more than 110 pt of them flow as their own block across the width, each bullet unbreakable.