Add the Neutral template family, template picker and text-only logo allowances

Linea (the vendor's original format.pdf design), Monogram and Serenity are
rebuilt from the Canva PDFs as one parametric family on the engine, with
the user's logo in the measured slot, a home for every GST field and
A4/Letter support. Adds static Montserrat, Open Sans and Poppins fonts and
a generated Ms Madi outline for Serenity's vertical word. Text-only logo
placeholders (Monolith, Tangerine) use a doc-derived allowance box. A
Carbon TemplatePicker with committed thumbnails opens from the page
setup controls.
This commit is contained in:
2026-10-04 07:27:12 +05:30
parent 490c5b9009
commit 3f7c12b7dd
65 changed files with 3278 additions and 110 deletions
+17
View File
@@ -139,3 +139,20 @@ Page is 595.5 x 842.25pt (Canva's A4). In react-pdf use A4 (595.28 x 841.89); th
- **Byte-identical page content to /media/Toto/Documents/bongbetic/invoice/format.pdf.** It is the same Canva page; only the Info/XMP title, export timestamps, Canva design ID, xref offsets and trailer /ID differ. So this IS the vendor's original format, still carrying Canva's sample data (Daniel Gallego / Richard Sanchez / Borcele Bank).
- **Not a duplicate of the in-app template.** The current src/pdf/InvoiceDocument.tsx only loosely adapts it (see group_notes).
- **Sibling of 5.pdf and 6.pdf.** They share the grid: rules 69.64-525.86, column centres 325.2 / 416.4, money right edge 514.4, meta label/value anchors about 447 / 519, totals label anchor 460.3. 5 changes fonts and decoration; 6 shifts the grid right. Build 4, 5 and 6 as one configurable 'Neutral' component family.
## Implementation notes
Built as `src/pdf/templates/neutral/` (one family component, `Layout.tsx`, with tokens in `linea.ts`; planning in `plan.ts`). Measured against `4.pdf` with `npm run templates:compare` (`/tmp/invoice-c3/compare-linea.png`, left Canva, right ours).
**Matches the design (measured, A4):** title baseline 161.6 pt and x 59.5 as in Canva; hairline starting 20 pt after the title and ending on the margin; 'ISSUED TO' at x 77.4; the Montserrat glyph widths are metrically identical to the PDF (label and value widths agree to 0.1 pt); header baseline to first row 36.3 pt; row pitch 21.4 pt (Canva 21.46); table rules at x 69.6-525.6 (Canva 69.64-525.86); one colour, #3D3B3A.
**Intentional deviations, and why:**
- **Margins.** The template margin is 59.55 pt left and right, 56 top and 60 bottom, plus a 16 pt footer reserve. The doc's 77.4 pt text column with negative margins would put the title (x 59.5) and the rules (x 69.6) outside the margin box, which the audit forbids for flowing content. Here the title starts on the margin, the rules start 10.09 pt inside it and the text 17.9 pt inside it, so every x is relative to the margin and Narrow/Normal work. The content area ends at y 766 (page height less 60 + 16); Canva's signature ink ends at 772.
- **Supplier block (FROM)** is right-aligned under the title rule (docs: band x 290-535, y 170-255), max 245 pt wide. Its height pushes the info row down by the lines it needs beyond the design's empty band; a long address can never touch the title.
- **PAY TO** stays under ISSUED TO as in the design, with Bank, Account Name, Account No., Branch and IFSC.
- **Table.** An HSN/SAC column appears only when an item carries a code. UNIT PRICE shows the amount with a short unit ('₹1,200.00/hr'); when that does not fit the column it goes on two lines (amount, then 'per hour'). Fixed columns widen to their widest token (an amount cannot wrap) and the description takes the rest, so the table never stacks. The 4 pt indent of the cells (Canva artefact) is dropped: text starts at x 77.4 in the header and the rows.
- **Totals.** SUBTOTAL runs full width; DISCOUNT, TAXABLE VALUE, `CGST @ 9%` / `SGST @ 9%` (or UTGST, IGST) with their amounts and TOTAL form the right-anchored column (236 pt, amounts 92 pt). Amount in words and the reverse-charge line sit left of that column; below 150 pt of room they move under it.
- **Closing.** Only the signature is bottom-right; the user's signature image or, without one, the signatory name and designation plus the computer-generated line. Canva's script signature is not reproduced. The block is pushed to the foot of the last page by the bottom spacer.
- **Logo.** None by default (so Linea matches `format.pdf`); `prefs.logo.show` (the Logo toggle next to the template button) puts the logo in the optional band above the title, at most 150 x 48 pt, bottom-aligned 4.85 pt above the title box.
- **Elastic gaps** (Letter, and A4 when a one-page invoice overflows by less than the slack): the band above the title (68.85 to 33.85 pt), the supplier-to-info gap (down to 14 pt) and the info-to-table gap (49.5 to 24 pt). Type is never scaled. 'TAX INVOICE' drops its tracking to 0.12 em only if the hairline would be under 40 pt.
- Footer ('Generated with Voiced', page n of N) at 7 pt Montserrat in the same ink; the design has none.
+16
View File
@@ -145,3 +145,19 @@ Page is 595.5x842.25 (A4). Same grid as Linea: rules x 69.64-525.86; text column
- 'RATE' instead of 'UNIT PRICE', and a bold SUBTOTAL.
- **Not similar to the current in-app template** beyond normal invoice structure.
- **Shares its type system with 6.pdf:** Open Sans sizes and weights, 1pt tracking, Medium address lines.
## Implementation notes
Built on the shared Neutral family (`src/pdf/templates/neutral/`, tokens in `monogram.ts`). Measured against `5.pdf` with `npm run templates:compare` (`/tmp/invoice-c3/compare-monogram.png`).
**Matches the design (measured, A4):** title baseline 144.0 pt (Canva 143.98) and x 69.6 (flush with the rule start, 69.3 in Canva); ISSUED TO and INVOICE NO baselines 325.4 pt and meta pitch 15 pt; header baseline to first row 36.3 pt; label and value widths agree to 0.1 pt (Open Sans at 0.10 em tracking); rules x 69.6-525.6; ink #3D3B3A only.
**Intentional deviations, and why:**
- **Data text is tracked 0.05 em, not 0.10 em.** Wider tracking makes PDF text extraction split words, so the table body, address lines and values use 0.05 em (layout rule 7). Titles, labels and table heads keep 0.10 em. Body lines are therefore a little narrower than Canva's.
- **Logo, not the ring.** The user's logo goes in the measured slot (up to 142.75 x 116.5 pt, right edge on the margin, vertically centred on the old ring centre). A wordmark such as Arun P's comes out about 100 x 22 pt because the weight factor matches the visual weight of the ring (ink density 0.14). Without a logo the vendor's initials are set in Open Sans Bold 46 pt in the same slot, with no ring and no caption; a vendor name is always printed as text in the supplier block.
- **Supplier block (FROM)** is right-aligned under the logo (max 240 pt), as the doc suggests, and may push the info row down.
- **Margins.** Left and right 69.64 pt (the rule edge, text 7.8 pt inside), top 58, bottom 60 plus a 16 pt footer reserve. The logo may not overshoot the rule end by Canva's 5 pt (the audit keeps flowing content inside the margin box); it sits 4.6 pt further left.
- **Payment block** sits in the bottom row with the signature, bottoms aligned; it grows with IFSC, Branch and Account Name, and the user's signature image replaces the script name (name and designation without one). 'Payment info:' keeps the design's label.
- **Totals** as Linea, except SUBTOTAL, TOTAL and the labels are bold and the rows 18.6 pt apart; the right column shows tax amounts (`CGST @ 9%`), not a rate.
- **Table.** RATE is shown as in Linea (amount plus short unit), HSN/SAC is a column when present.
- **Letter:** the band above the logo shrinks (23.25 to 8 pt after the 58 pt margin) and the header-to-info and info-to-table gaps take the rest; type is untouched.
+17
View File
@@ -158,3 +158,20 @@ Implied margins: left 162.9 (rules) / 171.8 (text); right 64.1 / 70.8; top about
- **Same internal grid as 4 and 5, shifted right:** rules 162.91-531.39 instead of 69.64-525.86 (left edge +93.3, right edge +5.5).
- **Unique within the trio:** the paper texture, vertical script title, circular-text stamp, drawn signature, and the 'BANK DETAILS' / 'THANK YOU' bottom row.
- **No resemblance to the in-app template.**
## Implementation notes
Built on the shared Neutral family (`src/pdf/templates/neutral/`, tokens in `serenity.ts`, decor in `src/pdf/decor/ScriptWord.tsx`). Measured against `6.pdf` with `npm run templates:compare` (`/tmp/invoice-c3/compare-serenity.png`).
**Matches the design (measured, A4):** text column at x 171.8 and rules from x 162.91; Open Sans label and value widths agree to 0.1 pt; header baseline to first row 36.3 pt; paper #ECE8E1 as the Page `backgroundColor`; ink #3D3B3A; the vertical word and swash occupy Canva's band (word x 38.5-120, y 420-780; swash joined to the word's end and running up to y 143).
**Intentional deviations, and why:**
- **The word 'invoice' is outline art, not text.** Canva's SimpleSerenityScript is not shipped or traced. The word is drawn from Ms Madi Regular (SIL OFL 1.1; chosen over Sacramento because its hairline strokes are closer to Canva's) as SVG paths generated at build time by `scripts/decor/script-word.mjs` into `src/pdf/decor/scriptWord.generated.ts`, with the licence note in a comment. The font file stays in `scripts/decor/source/` only; it is never bundled, registered or embedded. The glyph contours are merged and shrunk by 0.95 pt per side (clipper-lib, a build-time dev dependency) to thin Ms Madi to a script-like weight; it is still heavier than Canva's. The swash is our own drawing (a tapered spine), not Canva's path, and the word is not tilted 1.1 degrees. The band is `fixed` page-level decor on every page, shifted up 32 pt on Letter. A real text 'TAX INVOICE' / 'INVOICE' label sits above the meta block, so the document is searchable.
- **No paper texture.** Canva's JPEG is stock and is not bundled; the page is the flat measured colour #ECE8E1.
- **Logo, not the stamp.** The user's logo goes in the measured stamp slot (82 x 82 pt, right edge on the text column). No logo, nothing: no ring, no stamp, no caption.
- **Data text is tracked 0.05 em** (layout rule 7); labels and heads keep 0.10 em.
- **Table.** The column is only 368 pt wide, so HSN/SAC is not a column: it is an 8 pt second line under each description that carries a code. Rate is amount plus short unit, and falls back to two lines in the 90 pt column when it does not fit.
- **Totals.** The right-anchored column is 210 pt wide; the amount in words sits full width under it (the design's 200 pt left column does not exist at this width).
- **Bottom row.** BANK DETAILS (inset 10.9 pt, as in the design), then THANK YOU above the signature image or the name, designation and computer-generated line; bottoms aligned. Canva's drawn signature is not reproduced.
- **Margins.** Left 162.91 pt (never less, whatever the preset: the band is x 38-155), right 64.1, top 56, bottom 60 plus the 16 pt footer reserve. The header starts where the stamp slot does (y 131.75) and flows; without a logo the supplier block starts there instead.
- **Elastic gaps:** top 75.75 to 40 pt, supplier-to-info down to 14 pt, info-to-table 61 to 28 pt; Letter also moves the band up.