diff --git a/README.md b/README.md index 7412103..c721694 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Front-end work has changed a lot since the SPA-everything era: rendering moved b ## What's implemented - Scaffold: Next.js 15 App Router, React 19, strict TypeScript, Vitest + Testing Library, GitHub Actions CI, and a design-token stylesheet. The home route lists the planned concepts using an accessible `ConceptCard` component. +- Design tokens: a typed token tree in `src/tokens` that generates the app's CSS custom properties. The root layout injects the generated `:root` rule at render time, so the token module is the runtime source and there is no second copy to drift. See the `/tokens` route. ## Stack @@ -50,6 +51,15 @@ import { ConceptCard } from '@/components/concept-card' /> ``` +Styles reference tokens through a typed helper, so a bad name fails to compile: + +```tsx +import { token } from '@/tokens' + +
+// token('color', 'nope') -> type error +``` + ## Layout ``` diff --git a/app/globals.css b/app/globals.css index 3cb1f5c..6256ac0 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,20 +1,8 @@ +/* Token custom properties (--color-*, --space-*, --radius-*, --font-size-*) are + generated from src/tokens and injected by the root layout. Only values that + are not part of the token tree live here. */ :root { color-scheme: light dark; - - --color-bg: #0f1115; - --color-surface: #171a21; - --color-border: #262b36; - --color-text: #e7eaf0; - --color-muted: #9aa3b2; - --color-accent: #5eead4; - - --space-2: 0.5rem; - --space-3: 0.75rem; - --space-4: 1rem; - --space-6: 1.5rem; - --space-8: 2rem; - - --radius: 12px; --font-sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif; --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace; } diff --git a/app/layout.tsx b/app/layout.tsx index 7535867..418d709 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,7 +1,10 @@ import type { Metadata, Viewport } from 'next' import type { ReactNode } from 'react' +import { cssVariablesToRootRule, tokensToCssVariables } from '@/tokens' import './globals.css' +const tokenRootRule = cssVariablesToRootRule(tokensToCssVariables()) + export const metadata: Metadata = { title: 'Modern Frontend Lab', description: @@ -15,6 +18,9 @@ export const viewport: Viewport = { export default function RootLayout({ children }: { children: ReactNode }) { return ( + +