mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-22 14:22:16 +10:00
feat: add semantic CSS stylesheets (#3274)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor Agent
parent
4ac19f81b3
commit
d2ffbf9618
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,667 @@
|
||||
# Semantic CSS Stylesheet Design
|
||||
|
||||
## Status
|
||||
|
||||
Draft for user review. The product behavior in this document has been approved conversationally; the written
|
||||
architecture still requires review before implementation planning.
|
||||
|
||||
## Context
|
||||
|
||||
Reactive Resume renders its templates with React PDF rather than browser HTML. React PDF accepts style objects on a
|
||||
known component tree and supports a broad CSS-like property set, but it does not provide a browser DOM or a general
|
||||
selector engine.
|
||||
|
||||
The current customization system stores constrained rules in `metadata.styleRules`. Each rule targets all sections, a
|
||||
section type, or a section ID and applies an intent to one semantic slot. That design is safe and portable, but its form
|
||||
UI is cumbersome to reproduce or share, and its target model cannot reach headers, individual items or fields, page
|
||||
regions, or template-specific visual parts.
|
||||
|
||||
Semantic CSS replaces the form with a familiar text language. It retains typed compilation and semantic targets rather
|
||||
than promising that arbitrary browser CSS can run inside React PDF.
|
||||
|
||||
## Goals
|
||||
|
||||
- Provide one copy-pastable text stylesheet for all PDF-specific visual customization.
|
||||
- Keep Design, Typography, Layout, Page, and Picture controls as base settings.
|
||||
- Let the stylesheet override those base visuals wherever an exposed semantic PDF node permits it.
|
||||
- Target all sections, groups of section types, one section, one item, one field, structural regions, header content,
|
||||
rich text, and documented template-specific parts.
|
||||
- Support portable theme rules and optional resume-specific rules based on stable IDs.
|
||||
- Support nearly all style properties that the pinned React PDF renderer can safely implement.
|
||||
- Preserve invalid user text while rendering the last valid stylesheet.
|
||||
- Produce identical behavior in browser preview, browser export, public PDF views, and server PDF export.
|
||||
- Convert existing structured style rules without changing their rendered appearance.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- The stylesheet does not edit resume content or mutate builder layout metadata.
|
||||
- The stylesheet does not apply to DOCX or Markdown exports.
|
||||
- It does not expose a browser DOM, JavaScript, arbitrary renderer objects, or executable expressions.
|
||||
- It does not support animations, transitions, interactive pseudo-classes, CSS Grid, generated content, or browser-only
|
||||
properties.
|
||||
- It does not load fonts, images, imports, or any other remote or embedded asset.
|
||||
- Font-family selection remains owned by the Typography section.
|
||||
- Picture source, upload, crop, and visibility data remain owned by the Picture section. The rendered picture node can
|
||||
still be sized, positioned, transformed, or hidden by the stylesheet.
|
||||
|
||||
## Product Model
|
||||
|
||||
The existing visual controls remain the base layer. Semantic CSS is the final author-controlled layer:
|
||||
|
||||
1. Builder visual settings and template defaults.
|
||||
2. Template-specific computed styles.
|
||||
3. Semantic CSS declarations.
|
||||
4. Minimal crash-prevention invariants.
|
||||
|
||||
The stylesheet may visually hide, reorder, resize, or position existing output. These changes affect only PDF
|
||||
presentation. They do not rewrite content, section ordering, page assignments, or other builder data.
|
||||
|
||||
## Persisted Data
|
||||
|
||||
Resume metadata gains a versioned stylesheet value:
|
||||
|
||||
```ts
|
||||
type StylesheetSource = {
|
||||
languageVersion: number;
|
||||
text: string;
|
||||
};
|
||||
|
||||
type SemanticStylesheet = {
|
||||
mode: "legacy" | "semantic";
|
||||
source: StylesheetSource;
|
||||
applied: StylesheetSource;
|
||||
};
|
||||
|
||||
type StylesheetMutationState = {
|
||||
revision: number;
|
||||
stylesheet: SemanticStylesheet;
|
||||
};
|
||||
```
|
||||
|
||||
- `source.text` is the exact editable text and may be invalid.
|
||||
- `applied.text` is the most recent valid text and is the only text used for rendering.
|
||||
- Each value carries its own `languageVersion`, allowing an invalid source written for a future language version to
|
||||
preserve and render an older valid program.
|
||||
- `mode` is the persisted rendering discriminator. A missing stylesheet is interpreted as `legacy`.
|
||||
- `revision` is server-owned concurrency metadata, not resume content. It is stored in a dedicated database column and
|
||||
returned only in the stylesheet mutation envelope.
|
||||
|
||||
The compiled AST or intermediate representation is not persisted. Browser and server compilation is a pure operation
|
||||
cached by language version, source hash, compiler build, semantic registry fingerprint, and PDF adapter fingerprint.
|
||||
Caches are bounded and process-local; they are never treated as durable state.
|
||||
|
||||
Stylesheet state is owned by a dedicated authenticated mutation rather than the existing full-document autosave
|
||||
mutation. It accepts an expected stylesheet revision and resume render-data version. The generic `resume.update` path
|
||||
must preserve the database's stylesheet value instead of replacing it from submitted resume data. This preservation
|
||||
behavior must deploy before clients can send Semantic CSS data.
|
||||
|
||||
Compilation and PDF preflight never run while holding a database lock. The mutation reads an immutable resume snapshot,
|
||||
compiles and preflights against that snapshot, then performs a short transaction that compare-and-swaps both the
|
||||
stylesheet revision and resume render-data version. If either changed, it returns a conflict without writing; the client
|
||||
rebases its unsaved source onto the new snapshot and retries. This prevents promotion against content or base settings
|
||||
that differ from those preflighted.
|
||||
|
||||
The server defines separate state transitions. A source can replace `applied` only after compilation and a bounded PDF
|
||||
render preflight against the current resume succeed:
|
||||
|
||||
- **Edit source:** ignore client-applied text. Store the candidate in `source`. In semantic mode, also store it in
|
||||
`applied` only when compilation and preflight succeed; otherwise preserve the row's current `applied`. In legacy mode,
|
||||
edits remain an inactive draft.
|
||||
- **Activate converted source:** require successful compilation, set `mode` to `semantic`, and store the candidate in
|
||||
both source values after preflight. This requires an explicit **Activate Semantic CSS** action. Merely opening,
|
||||
editing, or autosaving a legacy draft does not activate it.
|
||||
- **Editor undo or redo:** independently compile the historical applied value carried by the local history entry, then
|
||||
preflight it and atomically restore the historical source/applied pair. Reject the transition if the applied value is
|
||||
invalid.
|
||||
- **Import:** compile imported source. If it is invalid, independently validate the imported applied value and retain it
|
||||
only after preflight; otherwise use an empty supported applied source.
|
||||
- **Duplicate:** copy the server-owned stylesheet content while initializing a fresh concurrency revision for the new
|
||||
resume.
|
||||
- **Restore version:** restore the server-owned source/applied pair from the selected snapshot after validating the
|
||||
applied value with its versioned compiler and preflight.
|
||||
|
||||
Every successful transition increments `revision` and returns the canonical state plus diagnostics. Worker jobs and
|
||||
network requests carry the local edit generation and expected revision. The client serializes stylesheet mutations:
|
||||
only one request is in flight, and later edits replace one queued candidate. Every acknowledgement advances the local
|
||||
revision; its source/applied payload updates editor state only when its generation is still current. The queued candidate
|
||||
then submits with the acknowledged revision. Warnings do not block application.
|
||||
|
||||
Concurrency revisions are excluded from JSON export and version snapshots. Import and duplicate initialize a fresh
|
||||
revision; version restore increments the current resume's revision rather than restoring historical concurrency
|
||||
metadata.
|
||||
|
||||
## Compiler Architecture
|
||||
|
||||
The compiler is a universal, environment-neutral package used by the web app, API, and PDF renderer:
|
||||
|
||||
```text
|
||||
source
|
||||
-> CSS tokenizer/parser
|
||||
-> syntax AST
|
||||
-> restricted-language validation
|
||||
-> selector and value compilation
|
||||
-> versioned StyleProgram + diagnostics
|
||||
```
|
||||
|
||||
`StyleProgram` contains normalized selectors, declaration values, source locations, specificity, media conditions, and
|
||||
structural directives. It contains no React or React PDF values. A PDF adapter translates resolved declarations into
|
||||
React PDF styles and primitive props.
|
||||
|
||||
The parser should use a standards-compatible CSS parser rather than a hand-written partial tokenizer. Semantic CSS
|
||||
validation sits on top of that parser and rejects unsupported CSS constructs explicitly.
|
||||
|
||||
Compilation and selector matching must remain deterministic. Diagnostics include severity, code, message, and exact
|
||||
source range.
|
||||
|
||||
Source compilation reports syntax and language-contract diagnostics without needing a resume. A separate semantic
|
||||
analysis pass evaluates a compiled program against the current resume's virtual tree and reports context-dependent
|
||||
warnings such as valid selectors that match no node. Both passes use shared diagnostic types and codes.
|
||||
|
||||
Language versions are positive integers. A compiler implementation for a released version is immutable. Unsupported
|
||||
source versions are preserved as opaque editable text but cannot replace `applied`; rendering continues with the
|
||||
supported applied version or base styles when no supported applied value exists.
|
||||
|
||||
Every compiler version referenced by persisted `applied` data remains available. A compiler can be retired only after a
|
||||
transactional migration recompiles and preflights every affected applied stylesheet with a newer version and no stored
|
||||
resume references the old version.
|
||||
|
||||
## Virtual Semantic Tree
|
||||
|
||||
Selectors match a versioned, immutable virtual resume tree, not React component names:
|
||||
|
||||
```text
|
||||
resume
|
||||
page
|
||||
region
|
||||
header
|
||||
picture
|
||||
name
|
||||
headline
|
||||
contact-list
|
||||
contact-item
|
||||
section
|
||||
section-heading
|
||||
section-items
|
||||
item
|
||||
item-header
|
||||
field
|
||||
link
|
||||
icon
|
||||
level
|
||||
rich-text
|
||||
paragraph
|
||||
list
|
||||
list-item
|
||||
list-marker
|
||||
```
|
||||
|
||||
Template-owned chrome is exposed as `template-part` nodes. Every part name must be registered, documented, and stable.
|
||||
Examples include `timeline-line`, `timeline-dot`, `featured-summary`, `sidebar-background`, and
|
||||
`item-header-border`.
|
||||
|
||||
Each node carries only documented semantic attributes, including the applicable subset of:
|
||||
|
||||
- `id`: stable section or item ID.
|
||||
- `type`: canonical section type.
|
||||
- `name`: field, contact, or template-part name.
|
||||
- `template`: selected template on the root.
|
||||
- `placement`: `main` or `sidebar`.
|
||||
- `region`: `header`, `main`, `sidebar`, `featured`, or another registered region.
|
||||
- `page-number`: one-based layout page number.
|
||||
- `role`: one or more stable roles such as `primary-text`, `secondary-text`, or `structured-link`.
|
||||
|
||||
Custom classes are not supported because resume data has no class-authoring surface. Groups are expressed through
|
||||
selector lists, attributes, `:is()`, and `:where()`.
|
||||
|
||||
All shared primitives and all 15 templates must register their semantic nodes before Semantic CSS becomes the default.
|
||||
Known semantic nodes that are absent from the current template are valid no-ops and produce warnings.
|
||||
|
||||
The normative node contract is:
|
||||
|
||||
```ts
|
||||
type SemanticNode = {
|
||||
key: string;
|
||||
kind: SemanticNodeKind;
|
||||
id?: string;
|
||||
attributes: Readonly<Record<string, string>>;
|
||||
roles: readonly string[];
|
||||
children: readonly SemanticNode[];
|
||||
};
|
||||
```
|
||||
|
||||
Each template builds one authoritative descriptor tree from `ResumeData`, template configuration, normalized rich-text
|
||||
content, and the typed semantic registries. Selector matching, context-dependent diagnostics, inheritance, structural
|
||||
resolution, and React rendering all consume that same tree. React components must not create unregistered semantic
|
||||
children independently.
|
||||
|
||||
The registries normatively define allowed parentage, cardinality, field names, role names, stable keys, and
|
||||
template-part placement. Experience roles, custom fields, rich-text nodes, featured summaries, and template-specific
|
||||
header structures are explicitly represented rather than inferred from React children.
|
||||
|
||||
## Selector Language
|
||||
|
||||
Semantic CSS supports:
|
||||
|
||||
- Type selectors and the universal selector.
|
||||
- ID and attribute selectors.
|
||||
- Selector lists separated by commas.
|
||||
- Descendant, child, adjacent-sibling, and general-sibling combinators.
|
||||
- `:is()`, `:where()`, and `:not()`.
|
||||
- Static structural pseudo-classes such as `:first-child`, `:last-child`, `:only-child`, `:nth-child()`, and
|
||||
`:nth-of-type()`.
|
||||
|
||||
Interactive or browser-state pseudo-classes are errors.
|
||||
|
||||
`SemanticNode.id` is reflected to both `#id` and `[id="…"]`. `roles` is reflected as a space-separated `role`
|
||||
attribute and matched with `[role~="token"]`. Other entries in `attributes` are exposed by their registered names.
|
||||
Presence, `=`, `~=`, `|=`, `^=`, `$=`, and `*=` attribute operators are supported. Semantic element, attribute, role,
|
||||
and registered keyword names are lowercase and ASCII case-sensitive. Values and IDs are case-sensitive. Selectors use
|
||||
standard CSS escaping; quoted `[id="…"]` is the recommended syntax for UUIDs that would require identifier escapes.
|
||||
|
||||
Examples:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--accent: #2563eb;
|
||||
--compact-gap: 4pt;
|
||||
}
|
||||
|
||||
section:is([type="experience"], [type="education"]) {
|
||||
margin-bottom: 8pt;
|
||||
}
|
||||
|
||||
section#experience > section-heading {
|
||||
color: var(--accent);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
region[placement="sidebar"] section,
|
||||
section#skills {
|
||||
background-color: rgba(20, 30, 40, 0.08);
|
||||
}
|
||||
|
||||
item[id="f27be2d2-13a9-4f16-8248-c8735a27dd1c"] field[name="period"] {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
resume[template="azurill"] template-part[name="timeline-dot"] {
|
||||
background-color: var(--accent);
|
||||
}
|
||||
```
|
||||
|
||||
Portable styles should prefer section types, roles, placements, regions, and template attributes. Exact section and item
|
||||
IDs are available when a rule intentionally belongs to one resume.
|
||||
|
||||
## Cascade and Inheritance
|
||||
|
||||
Semantic CSS follows familiar author-style cascade rules:
|
||||
|
||||
- `!important` declarations outrank normal declarations.
|
||||
- Specificity compares IDs, then attributes and pseudo-classes, then element names.
|
||||
- `:where()` contributes zero specificity.
|
||||
- Equal specificity is resolved by source order.
|
||||
- Custom properties cascade and inherit.
|
||||
- Cyclic or unresolved variables are errors unless a valid fallback exists.
|
||||
|
||||
Only properties marked inheritable in the property registry inherit through the semantic tree. Box and layout
|
||||
properties never inherit implicitly. The language supports `inherit`, `initial`, `unset`, and `revert`; `revert`
|
||||
removes the winning Semantic CSS declaration at that node and exposes its builder/template base value. If the property
|
||||
is inheritable and the semantic parent has a computed Semantic CSS value, normal inheritance can still supply that
|
||||
parent value. `initial` uses the property registry's initial value, `inherit` uses the semantic parent's computed value,
|
||||
and `unset` chooses `inherit` for inheritable properties and `initial` otherwise. `revert-layer` is unsupported.
|
||||
|
||||
Declarations are resolved after template styles. Existing cosmetic safety defaults such as text shrinking must move
|
||||
below the stylesheet in precedence. Only constraints required to prevent renderer failure may remain above user
|
||||
declarations, and each such constraint must be documented.
|
||||
|
||||
Resolution uses one immutable source-tree snapshot:
|
||||
|
||||
1. Match all selectors against original parentage and sibling order.
|
||||
2. Calculate selector specificity according to CSS rules: `:is()` and `:not()` take their most specific argument,
|
||||
while `:where()` has zero specificity.
|
||||
3. Cascade declarations and custom properties, then calculate inherited values.
|
||||
4. Resolve structural declarations once.
|
||||
5. Omit `display: none` subtrees and stable-sort remaining siblings by `order`, using original sibling order for ties.
|
||||
6. Render the resolved tree.
|
||||
|
||||
Hidden and reordered nodes never change which selectors match, positional pseudo-classes, sibling combinators, or
|
||||
inheritance. Structural declarations cannot trigger a second selector pass.
|
||||
|
||||
## Properties, Values, and Units
|
||||
|
||||
The property registry exposes the applicable React PDF surface under familiar kebab-case names:
|
||||
|
||||
- Flexbox layout, including gaps and `order`.
|
||||
- Width, height, minimum and maximum dimensions.
|
||||
- Relative and absolute positioning, overflow, stacking, and display.
|
||||
- Color, background color, and opacity.
|
||||
- Text size, weight, style, line height, spacing, alignment, decoration, transform, indentation, overflow, and line
|
||||
limits.
|
||||
- Margins, padding, borders, radii, and supported transforms.
|
||||
- Supported image sizing and object-fit behavior on the existing picture node.
|
||||
|
||||
`font-family` is rejected. Asset-bearing properties and functions such as `background-image`, `src`, and `url()` are
|
||||
rejected.
|
||||
|
||||
Common shorthands such as `margin`, `padding`, `border`, `gap`, `flex`, and `transform` compile into normalized values.
|
||||
Supported units are `pt`, `in`, `mm`, `cm`, `%`, `vw`, `vh`, `em`, and `rem`. Unitless PDF dimensions are interpreted
|
||||
as points. `px` is accepted for familiarity and converted from 96 DPI to 72-DPI PDF points.
|
||||
|
||||
`rem` resolves against the root body font size from Typography. For `font-size`, `em` resolves against the semantic
|
||||
parent's computed font size. For all other properties, it resolves against the target node's computed font size.
|
||||
Relative-unit cycles are errors.
|
||||
|
||||
Media queries use standard syntax and support page width, page height, and orientation:
|
||||
|
||||
```css
|
||||
@media (max-width: 500pt) {
|
||||
region[placement="sidebar"] {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Page and pagination behavior uses standard properties where possible and namespaced extensions where React PDF exposes
|
||||
primitive props rather than style properties:
|
||||
|
||||
```css
|
||||
section[type="experience"] {
|
||||
break-inside: avoid;
|
||||
-resume-min-presence-ahead: 24pt;
|
||||
}
|
||||
|
||||
page {
|
||||
size: A4;
|
||||
}
|
||||
|
||||
header {
|
||||
-resume-fixed: true;
|
||||
}
|
||||
```
|
||||
|
||||
Supported structural declarations include:
|
||||
|
||||
- `display: none` to omit a semantic node.
|
||||
- `order` to reorder siblings before React rendering.
|
||||
- `break-before: page`.
|
||||
- `break-inside: avoid`.
|
||||
- `orphans` and `widows`.
|
||||
- `-resume-fixed`.
|
||||
- `-resume-min-presence-ahead`.
|
||||
- `size` on page nodes.
|
||||
|
||||
Structural declarations are resolved while preparing semantic child descriptors, before the React component tree is
|
||||
created. CSS cannot move a node to a different parent; absolute positioning can only change its visual placement.
|
||||
|
||||
`page-number` identifies the one-based authored `metadata.layout.pages` entry. React PDF may wrap one authored page into
|
||||
multiple physical subpages; those physical subpages are not independently selectable. They inherit the authored page
|
||||
context, and fixed nodes repeat on physical subpages created from that authored page.
|
||||
|
||||
Page sizing is evaluated in a non-circular phase. Non-media `size` declarations resolve first against builder defaults.
|
||||
Media conditions then evaluate against that final authored page size. `size` inside `@media` is an error.
|
||||
|
||||
Values must be finite. Very large, negative, or overlap-prone values produce warnings rather than cosmetic clamping.
|
||||
Hard technical limits exist only to prevent crashes, pathological allocations, or denial of service.
|
||||
|
||||
## Editor Experience
|
||||
|
||||
The Custom Styles right-sidebar section becomes a monospaced stylesheet editor. It also offers an expanded mode with
|
||||
more editing space while retaining the live preview.
|
||||
|
||||
Editor capabilities include:
|
||||
|
||||
- CSS syntax highlighting.
|
||||
- Line and column diagnostics with error and warning severity.
|
||||
- Selector, attribute, property, keyword, and variable completion.
|
||||
- Hover documentation generated from semantic and property registries.
|
||||
- Color previews.
|
||||
- Search and replace.
|
||||
- Explicit formatting.
|
||||
- Standard copy and paste.
|
||||
- A clear applied state.
|
||||
|
||||
The editor preserves source text and formatting exactly unless the user explicitly formats it.
|
||||
|
||||
Compilation runs after a short debounce in a web worker. The status must distinguish:
|
||||
|
||||
- `Applied`.
|
||||
- Applied with warnings.
|
||||
- Errors, with an explicit message that preview and export use the last valid version.
|
||||
|
||||
The editor maintains source state separately from full-resume autosave. It runs a browser render preflight for a
|
||||
compiled candidate and sends serialized, debounced, revisioned stylesheet mutations. It always consumes response
|
||||
revisions, but replaces visible source/applied state only for the current edit generation. Existing coalesced undo and
|
||||
redo behavior includes both stylesheet values and uses the explicit restore transition, so undo restores matching text
|
||||
and rendered output.
|
||||
|
||||
## Diagnostics
|
||||
|
||||
Errors prevent a new source from becoming applied:
|
||||
|
||||
- Invalid CSS syntax.
|
||||
- Unknown semantic element or attribute.
|
||||
- Unknown or unsupported property.
|
||||
- Invalid value, unit, selector, pseudo-class, at-rule, or variable cycle.
|
||||
- Disallowed font or asset access.
|
||||
- Exceeded source, rule, nesting, or selector-complexity limit.
|
||||
|
||||
Warnings do not prevent application:
|
||||
|
||||
- A known selector matches no node in the current resume or template.
|
||||
- A property is valid but ineffective on the selected semantic node.
|
||||
- An extreme value is likely to cause overlap, clipping, or unreadable output.
|
||||
|
||||
The server returns compiler diagnostics for save responses. Browser diagnostics remain immediate and use the same
|
||||
compiler, semantic analyzer, and diagnostic codes.
|
||||
|
||||
Editable source, source locations, comments, and diagnostics are owner-only data. Public resume responses exclude both
|
||||
stylesheet source values. They contain a fully resolved projection:
|
||||
|
||||
```ts
|
||||
type PublicStyleProjection = {
|
||||
formatVersion: 1;
|
||||
languageVersion: number;
|
||||
semanticTreeVersion: number;
|
||||
registryFingerprint: string;
|
||||
adapterFingerprint: string;
|
||||
renderDataHash: string;
|
||||
nodes: Readonly<Record<string, ResolvedPdfNodeStyle>>;
|
||||
};
|
||||
```
|
||||
|
||||
The server builds this projection from the applied program and authoritative semantic tree. It contains final
|
||||
declarations and structural props keyed by stable node key, with variables already resolved and comments, variable
|
||||
names, selectors, source spans, and diagnostics removed. The public browser accepts it only when all versions,
|
||||
fingerprints, and render-data hash match.
|
||||
|
||||
`renderDataHash` is SHA-256 over a domain-separated, RFC 8785 JSON Canonicalization Scheme serialization of the complete
|
||||
public render input and resolved node projection. The domain includes the projection format version. It excludes
|
||||
owner-only metadata and both stylesheet source values. The browser recomputes the hash before accepting the projection.
|
||||
On mismatch it requests a fresh projection or falls back to the server-rendered PDF. That fallback uses the existing
|
||||
public-resume visibility/password policy and public rendering rate limits; it is not an authorization bypass. Server PDF
|
||||
export compiles the database's applied value directly.
|
||||
|
||||
## Legacy Migration
|
||||
|
||||
`metadata.styleRules` remains readable during compatibility rollout.
|
||||
|
||||
If a resume has legacy rules but no active Semantic CSS value:
|
||||
|
||||
1. Existing PDF rendering continues to use legacy rules.
|
||||
2. Opening Custom Styles deterministically converts the rules into Semantic CSS.
|
||||
3. The generated source preserves target specificity and array order.
|
||||
4. Camel-case intent properties become kebab-case CSS declarations.
|
||||
5. Numeric dimensions become explicit point values.
|
||||
6. Rule labels become comments.
|
||||
7. Disabled rules become clearly labeled commented blocks.
|
||||
8. Draft autosave keeps legacy rendering active.
|
||||
9. The user compares the converted preview and explicitly selects **Activate Semantic CSS**; active stylesheet
|
||||
rendering then takes precedence.
|
||||
|
||||
Legacy target and slot mappings compile to equivalent semantic selectors and roles. For example:
|
||||
|
||||
```css
|
||||
/* Experience heading */
|
||||
section[type="experience"] > section-heading {
|
||||
font-size: 20pt;
|
||||
}
|
||||
```
|
||||
|
||||
Conversion is behavioral rather than a blind property rename. It evaluates each rule through the legacy resolver,
|
||||
including specificity, numeric clamps, link-decoration ordering, bold/template precedence, icon-size translation, and
|
||||
known template exceptions. The serializer emits the effective stylesheet deltas needed to preserve the current
|
||||
resume's rendered appearance. It retains portable original scopes where behavior is equivalent and emits
|
||||
resume-specific role or ID exceptions where legacy composition requires them.
|
||||
|
||||
Labels, IDs, attribute values, comments, strings, and comment terminators are escaped through one CSS serializer. Legacy
|
||||
declarations that had no rendered effect remain non-applying and are explained in generated comments rather than
|
||||
silently gaining new behavior.
|
||||
|
||||
Visual parity is guaranteed at activation for the current resume data, template, and builder base settings. Subsequent
|
||||
template or base-setting changes follow Semantic CSS behavior; they are not guaranteed to reproduce how the retired
|
||||
legacy resolver would have reacted.
|
||||
|
||||
Legacy rules remain as read-only rollback data during the flagged compatibility phase. Old Reactive Resume JSON imports
|
||||
continue to parse them. New exports include the complete versioned stylesheet value. Copying from the editor copies only
|
||||
the editable `source`.
|
||||
|
||||
No bulk database migration is required.
|
||||
|
||||
The server-owned stylesheet revision requires a normal DDL migration that adds a revision column with a zero default.
|
||||
The statement above means no bulk backfill or rewrite of existing resume JSONB rows is required.
|
||||
|
||||
## Security and Resource Limits
|
||||
|
||||
Semantic CSS is declarative and cannot execute code or fetch resources.
|
||||
|
||||
The compiler enforces bounded:
|
||||
|
||||
- Source length.
|
||||
- Rule and declaration count.
|
||||
- Selector length and combinator count.
|
||||
- Functional pseudo-class nesting.
|
||||
- Variable expansion depth.
|
||||
- Media-query nesting.
|
||||
|
||||
Compiler caches are bounded by count and total memory. Browser compilation runs in a worker. Server compilation uses the
|
||||
same limits before rendering or persistence. Unsupported language versions are rejected explicitly rather than silently
|
||||
interpreted by a newer grammar.
|
||||
|
||||
The renderer-versioned property registry defines every property's value grammar, shorthand expansion, inheritance,
|
||||
allowed primitive kinds, relative-unit behavior, and hard technical bounds. Validation runs again after variable and
|
||||
shorthand expansion, so banned asset functions cannot be hidden inside either construct.
|
||||
|
||||
PDF generation additionally enforces maximum authored page dimensions, maximum output pages, render timeout, and memory
|
||||
budgets. Candidate promotion performs this bounded render preflight before replacing `applied`. A preflight failure
|
||||
saves the editable source, preserves the previous applied value, and returns a controlled diagnostic. Later renderer
|
||||
failures caused by subsequent content changes return a controlled preview/export error but do not silently mutate
|
||||
stylesheet history.
|
||||
|
||||
## Documentation Registry
|
||||
|
||||
Semantic element names, attributes, template-part names, properties, values, inheritance behavior, and supported node
|
||||
types come from typed registries. The editor completion data, user documentation, compiler validation, and template
|
||||
coverage tests are generated from these registries.
|
||||
|
||||
This makes undocumented template internals unreachable and prevents documentation from drifting away from runtime
|
||||
behavior.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Compiler
|
||||
|
||||
- Golden lexer and parser fixtures for valid and invalid source.
|
||||
- Selector matching, specificity, source order, `!important`, inheritance, variables, resets, shorthands, units, and
|
||||
media queries.
|
||||
- Structural directive resolution.
|
||||
- Exact source-range diagnostics.
|
||||
- Property-registry exhaustiveness against supported PDF adapter types.
|
||||
- Fuzz and resource-limit tests proving malformed text cannot crash or hang compilation.
|
||||
|
||||
### Schema and persistence
|
||||
|
||||
- Revision compare-and-swap rejects stale concurrent saves.
|
||||
- Preflight occurs outside database locks, followed by a short CAS on both stylesheet revision and resume render-data
|
||||
version.
|
||||
- Serialized mutations consume stale acknowledgements for revision advancement without replacing newer editor state.
|
||||
- Out-of-order worker results cannot replace newer editor state.
|
||||
- Valid source edits replace both stylesheet values.
|
||||
- Invalid source edits are stored while the current applied value is preserved.
|
||||
- Compile-valid but render-failing source is stored without replacing the current applied value.
|
||||
- Editor undo/redo restores historical invalid source with its historical valid applied value.
|
||||
- Generic full-resume updates preserve the server-owned stylesheet.
|
||||
- Clients cannot forge `applied` through normal edit transitions.
|
||||
- Imports with invalid source retain text and independently validate the imported applied value.
|
||||
- Duplicate and version restore preserve valid source/applied pairs.
|
||||
- Public DTOs redact source, comments, diagnostics, and source locations.
|
||||
- Public projections reject registry, tree, adapter, or render-data-hash mismatches and use the defined fallback.
|
||||
- Public render hashes use the canonical, domain-separated contract, and fallback rendering preserves public/password
|
||||
authorization and rate limiting.
|
||||
- Backend-first rolling deployment preserves stylesheet fields when old clients submit full resume data.
|
||||
- Undo, redo, JSON import, JSON export, duplication, and version restore preserve stylesheet state.
|
||||
- Legacy conversion preserves effective output across precedence quirks, clamps, template exceptions, and supported
|
||||
intent properties.
|
||||
|
||||
### PDF rendering
|
||||
|
||||
- Shared semantic primitives receive correct ancestry and attributes.
|
||||
- Header, picture, contacts, pages, regions, sections, items, fields, rich text, and template parts resolve styles.
|
||||
- Structural hiding and ordering occur before rendering.
|
||||
- Positional selectors and inheritance remain based on the immutable source tree after hiding and ordering.
|
||||
- Authored-page selectors, wrapped physical subpages, fixed nodes, page size, and media queries follow the defined phase
|
||||
model.
|
||||
- Browser and server adapters resolve identical programs.
|
||||
- Every template smoke-renders with a comprehensive stylesheet.
|
||||
- Every registered node and template part has resolved-style coverage.
|
||||
- All 15 templates have visual regression coverage; focused fixtures cover every unique template feature.
|
||||
- Preview and exported PDF use the same applied stylesheet value.
|
||||
|
||||
### Web editor
|
||||
|
||||
- Diagnostics, completions, formatting, search, copy and paste, color previews, autosave, and expanded mode.
|
||||
- Invalid edits preserve source and last-valid preview.
|
||||
- Correcting invalid text applies it without losing formatting.
|
||||
- Out-of-order compilation and save responses are discarded.
|
||||
- Stale save acknowledgements still advance the mutation revision before the queued edit is sent.
|
||||
- Revision conflicts rebase the editor without dropping unsaved source.
|
||||
- Known-but-absent selectors produce warnings.
|
||||
- Legacy conversion is deterministic and user-visible.
|
||||
|
||||
### End-to-end acceptance
|
||||
|
||||
One portable stylesheet is pasted into resumes using different templates. The test verifies group selectors, one
|
||||
section-specific rule, one item-specific rule, a header rule, a rich-text rule, a template-part rule, a media query, and
|
||||
a pagination directive. It then introduces an error, confirms that preview and export remain on the last valid version,
|
||||
corrects the error, and confirms that preview and export update together.
|
||||
|
||||
## Rollout
|
||||
|
||||
1. Deploy the dormant compiler and registries, tolerant schema handling, public projection/redaction,
|
||||
generic-update field preservation, and the dedicated revisioned stylesheet mutation to the entire backend fleet.
|
||||
No client can activate Semantic CSS during this stage.
|
||||
2. Introduce the legacy converter behind a disabled authoring feature flag.
|
||||
3. Instrument shared PDF primitives and structural child preparation.
|
||||
4. Instrument header and template-specific parts across all 15 templates.
|
||||
5. Add the editor and revision/conflict behavior.
|
||||
6. Run legacy and Semantic CSS rendering paths side by side in tests, without double-applying them.
|
||||
7. Enable Semantic CSS for opted-in resumes while retaining legacy rollback data and monitoring compile failures,
|
||||
revision conflicts, render latency, memory, output pages, and fallback usage.
|
||||
8. Enable it by default after mixed-client compatibility, public-redaction, template coverage, visual regression,
|
||||
resource-limit, and end-to-end gates pass.
|
||||
|
||||
The authoring flag controls editor availability and whether a rollout cohort creates new resumes in semantic mode.
|
||||
Before default enablement, resumes outside that cohort start in legacy mode; after default enablement they start in
|
||||
semantic mode with empty version-1 source values. Rendering always honors a persisted semantic mode even if authoring is
|
||||
later disabled. A stylesheet is never applied on top of legacy rules; an active stylesheet takes sole precedence for
|
||||
custom PDF styling.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- Users can copy one text block between resumes and reproduce portable PDF styling.
|
||||
- Every documented semantic node and template part can be targeted consistently.
|
||||
- One section or item can be targeted by stable ID without making portable selectors resume-specific.
|
||||
- Invalid text is never lost and never breaks preview or export.
|
||||
- Preview, public rendering, browser export, and server export agree.
|
||||
- Existing custom styles retain visual parity after deterministic conversion.
|
||||
- The system accepts no executable code, font choice, asset reference, or network-fetching construct.
|
||||
- All 15 templates pass semantic coverage and PDF smoke tests.
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
# Semantic CSS Author Reference and Unified Documentation Generation
|
||||
|
||||
**Date:** 2026-07-29
|
||||
**Status:** Approved
|
||||
|
||||
## Summary
|
||||
|
||||
Reactive Resume will provide one canonical, author-facing Semantic CSS reference at:
|
||||
|
||||
`https://docs.rxresu.me/guides/semantic-css-reference`
|
||||
|
||||
The existing `docs/guides/semantic-css-reference.mdx` page will be expanded rather than duplicated. It will combine
|
||||
hand-written explanations and copy-paste examples with generated tables sourced from the runtime registries and PDF
|
||||
template manifests.
|
||||
|
||||
The Custom Styles editor will include a compact, accessible help hint linking directly to that page.
|
||||
|
||||
A new root command, `pnpm docs:gen`, will replace `pnpm docs:semantic-css` and regenerate:
|
||||
|
||||
1. Semantic CSS reference tables.
|
||||
2. The resume-builder skill schema reference.
|
||||
3. The complete JSON Schema embedded in the public schema guide.
|
||||
4. The checked-in OpenAPI specification.
|
||||
|
||||
## Audience and goals
|
||||
|
||||
The reference is for resume authors who write Semantic CSS in the builder. It must let an author:
|
||||
|
||||
- Discover what selectors, properties, values, and directives exist.
|
||||
- Understand which semantic nodes and template parts can be targeted.
|
||||
- Copy working examples for common customizations.
|
||||
- Diagnose invalid or ineffective styles.
|
||||
- Understand portability, last-valid behavior, resource limits, and unsupported syntax.
|
||||
|
||||
The page is a language reference, not contributor documentation. Compiler architecture, AST implementation details,
|
||||
internal adapter names, and package ownership stay out of the public page.
|
||||
|
||||
## Canonical page structure
|
||||
|
||||
The reference is organized for lookup rather than linear reading.
|
||||
|
||||
### 1. Semantic CSS in one minute
|
||||
|
||||
- The `@version 1;` directive.
|
||||
- One complete, portable stylesheet.
|
||||
- The relationship between editable source, applied source, preview, and export.
|
||||
|
||||
### 2. Selector grammar
|
||||
|
||||
- Universal, semantic type, ID, and attribute selectors.
|
||||
- Supported attribute operators.
|
||||
- Descendant, child, adjacent-sibling, and general-sibling combinators.
|
||||
- Selector lists.
|
||||
- Supported functional and structural pseudo-classes.
|
||||
- Case-sensitivity behavior.
|
||||
- Explicitly unsupported selector syntax.
|
||||
- Paired valid and invalid examples.
|
||||
|
||||
### 3. Semantic element catalog
|
||||
|
||||
- Generated parent and child relationships.
|
||||
- Generated attributes and roles.
|
||||
- Known attribute value domains.
|
||||
- Portable section-type selectors versus resume-specific IDs.
|
||||
- Rich-text structure, including distinct list-item row and list-item content semantics.
|
||||
|
||||
### 4. Cascade and values
|
||||
|
||||
- Specificity, source order, selector-list specificity, inheritance, and `!important`.
|
||||
- Semantic CSS behavior for `initial`, `inherit`, `unset`, and `revert`.
|
||||
- Author custom properties, nested `var()` fallbacks, unresolved variables, and cycles.
|
||||
- Reserved read-only `--resume-*` system variables.
|
||||
- Numbers, lengths, units, colors, functions, and shorthands.
|
||||
|
||||
### 5. Property reference
|
||||
|
||||
- Generated property table grouped by category.
|
||||
- Applicability by semantic node.
|
||||
- Inheritance.
|
||||
- Accepted units and constrained keywords where authoritative metadata exists.
|
||||
- Examples for text, spacing, borders, flex layout, images, transforms, and structural properties.
|
||||
|
||||
The generated table must not present a loose registry hint as an exhaustive value grammar. Value syntax that is
|
||||
implemented by parser or cascade logic remains hand-written unless it has authoritative shared metadata.
|
||||
|
||||
### 6. PDF behavior
|
||||
|
||||
- Page sizing.
|
||||
- Hiding and stable sibling ordering.
|
||||
- Pagination, fixed content, minimum presence ahead, orphans, and widows.
|
||||
- Media-query grammar, evaluation order, and page-dimension behavior.
|
||||
- React PDF-specific layout limitations that affect authors.
|
||||
|
||||
### 7. Template-specific selectors
|
||||
|
||||
- A generated matrix for all 15 templates.
|
||||
- Exact template-part names.
|
||||
- Selector forms.
|
||||
- Owner or placement conditions.
|
||||
- Allowed semantic children.
|
||||
- Portability warnings and guarded selector examples.
|
||||
|
||||
The matrix is generated from actual template manifests, not an independently maintained list.
|
||||
|
||||
### 8. Diagnostics and limits
|
||||
|
||||
- Stable compiler and preflight diagnostic codes.
|
||||
- Severity.
|
||||
- Meaning and likely corrective action.
|
||||
- Source, selector, declaration, node, page, size, timeout, and memory limits.
|
||||
- Last-valid preview and export behavior after an invalid edit.
|
||||
|
||||
### 9. Copy-paste recipes
|
||||
|
||||
- Restyle section headings.
|
||||
- Target a section type.
|
||||
- Target one section, item, or field.
|
||||
- Style sidebar content by placement.
|
||||
- Customize rich-text lists.
|
||||
- Change authored page dimensions.
|
||||
- Prevent awkward page breaks.
|
||||
- Customize optional template decoration.
|
||||
- Apply dimension-dependent PDF styles with `@media`.
|
||||
|
||||
### 10. Unsupported capabilities and portability checklist
|
||||
|
||||
- Unsupported selector, at-rule, layout, asset, font, script, interaction, and network capabilities.
|
||||
- Guidance for keeping a stylesheet portable across templates.
|
||||
|
||||
## Generated documentation architecture
|
||||
|
||||
### Command
|
||||
|
||||
The root package exposes:
|
||||
|
||||
```bash
|
||||
pnpm docs:gen
|
||||
```
|
||||
|
||||
The existing `docs:semantic-css` command is replaced by `docs:gen`, leaving one canonical documentation-generation
|
||||
entrypoint.
|
||||
|
||||
### Semantic CSS reference data
|
||||
|
||||
Generated Semantic CSS sections consume existing authoritative sources:
|
||||
|
||||
- Supported versions and compile limits.
|
||||
- Semantic element registry.
|
||||
- Property registry.
|
||||
- Read-only system-variable registry.
|
||||
- PDF template manifests.
|
||||
- Shared compiler and preflight diagnostic catalogs.
|
||||
|
||||
The generator emits deterministic, marker-delimited sections into
|
||||
`docs/guides/semantic-css-reference.mdx`.
|
||||
|
||||
Generated factual sections include:
|
||||
|
||||
- Semantic elements, parents, attributes, roles, and known value domains.
|
||||
- Property category, applicability, inheritance, units, and constrained keywords.
|
||||
- System variables.
|
||||
- Per-template template parts.
|
||||
- Diagnostics.
|
||||
- Compile and preflight limits.
|
||||
|
||||
Manual prose remains outside generated markers.
|
||||
|
||||
### Resume JSON Schema
|
||||
|
||||
The generator computes the canonical Resume JSON Schema once from `resumeDataSchema` using Zod's JSON Schema
|
||||
conversion.
|
||||
|
||||
That canonical schema drives two outputs:
|
||||
|
||||
1. `skills/resume-builder/references/schema.md`
|
||||
- A compact, AI-friendly Markdown reference.
|
||||
- Field hierarchy, types, required fields, constraints, and representative shapes.
|
||||
- Derived from the canonical JSON Schema rather than maintained separately.
|
||||
|
||||
2. `docs/guides/json-resume-schema.mdx`
|
||||
- The complete canonical JSON Schema inside a generated, marker-delimited JSON block.
|
||||
- Human-written explanation remains outside the generated block.
|
||||
|
||||
### OpenAPI specification
|
||||
|
||||
OpenAPI generation is exposed through one reusable, pure generator owned by `apps/server/src/openapi`.
|
||||
|
||||
- The runtime `/api/openapi/spec.json` handler calls it with `env.APP_URL`.
|
||||
- A sibling server documentation-generation script calls it with `https://rxresu.me` and writes `docs/spec.json`.
|
||||
- The root `docs:gen` command orchestrates the tooling generator and this server-owned OpenAPI generator.
|
||||
- The checked-in output is `docs/spec.json`.
|
||||
- The API version comes from the current application version.
|
||||
|
||||
This removes drift between runtime OpenAPI output and the checked-in documentation artifact, including stale versions
|
||||
and localhost server URLs.
|
||||
|
||||
### Determinism and failure behavior
|
||||
|
||||
Generation must:
|
||||
|
||||
- Produce stable ordering and formatting.
|
||||
- Require every expected marker.
|
||||
- Fail on duplicate or missing markers.
|
||||
- Fail on inconsistent template-manifest coverage.
|
||||
- Avoid silently leaving a partially updated reference that appears authoritative.
|
||||
|
||||
The generator computes all output text before writing any target. It does not add a general transaction framework.
|
||||
|
||||
## Custom Styles help hint
|
||||
|
||||
The Semantic CSS editor's shared chrome displays this hint directly above the code editor:
|
||||
|
||||
> **Not sure what to write?** Browse the Semantic CSS language reference.
|
||||
|
||||
The link:
|
||||
|
||||
- Targets `https://docs.rxresu.me/guides/semantic-css-reference`.
|
||||
- Opens in a new tab.
|
||||
- Uses `rel="noopener noreferrer"`.
|
||||
- Uses the existing `BookOpenIcon`, marked as decorative.
|
||||
- Has translated visible text.
|
||||
- Includes translated screen-reader text indicating that it opens in a new tab.
|
||||
- Appears in both the standard desktop editor and the mobile focus sheet because both use the same editor chrome.
|
||||
|
||||
The implementation stays local to the stylesheet editor. It does not introduce a shared component or central URL
|
||||
registry for one link.
|
||||
|
||||
## Documentation navigation
|
||||
|
||||
`docs/docs.json` lists `guides/semantic-css-reference` immediately after `guides/using-custom-styles`.
|
||||
|
||||
The public route is:
|
||||
|
||||
`https://docs.rxresu.me/guides/semantic-css-reference`
|
||||
|
||||
## Verification
|
||||
|
||||
### Generator verification
|
||||
|
||||
- `pnpm docs:gen` regenerates all four artifact groups.
|
||||
- A non-mutating test generates into temporary files and compares them byte-for-byte with committed outputs.
|
||||
- Generated output is deterministic across repeated runs.
|
||||
- Every runtime template part appears in the generated template matrix.
|
||||
- Cross-registry checks reject inconsistent template-part parent or child coverage.
|
||||
- The generated OpenAPI document matches the shared runtime generator for the documentation URL and current version.
|
||||
- Both schema Markdown targets are derived from the same canonical Resume JSON Schema.
|
||||
|
||||
### Example verification
|
||||
|
||||
- Complete copy-paste examples marked as valid compile successfully.
|
||||
- Selected intentionally invalid examples produce their documented diagnostic.
|
||||
- Small illustrative fragments that are not complete stylesheets are not forced through a full compiler test.
|
||||
|
||||
### UI verification
|
||||
|
||||
The stylesheet editor test verifies:
|
||||
|
||||
- Accessible link name.
|
||||
- Exact public URL.
|
||||
- New-tab target.
|
||||
- `noopener noreferrer`.
|
||||
- Presence in the standard editor.
|
||||
- Presence in the mobile focus sheet.
|
||||
|
||||
### Focused gates
|
||||
|
||||
- Tooling tests and typecheck.
|
||||
- Resume/schema tests and typechecks affected by exported metadata.
|
||||
- PDF manifest/reference consistency tests and typecheck.
|
||||
- API/server OpenAPI tests and typechecks.
|
||||
- Web editor tests and typecheck.
|
||||
- Workspace boundary check.
|
||||
- Focused formatting and Markdown validation.
|
||||
|
||||
Chrome verification is not required.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Contributor/compiler architecture documentation.
|
||||
- A second Semantic CSS reference route.
|
||||
- Splitting the reference across multiple pages.
|
||||
- Interactive documentation playgrounds.
|
||||
- New editor completion or hover features.
|
||||
- New Semantic CSS syntax or rendering behavior, except for correcting factual registry inconsistencies required to generate an
|
||||
accurate reference.
|
||||
- General documentation URL centralization.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- The canonical reference documents every author-facing Semantic CSS selector, semantic element, property, variable, directive,
|
||||
value family, template part, diagnostic family, limit, and unsupported syntax category.
|
||||
- The reference contains copy-paste examples for common author goals.
|
||||
- Generated facts come from authoritative runtime metadata and have staleness coverage.
|
||||
- `pnpm docs:gen` refreshes the Semantic CSS tables, both Resume JSON Schema references, and `docs/spec.json`.
|
||||
- Runtime and checked-in OpenAPI output share one generator.
|
||||
- The reference is visible in documentation navigation.
|
||||
- The Custom Styles editor links to the exact public reference route on desktop and mobile.
|
||||
- No unrelated product behavior or documentation architecture is introduced.
|
||||
@@ -0,0 +1,83 @@
|
||||
# Semantic CSS Complete Rename Design
|
||||
|
||||
## Goal
|
||||
|
||||
Use **Semantic CSS** as the feature's only name. Remove the former acronym and its prefixes before the feature is merged
|
||||
so authors, contributors, diagnostics, and documentation all use one vocabulary.
|
||||
|
||||
## Naming Contract
|
||||
|
||||
The rename applies to every tracked source, test, fixture, generated marker, guide, plan, and specification in this
|
||||
branch. Git history is not rewritten.
|
||||
|
||||
| Context | Canonical form |
|
||||
| --- | --- |
|
||||
| Product and language name | Semantic CSS |
|
||||
| TypeScript symbol form | `SemanticCss*` |
|
||||
| Constant prefix | `SEMANTIC_CSS_*` |
|
||||
| Slug and cache form | `semantic-css-*` |
|
||||
| Version directive | `@version 1;` |
|
||||
| System variables | `--resume-*` |
|
||||
| Renderer properties | `-resume-*` |
|
||||
| Empty source constant | `EMPTY_SEMANTIC_CSS_SOURCE` |
|
||||
| Documentation markers | `SEMANTIC-CSS-*` |
|
||||
|
||||
Existing neutral names remain unchanged, including `stylesheet`, `mode: "semantic"`, `languageVersion`, semantic node
|
||||
names, API routes, database columns, and the `/applying-custom-styles` documentation URL.
|
||||
|
||||
## Language Syntax
|
||||
|
||||
New stylesheets and formatted output start with:
|
||||
|
||||
```css
|
||||
@version 1;
|
||||
```
|
||||
|
||||
Resolved builder values use the `--resume-*` namespace:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--accent: var(--resume-primary-color);
|
||||
}
|
||||
```
|
||||
|
||||
Renderer-specific properties use the `-resume-*` namespace:
|
||||
|
||||
```css
|
||||
section {
|
||||
-resume-min-presence-ahead: 24pt;
|
||||
}
|
||||
```
|
||||
|
||||
The compiler accepts only the new syntax. There are no deprecated aliases, conversion paths, or compatibility warnings
|
||||
because the feature has not shipped.
|
||||
|
||||
## Product and Documentation
|
||||
|
||||
All visible editor labels, help text, errors, diagnostics, logs intended for operators, tests that assert visible copy,
|
||||
and the Applying Custom Styles guide say **Semantic CSS**. The guide and examples teach only `@version`,
|
||||
`--resume-*`, and `-resume-*`.
|
||||
|
||||
The guide remains manually authored. `pnpm docs:gen` continues to regenerate only the Resume schema references and
|
||||
OpenAPI specification; example compilation tests continue to validate the guide's marked Semantic CSS examples.
|
||||
|
||||
## Internal Code
|
||||
|
||||
Public package exports and internal identifiers use `SemanticCss` or `SEMANTIC_CSS` when the language name is required.
|
||||
Identifiers already scoped by a stylesheet module may retain a neutral `Stylesheet*` name instead of repeating
|
||||
`SemanticCss`.
|
||||
|
||||
The compiler build/cache identifier changes so cached output produced under the old grammar cannot be reused. No data
|
||||
migration is added.
|
||||
|
||||
## Verification
|
||||
|
||||
The implementation is complete when:
|
||||
|
||||
1. A case-insensitive tracked-file search finds no occurrence of the former four-letter acronym.
|
||||
2. A tracked-file search finds none of the former directive, variable, or renderer-property prefixes.
|
||||
3. Compiler tests prove `@version 1;` is required and the old directive is rejected as unsupported.
|
||||
4. Registry and rendering tests cover the renamed system variables and renderer properties.
|
||||
5. The public guide's marked examples compile.
|
||||
6. Focused package tests, typechecks, documentation generation, Knip, Biome, and the existing E2E workflow pass.
|
||||
7. No local Chrome run is required; browser verification remains CI-owned.
|
||||
Reference in New Issue
Block a user