17edf19f89
cv-builder.md (variant model, rendering pipeline, API, builder workflow, extension points, known deep-link limitation) + cv-theme-engine.md (how a theme is data and how to add one). Roadmap Phase 4 marked foundation-shipped with the remaining polish itemised. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
54 lines
2.8 KiB
Markdown
54 lines
2.8 KiB
Markdown
# CV Theme Engine
|
|
|
|
> Phase 4 (2026-07-18). How CV themes work and how to add one. Companion to
|
|
> `docs/architecture/cv-builder.md`. Verified against code.
|
|
|
|
## The rule
|
|
|
|
**A theme is data, not code.** There is exactly one renderer — `ThemedCvRenderer`
|
|
(`JobTrackerApi/Services/ThemedCvRenderer.cs`) — with a single render path. Every visual difference
|
|
between themes is expressed by the fields of a `CvTheme` record (`Models/CvTheme.cs`). Adding a theme
|
|
never touches the renderer.
|
|
|
|
This replaces the previous approach (`CvTemplateRenderer`, one hand-written HTML method per template),
|
|
which is retained only for the legacy tailored-draft flow and is not used by the builder.
|
|
|
|
## `CvTheme` fields (the knobs)
|
|
|
|
| Group | Fields |
|
|
|---|---|
|
|
| Identity | `Id`, `Name`, `Category`, `Description` |
|
|
| Layout | `Layout` (`single` \| `sidebar-left` \| `sidebar-right` \| `header-band`), `SidebarWidthMm`, `SidebarSections` |
|
|
| Palette | `Accent`, `Ink`, `Muted`, `Line`, `Paper`, `SidebarBg`, `SidebarInk`, `HeadingColor` |
|
|
| Typography | `HeadingFont`, `BodyFont`, `NameSizePt`, `HeadingSizePt`, `BodySizePt`, `LineHeight` |
|
|
| Spacing | `PageMarginMm`, `SectionGapMm`, `EntryGapMm` |
|
|
| Styling | `HeaderStyle` (`plain`\|`band`\|`centered`\|`kicker`), `HeadingStyle` (`caps-rule`\|`underline`\|`plain`\|`bar`), `PhotoShape` (`none`\|`square`\|`rounded`\|`circle`), `DefaultIcons` |
|
|
|
|
The renderer computes CSS variables from these plus the variant's runtime overrides (accent, fonts,
|
|
density, page size, photo, icons) and picks one of the layout wrappers. `SidebarSections` decides which
|
|
section keys move to the sidebar for the two-column layouts.
|
|
|
|
## Adding a theme
|
|
|
|
1. Append one `CvTheme { … }` to `CvThemeCatalog.Themes` (`Models/CvTheme.cs`). Only override the
|
|
fields that differ from the defaults.
|
|
2. Nothing else. It appears in `GET /api/cv/themes`, the Customize tab picker, and renders.
|
|
|
|
Add a `CvBuilderTests.Every_catalog_theme_renders_valid_html` already loops the whole catalog, so a new
|
|
theme is smoke-tested automatically.
|
|
|
|
## Shipped themes (8)
|
|
|
|
`modern` (header-band), `minimal` (single), `executive` (single, serif), `technical` (sidebar-left,
|
|
dense), `ats-classic` (single, no graphics), `nordic` (sidebar-right), `elegant` (single, editorial),
|
|
`creative` (sidebar-left, bold).
|
|
|
|
## Deliberately not here (yet)
|
|
|
|
- **Rich-text inside bullets.** The render model treats bullets as plain strings, so the builder's text
|
|
areas are plain text. Adding bold/italic/links means the render model carries inline runs and the
|
|
renderer emits them — a self-contained extension, no theme changes.
|
|
- **PDF page numbers.** `ShowPageNumbers` is carried through settings but the actual footer is a
|
|
Playwright `footerTemplate` concern (the PDF exporter), not CSS paged-media (Chromium's margin boxes
|
|
are unreliable). Wire it in `PlaywrightCvPdfExporter` when needed.
|