feat(templates): add the EditorialProposal structured proposal preset - #612
Merged
DemchaAV merged 1 commit intoAug 30, 2026
Merged
Conversation
The structured proposal model had one consumer. EditorialProposal is the second, and it renders the same document in a different hand: an orange accent, section headings set in the display serif over short accent rules rather than in the body sans inside icon badges, a brand mark drawn from vector paths rather than set as a monogram letter, an untitled fact card, a scope ordinal in plain accent text, and a hairline page foot instead of a filled band. It ports the rendered layout of the published standalone northline-proposal-orange template and needed no change to the model - which is what the model's second consumer was meant to prove. The preset owns its session geometry and draws the brand line and page numbers as footer chrome; it issues no explicit page break, because the page-two masthead is keepWithNext. Its SVG icon set ships inside the artifact, and each icon node is named after its token so a swapped token reaches the layout snapshot rather than only the pixels. A goal cell takes the goal's own icon token and falls back to the band's, which is how this design marks every cell alike. Moving a document between the two proposal presets is a one-line change plus two data checks, both now stated in the class documentation and pinned by a test: the badge and goal tokens are preset-scoped vocabulary while the four fact tokens are shared, and headings are drawn as authored. qa: one fixtures class feeds the smoke, the exact two-page layout snapshot and the pixel gate; the smoke drives full layout and render, asserts the table content on the text layer, and names both data contracts. Examples gain EditorialProposalV2Example (proposal-editorial-v2) with its preview.
Comment on lines
+120
to
+121
| row.verticalAlign(RowVerticalAlign.TOP) | ||
| .gap(SUMMARY_GAP) |
| double dividerHeight = GOAL_TEXT_LINES * lineHeight(TABLE_SIZE); | ||
| page.addRow("GoalCells", row -> { | ||
| row.margin(DocumentInsets.top(BAND_TOP)); | ||
| row.verticalAlign(RowVerticalAlign.TOP).gap(GOAL_GAP); |
Comment on lines
+288
to
+289
| row.verticalAlign(RowVerticalAlign.TOP) | ||
| .gap(SCOPE_GAP) |
Comment on lines
+94
to
+95
| row.verticalAlign(RowVerticalAlign.TOP) | ||
| .gap(0) |
Comment on lines
+206
to
+207
| row.verticalAlign(RowVerticalAlign.TOP) | ||
| .gap(MONEY_GAP) |
Comment on lines
+337
to
+338
| row.verticalAlign(RowVerticalAlign.BOTTOM) | ||
| .gap(SIGNATURE_LABEL_GAP) |
Comment on lines
+74
to
+75
| row.verticalAlign(RowVerticalAlign.CENTER) | ||
| .gap(LOGO_GAP) |
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 proposal model landed with one consumer,
NorthlineProposal. A model shaped around one document is a model nobody has tested — and the second look it was meant to carry existed only as a published standalone template pinned tograph-compose:2.2.0, with its assets on the filesystem.What changed
proposal/presets/EditorialProposal— aDocumentTemplate<StructuredProposalDocumentSpec>viacreate(), split for the 500-LOC rule into package-privateEditorialStyles(measured geometry, the Spectral/Lato scale),EditorialIcons,EditorialWidgets(masthead, drawn mark, heading, bullet, stacked-line box) andEditorialPageOne/EditorialPageTwo. It renders the same document as its sibling in a different hand: section headings set in the display serif over short accent rules rather than in the body sans inside icon badges, a brand mark drawn from four vector paths rather than set as a monogram letter, an untitled fact card, a scope ordinal in plain accent text, and a hairline page foot instead of a filled band.StructuredProposalDatacarried the second design as authored, including the parts the orange look does not use (section icon tokens, the fact-card heading, the monogram), because they normalize to their empty forms.fact-*tokens are named alike in both packaged sets, and headings are drawn as authored, so the sibling's tracked capitals stay capitals here.templates/proposal/editorial/icons/.package-infonow describes both preset shapes the package holds — the narrative one onBrandTheme, and the structured one on preset-local tokens — which had drifted when the first structured preset landed.Verification
Full reactor gate (the eight CI modules) → BUILD SUCCESS; proposal qa suite 27/27; examples suite 75/75 including
CommittedAssetDriftTestwith the new preview;javadoc:javadoc→ 0 warnings.Port parity, verified on one machine against the published template itself: the preset fed the template's own fixture is pixel-identical to the standalone render — 0 / 2,173,720 differing pixels on each of the two pages. The bundle's geometry is identical on its pinned 2.2.0 and on this branch (177/177 nodes, zero deltas > 0.01pt); the two engines differ only by the released ligature fix (#601), so the current-engine render is the parity target and the approved preview differs from it by that fix alone.
Notes
goalColumns,wrappingCell, the money band, the phase grid (including a verbatim-copied header-count message), the investment row loop, the glance fact box. That duplication is the price of porting with parity; extracting the composition helpers intotemplates.core.*with style and geometry as parameters is the natural follow-up, and it should happen before a third structured preset lands rather than after.Lane: canonical (templates.proposal.presets + qa + examples) — no engine changes, no model changes.