Skip to content

v2(Phase 3): widgets/ layer — LEGO bricks for preset authors#49

Merged
DemchaAV merged 1 commit into
developfrom
feature/cv-v2-widgets
May 24, 2026
Merged

v2(Phase 3): widgets/ layer — LEGO bricks for preset authors#49
DemchaAV merged 1 commit into
developfrom
feature/cv-v2-widgets

Conversation

@DemchaAV
Copy link
Copy Markdown
Owner

Summary

Closes the «пишу свой preset — выбираю кубики и вставляю» gap.
Until now, an author who wanted a section title style different
from BoxedSections' banner had to read another preset's private
rendering methods and copy-paste. With widgets, they pick a named
visual building block.

This is what gives v2 its «понятный, читаемый, переиспользуемый»
authoring story.

⚠️ Stacked on #47 and #48. After both merge, this PR's diff
shrinks to just the widgets-layer commit.

What changes for preset authors

Before — preset's compose() had ~30 lines of DSL plumbing or
called CV-specific renderers:

host.accentBottom(theme.palette().rule(), theme.spacing().accentRuleWidth())
    .padding(new DocumentInsets(8, 0, 2, 0))
    .addParagraph(p -> p
        .text(TextOrnaments.spacedUpper(title))
        .textStyle(theme.entryTitleStyle())
        .align(TextAlign.LEFT)
        .margin(DocumentInsets.zero()));

After — preset reads as a sequence of visual decisions:

SectionHeader.underlined(host, title, theme);

A full preset's compose() is now ~12 lines (was ~30). Reading it
no longer requires mentally executing DSL.

New: cv/v2/widgets/

File Variants
Headline.java .spacedCentered, .rightAligned, .render(align, spacedCaps)
ContactLine.java .centered, .rightAligned, .render(align, order)
SectionHeader.java .banner, .underlined, .flat(color)

Three layers of customisation per widget:

  1. Convenience factory — one line, common case
  2. Low-level render(...) — same widget, more knobs
  3. Inline DSL — when no widget fits, bypass it; widgets are
    optional helpers, not required wrappers

Refactor — 3 presets use widgets

  • BoxedSections: 3 widget calls in compose()
  • MinimalUnderlined: 3 widget calls, private renderUnderlinedTitle deleted
  • ModernProfessional: 1 widget call (SectionHeader.flat) plus
    renderHeader / renderContact kept inline because the
    preset-specific colours (slate-blue name, royal-blue links) don't
    fit widget defaults. This is the documented "widget doesn't fit
    → inline" pattern.

Backward compatibility

  • components/HeadlineRenderer@Deprecated, delegates to widget
  • components/ContactRenderer@Deprecated, delegates to widget
  • components/BannerRenderer@Deprecated, delegates to widget

Old v2 callers keep compiling unchanged.

Docs

  • AUTHORS.md gains full "Widget cookbook" section: catalog
    table per widget, 12-line composing-a-preset example,
    when-to-add-a-widget guidance, "doesn't fit → inline" recipe,
    forward-looking examples (Badge, IconLabel, Divider — not yet
    implemented, included as illustration where the catalog can
    grow).
  • package-info.java ASCII diagram updated with widgets/ layer
    between presets/ and components/.

What's NOT changed

  • Engine — zero edits.
  • v1 CV surface — zero edits.
  • Visual output — all 3 v2 PDFs render pixel-identical to
    baseline. Refactor proven.
  • Public v2 API — old *Renderer classes still work
    (deprecated, delegating); widgets are additive.

Test plan

  • WidgetSmokeTest — 4 new tests cover every widget variant
  • All prior v2 tests stay green (38 tests across data/theme/presets)
  • mvn test889/889 pass
  • cv-boxed-sections-v2.pdf — pixel-identical to baseline
  • cv-minimal-underlined.pdf — pixel-identical to baseline
  • cv-modern-professional-v2.pdf — pixel-identical to baseline
  • CI green

