Implemented by Ralph autonomous loop. Iteration: 5 Co-Authored-By: Claude <noreply@anthropic.com>
796 lines
23 KiB
Markdown
796 lines
23 KiB
Markdown
# Design Tokens Reference
|
|
|
|
**Version:** 2.0.0
|
|
**Last Updated:** 2025-11-19
|
|
**Status:** ✅ Complete
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Design tokens are the visual design atoms of the ROA2WEB design system. They are represented as CSS custom properties (`--token-name`) and ensure consistency across the application.
|
|
|
|
**Location:** `src/assets/css/core/variables.css` and `src/assets/css/core/tokens.css`
|
|
|
|
---
|
|
|
|
## Spacing Scale
|
|
|
|
| Token | Value | Pixels | Use Case |
|
|
|-------|-------|--------|----------|
|
|
| `--space-xs` | 0.25rem | 4px | Tight spacing, icon gaps, badges |
|
|
| `--space-sm` | 0.5rem | 8px | Default gap between related items |
|
|
| `--space-md` | 1rem | 16px | Standard component padding |
|
|
| `--space-lg` | 1.5rem | 24px | Section padding, card spacing |
|
|
| `--space-xl` | 2rem | 32px | Page margins, large separations |
|
|
| `--space-2xl` | 3rem | 48px | Major section gaps |
|
|
| `--space-3xl` | 4rem | 64px | Hero sections, page-level spacing |
|
|
|
|
**Usage:**
|
|
```css
|
|
.card {
|
|
padding: var(--space-md); /* 16px */
|
|
margin-bottom: var(--space-lg); /* 24px */
|
|
}
|
|
|
|
.button-group {
|
|
gap: var(--space-sm); /* 8px */
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Typography Scale
|
|
|
|
### Font Sizes
|
|
|
|
| Token | Value | Pixels | Use Case |
|
|
|-------|-------|--------|----------|
|
|
| `--text-xs` | 0.75rem | 12px | Tiny labels, timestamps, badges |
|
|
| `--text-sm` | 0.875rem | 14px | Small text, table cells, secondary info |
|
|
| `--text-base` | 1rem | 16px | Body text (default) |
|
|
| `--text-lg` | 1.125rem | 18px | Emphasized text, large buttons |
|
|
| `--text-xl` | 1.25rem | 20px | Small headings, card titles |
|
|
| `--text-2xl` | 1.5rem | 24px | Medium headings, metric values |
|
|
| `--text-3xl` | 2rem | 32px | Large headings, page titles |
|
|
| `--text-4xl` | 2.5rem | 40px | Hero text, dashboard values |
|
|
|
|
### Font Weights
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--font-light` | 300 | Rarely used, light emphasis |
|
|
| `--font-normal` | 400 | Body text, default |
|
|
| `--font-medium` | 500 | Labels, buttons, emphasis |
|
|
| `--font-semibold` | 600 | Headings, important text |
|
|
| `--font-bold` | 700 | Strong emphasis, titles |
|
|
|
|
### Line Heights
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--leading-tight` | 1.2 | Headings, compact text |
|
|
| `--leading-normal` | 1.5 | Body text (default) |
|
|
| `--leading-loose` | 1.75 | Relaxed reading, large text |
|
|
|
|
**Usage:**
|
|
```css
|
|
.heading {
|
|
font-size: var(--text-2xl);
|
|
font-weight: var(--font-semibold);
|
|
line-height: var(--leading-tight);
|
|
}
|
|
|
|
.body-text {
|
|
font-size: var(--text-base);
|
|
font-weight: var(--font-normal);
|
|
line-height: var(--leading-normal);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Color Palette
|
|
|
|
### Primary Colors
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--color-primary` | #2563eb | Primary actions, links, focus states |
|
|
| `--color-primary-dark` | #1d4ed8 | Primary hover, active states |
|
|
| `--color-primary-light` | #3b82f6 | Backgrounds, light accents |
|
|
|
|
### Status Colors
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--color-success` | #059669 | Success messages, positive trends |
|
|
| `--color-warning` | #d97706 | Warnings, cautions |
|
|
| `--color-error` | #dc2626 | Errors, destructive actions, negative trends |
|
|
| `--color-info` | #0891b2 | Info messages, neutral alerts |
|
|
|
|
### Text Colors
|
|
|
|
| Token | Value | Contrast | Use Case |
|
|
|-------|-------|----------|----------|
|
|
| `--color-text` | #111827 | 16.9:1 | Primary text, headings |
|
|
| `--color-text-secondary` | #6b7280 | 4.6:1 | Secondary text, labels |
|
|
| `--color-text-muted` | #9ca3af | 2.8:1 | Muted text, disabled text |
|
|
| `--color-text-inverse` | #ffffff | - | Text on dark backgrounds |
|
|
|
|
### Background Colors
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--color-bg` | #ffffff | Primary background, cards |
|
|
| `--color-bg-secondary` | #f9fafb | Alternate backgrounds, hover states |
|
|
| `--color-bg-muted` | #f3f4f6 | Disabled backgrounds, subtle sections |
|
|
| `--color-bg-dark` | #111827 | Dark backgrounds |
|
|
|
|
### Semantic Surface Tokens (PrimeVue-compatible)
|
|
|
|
**CRITICAL for dark mode support!** These tokens automatically switch values in dark mode.
|
|
|
|
| Token | Light Value | Dark Value | Use Case |
|
|
|-------|-------------|------------|----------|
|
|
| `--surface-card` | #ffffff | #1e293b | Card backgrounds, elevated surfaces |
|
|
| `--surface-ground` | #f8fafc | #0f172a | Page background, base layer |
|
|
| `--surface-section` | #ffffff | #1e293b | Section backgrounds |
|
|
| `--surface-hover` | #f1f5f9 | #334155 | Hover states on surfaces |
|
|
| `--surface-border` | #e2e8f0 | #475569 | Borders on surfaces |
|
|
| `--surface-overlay` | #ffffff | #1e293b | Modal/overlay backgrounds |
|
|
|
|
**Usage:**
|
|
```css
|
|
.card {
|
|
background: var(--surface-card);
|
|
border: 1px solid var(--surface-border);
|
|
}
|
|
|
|
.page {
|
|
background: var(--surface-ground);
|
|
}
|
|
```
|
|
|
|
### Border Colors
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--color-border` | #e5e7eb | Default borders |
|
|
| `--color-border-light` | #f3f4f6 | Subtle borders |
|
|
| `--color-border-dark` | #d1d5db | Emphasized borders |
|
|
|
|
**Usage:**
|
|
```css
|
|
.btn-primary {
|
|
background: var(--color-primary);
|
|
color: var(--color-text-inverse);
|
|
border: 1px solid var(--color-primary);
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
background: var(--color-primary-dark);
|
|
}
|
|
|
|
.card {
|
|
background: var(--color-bg);
|
|
border: 1px solid var(--color-border);
|
|
color: var(--color-text);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Shadows
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--shadow-sm` | 0 1px 2px rgba(0,0,0,0.05) | Subtle depth, hover states |
|
|
| `--shadow-md` | 0 4px 6px rgba(0,0,0,0.1) | Cards, dropdowns |
|
|
| `--shadow-lg` | 0 10px 15px rgba(0,0,0,0.1) | Elevated cards, modals |
|
|
| `--shadow-xl` | 0 20px 25px rgba(0,0,0,0.1) | Popovers, large modals |
|
|
|
|
**Usage:**
|
|
```css
|
|
.card {
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.card:hover {
|
|
box-shadow: var(--shadow-md);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Border Radius
|
|
|
|
| Token | Value | Pixels | Use Case |
|
|
|-------|-------|--------|----------|
|
|
| `--radius-sm` | 0.25rem | 4px | Small elements, badges |
|
|
| `--radius-md` | 0.5rem | 8px | Buttons, inputs, cards (default) |
|
|
| `--radius-lg` | 0.75rem | 12px | Large cards, images |
|
|
| `--radius-xl` | 1rem | 16px | Hero cards, special elements |
|
|
| `--radius-full` | 9999px | - | Pills, circles, avatars |
|
|
|
|
**Usage:**
|
|
```css
|
|
.btn {
|
|
border-radius: var(--radius-md);
|
|
}
|
|
|
|
.avatar {
|
|
border-radius: var(--radius-full);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Transitions
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--transition-fast` | 150ms ease | Hover states, quick interactions |
|
|
| `--transition-normal` | 250ms ease | Default transitions |
|
|
| `--transition-slow` | 350ms ease | Complex animations, modals |
|
|
|
|
**Usage:**
|
|
```css
|
|
.btn {
|
|
transition: all var(--transition-fast);
|
|
}
|
|
|
|
.modal {
|
|
transition: opacity var(--transition-normal);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Extended Tokens (Dashboard & Metrics)
|
|
|
|
### Card Tokens
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--card-padding` | var(--space-lg) | Standard card padding (24px) |
|
|
| `--card-padding-sm` | var(--space-md) | Compact card padding (16px) |
|
|
| `--card-padding-lg` | var(--space-xl) | Large card padding (32px) |
|
|
| `--card-gap` | var(--space-md) | Gap between card elements (16px) |
|
|
| `--card-min-height` | 280px | Minimum card height |
|
|
| `--card-radius` | var(--radius-md) | Card border radius (8px) |
|
|
|
|
### Interactive Tokens
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--hover-lift` | -2px | Vertical lift on hover |
|
|
| `--active-lift` | 0px | Reset lift on click |
|
|
| `--focus-ring` | 0 0 0 3px rgba(...) | Focus outline |
|
|
|
|
### Spinner Sizes
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--spinner-size` | 40px | Default spinner |
|
|
| `--spinner-size-sm` | 24px | Small spinner (buttons) |
|
|
| `--spinner-size-lg` | 56px | Large spinner (page loading) |
|
|
| `--spinner-border` | 4px | Spinner border width |
|
|
|
|
### Dashboard Metrics
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--value-size` | 1.5rem | Default metric value (24px) |
|
|
| `--value-size-lg` | 2rem | Large metric value (32px) |
|
|
| `--label-size` | 0.875rem | Metric label (14px) |
|
|
| `--sublabel-size` | 0.8125rem | Sub-label (13px) |
|
|
| `--metric-gap` | 1rem | Gap between metrics (16px) |
|
|
| `--sparkline-height` | 80px | Sparkline chart height |
|
|
| `--sparkline-height-lg` | 150px | Large sparkline height |
|
|
|
|
---
|
|
|
|
## Layout Tokens
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--header-height` | 56px | App header height |
|
|
| `--sidebar-width` | 240px | Sidebar width |
|
|
| `--container-max-width` | 1400px | Max content width |
|
|
|
|
---
|
|
|
|
## Z-Index Scale
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--z-dropdown` | 1200 | Dropdown menus |
|
|
| `--z-sticky` | 1020 | Sticky headers |
|
|
| `--z-fixed` | 1030 | Fixed elements |
|
|
| `--z-modal-backdrop` | 1040 | Modal backdrop |
|
|
| `--z-modal` | 1050 | Modal dialogs |
|
|
| `--z-popover` | 1060 | Popovers |
|
|
| `--z-tooltip` | 1070 | Tooltips (highest) |
|
|
|
|
---
|
|
|
|
## Breakpoints (Reference)
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--breakpoint-mobile` | 480px | Mobile devices |
|
|
| `--breakpoint-tablet` | 768px | Tablets, small laptops |
|
|
| `--breakpoint-desktop` | 1024px | Desktops |
|
|
| `--breakpoint-wide` | 1400px | Large screens |
|
|
|
|
**Usage:**
|
|
```css
|
|
@media (max-width: 768px) {
|
|
.card {
|
|
padding: var(--space-md);
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1024px) {
|
|
.container {
|
|
max-width: var(--container-max-width);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Utility Patterns
|
|
|
|
### Color With Opacity
|
|
|
|
```css
|
|
/* Use RGB values for transparency */
|
|
background: rgba(var(--color-primary-rgb), 0.1);
|
|
/* = rgba(37, 99, 235, 0.1) */
|
|
|
|
border-color: rgba(var(--color-success-rgb), 0.5);
|
|
/* = rgba(5, 150, 105, 0.5) */
|
|
```
|
|
|
|
### Status Background Colors (10% opacity)
|
|
|
|
| Token | Value | Use Case |
|
|
|-------|-------|----------|
|
|
| `--color-success-bg` | rgba(5, 150, 105, 0.1) | Success alerts background |
|
|
| `--color-warning-bg` | rgba(217, 119, 6, 0.1) | Warning alerts background |
|
|
| `--color-error-bg` | rgba(220, 38, 38, 0.1) | Error alerts background |
|
|
| `--color-info-bg` | rgba(8, 145, 178, 0.1) | Info alerts background |
|
|
|
|
### Monospace Font
|
|
|
|
```css
|
|
/* For numbers, code, metrics */
|
|
font-family: var(--font-mono);
|
|
/* = 'SF Mono', Consolas, 'Liberation Mono', Menlo, Courier, monospace */
|
|
```
|
|
|
|
---
|
|
|
|
## Compatibility Aliases
|
|
|
|
For backwards compatibility with existing code:
|
|
|
|
| Alias | Maps To |
|
|
|-------|---------|
|
|
| `--primary-color` | `var(--color-primary)` |
|
|
| `--primary-color-dark` | `var(--color-primary-dark)` |
|
|
| `--text-color` | `var(--color-text)` |
|
|
| `--text-color-secondary` | `var(--color-text-secondary)` |
|
|
|
|
---
|
|
|
|
## Usage Examples
|
|
|
|
### Complete Button
|
|
|
|
```css
|
|
.btn-primary {
|
|
/* Typography */
|
|
font-size: var(--text-sm);
|
|
font-weight: var(--font-medium);
|
|
line-height: var(--leading-normal);
|
|
|
|
/* Spacing */
|
|
padding: var(--space-sm) var(--space-md);
|
|
gap: var(--space-xs);
|
|
|
|
/* Colors */
|
|
background: var(--color-primary);
|
|
color: var(--color-text-inverse);
|
|
border: 1px solid var(--color-primary);
|
|
|
|
/* Visual */
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
/* Interaction */
|
|
transition: all var(--transition-fast);
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
background: var(--color-primary-dark);
|
|
box-shadow: var(--shadow-md);
|
|
transform: translateY(var(--hover-lift));
|
|
}
|
|
```
|
|
|
|
### Complete Card
|
|
|
|
```css
|
|
.card {
|
|
/* Layout */
|
|
padding: var(--card-padding);
|
|
min-height: var(--card-min-height);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--card-gap);
|
|
|
|
/* Colors */
|
|
background: var(--color-bg);
|
|
border: 1px solid var(--color-border);
|
|
color: var(--color-text);
|
|
|
|
/* Visual */
|
|
border-radius: var(--card-radius);
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
/* Interaction */
|
|
transition: all var(--transition-fast);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### ✅ Do
|
|
|
|
```css
|
|
/* Use tokens for all values */
|
|
.element {
|
|
color: var(--color-text);
|
|
font-size: var(--text-base);
|
|
padding: var(--space-md);
|
|
border-radius: var(--radius-md);
|
|
}
|
|
|
|
/* Combine tokens */
|
|
.card-padding {
|
|
padding: var(--space-lg) var(--space-xl);
|
|
}
|
|
```
|
|
|
|
### ❌ Don't
|
|
|
|
```css
|
|
/* Don't hardcode values */
|
|
.element {
|
|
color: #111827; /* Use var(--color-text) */
|
|
font-size: 16px; /* Use var(--text-base) */
|
|
padding: 16px; /* Use var(--space-md) */
|
|
border-radius: 8px; /* Use var(--radius-md) */
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Dark Mode (ACTIVE)
|
|
|
|
ROA2WEB folosește un **sistem two-tier** pentru teme cu toggle manual în header.
|
|
|
|
### Theme Toggle UI
|
|
|
|
Butonul de temă din header ciclează prin 3 moduri:
|
|
|
|
| Mode | Icon | Label | Comportament |
|
|
|------|------|-------|--------------|
|
|
| `auto` | 🖥️ `pi-desktop` | "Tema: Auto (sistem)" | Urmează preferința OS |
|
|
| `light` | ☀️ `pi-sun` | "Tema: Light" | Forțează light mode |
|
|
| `dark` | 🌙 `pi-moon` | "Tema: Dark" | Forțează dark mode |
|
|
|
|
**Implementare:** `src/shared/components/layout/AppHeader.vue` (lines 137-175)
|
|
|
|
### Persistență
|
|
|
|
- **Key:** `localStorage['user-theme']`
|
|
- **Values:** `'light'`, `'dark'`, sau absent (= auto)
|
|
- **Init:** La mount, aplică tema salvată
|
|
|
|
### CSS Priority Order
|
|
|
|
```
|
|
1. [data-theme="dark/light"] → Manual override (highest)
|
|
2. @media (prefers-color-scheme) → System preference (fallback)
|
|
3. :root (light) → Default
|
|
```
|
|
|
|
### How It Works
|
|
|
|
```css
|
|
/* 1. Default light mode */
|
|
:root {
|
|
--surface-card: #ffffff;
|
|
--text-color: #111827;
|
|
}
|
|
|
|
/* 2. Manual dark override (user clicks toggle) */
|
|
[data-theme="dark"] {
|
|
--surface-card: #1e293b;
|
|
--text-color: #f9fafb;
|
|
}
|
|
|
|
/* 3. Auto-detect (when mode=auto + OS dark) */
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme]) {
|
|
--surface-card: #1e293b;
|
|
--text-color: #f9fafb;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Key Dark Mode Tokens
|
|
|
|
| Token | Light | Dark | Purpose |
|
|
|-------|-------|------|---------|
|
|
| `--surface-card` | #ffffff | #1e293b | Card/container backgrounds |
|
|
| `--surface-ground` | #f8fafc | #0f172a | Page background |
|
|
| `--surface-hover` | #f1f5f9 | #334155 | Hover states |
|
|
| `--surface-border` | #e2e8f0 | #475569 | Borders |
|
|
| `--text-color` | #111827 | #f9fafb | Primary text |
|
|
| `--text-color-secondary` | #6b7280 | #d1d5db | Secondary text |
|
|
|
|
### Color Scales for Status
|
|
|
|
Each color has a full scale (50-900) that inverts appropriately in dark mode:
|
|
|
|
| Color | Light Background | Dark Background | Use Case |
|
|
|-------|-----------------|-----------------|----------|
|
|
| `--green-50/100` | Light green bg | Dark green bg | Success backgrounds |
|
|
| `--green-500/600` | Green text/icons | Same | Success accents |
|
|
| `--yellow-50/100` | Light yellow bg | Dark yellow bg | Warning backgrounds |
|
|
| `--yellow-500/600` | Yellow text/icons | Same | Warning accents |
|
|
| `--red-50/100` | Light red bg | Dark red bg | Error backgrounds |
|
|
| `--red-500/600` | Red text/icons | Same | Error accents |
|
|
|
|
### Testing Dark Mode
|
|
|
|
**IMPORTANT:** Testează întotdeauna ambele scenarii!
|
|
|
|
1. **Toggle manual:** Click buton temă în header (ciclează auto→light→dark)
|
|
2. **DevTools:** Rendering → Emulate CSS media → `prefers-color-scheme: dark`
|
|
3. **Playwright:** `await page.emulateMedia({ colorScheme: 'dark' })`
|
|
4. **System:** Change OS dark mode setting
|
|
|
|
---
|
|
|
|
## Material Design 3 Tokens
|
|
|
|
ROA2WEB implementează **Material Design 3 (MD3)** color tokens pentru componente mobile și touch-friendly. Aceste tokens urmează convenția de denumire MD3 și se mapează la token-urile existente pentru consistență.
|
|
|
|
**Location:** `src/assets/css/core/md3-tokens.css`
|
|
|
|
**Reference:** [Material Design 3 Color System](https://m3.material.io/styles/color/system/overview)
|
|
|
|
### MD3 Color Token Overview
|
|
|
|
MD3 folosește un sistem de culori bazat pe **roluri semantice** în loc de valori specifice. Fiecare culoare principală are variante asociate:
|
|
|
|
| Prefix | Purpose |
|
|
|--------|---------|
|
|
| `--md-sys-color-{name}` | Culoarea principală pentru acel rol |
|
|
| `--md-sys-color-on-{name}` | Text/iconițe PE acea culoare (contrast garantat) |
|
|
| `--md-sys-color-{name}-container` | Background mai subtle pentru componente |
|
|
| `--md-sys-color-on-{name}-container` | Text pe container (contrast garantat) |
|
|
|
|
### Primary Colors
|
|
|
|
| MD3 Token | Light Mode Maps To | Dark Mode Maps To | Use Case |
|
|
|-----------|-------------------|-------------------|----------|
|
|
| `--md-sys-color-primary` | `--color-primary` | `--primary-300` | FAB, prominent buttons, active states |
|
|
| `--md-sys-color-on-primary` | `--color-text-inverse` | `--primary-900` | Text/icons on primary color |
|
|
| `--md-sys-color-primary-container` | `--primary-100` | `--primary-700` | Chips, cards with primary tint |
|
|
| `--md-sys-color-on-primary-container` | `--primary-900` | `--primary-100` | Text on primary container |
|
|
|
|
### Secondary Colors
|
|
|
|
| MD3 Token | Light Mode Maps To | Dark Mode Maps To | Use Case |
|
|
|-----------|-------------------|-------------------|----------|
|
|
| `--md-sys-color-secondary` | `--color-secondary` | `--gray-300` | Less prominent components |
|
|
| `--md-sys-color-on-secondary` | `--color-text-inverse` | `--gray-900` | Text/icons on secondary |
|
|
| `--md-sys-color-secondary-container` | `--gray-100` | `--gray-700` | Secondary component backgrounds |
|
|
| `--md-sys-color-on-secondary-container` | `--gray-900` | `--gray-100` | Text on secondary container |
|
|
|
|
### Surface Colors
|
|
|
|
| MD3 Token | Light Mode Maps To | Dark Mode Maps To | Use Case |
|
|
|-----------|-------------------|-------------------|----------|
|
|
| `--md-sys-color-surface` | `--surface-card` | `--surface-card` | Cards, sheets, dialogs |
|
|
| `--md-sys-color-on-surface` | `--color-text` | `--color-text` | Primary text on surface |
|
|
| `--md-sys-color-surface-variant` | `--surface-50` | `--surface-200` | Alternate surface |
|
|
| `--md-sys-color-on-surface-variant` | `--color-text-secondary` | `--color-text-secondary` | Secondary text |
|
|
|
|
### Background & Outline
|
|
|
|
| MD3 Token | Light Mode Maps To | Dark Mode Maps To | Use Case |
|
|
|-----------|-------------------|-------------------|----------|
|
|
| `--md-sys-color-background` | `--surface-ground` | `--surface-ground` | Base page layer |
|
|
| `--md-sys-color-on-background` | `--color-text` | `--color-text` | Text on background |
|
|
| `--md-sys-color-outline` | `--surface-border` | `--surface-border` | Component borders |
|
|
| `--md-sys-color-outline-variant` | `--color-border-light` | `--surface-300` | Subtle dividers |
|
|
|
|
### Error Colors
|
|
|
|
| MD3 Token | Light Mode Maps To | Dark Mode Maps To | Use Case |
|
|
|-----------|-------------------|-------------------|----------|
|
|
| `--md-sys-color-error` | `--color-error` | `--red-300` | Error states, destructive actions |
|
|
| `--md-sys-color-on-error` | `--color-text-inverse` | `--red-900` | Text on error |
|
|
| `--md-sys-color-error-container` | `--red-100` | `--red-800` | Error state backgrounds |
|
|
| `--md-sys-color-on-error-container` | `--red-900` | `--red-100` | Text on error container |
|
|
|
|
### Surface Elevation Levels (Tonal Surfaces)
|
|
|
|
MD3 înlocuiește shadowurile cu **suprafețe tonale** - culorile devin mai deschise/închise pentru a indica elevația:
|
|
|
|
| MD3 Token | Light Mode | Dark Mode | Elevation Level |
|
|
|-----------|------------|-----------|-----------------|
|
|
| `--md-sys-color-surface-dim` | `--surface-100` | `--surface-0` | Below surface |
|
|
| `--md-sys-color-surface-bright` | `--surface-0` | `--surface-200` | Above surface |
|
|
| `--md-sys-color-surface-container-lowest` | `--surface-0` | `--surface-0` | Level 0 |
|
|
| `--md-sys-color-surface-container-low` | `--surface-50` | `--surface-50` | Level 1 |
|
|
| `--md-sys-color-surface-container` | `--surface-100` | `--surface-100` | Level 2 (default) |
|
|
| `--md-sys-color-surface-container-high` | `--surface-200` | `--surface-200` | Level 3 |
|
|
| `--md-sys-color-surface-container-highest` | `--surface-300` | `--surface-300` | Level 4 |
|
|
|
|
### Inverse & Scrim
|
|
|
|
| MD3 Token | Light Mode | Dark Mode | Use Case |
|
|
|-----------|------------|-----------|----------|
|
|
| `--md-sys-color-inverse-surface` | `--surface-800` | `--surface-800` | Snackbars, tooltips |
|
|
| `--md-sys-color-inverse-on-surface` | `--surface-50` | `--surface-100` | Text on inverse surface |
|
|
| `--md-sys-color-inverse-primary` | `--primary-300` | `--primary-600` | Primary accent on inverse |
|
|
| `--md-sys-color-scrim` | `rgba(0,0,0,0.32)` | `rgba(0,0,0,0.64)` | Modal/sheet overlays |
|
|
|
|
### MD3 Token Mapping Quick Reference
|
|
|
|
Pentru referință rapidă, iată mapping-ul complet între MD3 tokens și tokens-urile existente ROA2WEB:
|
|
|
|
| MD3 Token | ROA2WEB Equivalent |
|
|
|-----------|-------------------|
|
|
| `--md-sys-color-primary` | `--color-primary` |
|
|
| `--md-sys-color-on-primary` | `--color-text-inverse` |
|
|
| `--md-sys-color-surface` | `--surface-card` |
|
|
| `--md-sys-color-on-surface` | `--color-text` / `--text-color` |
|
|
| `--md-sys-color-background` | `--surface-ground` |
|
|
| `--md-sys-color-outline` | `--surface-border` |
|
|
| `--md-sys-color-error` | `--color-error` |
|
|
|
|
### Dark Mode Examples
|
|
|
|
**Exemplu 1: Card cu MD3 tokens**
|
|
|
|
```css
|
|
/* Light mode: fundal alb, text închis */
|
|
/* Dark mode: fundal închis, text deschis */
|
|
.md3-card {
|
|
background: var(--md-sys-color-surface);
|
|
color: var(--md-sys-color-on-surface);
|
|
border: 1px solid var(--md-sys-color-outline);
|
|
}
|
|
|
|
.md3-card-header {
|
|
background: var(--md-sys-color-surface-container-high);
|
|
color: var(--md-sys-color-on-surface);
|
|
}
|
|
```
|
|
|
|
**Exemplu 2: Button primary cu MD3 tokens**
|
|
|
|
```css
|
|
/* Light: background albastru (#2563eb), text alb */
|
|
/* Dark: background albastru deschis (--primary-300), text închis */
|
|
.md3-button-filled {
|
|
background: var(--md-sys-color-primary);
|
|
color: var(--md-sys-color-on-primary);
|
|
}
|
|
|
|
.md3-button-filled:hover {
|
|
background: var(--md-sys-color-primary-container);
|
|
color: var(--md-sys-color-on-primary-container);
|
|
}
|
|
```
|
|
|
|
**Exemplu 3: Error state cu MD3 tokens**
|
|
|
|
```css
|
|
/* Light: fundal roșu deschis, text roșu închis */
|
|
/* Dark: fundal roșu închis, text roșu deschis */
|
|
.md3-error-message {
|
|
background: var(--md-sys-color-error-container);
|
|
color: var(--md-sys-color-on-error-container);
|
|
border: 1px solid var(--md-sys-color-error);
|
|
}
|
|
```
|
|
|
|
**Exemplu 4: Elevated surface cu tonal levels**
|
|
|
|
```css
|
|
/* Folosește suprafețe tonale în loc de shadow pentru elevație */
|
|
.md3-bottom-sheet {
|
|
background: var(--md-sys-color-surface-container-low);
|
|
}
|
|
|
|
.md3-dialog {
|
|
background: var(--md-sys-color-surface-container-high);
|
|
}
|
|
|
|
.md3-navigation-drawer {
|
|
background: var(--md-sys-color-surface-container);
|
|
}
|
|
```
|
|
|
|
**Exemplu 5: Scrim pentru modal overlay**
|
|
|
|
```css
|
|
.md3-modal-backdrop {
|
|
background: var(--md-sys-color-scrim);
|
|
/* Light: rgba(0,0,0,0.32) - semi-transparent */
|
|
/* Dark: rgba(0,0,0,0.64) - more opaque for better contrast */
|
|
}
|
|
```
|
|
|
|
### When to Use MD3 Tokens vs Existing Tokens
|
|
|
|
| Scenario | Recommended Tokens |
|
|
|----------|-------------------|
|
|
| Mobile-first components | MD3 tokens (`--md-sys-color-*`) |
|
|
| Touch-friendly UI | MD3 tokens |
|
|
| Desktop components | Existing tokens (`--color-*`, `--surface-*`) |
|
|
| Legacy code | Existing tokens |
|
|
| New cross-platform components | MD3 tokens (better dark mode support) |
|
|
|
|
### CSS Priority for Dark Mode
|
|
|
|
MD3 tokens urmează aceeași ordine de prioritate ca restul sistemului:
|
|
|
|
```css
|
|
/* 1. Manual override (highest priority) */
|
|
[data-theme="dark"] {
|
|
--md-sys-color-primary: var(--primary-300);
|
|
}
|
|
|
|
/* 2. System preference (fallback when no manual theme) */
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme]) {
|
|
--md-sys-color-primary: var(--primary-300);
|
|
}
|
|
}
|
|
|
|
/* 3. Default light mode */
|
|
:root {
|
|
--md-sys-color-primary: var(--color-primary);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Resources
|
|
|
|
- **Pattern Library:** [CSS_PATTERNS.md](./CSS_PATTERNS.md)
|
|
- **Component Guidelines:** [COMPONENT_STYLING.md](./COMPONENT_STYLING.md)
|
|
- **Styling Guidelines:** [STYLING_GUIDELINES.md](./STYLING_GUIDELINES.md)
|
|
- **Mobile Patterns:** [MOBILE_PATTERNS.md](./MOBILE_PATTERNS.md)
|
|
- **MD3 Official Docs:** [Material Design 3](https://m3.material.io/)
|
|
|
|
---
|
|
|
|
**Last Updated:** 2026-01-12
|
|
**Version:** 2.1.0
|
|
**Maintained By:** Frontend Team
|