v2(Phase 1): slot mapping — CvDocument supports multi-column placement#47
Merged
Conversation
| void deprecated_ofMainSections_wraps_everything_in_main() { | ||
| ParagraphSection a = new ParagraphSection("A", "x"); | ||
| ParagraphSection b = new ParagraphSection("B", "y"); | ||
| CvDocument doc = CvDocument.ofMainSections(identity(), List.of(a, b)); |
Closes the single-column-only regression that v2 had vs. the legacy
CvBuilder.place(slot, name) API. Single PR, no engine changes, no v1
edits, no behavioural change for existing single-column callers.
What's new
----------
- data/Slot.java — enum {MAIN, SIDEBAR, FOOTER}. MAIN is the default
when a section is built without an explicit slot.
- data/CvDocument refactor: canonical record is now
(CvIdentity, List<Placement>) where Placement(Slot, CvSection).
Custom sections() method still returns the flat list (source-order)
so debug/inspect call sites keep working. New sectionsIn(Slot) and
slotOf(CvSection) accessors.
- CvDocument.Builder gains:
.section(Slot slot, CvSection section)
.sections(Slot slot, CvSection... values)
The pre-existing zero-slot calls (.section(s), .sections(s1, s2))
default to MAIN — every existing call site keeps compiling and
rendering identically.
- @deprecated CvDocument.ofMainSections(identity, list) — migration
helper for any caller that used a direct two-arg constructor. The
Builder is the recommended path forward.
What's updated
--------------
- presets/BoxedSections + presets/MinimalUnderlined now iterate
doc.sectionsIn(Slot.MAIN) instead of doc.sections(). Sidebar /
footer placements are silently dropped by single-column presets —
documented in AUTHORS.md.
- AUTHORS.md gains Recipe 6 ("place sections in slots") with both the
builder-side and the preset-side patterns. Old Recipe 6 (conditional
sections) renumbered to 7.
- package-info.java gains a "Slots — placing sections in columns"
section in the root v2 package.
- data/package-info.java mentions Placement and Slot.
Tests
-----
- New CvDocumentSlotTest with 10 cases (default MAIN, explicit slot,
source-order across slots, sectionsIn filter, slotOf, deprecated
ofMainSections, null guards).
- All existing v2 tests stay green (BoxedSectionsSmokeTest,
MinimalUnderlinedSmokeTest, CvDecorationTest, CvNameTest,
CvContactTest).
- Full mvn test: 881/881 pass.
- cv-boxed-sections-v2.pdf and cv-minimal-underlined.pdf render
pixel-identical to baseline (sample data is all MAIN today).
6c40f97 to
36b8d09
Compare
This was referenced May 24, 2026
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.
Summary
Closes the single-column-only regression v2 had vs. the legacy
CvBuilder.place(slot, name)API. Multi-column presets can now placesections into named slots without forking the data model.
What's new
data/Slot.java— enum{MAIN, SIDEBAR, FOOTER}.MAINis thedefault when a section is built without an explicit slot.
CvDocumentrefactor — canonical record is now(CvIdentity, List<Placement>)wherePlacement(Slot, CvSection).Custom
sections()still returns the flat list (source-order) sodebug/inspect code keeps working. New
sectionsIn(Slot)andslotOf(CvSection)accessors..section(s),.sections(s1, s2)) default toMAIN. Every existing call site keeps compiling unchanged.@Deprecatedmigration helperCvDocument.ofMainSections(identity, list)—for any caller that used a direct two-arg constructor pattern.
What's updated
BoxedSections+MinimalUnderlinednow iteratedoc.sectionsIn(Slot.MAIN)instead ofdoc.sections(). Sidebar /footer content is silently dropped by single-column presets —
documented in
AUTHORS.md.AUTHORS.mdgains Recipe 6 ("place sections in slots") withboth builder-side and preset-side patterns. Old Recipe 6
(conditional sections) renumbered to 7.
package-info.java(both root v2 anddata/) gains a Slotssection.
What's NOT changed
baseline (sample data is all
MAINtoday)..section(...)/.sections(...)call works unchanged. NewSlot-parameterisedoverloads are additive.
Test plan
CvDocumentSlotTest— 10 new tests (default MAIN, explicitslot, sectionsIn filter, slotOf, source-order across slots,
varargs into a slot, deprecated
ofMainSections, null guards)BoxedSectionsSmokeTest,MinimalUnderlinedSmokeTest,CvDecorationTest,CvNameTest,CvContactTestmvn test— 881/881 passcv-boxed-sections-v2.pdfrendered, pixel-identical to baselinecv-minimal-underlined.pdfrendered, pixel-identical to baselineNext phase
Phase 2 — port
TimelineMinimal(single-column v1 preset) onto v2.Will exercise the data/theme/components/presets shape on a non-trivial
visual style. Phase 3 then uses slots for real with a
TwoColumnSidebarport.