What this PR completes (and what it doesn't)

This PR finishes the concept: 4 layers (data / theme /
components / presets) + widgets layer in between gives authors
both structural understanding ("what goes where") AND
compositional ergonomics ("pick a brick, place it").

This PR does NOT migrate v1 templates. That's a separate decision —
"when do we deprecate v1 and port the remaining 13 presets". With
this PR, the concept is sufficiently proven that we can make that
call from data, not theory.

@DemchaAV DemchaAV force-pushed the feature/cv-v2-widgets branch from 1d936dd to 486202e Compare May 24, 2026 12:42
DemchaAV added a commit that referenced this pull request May 24, 2026
…h audit

Phase 3 of the documentation work after audit (#50 added the
templates-layered/ guide; #51 here restructures the entire docs/
tree and fixes terminology + link hygiene).

Reorg — docs/ structure
-----------------------

Was: 21 flat .md files in docs/ with no obvious category. Now
grouped by purpose, mirroring the personas:

  docs/
  ├── README.md                            ← NEW real docs index
  ├── SHOWCASE.md                          ← renamed from docs/README.md
  │                                          (GitHub Pages showcase doc)
  ├── getting-started.md                   ← kept flat (high traffic)
  ├── recipes.md                           ← kept flat (recipes index)
  ├── adr/                                 ← unchanged (8 ADRs)
  ├── archive/                             ← unchanged (3 archived docs)
  ├── recipes/                             ← unchanged (7 recipes)
  ├── architecture/                        ← NEW (5 files moved)
  │   ├── overview.md                      ← was architecture.md
  │   ├── lifecycle.md
  │   ├── pagination-ordering.md
  │   ├── canonical-legacy-parity.md
  │   └── package-map.md
  ├── operations/                          ← NEW (5 files moved)
  │   ├── benchmarks.md
  │   ├── logging.md
  │   ├── performance.md
  │   ├── production-rendering.md
  │   └── layout-snapshot-testing.md
  ├── contributing/                        ← NEW (3 files moved)
  │   ├── extension-guide.md
  │   ├── implementation-guide.md
  │   └── release-process.md
  ├── roadmaps/                            ← NEW (3 files moved)
  │   ├── v1.6-roadmap.md
  │   ├── migration-v1-4-to-v1-5.md
  │   └── migration-v1-5-to-v1-6.md
  └── templates/                           ← NEW (groups both surfaces)
      ├── v1-classic/                      ← was docs/templates-v2.md + template-authoring.md
      │   ├── README.md                    ← v1.6 "Templates v2" landing
      │   └── authoring.md                 ← was template-authoring.md
      └── v2-layered/                      ← was docs/templates-layered/
          ├── README.md
          ├── quickstart.md
          ├── using-templates.md
          ├── authoring-presets.md
          └── contributor-guide.md

20 files moved via `git mv` so the history is preserved.

Documentation index — docs/README.md
------------------------------------

The old docs/README.md was about the GitHub Pages showcase site,
not a docs index — opening docs/ on GitHub showed the wrong thing.

  - Renamed old docs/README.md → docs/SHOWCASE.md
  - Wrote new docs/README.md as the canonical docs landing:
    persona map + category map + ADR list + recipe list + quick
    links.

v1/v2 terminology — explicit callouts
-------------------------------------

The codebase has TWO surfaces both casually called "v2":
  - The v1.6 rebuilt templates (CvSpec / CvBuilder / *Presets)
    which the project calls "Templates v2" internally (ADR-0011).
  - The newer layered cv/v2/ architecture introduced in PRs
    #45-#49.

Added clarifying callouts at the top of:
  - docs/templates/v1-classic/README.md  — "this is the v1.6
    surface; for the newer layered pattern see v2-layered/"
  - docs/templates/v1-classic/authoring.md — same callout
  - docs/templates/v2-layered/README.md   — "this is the layered
    architecture; NOT the older v1.6 'Templates v2'"

Both surfaces are still shipped and supported; neither is
deprecated. The callouts just kill the confusion.

CONTRIBUTING.md update
----------------------

The "New built-in template" section now opens with a fork:
  - For a NEW template family from scratch → layered architecture
    (with link to contributor-guide.md)
  - For a new preset inside an existing v1-classic family → keep
    using BusinessTheme + CvBuilder + the existing presets pattern

Plus a "📚 Map of template docs" pointer to docs/README.md so
contributors don't have to guess.

Orphan resolution
-----------------

  - docs/performance.md was nowhere-linked. Moved to operations/
    and indexed from docs/README.md.
  - docs/recipes/shapes.md was nowhere-linked-from-root-README but
    IS linked from recipes.md (the recipe index). Root README now
    links recipes.md so it's discoverable.
  - ADR numbering gap (0005-0010 missing) explained inline in
    docs/README.md as a note next to the ADR list.

Link integrity
--------------

  - sed sweep across 58 .md files updated every absolute
    `docs/X.md` reference to its new categorised path.
  - Internal relative links inside moved files (e.g. `./benchmarks.md`
    from within docs/architecture/) updated by hand for every
    affected file.
  - Final automated sweep verifies **zero broken markdown links**
    repo-wide.

Tech accuracy spot-check
------------------------

Sampled 4 high-traffic docs against the current code:
  - getting-started.md — every referenced class (DocumentSession,
    BusinessTheme, etc.) exists in src/.
  - templates/v1-classic/authoring.md — every layout class
    (SingleColumn, TwoColumnSidebar, ThreeColumnMagazine, etc.)
    exists.
  - templates/v1-classic/README.md — accurate.
  - contributing/extension-guide.md — accurate.

No stale class references found.

Root README update
------------------

Documentation section reorganised:
  - New "📚 Full docs index" link to docs/README.md.
  - Templates split into v2-layered (new) and v1-classic (legacy
    but shipped) with cross-link to authoring guides.
  - Sub-grouped: Templates / Architecture & operations / Recipes
    & examples / Contributing & releases.

No engine, source, or test changes. Pure documentation.
Closes the "concept" gap surfaced in conversation: until now, an
author who wanted a preset with section titles different from
BoxedSections' banner had to read another preset's private rendering
methods and copy-paste. With widgets, the author picks a named
visual building block and inserts it.

What's new
----------

- cv/v2/widgets/Headline.java
    .spacedCentered  — BoxedSections/MinimalUnderlined style
    .rightAligned    — ModernProfessional style
    .render(...)     — low-level: any (alignment, spacedCaps) combo
- cv/v2/widgets/ContactLine.java
    .centered        — BoxedSections/MinimalUnderlined style
    .rightAligned    — ModernProfessional style
    .render(...)     — low-level: alignment + field Order
- cv/v2/widgets/SectionHeader.java
    .banner          — pale-grey panel, centred spaced-caps
    .underlined      — left spaced-caps + accent rule below
    .flat(color)     — large bold colour, no panel
- cv/v2/widgets/package-info.java — philosophy doc

Each widget has 2–3 named factory methods plus an escape-hatch
.render() with parameters. No spec record / builder for now — keep
the API tight; expand when patterns repeat.

Refactor
--------

- BoxedSections.compose()      — Headline.spacedCentered +
                                  ContactLine.centered +
                                  SectionHeader.banner
- MinimalUnderlined.compose()  — Headline.spacedCentered +
                                  ContactLine.centered +
                                  SectionHeader.underlined
                                  (private renderUnderlinedTitle deleted)
- ModernProfessional.compose() — SectionHeader.flat(SECTION_TITLE_COLOR)
                                  (private renderHeader / renderContact
                                  kept inline — preset-specific colours
                                  don't fit widget defaults; documented
                                  as the "widget doesn't fit → inline"
                                  pattern in AUTHORS.md)

Each preset's compose() shrank from ~30 lines of DSL plumbing to
~12 lines of widget calls. Reading a preset now reads as a sequence
of visual decisions, not as rendering code.

Backward compatibility
----------------------

- components/HeadlineRenderer  → @deprecated, delegates to Headline.spacedCentered
- components/ContactRenderer   → @deprecated, delegates to ContactLine.centered
- components/BannerRenderer    → @deprecated, delegates to SectionHeader.banner

Old v2 callers keep compiling unchanged. @deprecated marks the
forward path so new code reaches for widgets directly.

Docs
----

- AUTHORS.md gains a full "Widget cookbook" section: catalog table
  per widget, composing-a-preset example (12-line full compose()),
  when-to-add-a-widget guidance, "doesn't fit → inline" recipe,
  forward-looking examples (Badge, IconLabel, Divider — not yet
  implemented, included as illustration of where the catalog can
  grow).
- package-info.java ASCII diagram updated to show widgets/ layer
  between presets/ and components/.

Tests
-----

- New WidgetSmokeTest (4 cases) covers every public widget variant
  against the default theme + the modernProfessional theme.
- All 3 v2 preset PDFs render pixel-identical to baseline — proof
  that the widget extraction is purely a refactor.
- Full mvn test: 889/889 pass.

Engine and v1 surface untouched.
@DemchaAV DemchaAV force-pushed the feature/cv-v2-widgets branch from 486202e to d5c09d4 Compare May 24, 2026 13:53
@DemchaAV DemchaAV merged commit 8a00bd6 into develop May 24, 2026
9 checks passed
@DemchaAV DemchaAV deleted the feature/cv-v2-widgets branch May 24, 2026 13:58
DemchaAV added a commit that referenced this pull request May 24, 2026
…h audit

Phase 3 of the documentation work after audit (#50 added the
templates-layered/ guide; #51 here restructures the entire docs/
tree and fixes terminology + link hygiene).

Reorg — docs/ structure
-----------------------

Was: 21 flat .md files in docs/ with no obvious category. Now
grouped by purpose, mirroring the personas:

  docs/
  ├── README.md                            ← NEW real docs index
  ├── SHOWCASE.md                          ← renamed from docs/README.md
  │                                          (GitHub Pages showcase doc)
  ├── getting-started.md                   ← kept flat (high traffic)
  ├── recipes.md                           ← kept flat (recipes index)
  ├── adr/                                 ← unchanged (8 ADRs)
  ├── archive/                             ← unchanged (3 archived docs)
  ├── recipes/                             ← unchanged (7 recipes)
  ├── architecture/                        ← NEW (5 files moved)
  │   ├── overview.md                      ← was architecture.md
  │   ├── lifecycle.md
  │   ├── pagination-ordering.md
  │   ├── canonical-legacy-parity.md
  │   └── package-map.md
  ├── operations/                          ← NEW (5 files moved)
  │   ├── benchmarks.md
  │   ├── logging.md
  │   ├── performance.md
  │   ├── production-rendering.md
  │   └── layout-snapshot-testing.md
  ├── contributing/                        ← NEW (3 files moved)
  │   ├── extension-guide.md
  │   ├── implementation-guide.md
  │   └── release-process.md
  ├── roadmaps/                            ← NEW (3 files moved)
  │   ├── v1.6-roadmap.md
  │   ├── migration-v1-4-to-v1-5.md
  │   └── migration-v1-5-to-v1-6.md
  └── templates/                           ← NEW (groups both surfaces)
      ├── v1-classic/                      ← was docs/templates-v2.md + template-authoring.md
      │   ├── README.md                    ← v1.6 "Templates v2" landing
      │   └── authoring.md                 ← was template-authoring.md
      └── v2-layered/                      ← was docs/templates-layered/
          ├── README.md
          ├── quickstart.md
          ├── using-templates.md
          ├── authoring-presets.md
          └── contributor-guide.md

20 files moved via `git mv` so the history is preserved.

Documentation index — docs/README.md
------------------------------------

The old docs/README.md was about the GitHub Pages showcase site,
not a docs index — opening docs/ on GitHub showed the wrong thing.

  - Renamed old docs/README.md → docs/SHOWCASE.md
  - Wrote new docs/README.md as the canonical docs landing:
    persona map + category map + ADR list + recipe list + quick
    links.

v1/v2 terminology — explicit callouts
-------------------------------------

The codebase has TWO surfaces both casually called "v2":
  - The v1.6 rebuilt templates (CvSpec / CvBuilder / *Presets)
    which the project calls "Templates v2" internally (ADR-0011).
  - The newer layered cv/v2/ architecture introduced in PRs
    #45-#49.

Added clarifying callouts at the top of:
  - docs/templates/v1-classic/README.md  — "this is the v1.6
    surface; for the newer layered pattern see v2-layered/"
  - docs/templates/v1-classic/authoring.md — same callout
  - docs/templates/v2-layered/README.md   — "this is the layered
    architecture; NOT the older v1.6 'Templates v2'"

Both surfaces are still shipped and supported; neither is
deprecated. The callouts just kill the confusion.

CONTRIBUTING.md update
----------------------

The "New built-in template" section now opens with a fork:
  - For a NEW template family from scratch → layered architecture
    (with link to contributor-guide.md)
  - For a new preset inside an existing v1-classic family → keep
    using BusinessTheme + CvBuilder + the existing presets pattern

Plus a "📚 Map of template docs" pointer to docs/README.md so
contributors don't have to guess.

Orphan resolution
-----------------

  - docs/performance.md was nowhere-linked. Moved to operations/
    and indexed from docs/README.md.
  - docs/recipes/shapes.md was nowhere-linked-from-root-README but
    IS linked from recipes.md (the recipe index). Root README now
    links recipes.md so it's discoverable.
  - ADR numbering gap (0005-0010 missing) explained inline in
    docs/README.md as a note next to the ADR list.

Link integrity
--------------

  - sed sweep across 58 .md files updated every absolute
    `docs/X.md` reference to its new categorised path.
  - Internal relative links inside moved files (e.g. `./benchmarks.md`
    from within docs/architecture/) updated by hand for every
    affected file.
  - Final automated sweep verifies **zero broken markdown links**
    repo-wide.

Tech accuracy spot-check
------------------------

Sampled 4 high-traffic docs against the current code:
  - getting-started.md — every referenced class (DocumentSession,
    BusinessTheme, etc.) exists in src/.
  - templates/v1-classic/authoring.md — every layout class
    (SingleColumn, TwoColumnSidebar, ThreeColumnMagazine, etc.)
    exists.
  - templates/v1-classic/README.md — accurate.
  - contributing/extension-guide.md — accurate.

No stale class references found.

Root README update
------------------

Documentation section reorganised:
  - New "📚 Full docs index" link to docs/README.md.
  - Templates split into v2-layered (new) and v1-classic (legacy
    but shipped) with cross-link to authoring guides.
  - Sub-grouped: Templates / Architecture & operations / Recipes
    & examples / Contributing & releases.

No engine, source, or test changes. Pure documentation.
DemchaAV added a commit that referenced this pull request May 24, 2026
…h audit (#51)

Phase 3 of the documentation work after audit (#50 added the
templates-layered/ guide; #51 here restructures the entire docs/
tree and fixes terminology + link hygiene).

Reorg — docs/ structure
-----------------------

Was: 21 flat .md files in docs/ with no obvious category. Now
grouped by purpose, mirroring the personas:

  docs/
  ├── README.md                            ← NEW real docs index
  ├── SHOWCASE.md                          ← renamed from docs/README.md
  │                                          (GitHub Pages showcase doc)
  ├── getting-started.md                   ← kept flat (high traffic)
  ├── recipes.md                           ← kept flat (recipes index)
  ├── adr/                                 ← unchanged (8 ADRs)
  ├── archive/                             ← unchanged (3 archived docs)
  ├── recipes/                             ← unchanged (7 recipes)
  ├── architecture/                        ← NEW (5 files moved)
  │   ├── overview.md                      ← was architecture.md
  │   ├── lifecycle.md
  │   ├── pagination-ordering.md
  │   ├── canonical-legacy-parity.md
  │   └── package-map.md
  ├── operations/                          ← NEW (5 files moved)
  │   ├── benchmarks.md
  │   ├── logging.md
  │   ├── performance.md
  │   ├── production-rendering.md
  │   └── layout-snapshot-testing.md
  ├── contributing/                        ← NEW (3 files moved)
  │   ├── extension-guide.md
  │   ├── implementation-guide.md
  │   └── release-process.md
  ├── roadmaps/                            ← NEW (3 files moved)
  │   ├── v1.6-roadmap.md
  │   ├── migration-v1-4-to-v1-5.md
  │   └── migration-v1-5-to-v1-6.md
  └── templates/                           ← NEW (groups both surfaces)
      ├── v1-classic/                      ← was docs/templates-v2.md + template-authoring.md
      │   ├── README.md                    ← v1.6 "Templates v2" landing
      │   └── authoring.md                 ← was template-authoring.md
      └── v2-layered/                      ← was docs/templates-layered/
          ├── README.md
          ├── quickstart.md
          ├── using-templates.md
          ├── authoring-presets.md
          └── contributor-guide.md

20 files moved via `git mv` so the history is preserved.

Documentation index — docs/README.md
------------------------------------

The old docs/README.md was about the GitHub Pages showcase site,
not a docs index — opening docs/ on GitHub showed the wrong thing.

  - Renamed old docs/README.md → docs/SHOWCASE.md
  - Wrote new docs/README.md as the canonical docs landing:
    persona map + category map + ADR list + recipe list + quick
    links.

v1/v2 terminology — explicit callouts
-------------------------------------

The codebase has TWO surfaces both casually called "v2":
  - The v1.6 rebuilt templates (CvSpec / CvBuilder / *Presets)
    which the project calls "Templates v2" internally (ADR-0011).
  - The newer layered cv/v2/ architecture introduced in PRs
    #45-#49.

Added clarifying callouts at the top of:
  - docs/templates/v1-classic/README.md  — "this is the v1.6
    surface; for the newer layered pattern see v2-layered/"
  - docs/templates/v1-classic/authoring.md — same callout
  - docs/templates/v2-layered/README.md   — "this is the layered
    architecture; NOT the older v1.6 'Templates v2'"

Both surfaces are still shipped and supported; neither is
deprecated. The callouts just kill the confusion.

CONTRIBUTING.md update
----------------------

The "New built-in template" section now opens with a fork:
  - For a NEW template family from scratch → layered architecture
    (with link to contributor-guide.md)
  - For a new preset inside an existing v1-classic family → keep
    using BusinessTheme + CvBuilder + the existing presets pattern

Plus a "📚 Map of template docs" pointer to docs/README.md so
contributors don't have to guess.

Orphan resolution
-----------------

  - docs/performance.md was nowhere-linked. Moved to operations/
    and indexed from docs/README.md.
  - docs/recipes/shapes.md was nowhere-linked-from-root-README but
    IS linked from recipes.md (the recipe index). Root README now
    links recipes.md so it's discoverable.
  - ADR numbering gap (0005-0010 missing) explained inline in
    docs/README.md as a note next to the ADR list.

Link integrity
--------------

  - sed sweep across 58 .md files updated every absolute
    `docs/X.md` reference to its new categorised path.
  - Internal relative links inside moved files (e.g. `./benchmarks.md`
    from within docs/architecture/) updated by hand for every
    affected file.
  - Final automated sweep verifies **zero broken markdown links**
    repo-wide.

Tech accuracy spot-check
------------------------

Sampled 4 high-traffic docs against the current code:
  - getting-started.md — every referenced class (DocumentSession,
    BusinessTheme, etc.) exists in src/.
  - templates/v1-classic/authoring.md — every layout class
    (SingleColumn, TwoColumnSidebar, ThreeColumnMagazine, etc.)
    exists.
  - templates/v1-classic/README.md — accurate.
  - contributing/extension-guide.md — accurate.

No stale class references found.

Root README update
------------------

Documentation section reorganised:
  - New "📚 Full docs index" link to docs/README.md.
  - Templates split into v2-layered (new) and v1-classic (legacy
    but shipped) with cross-link to authoring guides.
  - Sub-grouped: Templates / Architecture & operations / Recipes
    & examples / Contributing & releases.

No engine, source, or test changes. Pure documentation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants