feat(design-system): TS token source-of-truth + light theme [Phase 1a]#616
feat(design-system): TS token source-of-truth + light theme [Phase 1a]#616barach6662001-bit merged 3 commits intomainfrom
Conversation
Phase 1a of the design-system overhaul. WHAT - New folder `src/design-system/tokens/` holds all design tokens as TS: colors (palette + semanticDark + semanticLight + cropColors + chartColors), typography (fluid clamp() scale, weights, families, tracking), spacing (4 px grid), radius, elevation (5-level layered shadows for both themes), motion (durations + easings), breakpoints (+ media helpers), zIndex. - New `scripts/build-tokens.ts` generates `src/styles/tokens.css` from the TS sources. Adds a `build:tokens` npm script (run automatically before `build`); `build:tokens:watch` available for active editing. - `src/styles/tokens.css` is now AUTO-GENERATED. Banner at the top of the file warns against hand-edits. - `lightTheme.ts` is now a real AntD ThemeConfig (was an empty stub). Theme switching is one DOM attribute toggle (`data-theme="light"`) — no React re-render required, because every value resolves through CSS vars. WHY - Single source of truth: tokens edited in TS, types flow to all consumers, CSS regenerates deterministically. - Layered shadows + fluid typography + motion tokens unblock the rest of the design-system roll-out (primitives, AppShell, Storybook, visual reg). - Light theme parity restores the user-facing dark/light toggle that has been advertised but unimplemented. COMPATIBILITY - Every existing CSS variable name is preserved (`--brand`, `--bg-page`, `--text-primary`, `--space-1`, `--radius-md`, `--shadow-md`, etc). - Legacy aliases (`--bg-app`, `--color-primary`, `--transition-base`, …) remain as pointers to the new canonical names. - `darkTheme.ts` is unchanged. - No component files modified. Existing pages render identically. NEXT - PR 1b — layout + typography primitives (Stack, Cluster, Container, Heading, Text) - PR 1c — form + surface primitives (Button, Input, Field, Card, Surface) - PR 1d — AppShell refactor - PR 1e — Storybook + visual regression infrastructure
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c6d0695f87
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "jsdom": "^25.0.1", | ||
| "typescript": "~5.6.2", | ||
| "typescript-eslint": "^8.0.0", | ||
| "tsx": "^4.19.2", |
There was a problem hiding this comment.
Update lockfile after adding tsx to devDependencies
This change adds tsx to frontend/package.json but does not update frontend/package-lock.json, which makes the frontend install/build path fail in CI and local Docker builds that run npm ci (see .github/workflows/ci.yml and frontend/Dockerfile). npm ci requires package.json and lockfile to match exactly, so this commit can block all frontend pipelines until the lockfile is regenerated and committed.
Useful? React with 👍 / 👎.
| textTransform?: 'uppercase' | 'lowercase' | 'capitalize' | 'none'; | ||
| } | ||
|
|
||
| export const fontScale: Record<string, FontStep> = { |
There was a problem hiding this comment.
Preserve literal font scale keys for exported type safety
Typing fontScale as Record<string, FontStep> widens the key type, so FontScaleKey becomes just string instead of the intended union ('xs' | 'sm' | ...). That removes compile-time validation for token keys and undermines the typed token API introduced in this commit, allowing invalid font-scale names to pass type checks in downstream code.
Useful? React with 👍 / 👎.
- Add tsx@4.19.2 to package-lock.json (required by build:tokens script) - Drop unused eslint-disable directive in build-tokens.ts Local CI parity verified: - npm run lint → 0 errors (only pre-existing warnings) - npx tsc -b --noEmit → clean - npm run build (incl. tokens) → succeeds - npm test → 101/101 pass
…[Phase 1f] (#625) Finishes the DashboardV2 row-card migration. Both remaining sibling panels (OperationsTimeline in row 4, UpcomingPanel in row 5) now use the design-system <Card> primitive instead of the local `s.card` wrapper. Combined with Phase 1d (WarehouseSnapshot) and Phase 1e (AlertsPanel), every dashboard surface in this row is now driven by the same primitive. Wrapper migration (DashboardV2.tsx) ----------------------------------- - <div className={s.card}><OperationsTimeline …/></div> → <Card>…</Card> - <div className={s.card}><UpcomingPanel …/></div> → <Card>…</Card> Both sites are pure wrapper swaps. <Card> defaults (variant=subtle, radius=xl=16px, padding=5=20px, bordered=true) are an exact drop-in for the legacy `.card` rule, so the visual contract (background, border, radius, padding) is preserved. The internal list/item content of each panel is untouched. CSS dead-code removal (DashboardV2.module.css) ---------------------------------------------- With both consumers gone, these rules become unreferenced and are deleted (≈39 lines): - .card (background, border, radius, padding, transition) - .card:hover (subtle background lift) - .card::before (decorative top hairline) - .cardHeader (flex justify-between row, never used in DashboardV2.tsx) - .cardLink, .cardLink:hover (eyebrow link button, never used in DashboardV2.tsx) A short tombstone comment is left in place so future readers see why the section is empty and where to look (Card primitive path). Out of scope ------------ - No route changes - No API changes - No business-logic changes - No refactor of inner panel markup - No new dependencies - No Card highlight prop introduction - No new tests (spec: only update if coverage exists; none did) Verification (local) -------------------- - frontend tsc -b: clean - frontend lint: 0 errors (warning count unchanged) - vitest design-system + dashboard subset: 67/67 passing - Full test + build run delegated to CI. Phase 1 status after this PR ---------------------------- - ✅ 1a — TS tokens (#616) - ✅ 1b — Layout + Typography primitives (#620) - ✅ 1c — PageHeader migration (#621) - ✅ 1d — Surface + Card primitives + first dashboard adoption (#622) - ✅ 1e — AlertsPanel adoption (#624) - ✅ 1f — OperationsTimeline + UpcomingPanel adoption (this PR) Co-authored-by: replit-agent <agent@replit.local>
…a/b/c (#641) - Move PR #614 core (impersonation + /admin/users + /admin/audit-log) to Completed - Promote PR #615 (Warehouse: grain receipt + inventory) to In progress - Create new 'Deferred (post-core, before Phase B)' section for #614a/b/c - Move #614a (/admin/system), #614b (/admin/catalogs), #614c (/admin/broadcast) to Deferred - Reorder Upcoming to start with PR #616 (Notifications center) - Update TZ.md: mark ПУНКТ 9 + 10 as [IN PROGRESS in PR #615]
Phase 1a — Foundation
This is the first PR of the design-system overhaul. It introduces the foundation that every subsequent PR will build on. Zero breaking changes; the existing UI renders pixel-identically because every previous CSS variable name is preserved.
What changed
1. Tokens are now TypeScript —
src/design-system/tokens/colors.tspaletteprimitives,semanticDark+semanticLight(mirror schemas),cropColors,chartColorstypography.tsclamp()scale (xs … display + eyebrow), weights, families, trackingspacing.tsradius.tselevation.tsmotion.tsbreakpoints.tsreducedMotion,hover)zIndex.tsindex.tstokens(theme-independent) andthemeTokens(theme-aware) namespaces2. Generator —
scripts/build-tokens.tssrc/styles/tokens.cssdeterministically.:root(default = dark),[data-theme='dark'], and[data-theme='light']blocks.3. New npm scripts
npm run build:tokens— regenerate CSS from TS (also runs automatically beforenpm run build).npm run build:tokens:watch— for active token authoring.tsx@^4.19.2(zero-config TS executor).4. Light theme is now real —
src/theme/lightTheme.tsWas an empty
export {}stub. Now a fullThemeConfigmirroringdarkTheme.ts. Theme switching is a singledocument.documentElement.dataset.theme = 'light'toggle — no React re-render required because every value resolves through CSS vars.Why
tokens.css(CSS vars),darkTheme.ts(raw hex), and component CSS — easy to driftSemanticTokenKey,FontScaleKey,SpacingKeyetc. exportedclamp()ramps automaticallyCompatibility — what reviewers should verify
Visual regression: pages should look identical. Only addition is the dormant
[data-theme='light']block. Every previous var name (--brand,--bg-page,--text-primary,--space-*,--radius-*,--shadow-*,--transition-*) is preserved.darkTheme.tsis unchanged.Out of scope (next PRs)
lightThemeto user preference)Each of those will be its own focused PR.