feat(templates): promote the Luma Studio invoice onto the structured model - #623
Merged
DemchaAV merged 1 commit intoAug 31, 2026
Merged
Conversation
Comment on lines
+126
to
+128
| page.addRow("Masthead", row -> row | ||
| .spacing(0) | ||
| .gap(0) |
Comment on lines
+140
to
+142
| page.addRow("Parties", row -> row | ||
| .spacing(0) | ||
| .gap(0) |
Comment on lines
+157
to
+159
| page.addRow("Closing", row -> row | ||
| .spacing(0) | ||
| .gap(0) |
DemchaAV
changed the base branch from
feat/structured-invoice-luma-fields
to
feature/template-promotion
August 31, 2026 11:59
…model The structured invoice model landed with one consumer. The fields added beside it fitted a second published invoice; this is that invoice — `luma-co-studio-invoice`, a studio sheet built around a cream sidebar — brought into the templates module so it ships with the library. It is the first promoted preset that has to paginate. The line-items table repeats its dark header, the totals stack and each closing block stay whole, and the paper tint, the sidebar column and the dark foot band are page backgrounds, so every page carries the same frame and the folio always has a dark ground. The sign-off carries its own strip rather than relying on that background band, which is the one deliberate departure from the sheet being ported: the band is pinned to the paper's edge, so on the last page of a longer invoice the published template sets white words on pale paper. Drawing the strip with the words fixes it wherever they land, at 7,440 of 2,173,720 pixels on the reference sheet and one extra layout node. It is flow content only because footer chrome carries text today; once a footer zone can hold a node the sign-off belongs in one. Amounts take their mark from the data's currency code rather than a second stated field, and the contact channels carry dial, mail and web targets derived from their values, with a parenthesised trunk prefix dropped from the dial target. Guarded by a smoke test, an exact layout snapshot over a one-page and a three-page invoice, and a pixel-parity gate; the examples showcase gains `invoice-luma-studio-v2`.
DemchaAV
force-pushed
the
feat/luma-studio-invoice-preset
branch
from
August 31, 2026 11:59
bd0eed7 to
b14607b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The structured invoice model landed with one consumer. #622 fitted a second published
invoice to it and added the six things it could not say; this is that invoice —
luma-co-studio-invoice, a studio sheet built around a cream sidebar — brought intothe
templates/module so it ships with the library instead of living as a standalonebundle.
It is also the first promoted preset that has to paginate. The CV presets before it
reproduce one sheet and refuse anything longer; an invoice's length belongs to the
document, so the line-items table has to flow and every page has to keep the same
frame.
What
invoice.presets.LumaStudioInvoiceonStructuredInvoiceDocumentSpec, composed fromseven package-private files — the measured geometry and type scale, the icon loader,
the idioms the sheet repeats, and one file per region.
The sheet: the brand lockup on a terracotta block at the head of the sidebar with the
ornament running down the rest of it; the sender over the document title and its
metadata; the billed-to and shipped-to pair across a rule; the priced service lines
with a VAT column; the totals stack closing on a filled total-due band; the notes and
bank details side by side; the sign-off band.
Long invoices flow. The table repeats its dark header, the totals stack and each
closing block stay whole, and the paper tint, the sidebar column and the dark foot
band are page backgrounds, so every page carries the same frame and the folio always
has a dark ground.
One deliberate departure from the sheet it ports. On the published template the
sign-off relies on that background band, which is pinned to the paper's edge — right
on a one-page invoice, and white-on-cream in the middle of the last page of a longer
one, where the flow ends well above the paper's foot. Here the sign-off draws its own
strip, so it is legible wherever it lands. The cost is measured: 7 440 of 2 173 720
pixels on the reference sheet, where the strip starts three points above the
background band it sits on, and one extra layout node. It is flow content only
because footer chrome carries text today — one size, one colour, no glyph, where this
band needs two faces and a disc. Once
feat/chrome-footerlands, the sign-off belongsin a footer zone pinned to the foot of the last page and the strip goes away; both
class Javadocs say so.
Two details worth naming. Amounts take their mark from
currencyCode()rather than asecond stated field, so the sheet cannot contradict itself; an unknown code prints
itself rather than leaving a figure bare. And the contact channels carry
tel:,mailto:andhttps:targets derived from their values, with a parenthesised trunkprefix — the
(0)in+44 (0)20 …— dropped from the dial target the way a callerdialling from abroad drops it.
Also here: the example (
invoice-luma-studio-v2), its showcase row and its committedpreview.
Tests
./mvnw -B -ntp clean verify -pl :graph-compose-core,:graph-compose-render-pdf,:graph-compose-render-docx,:graph-compose-render-pptx,:graph-compose-templates,:graph-compose-testing,:graph-compose-qa,:graph-compose-coverage -am— BUILD SUCCESS.LumaStudioInvoiceSmokeTest(13) — identity, the canonical render, the emptydocument through every guard, the table / totals / bank text, the currency mark for a
known, an unknown and a blank code, the link targets, a supplier with one
registration and with none, every line priced on the overflow document, the repeated
header and folio on a continuation page, and the sign-off landing on its own dark
ground. The last one was sabotaged and watched go red.
LumaStudioInvoiceLayoutSnapshotTest(2) — an exact snapshot of the one-page sheetand of the three-page one, where the table spans the first two pages and the closing
blocks move whole onto the third.
LumaStudioInvoiceVisualParityTest(1) — pixel baseline, same budget and toleranceas the other structured-invoice gates.
The port itself was proven before the gates were written: rendered against the
published bundle's own fixtures on this engine, 0 of 2 173 720 pixels differ on the
one-page sheet and 0 on all three pages of its overflow fixture, with 121 of 121
layout nodes identical in geometry — the only differences being the four node names
the promotion deliberately changes. The sign-off strip above is the one change made
after that.
Stacked on #622, which it needs for
monogramTop/monogramBottom,taxRegistration*,shipTo,vatRate/Columns.vatandaccountHolder/signOff.