Add the Marble and Highlighter templates, completing the 13 Canva templates

Marble uses a flat-to-gradient band in place of the marble photo and bundles Lustria (OFL).
Both logo slots are opt-in. Quirk 13 documents a fontkit glyph-cache issue that the
tests work around with warm-up renders; the engine fix follows separately.
This commit is contained in:
2026-10-04 12:47:05 +05:30
parent 385d7974cb
commit a2152ae3c6
30 changed files with 3190 additions and 27 deletions
+16
View File
@@ -155,3 +155,19 @@ Voiced fields with no Canva slot, and where they go:
## Similarity to other templates
Closest siblings are 7 and 11 (Poppins, a colour-filled header on a boxed grid table, boxed totals) and 8 (filled blue header plus an icon contact row). Only 2 has underlined fill-in fields, a detached header bar and 3pt frames. It is unrelated to the in-app template and to format.pdf/4.pdf. If 7 and 11 are built too, share one 'boxed grid table' component with accent colour and frame weight as parameters.
## Implementation notes
Built as `src/pdf/templates/highlighter/`: a standalone template (`tokens.ts` the type roles, palette and Canva distances, `plan.ts` the pure planner, `Layout.tsx` the body, `highlighter.tsx` the definition) on the shared blocks and the Carbon icon paths (`ContactIcon`). Measured against `2.pdf` with `npm run templates:compare -- highlighter --rows=3` (images in `/tmp/invoice-c6b/`, left Canva, right ours; `--numbers` prints the baselines). The Canva page is a blank form, so the comparison sample here fills the fields and rows; every distance below was measured with the design's own content shape (no due date, no address, a two-line payment block).
**Matches the design (measured, A4):** the title baseline 98.0 at x 60.3 (98.0 / 60.3); the fields at 132.2 / 166.3 / 200.4 (132.2 / 166.0 / 200.4) with their label at x 60.3 and the value 5 pt after it on a 0.75 pt `#423869` underline ending at x 266; "Payment Method:" at 162.9 and the bold bank lines at 185.1 and the 16.5 pt pitch (162.9 / 185.1 / 201.6), x 352.5; the table bar 38.4 pt tall (frame included) with the Qty and Price headings centred on x 277.4 and 360.8 (277.4 / 360.8) and the Total heading 1.9 pt right of the design's (the design sets it 2.4 pt left of its column centre); a 4.5 pt gap under the bar, the body's own 3 pt frame, hairlines between the rows and columns; rows of 30.65 pt; the totals box one price-column wide plus one total column, its total label cell yellow; the sign-off and its ruled lines 212.3 pt wide ending 1.5 pt inside the frame's edge. Every colour is one of the design's four (a test scans the sources); the type is Poppins 400/700 and Montserrat 400 at the design's sizes.
**Intentional deviations, and why:**
- **Content box.** The 3 pt strokes are centred on x 59.6 and 536.0, so the frames reach 1.5 pt outside them: the content box is the frame's outer edge (58.1 to 537.5, 479.4 wide), and everything is measured from it. Margins are 58.1 / 57.8 pt at the sides, 50 pt at the top (the title's line box is the design's 64 pt zone) and 36 pt plus the footer reserve at the foot; the narrow and normal presets replace the margins with 36 and 54 pt, and the frame, the table columns and the totals box follow the content width.
- **Fields.** Date, Invoice number, a Due date field in the same style (only when the invoice has one), then Billed to with the client's name on its underline; the address, GSTIN, place of supply and PO number are 11 pt lines under it. A value that does not fit its underline wraps (the underline moves down) or, for an unbreakable token, shrinks and then splits at `@ . / -`. Pitch is a steady 34.1 pt (the design's is 33.8 / 34.4). The fields and the payment block sit side by side and the table starts under the taller one, at least 18 pt below it (the design leaves 64 pt, which Letter and a longer client block take back, down to 14 pt).
- **Top right.** The vendor's name (Poppins Bold 13), GSTIN and PAN, right-aligned in x 352 to 536, or the opt-in logo (off by default; 150 x 50, right-aligned, its top on y 50) above them; a wordmark replaces the name, a mark keeps it under the mark. The zone is 64 pt tall and grows with a logo, which moves the rest down. A cancelled invoice has a red CANCELLED line there and its sentence at the foot.
- **Payment block.** The account holder's name is added as its own line, and the bank lines read "Bank Name : ...", "Account No : ..." (then Branch and IFSC).
- **Table.** The design's rows are empty; ours carry the item: description left (9 pt in) with an HSN/SAC sub-line, qty centred, price and total right-aligned 9 pt inside their cells (the unit stays on the rate's line, "₹1,200.00/hr", while the column can take it). The form look pads with empty rows to 8 on A4 and 7 on Letter, but the pad rows give way first: they are dropped before the sign-off would have to move to a second page, and a long invoice has none. The 3 pt frame is closed at the foot after the last row only; where a table breaks onto a second page the page ends on the row's hairline (the frame's sides run to it), and the next page repeats the bar and the body's top rule.
- **Totals.** A stack of two-cell rows (label cell | value cell) lined up with the price and total columns: Subtotal, Discount, Taxable value, CGST / SGST / IGST ("CGST @ 9% :") with 0.75 pt rules between the rows and the 3 pt frame around them, and the "total :" row with the yellow label cell and a bold value. When a label needs more room than the price column has, the box grows to the left. The amount in words and the reverse-charge line are at its left, level with its first row.
- **Sign-off.** THANK YOU and the phone, e-mail and address with Carbon icons (the design's own Material paths are not used, so the app keeps one icon set); the phone and e-mail are one fitted line each (a wrapped phone number can break after a bracket), the address wraps. The ruled lines carry the notes, one wrapped line per ruled line (three lines at least; more than six lines and the notes flow as a block of their own before the sign-off), and the signature block (the image or "Computer-generated invoice; no signature is required.", the rule, the name and designation) takes the last one. The sign-off sits at the foot of the last page.
- **Elastic gaps** (Letter, and A4 when a one-page invoice overflows by less than the slack): fields to table bar (down to 14 pt), the row padding (down to 4.5 pt a side) and the totals to the sign-off (24 to 12 pt). The type is never scaled.