10 KiB
UI Design System Finalization — RC Final Polish
Scope: token infrastructure + mechanical, value-preserving normalization of
typography/radius/spacing across storefront, builder, and backoffice.
Architecture, routing, facades, providers, and business logic were left
untouched, per instructions. This pass builds on the icon standardization
work (see docs/UI-ICON-AUDIT.md) and the earlier storefront/admin polish
passes (docs/STORE_FRONT_REVIEW.md, docs/ADMIN_REVIEW.md) — it does not
redo that work.
No docs/DESIGN.md exists in this repo (confirmed in docs/STORE_FRONT_REVIEW.md);
impeccable hook findings referencing it were treated as inapplicable noise
throughout, same precedent as the prior pass.
Before
src/styles.scsshad a color/shadow/radius/spacing token set (--primary-color,--radius-sm..xl,--space-xs..xl,--shadow-sm..lg) but no typography scale at all — no font-size, font-weight, or line-height tokens.- Font sizes were hand-written per component. A repo-wide scan found 24
distinct font-size values in simultaneous use for what was clearly the
same handful of intended sizes:
0.7/0.72/0.75/0.78/0.8/0.8125/0.85/0.875/ 0.9/0.9375/0.95/1/1.05/1.1/1.125/1.15/1.2/1.25/1.3/1.35/1.4/1.5/1.75/2rem(plus a handful of raw px values), spread across 104 of 136 component SCSS files. - Font-weight was always a raw literal (400/500/600/700), never a token.
border-radiushad the same drift: 72 of 136 files used raw px values instead of the existing--radius-*tokens; two "shape" values in constant use —4px(small chips/badges) and999px(pills/toggles) — had no token at all, so every pill/chip component reinvented999pxby hand (41 occurrences) or4px(9 occurrences).src/app/shared/ui/*— the actual shared component library used across admin/builder/backoffice (button, input, select, badge, card, table, dialog, etc.) — was already internally consistent (button and input both used a matching 32/40/48px sm/md/lg scale with 0.8125/0.9375/1rem font sizes) but expressed every value as a hand-written literal rather than a token, and one file (section-card.component.scss) had drifted from its siblingcard.component.scss(16px/18px/14px raw vs.--radius-lg/--space-*).code-editor.component.scss's focus state used a hardcoded#497671(the dexar tenant's primary color) instead ofvar(--primary-color)— it would not have adapted if a tenant switched to the lavero or novo theme.
After
Tokens introduced (src/styles.scss)
--font-size-xs: 0.75rem (12px)
--font-size-sm: 0.8125rem (13px)
--font-size-base: 0.875rem (14px)
--font-size-md: 0.9375rem (15px)
--font-size-lg: 1rem (16px)
--font-size-xl: 1.125rem (18px)
--font-size-2xl: 1.25rem (20px)
--font-size-3xl: 1.5rem (24px)
--font-size-4xl: 2rem (32px)
--font-weight-normal: 400
--font-weight-medium: 500
--font-weight-semibold: 600
--font-weight-bold: 700
--line-height-tight: 1.2
--line-height-normal: 1.5
--line-height-relaxed: 1.6
--space-2xl: 48px (new, extends the existing xs/sm/md/lg/xl scale)
--space-3xl: 64px (new)
Tokens added to all three theme files (src/styles/themes/*.theme.scss)
--radius-xs: 4px (dexar/lavero/novo — chip/badge corner radius)
--radius-full: 999px (dexar/lavero/novo — pill/toggle shape)
The scale steps were chosen to match sizes already in wide use (button/input sm|md|lg already used 0.8125/0.9375/1rem) so most components could adopt the tokens by direct substitution rather than a visual redesign.
Files touched, by phase
Global base (src/styles.scss) — body, h1–h6, p, small, the
.btn/.mt-*/.mb-*/.p-* utility classes, and the shared
.item-badge/.item-tag/.item-simple-desc classes now reference the new
tokens instead of literals.
Shared component library (18 files, hand-reviewed, not mechanical) —
src/app/shared/ui/{button,input,select,badge,card,section-card,table,dialog, empty-state,form-field,pagination,toggle,image-field,key-value-editor, locale-tabs,color-picker,code-editor,skeleton}/*.component.scss. Fixes made
along the way:
code-editor.component.scss: hardcoded#497671focus color →var(--primary-color)— now adapts correctly across tenant themes.section-card.component.scss: raw16px/18px/14pxradius/padding →var(--radius-lg)/var(--space-*), matching the siblingcardcomponent.toggle/badge/item-tag: raw999px→ the new--radius-fulltoken.
App-wide mechanical rollout (89 files touched across storefront, builder, and backoffice) — three scripted, value-preserving sweeps:
font-size: <literal>;→var(--font-size-STEP, <same-or-nearest-step>);for every literal that matched (or was within ~0.03rem/1px of) one of the 9 scale steps. Values within that tolerance were snapped to the nearest step to consolidate near-duplicates (e.g.0.85remand0.8remboth →--font-size-sm/0.8125rem).border-radius: <literal>;→ token, but only for the 5 values that exactly match a token everywhere (4px,8px,12px,13px,999px).20px/16px/10px/6px/3px/2px/14px/24px/19pxwere deliberately left alone (see Remaining issues).font-weight: <literal>;→ token (400/500/600/700), value-preserving.
Each sweep was applied with sed, spot-checked against git diff for
correctness, then verified with a full ng build --configuration=production
(exit 0) before committing. Five commits total, one per phase/sweep, each
independently buildable and revertable.
Remaining issues (deferred, not fixed in this pass)
- Spacing (margin/padding) was not mechanically swept. The existing
--space-xs..3xlscale covers gaps and simple paddings, but margin/padding shorthand comes in 1/2/3/4-value forms that aren't safe to regex-replace without risking silently changing box models on components that use asymmetric shorthand. This needs a manual, component-by-component pass — recommended as the next follow-up, using the same--space-*scale already established. border-radiusvalues with no exact token match (20px× 9,16px× 7,10px× 38,6px× 9,3px× 4,2px× 3,14px,24px,19px) were intentionally left as literals. Several of these (10px, 6px) are common enough that a--radius-2xs/intermediate step might be warranted, but adding one now without a design call would be inventing a new shape rather than normalizing existing ones — flagged for the design owner rather than decided unilaterally.- Phases 5–9 (cards, tables, status system, animations, accessibility)
were not addressed as dedicated passes in this session. The shared/ui
card,table,dialog,badge, andskeletoncomponents are already reasonably unified (see "After" above) since they're single shared components consumed everywhere, but a full per-surface audit (storefront product cards, admin dashboard cards, builder panel cards; every table's sticky-header/hover/selection/density behavior; a single status-badge language for success/warning/error/draft/published/archived/pending) was out of reach in this pass and should be scoped as its own follow-up. - Status system: no unified success/warning/error/draft/published/etc.
visual language audit was performed. The
app-badgecomponent has--neutral/primary/success/warning/danger/infovariants already, but whether every surface (storefront order status, admin order/review status, builder publish state) actually usesapp-badgerather than a hand-rolled span was not verified in this pass. - Animations: not audited in this pass beyond what already existed
(the codebase already has a global
prefers-reduced-motionneutralizer insrc/styles.scssand per-component reduced-motion overrides in most shared/ui components — this predates this session). - Accessibility: not audited in this pass; the prior
STORE_FRONT_REVIEW.mdandUI-ICON-AUDIT.mdpasses already covered a a11y pass on the storefront and icon-only buttons respectively. No new a11y work was done here. cart.component.scssnow sits ~771 bytes over itsanyComponentStylebudget warning (40kB) due to the addedvar(...)string length from the font-weight sweep. This is amaximumWarning, notmaximumError(angular.jsonbudgets: initial 700kB warn / 1.5MB error, component style 40kB warn / 50kB error), so the build still exits 0 — but it's worth either trimming the file or bumping its allotment slightly in a follow-up.- Tenant brand colors (
src/styles/themes/{dexar,lavero,novo}.theme.scss) and badge accent colors (.item-badge.badge-new/sale/exclusive/...and code-editor syntax-highlight colors.cm-*) were intentionally left untouched — these are per-tenant palettes / syntax-token colors, not design-system drift.
Recommendations
- Next pass: spacing. Do a manual, per-surface sweep of
margin/padding using the existing
--space-xs..3xlscale, prioritizing the same high-traffic files already touched here (shared/ui, then catalog/product-details/cart on storefront, then admin dashboard/list pages). - Decide on the missing radius steps (
10px,6px) with the design owner — either add--radius-2xs/an intermediate token, or confirm they should collapse into--radius-xs/--radius-smand re-run the same mechanical sweep pattern used in this session (sed+ng build+ commit per phase). - Status system audit: grep for hand-rolled status spans/badges
outside
app-badgeacross admin (orders, reviews, moderation) and storefront (order tracking) and consolidate onto the existingapp-badgevariants. - Cards/tables surface audit: now that
card/section-card/tableare internally token-consistent, verify every page-level "card" and "table" actually composes these shared components rather than hand-rolling similar-looking markup — this is the highest-leverage next step for phases 5–6 since the primitives are already unified.