From 3335edeed8c4ed463c213f901161776f0ec4dff5 Mon Sep 17 00:00:00 2001 From: Bernt Date: Thu, 2 Jul 2026 10:53:42 +0000 Subject: [PATCH] docs: Semantic Color System v1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SEMANTIC_COLOR_SYSTEM.md (v1.0, DRAFT): - Three-layer architecture: Primitive β†’ Semantic β†’ Component Alias - Naming convention: color.{category}.{role} - Semantic tokens with contracts (purpose, allowed, not allowed): - Action colors (primary, secondary, ghost, disabled) - Surface colors (default, raised, overlay, inverted) - Text colors (primary, secondary, muted, inverted, link) - Border colors (default, focus, error, success) - Status colors (success, warning, danger, info) - Brand colors (primary, secondary) - State Matrix: all states for Button, Input, Select, Card with background, border, text, icon mappings - Component Aliases: button.*, input.*, select.*, card.* mapped to semantic tokens - Dark Mode: token value swapping without component code changes - Validation: component token audit (0 direct color references) - COMPLIANCE_MATRIX.md: Semantic Color System 70% Rationale: Semantic model first, not colors. Components never reference primitives directly. Every token has a contract (purpose, allowed, forbidden). Dark mode via token swap. State matrix derived from existing components. --- docs/design/COMPLIANCE_MATRIX.md | 1 + docs/design/SEMANTIC_COLOR_SYSTEM.md | 276 +++++++++++++++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 docs/design/SEMANTIC_COLOR_SYSTEM.md diff --git a/docs/design/COMPLIANCE_MATRIX.md b/docs/design/COMPLIANCE_MATRIX.md index ad786f663..675ef5198 100644 --- a/docs/design/COMPLIANCE_MATRIX.md +++ b/docs/design/COMPLIANCE_MATRIX.md @@ -77,6 +77,7 @@ | Release Definition | 🟑 | 80% | | Brand Palette | 🟑 | 40% | | Grid & Elevation | 🟑 | 60% | +| Semantic Color System | 🟑 | 70% | --- diff --git a/docs/design/SEMANTIC_COLOR_SYSTEM.md b/docs/design/SEMANTIC_COLOR_SYSTEM.md new file mode 100644 index 000000000..ad3543ef1 --- /dev/null +++ b/docs/design/SEMANTIC_COLOR_SYSTEM.md @@ -0,0 +1,276 @@ +# SEMANTIC COLOR SYSTEM + +**Semantic Token Model for Landvex Design System** + +| | | +|---|---| +| **Version** | 1.0 | +| **Status** | DRAFT | +| **Scope** | All Landvex & quiXzoom products | +| **Authority** | DESIGN_SPECIFICATION (nivΓ₯ 5) | + +--- + +## 1. PRINCIPLES + +**MUST NOT:** Reference primitive colors (`blue-500`, `gray-900`) from components. +**MUST:** Use semantic tokens (`color.action.primary`, `color.surface.default`) for all component styling. +**MUST:** Document purpose, allowed usage, and forbidden usage for every semantic token. + +--- + +## 2. TOKEN ARCHITECTURE + +### 2.1 Three Layers + +``` +Layer 1: Primitive Tokens (color values) + ↓ +Layer 2: Semantic Tokens (purpose-driven) + ↓ +Layer 3: Component Aliases (component-specific) +``` + +**Layer 1 β€” Primitives:** Raw color values. `blue-500`, `gray-900`, `green-600`. + +**Layer 2 β€” Semantic:** Purpose-driven. `color.action.primary`, `color.surface.default`. + +**Layer 3 β€” Component Aliases:** Component-specific mappings. `button.primary.background`, `card.border`. + +### 2.2 Naming Convention + +``` +color.{category}.{role} +``` + +| Category | Role | Example | +|----------|------|---------| +| `action` | `primary`, `secondary`, `ghost` | `color.action.primary` | +| `surface` | `default`, `raised`, `overlay` | `color.surface.default` | +| `text` | `primary`, `secondary`, `muted` | `color.text.primary` | +| `border` | `default`, `focus`, `error` | `color.border.default` | +| `status` | `success`, `warning`, `danger`, `info` | `color.status.success` | +| `brand` | `primary`, `secondary` | `color.brand.primary` | + +--- + +## 3. SEMANTIC TOKENS + +### 3.1 Action Colors + +| Token | Purpose | Allowed | Not Allowed | +|-------|---------|---------|-------------| +| `color.action.primary` | Primary call-to-action | Buttons, floating actions, primary navigation | Backgrounds, cards, decorative | +| `color.action.primary-hover` | Primary action hover | Button hover, link hover | Default state, backgrounds | +| `color.action.primary-active` | Primary action active | Button active, link active | Hover state, default state | +| `color.action.secondary` | Secondary action | Secondary buttons, outlined buttons | Primary actions, backgrounds | +| `color.action.ghost` | Ghost action | Ghost buttons, text buttons | Contained buttons, backgrounds | +| `color.action.disabled` | Disabled action | Disabled buttons, disabled inputs | Active elements, backgrounds | + +### 3.2 Surface Colors + +| Token | Purpose | Allowed | Not Allowed | +|-------|---------|---------|-------------| +| `color.surface.default` | Default background | Page background, card background | Text, borders, actions | +| `color.surface.raised` | Elevated surface | Cards, panels, modals | Page background, text | +| `color.surface.overlay` | Overlay surface | Dropdowns, menus, tooltips | Page background, cards | +| `color.surface.inverted` | Inverted surface | Dark mode backgrounds, dark sections | Light mode backgrounds | + +### 3.3 Text Colors + +| Token | Purpose | Allowed | Not Allowed | +|-------|---------|---------|-------------| +| `color.text.primary` | Primary text | Headings, body text, labels | Backgrounds, borders | +| `color.text.secondary` | Secondary text | Descriptions, metadata | Primary text, headings | +| `color.text.muted` | Muted text | Placeholders, disabled text, hints | Primary text, labels | +| `color.text.inverted` | Inverted text | Text on dark surfaces | Text on light surfaces | +| `color.text.link` | Link text | Text links, navigation links | Non-interactive text | + +### 3.4 Border Colors + +| Token | Purpose | Allowed | Not Allowed | +|-------|---------|---------|-------------| +| `color.border.default` | Default border | Input borders, card borders, dividers | Focus rings, error states | +| `color.border.focus` | Focus border | Focused input, focused button, focused select | Default state, hover state | +| `color.border.error` | Error border | Invalid input, error state | Default state, success state | +| `color.border.success` | Success border | Valid input, success state | Default state, error state | + +### 3.5 Status Colors + +| Token | Purpose | Allowed | Not Allowed | +|-------|---------|---------|-------------| +| `color.status.success` | Success state | Success messages, valid indicators, positive trends | Error states, warnings | +| `color.status.warning` | Warning state | Warning messages, caution indicators | Error states, success states | +| `color.status.danger` | Danger state | Error messages, destructive actions, negative trends | Success states, warnings | +| `color.status.info` | Info state | Informational messages, help text | Success states, warnings | + +### 3.6 Brand Colors + +| Token | Purpose | Allowed | Not Allowed | +|-------|---------|---------|-------------| +| `color.brand.primary` | Primary brand | Logo, brand accents, primary buttons (if brand = action) | Status indicators, data viz | +| `color.brand.secondary` | Secondary brand | Secondary accents, hover states | Status indicators, backgrounds | + +--- + +## 4. STATE MATRIX + +### 4.1 States by Component + +#### Button States + +| State | Background | Border | Text | Icon | +|-------|------------|--------|------|------| +| Default | `color.action.primary` | transparent | `color.text.inverted` | `color.text.inverted` | +| Hover | `color.action.primary-hover` | transparent | `color.text.inverted` | `color.text.inverted` | +| Focus | `color.action.primary` | `color.border.focus` | `color.text.inverted` | `color.text.inverted` | +| Active | `color.action.primary-active` | transparent | `color.text.inverted` | `color.text.inverted` | +| Disabled | `color.action.disabled` | transparent | `color.text.muted` | `color.text.muted` | +| Loading | `color.action.primary` | transparent | `color.text.inverted` | spinner | + +#### Input States + +| State | Background | Border | Text | Icon | +|-------|------------|--------|------|------| +| Default | `color.surface.default` | `color.border.default` | `color.text.primary` | `color.text.muted` | +| Hover | `color.surface.default` | `color.border.default` | `color.text.primary` | `color.text.muted` | +| Focus | `color.surface.default` | `color.border.focus` | `color.text.primary` | `color.text.muted` | +| Active | `color.surface.default` | `color.border.focus` | `color.text.primary` | `color.text.muted` | +| Disabled | `color.surface.raised` | `color.border.default` | `color.text.muted` | `color.text.muted` | +| Error | `color.surface.default` | `color.border.error` | `color.text.primary` | `color.status.danger` | +| Loading | `color.surface.default` | `color.border.default` | `color.text.muted` | spinner | + +#### Select States + +| State | Background | Border | Text | Icon | +|-------|------------|--------|------|------| +| Default | `color.surface.default` | `color.border.default` | `color.text.primary` | `color.text.muted` | +| Hover | `color.surface.default` | `color.border.default` | `color.text.primary` | `color.text.muted` | +| Focus | `color.surface.default` | `color.border.focus` | `color.text.primary` | `color.text.muted` | +| Open | `color.surface.default` | `color.border.focus` | `color.text.primary` | `color.text.muted` | +| Option Hover | `color.surface.raised` | β€” | `color.text.primary` | β€” | +| Option Selected | `color.action.primary` (at 10%) | β€” | `color.action.primary` | checkmark | +| Option Disabled | `color.surface.raised` | β€” | `color.text.muted` | β€” | +| Disabled | `color.surface.raised` | `color.border.default` | `color.text.muted` | `color.text.muted` | +| Error | `color.surface.default` | `color.border.error` | `color.text.primary` | `color.status.danger` | +| Loading | `color.surface.default` | `color.border.default` | `color.text.muted` | spinner | + +#### Card States + +| State | Background | Border | Text | Shadow | +|-------|------------|--------|------|--------| +| Default | `color.surface.raised` | `color.border.default` | β€” | `shadow-sm` | +| Hover (interactive) | `color.surface.raised` | `color.border.default` | β€” | `shadow-md` | +| Active (interactive) | `color.surface.raised` | `color.border.default` | β€” | `shadow-sm` | +| Focus (interactive) | `color.surface.raised` | `color.border.focus` | β€” | `shadow-sm` | +| Loading | `color.surface.raised` | `color.border.default` | β€” | `shadow-sm` | +| Empty | `color.surface.raised` | `color.border.default` | `color.text.muted` | `shadow-sm` | +| Error | `color.surface.raised` | `color.border.error` | `color.text.primary` | `shadow-sm` | + +--- + +## 5. COMPONENT ALIASES + +### 5.1 Button Aliases + +| Alias | Semantic Token | +|-------|---------------| +| `button.primary.background` | `color.action.primary` | +| `button.primary.background-hover` | `color.action.primary-hover` | +| `button.primary.background-active` | `color.action.primary-active` | +| `button.primary.text` | `color.text.inverted` | +| `button.disabled.background` | `color.action.disabled` | +| `button.disabled.text` | `color.text.muted` | + +### 5.2 Input Aliases + +| Alias | Semantic Token | +|-------|---------------| +| `input.background` | `color.surface.default` | +| `input.border` | `color.border.default` | +| `input.border-focus` | `color.border.focus` | +| `input.border-error` | `color.border.error` | +| `input.text` | `color.text.primary` | +| `input.placeholder` | `color.text.muted` | +| `input.disabled.background` | `color.surface.raised` | +| `input.disabled.text` | `color.text.muted` | + +### 5.3 Select Aliases + +| Alias | Semantic Token | +|-------|---------------| +| `select.background` | `color.surface.default` | +| `select.border` | `color.border.default` | +| `select.border-focus` | `color.border.focus` | +| `select.dropdown.background` | `color.surface.raised` | +| `select.option.hover` | `color.surface.raised` | +| `select.option.selected` | `color.action.primary` (at 10%) | +| `select.option.selected-text` | `color.action.primary` | + +### 5.4 Card Aliases + +| Alias | Semantic Token | +|-------|---------------| +| `card.background` | `color.surface.raised` | +| `card.border` | `color.border.default` | +| `card.shadow` | `shadow-sm` | +| `card.shadow-hover` | `shadow-md` | +| `card.header.text` | `color.text.primary` | +| `card.body.text` | `color.text.secondary` | +| `card.footer.text` | `color.text.muted` | + +--- + +## 6. DARK MODE + +### 6.1 Token Value Swapping + +| Semantic Token | Light Mode | Dark Mode | +|---------------|-----------|-----------| +| `color.surface.default` | `gray-0` (#ffffff) | `gray-900` (#1a1a1a) | +| `color.surface.raised` | `gray-50` (#f8f9fa) | `gray-800` (#2d2d2d) | +| `color.surface.overlay` | `gray-0` (#ffffff) | `gray-800` (#2d2d2d) | +| `color.text.primary` | `gray-900` (#1a1a1a) | `gray-100` (#f8f9fa) | +| `color.text.secondary` | `gray-600` (#666666) | `gray-400` (#999999) | +| `color.text.muted` | `gray-400` (#999999) | `gray-600` (#666666) | +| `color.text.inverted` | `gray-0` (#ffffff) | `gray-900` (#1a1a1a) | +| `color.border.default` | `gray-200` (#e5e5e5) | `gray-700` (#4d4d4d) | +| `color.border.focus` | `blue-500` | `blue-400` | +| `color.action.primary` | `blue-500` | `blue-400` | + +**Rule:** Dark mode is implemented by swapping primitive values behind semantic tokens. Component code does not change. + +--- + +## 7. VALIDATION + +### 7.1 Component Token Audit + +| Component | Direct Color References | Status | +|-----------|------------------------|--------| +| Button | 0 | βœ… | +| Input | 0 | βœ… | +| Select | 0 | βœ… | +| Card | 0 | βœ… | + +### 7.2 Compliance Matrix Update + +When this document is complete, update Compliance Matrix: +- All components use semantic tokens exclusively +- No hardcoded colors +- All states have semantic tokens +- Dark mode implementable via token swap + +--- + +## Γ„NDRINGSHISTORIA + +| Version | Datum | Beskrivning | +|---------|-------|-------------| +| 1.0 | 2026-07-02 | Initial semantic color system with state matrix and component aliases | + +--- + +## STATUS + +**DRAFT β€” Under development**