@fastwork/xosmoz-theme 0.42.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/dart/xz_colors.generated.dart +108 -0
- package/dist/figma-plugin.zip +0 -0
- package/dist/figma-tokens/Dark.json +971 -217
- package/dist/figma-tokens/Light.json +977 -223
- package/dist/index.js +32 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32 -16
- package/dist/index.mjs.map +1 -1
- package/dist/themes/dark.css +8 -0
- package/dist/themes/light.css +8 -0
- package/dist/themes.css +16 -0
- package/llms.txt +374 -167
- package/package.json +1 -1
package/llms.txt
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
# @fastwork/xosmoz-theme
|
|
1
|
+
# @fastwork/xosmoz-theme — Color Tokens & Usage Guide
|
|
2
2
|
|
|
3
|
-
> Design
|
|
3
|
+
> Design token system for Xosmoz. Uses OKLCH color space. Supports light and dark themes via CSS variables and `data-theme` attribute. This guide covers color tokens only (CSS variables).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
### Install
|
|
6
10
|
|
|
7
11
|
```bash
|
|
8
12
|
npm install @fastwork/xosmoz-theme
|
|
9
13
|
```
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
### CSS Imports
|
|
12
16
|
|
|
13
17
|
```css
|
|
14
|
-
/* Base styles: CSS reset, font imports, typography/spacing
|
|
18
|
+
/* Base styles: CSS reset, font imports, typography/spacing tokens */
|
|
15
19
|
@import '@fastwork/xosmoz-theme/base.css';
|
|
16
20
|
|
|
17
21
|
/* All themes (light + dark) */
|
|
@@ -22,227 +26,241 @@ npm install @fastwork/xosmoz-theme
|
|
|
22
26
|
@import '@fastwork/xosmoz-theme/themes/dark.css';
|
|
23
27
|
```
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
### Theme Switching
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
Light theme is the default. Set `data-theme="dark"` on `<html>` for dark mode.
|
|
28
32
|
|
|
29
33
|
```html
|
|
30
|
-
<html>...</html>
|
|
31
|
-
<html data-theme="dark">...</html>
|
|
34
|
+
<html>...</html> <!-- Light theme (default) -->
|
|
35
|
+
<html data-theme="dark">...</html> <!-- Dark theme -->
|
|
32
36
|
```
|
|
33
37
|
|
|
34
38
|
```javascript
|
|
35
|
-
// Switch
|
|
39
|
+
// Switch at runtime
|
|
36
40
|
document.documentElement.setAttribute('data-theme', 'dark');
|
|
41
|
+
document.documentElement.removeAttribute('data-theme'); // back to light
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
## Color Token Architecture
|
|
47
|
+
|
|
48
|
+
The system has two layers:
|
|
49
|
+
|
|
50
|
+
### Layer 1 — Palette Tokens (primitives)
|
|
51
|
+
Eight raw color values. These are single CSS variables (no numbered scales). They are the same in both light and dark themes.
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
--xz-color-fastwork (brand blue-purple)
|
|
55
|
+
--xz-color-gray
|
|
56
|
+
--xz-color-green
|
|
57
|
+
--xz-color-yellow
|
|
58
|
+
--xz-color-red
|
|
59
|
+
--xz-color-orange
|
|
60
|
+
--xz-color-purple
|
|
61
|
+
--xz-color-cyan
|
|
40
62
|
```
|
|
41
63
|
|
|
42
|
-
|
|
64
|
+
**Rule: Do not use palette tokens directly in UI.** They exist as internal primitives. Always use semantic tokens instead.
|
|
43
65
|
|
|
44
|
-
|
|
66
|
+
### Layer 2 — Semantic Tokens (theme-aware)
|
|
67
|
+
These tokens change values between light and dark themes. Always use these for UI components, text, borders, and backgrounds.
|
|
45
68
|
|
|
46
|
-
|
|
69
|
+
Pattern: `--xz-color-{category}-{property}-{scale}`
|
|
47
70
|
|
|
48
|
-
|
|
71
|
+
---
|
|
49
72
|
|
|
50
|
-
|
|
51
|
-
|----------|---------|
|
|
52
|
-
| `--xz-color-surface-100` | Page background |
|
|
53
|
-
| `--xz-color-surface-200` | Elevated surface (cards, modals) |
|
|
54
|
-
| `--xz-color-surface-300` | Secondary surface |
|
|
55
|
-
| `--xz-color-surface-400` | Tertiary surface / popovers |
|
|
56
|
-
| `--xz-color-text-100` | Primary text color |
|
|
57
|
-
| `--xz-color-text-200` | Secondary/muted text (70% opacity) |
|
|
58
|
-
| `--xz-color-text-300` | Tertiary/disabled text (50% opacity) |
|
|
59
|
-
| `--xz-color-bg-100` | Extreme base background (near-black in light, near-white in dark) |
|
|
60
|
-
| `--xz-color-fg-100` | Text on bg-100 (white in light, black in dark) |
|
|
61
|
-
| `--xz-color-soft-100` | Very subtle overlay (5% opacity of bg) |
|
|
62
|
-
| `--xz-color-soft-200` | Subtle overlay (10% opacity of bg) |
|
|
63
|
-
| `--xz-color-line-100` | Subtle borders |
|
|
64
|
-
| `--xz-color-line-200` | Default borders |
|
|
65
|
-
| `--xz-color-line-300` | Strong/emphasized borders |
|
|
73
|
+
## Base Tokens
|
|
66
74
|
|
|
67
|
-
|
|
75
|
+
Base tokens cover surfaces, text, borders, and neutral overlays. They are theme-aware (change in dark mode).
|
|
68
76
|
|
|
69
|
-
|
|
77
|
+
| CSS Variable | Purpose |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `--xz-color-surface-50` | Absolute white/darkest background (page canvas extreme) |
|
|
80
|
+
| `--xz-color-surface-100` | Default page background |
|
|
81
|
+
| `--xz-color-surface-200` | Elevated surface — cards, modals |
|
|
82
|
+
| `--xz-color-surface-300` | Secondary elevated surface |
|
|
83
|
+
| `--xz-color-surface-400` | Tertiary elevated surface — popovers, dropdowns |
|
|
84
|
+
| `--xz-color-bg-100` | Extreme base (near-black in light / near-white in dark) |
|
|
85
|
+
| `--xz-color-bg-200` | Secondary extreme base |
|
|
86
|
+
| `--xz-color-fg-100` | Text/icon on bg-100 and bg-200 |
|
|
87
|
+
| `--xz-color-text-100` | Primary text |
|
|
88
|
+
| `--xz-color-text-200` | Secondary / muted text (70% opacity) |
|
|
89
|
+
| `--xz-color-text-300` | Disabled / placeholder text (60% opacity) |
|
|
90
|
+
| `--xz-color-soft-100` | Very subtle neutral overlay (5% opacity) |
|
|
91
|
+
| `--xz-color-soft-200` | Subtle neutral overlay (10% opacity) |
|
|
92
|
+
| `--xz-color-line-100` | Subtle border |
|
|
93
|
+
| `--xz-color-line-200` | Default border |
|
|
94
|
+
| `--xz-color-line-300` | Emphasized border |
|
|
70
95
|
|
|
71
|
-
|
|
96
|
+
---
|
|
72
97
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
## Semantic Tokens
|
|
99
|
+
|
|
100
|
+
Eight categories. Categories: `primary`, `danger`, `success`, `warning`, `info`, `neutral`, `orange`, `purple`. Most categories have 11 tokens; `neutral` has 12 (includes an extra `text-200`).
|
|
101
|
+
|
|
102
|
+
### Token Pattern per Category
|
|
103
|
+
|
|
104
|
+
Replace `{name}` with the category:
|
|
105
|
+
|
|
106
|
+
| CSS Variable | Purpose |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `--xz-color-{name}-soft-100` | Tinted transparent background — lightest (10% opacity of base color) |
|
|
109
|
+
| `--xz-color-{name}-soft-200` | Tinted transparent background — stronger (16% opacity), use for hover |
|
|
110
|
+
| `--xz-color-{name}-soft-solid-100` | Opaque version of soft-100 (mixed into surface-100) — use on overlapping surfaces |
|
|
111
|
+
| `--xz-color-{name}-soft-solid-200` | Opaque version of soft-200 |
|
|
77
112
|
| `--xz-color-{name}-line-100` | Subtle colored border |
|
|
78
113
|
| `--xz-color-{name}-line-200` | Default colored border |
|
|
79
114
|
| `--xz-color-{name}-line-300` | Strong colored border |
|
|
80
|
-
| `--xz-color-{name}-bg-100` | Solid fill background
|
|
81
|
-
| `--xz-color-{name}-bg-200` |
|
|
82
|
-
| `--xz-color-{name}-fg-100` | Text on solid bg —
|
|
83
|
-
| `--xz-color-{name}-text-100` | Colored text on surfaces
|
|
115
|
+
| `--xz-color-{name}-bg-100` | Solid fill background — buttons, chips, badges |
|
|
116
|
+
| `--xz-color-{name}-bg-200` | Solid fill hover/pressed state |
|
|
117
|
+
| `--xz-color-{name}-fg-100` | Text/icon on solid bg — **always pair with bg-100 / bg-200** |
|
|
118
|
+
| `--xz-color-{name}-text-100` | Colored text on light surfaces — links, status labels |
|
|
84
119
|
|
|
85
|
-
|
|
120
|
+
> **`neutral` exception:** also includes `--xz-color-neutral-text-200` — Muted neutral text, lighter than `text-100`. Use for supporting content, secondary labels.
|
|
86
121
|
|
|
87
|
-
###
|
|
122
|
+
### Key Rules for Semantic Tokens
|
|
88
123
|
|
|
89
|
-
|
|
124
|
+
- **`bg-100` + `fg-100`**: Solid fill components (buttons, solid badges). `fg-100` provides correct contrast (white or dark depending on the category color).
|
|
125
|
+
- **`soft-100` + `text-100` + `line-100`**: Soft/tinted style (alerts, soft badges, highlighted rows).
|
|
126
|
+
- **`soft-solid-*`**: Use instead of `soft-*` when the component sits on a non-transparent surface (e.g., inside a card that has its own background).
|
|
127
|
+
- **`text-100`**: Use for colored text that sits on surface backgrounds (not on solid fills). Examples: link text, status label text, tag text.
|
|
128
|
+
- **`line-*`**: Colored borders. Use `line-200` as the default, `line-100` for subtle, `line-300` for strong/emphasized.
|
|
90
129
|
|
|
91
|
-
|
|
92
|
-
--xz-color-{palette}-100 (lightest)
|
|
93
|
-
--xz-color-{palette}-200
|
|
94
|
-
...
|
|
95
|
-
--xz-color-{palette}-1000 (darkest)
|
|
96
|
-
```
|
|
130
|
+
---
|
|
97
131
|
|
|
98
|
-
Alpha
|
|
132
|
+
## Alpha & Overlay Tokens
|
|
99
133
|
|
|
100
|
-
|
|
134
|
+
These use a 100–1000 scale representing opacity from 0.1 to 1.0.
|
|
101
135
|
|
|
102
136
|
```
|
|
103
|
-
--xz-
|
|
104
|
-
--xz-
|
|
105
|
-
|
|
106
|
-
--xz-
|
|
107
|
-
--xz-font-size-400 (1rem / 16px)
|
|
108
|
-
--xz-font-size-500 (1.125rem / 18px)
|
|
109
|
-
--xz-font-size-600 (1.25rem / 20px)
|
|
110
|
-
--xz-font-size-700 (1.5rem / 24px)
|
|
111
|
-
--xz-font-size-800 (1.625rem / 26px)
|
|
112
|
-
--xz-font-size-900 (2rem / 32px)
|
|
113
|
-
--xz-font-size-1000 (2.375rem / 38px)
|
|
114
|
-
--xz-font-size-1100 (2.5rem / 40px)
|
|
115
|
-
--xz-font-size-1200 (2.6875rem / 43px)
|
|
116
|
-
--xz-font-size-1300 (3rem / 48px)
|
|
117
|
-
--xz-font-size-1400 (3.5rem / 56px)
|
|
118
|
-
--xz-font-size-1500 (4rem / 64px)
|
|
119
|
-
--xz-font-size-1600 (4.5rem / 72px)
|
|
120
|
-
|
|
121
|
-
--xz-font-family-primary (system-ui sans-serif stack)
|
|
122
|
-
--xz-font-family-secondary ("Fastwork" + "Noto Sans Thai" + system fallbacks)
|
|
123
|
-
|
|
124
|
-
--xz-line-height-100pct (1)
|
|
125
|
-
--xz-line-height-125pct (1.25)
|
|
126
|
-
--xz-line-height-135pct (1.35)
|
|
127
|
-
--xz-line-height-150pct (1.5)
|
|
128
|
-
--xz-line-height-165pct (1.65)
|
|
129
|
-
--xz-line-height-200pct (2)
|
|
130
|
-
```
|
|
137
|
+
--xz-color-black-alpha-100 (black at 10% opacity)
|
|
138
|
+
--xz-color-black-alpha-200 (black at 20% opacity)
|
|
139
|
+
...
|
|
140
|
+
--xz-color-black-alpha-1000 (black at 100% opacity)
|
|
131
141
|
|
|
132
|
-
|
|
142
|
+
--xz-color-white-alpha-100 (white at 10% opacity)
|
|
143
|
+
...
|
|
144
|
+
--xz-color-white-alpha-1000 (white at 100% opacity)
|
|
133
145
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
--xz-
|
|
137
|
-
--xz-font-subtitle1-bold, --xz-font-subtitle1-regular
|
|
138
|
-
--xz-font-subtitle2-bold, --xz-font-subtitle2-regular
|
|
139
|
-
--xz-font-subtitle3-bold, --xz-font-subtitle3-regular
|
|
140
|
-
--xz-font-body1 through --xz-font-body4 (primary font, regular)
|
|
146
|
+
--xz-color-overlay-100 (dark overlay at 10% opacity)
|
|
147
|
+
...
|
|
148
|
+
--xz-color-overlay-1000 (dark overlay at 100% opacity)
|
|
141
149
|
```
|
|
142
150
|
|
|
143
|
-
|
|
151
|
+
Use `overlay-*` for modal/drawer backdrops. Use `black-alpha-*` / `white-alpha-*` for scrim layers or icon fills with transparency.
|
|
144
152
|
|
|
145
|
-
|
|
153
|
+
---
|
|
146
154
|
|
|
147
|
-
|
|
148
|
-
--xz-box-shadow-100 (subtle: 0 1px 2px)
|
|
149
|
-
--xz-box-shadow-200 (small: 0 2px 6px)
|
|
150
|
-
--xz-box-shadow-300 (medium: 0 4px 16px)
|
|
151
|
-
--xz-box-shadow-400 (large: 0 8px 20px)
|
|
152
|
-
```
|
|
155
|
+
## Usage Guidelines
|
|
153
156
|
|
|
154
|
-
|
|
157
|
+
### Backgrounds & Surfaces
|
|
155
158
|
|
|
156
|
-
|
|
159
|
+
| Situation | Use |
|
|
160
|
+
|---|---|
|
|
161
|
+
| Page background | `--xz-color-surface-100` |
|
|
162
|
+
| Card, modal, dialog | `--xz-color-surface-200` |
|
|
163
|
+
| Nested card or secondary panel | `--xz-color-surface-300` |
|
|
164
|
+
| Popover, dropdown, tooltip | `--xz-color-surface-400` |
|
|
165
|
+
| Inverted/dark block on page | `--xz-color-bg-100` |
|
|
166
|
+
| Text on inverted block | `--xz-color-fg-100` |
|
|
157
167
|
|
|
158
|
-
|
|
159
|
-
import { lightTheme, darkTheme, themes, getTheme, getThemeNames } from '@fastwork/xosmoz-theme';
|
|
168
|
+
### Text
|
|
160
169
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
170
|
+
| Situation | Use |
|
|
171
|
+
|---|---|
|
|
172
|
+
| Body text, headings | `--xz-color-text-100` |
|
|
173
|
+
| Secondary / helper text | `--xz-color-text-200` |
|
|
174
|
+
| Placeholder / disabled text | `--xz-color-text-300` |
|
|
175
|
+
| Colored status text (link, tag, label) | `--xz-color-{name}-text-100` |
|
|
164
176
|
|
|
165
|
-
|
|
166
|
-
lightTheme.colors.primary.bg[100] // solid fill color
|
|
167
|
-
lightTheme.colors.primary.fg[100] // white text for solid bg
|
|
168
|
-
lightTheme.colors.primary.text[100] // colored text on surfaces
|
|
169
|
-
lightTheme.colors.primary.soft[100] // tinted background
|
|
170
|
-
lightTheme.colors.primary.line[200] // border color
|
|
177
|
+
### Borders
|
|
171
178
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
179
|
+
| Situation | Use |
|
|
180
|
+
|---|---|
|
|
181
|
+
| Subtle separator, divider | `--xz-color-line-100` |
|
|
182
|
+
| Default input or card border | `--xz-color-line-200` |
|
|
183
|
+
| Strong border, active outline | `--xz-color-line-300` |
|
|
184
|
+
| Colored border (semantic) | `--xz-color-{name}-line-100/200/300` |
|
|
175
185
|
|
|
176
|
-
|
|
177
|
-
lightTheme.boxShadows[100] // '0 1px 2px 0 rgba(0, 0, 0, 0.08)'
|
|
178
|
-
lightTheme.boxShadows[200] // '0 2px 6px 0 rgba(0, 0, 0, 0.10)'
|
|
179
|
-
lightTheme.boxShadows[300] // '0 4px 16px 0 rgba(0, 0, 0, 0.12)'
|
|
180
|
-
lightTheme.boxShadows[400] // '0 8px 20px 0 rgba(0, 0, 0, 0.14)'
|
|
186
|
+
### Solid Components (Buttons, Solid Badges)
|
|
181
187
|
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
```
|
|
189
|
+
background: --xz-color-{name}-bg-100
|
|
190
|
+
color: --xz-color-{name}-fg-100 ← always use fg-100 on bg-100
|
|
191
|
+
hover bg: --xz-color-{name}-bg-200
|
|
192
|
+
```
|
|
184
193
|
|
|
185
|
-
|
|
186
|
-
|
|
194
|
+
### Soft/Tinted Components (Alerts, Soft Badges)
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
background: --xz-color-{name}-soft-100
|
|
198
|
+
color: --xz-color-{name}-text-100
|
|
199
|
+
border: 1px solid --xz-color-{name}-line-100
|
|
187
200
|
```
|
|
188
201
|
|
|
189
|
-
###
|
|
202
|
+
### Outline/Ghost Components
|
|
190
203
|
|
|
191
|
-
```
|
|
192
|
-
|
|
204
|
+
```
|
|
205
|
+
background: transparent
|
|
206
|
+
color: --xz-color-{name}-text-100
|
|
207
|
+
border: 1px solid --xz-color-{name}-line-200
|
|
208
|
+
```
|
|
193
209
|
|
|
194
|
-
|
|
195
|
-
fontSize[700] // '1.5rem'
|
|
196
|
-
fontWeight[700] // 700
|
|
197
|
-
fontFamily.primary // system sans-serif stack
|
|
198
|
-
fontFamily.secondary // "Fastwork" + fallbacks
|
|
199
|
-
lineHeight['150pct'] // '1.5'
|
|
210
|
+
### Focus Ring
|
|
200
211
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
font.body1
|
|
212
|
+
```
|
|
213
|
+
border-color: --xz-color-{name}-line-200
|
|
214
|
+
box-shadow: 0 0 0 3px --xz-color-{name}-soft-100
|
|
205
215
|
```
|
|
206
216
|
|
|
207
|
-
###
|
|
208
|
-
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
ThemeConfig,
|
|
212
|
-
ThemeName,
|
|
213
|
-
ThemeRegistry,
|
|
214
|
-
ColorToken,
|
|
215
|
-
TypographyToken,
|
|
216
|
-
TypographyScale,
|
|
217
|
-
FontWeights,
|
|
218
|
-
} from '@fastwork/xosmoz-theme';
|
|
217
|
+
### Modal Backdrop
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
background: --xz-color-overlay-600
|
|
219
221
|
```
|
|
220
222
|
|
|
221
|
-
|
|
223
|
+
---
|
|
222
224
|
|
|
223
|
-
|
|
225
|
+
## Common UI Patterns
|
|
226
|
+
|
|
227
|
+
### Primary Button
|
|
224
228
|
|
|
225
229
|
```css
|
|
226
|
-
.
|
|
230
|
+
.btn-primary {
|
|
227
231
|
background: var(--xz-color-primary-bg-100);
|
|
228
|
-
color: var(--xz-color-primary-fg-100);
|
|
229
|
-
font: var(--xz-font-subtitle1-bold);
|
|
232
|
+
color: var(--xz-color-primary-fg-100);
|
|
230
233
|
border: none;
|
|
231
|
-
border-radius: 0.5rem;
|
|
232
234
|
}
|
|
233
|
-
.
|
|
235
|
+
.btn-primary:hover {
|
|
234
236
|
background: var(--xz-color-primary-bg-200);
|
|
235
237
|
}
|
|
236
238
|
```
|
|
237
239
|
|
|
238
|
-
###
|
|
240
|
+
### Outline Button
|
|
239
241
|
|
|
240
242
|
```css
|
|
241
|
-
.
|
|
243
|
+
.btn-outline {
|
|
242
244
|
background: transparent;
|
|
243
245
|
color: var(--xz-color-primary-text-100);
|
|
244
246
|
border: 1px solid var(--xz-color-primary-line-200);
|
|
245
247
|
}
|
|
248
|
+
.btn-outline:hover {
|
|
249
|
+
background: var(--xz-color-primary-soft-100);
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Danger Button
|
|
254
|
+
|
|
255
|
+
```css
|
|
256
|
+
.btn-danger {
|
|
257
|
+
background: var(--xz-color-danger-bg-100);
|
|
258
|
+
color: var(--xz-color-danger-fg-100);
|
|
259
|
+
border: none;
|
|
260
|
+
}
|
|
261
|
+
.btn-danger:hover {
|
|
262
|
+
background: var(--xz-color-danger-bg-200);
|
|
263
|
+
}
|
|
246
264
|
```
|
|
247
265
|
|
|
248
266
|
### Card
|
|
@@ -252,44 +270,233 @@ import type {
|
|
|
252
270
|
background: var(--xz-color-surface-200);
|
|
253
271
|
color: var(--xz-color-text-100);
|
|
254
272
|
border: 1px solid var(--xz-color-line-100);
|
|
255
|
-
border-radius: 0.75rem;
|
|
256
|
-
box-shadow: var(--xz-box-shadow-200);
|
|
257
273
|
}
|
|
258
274
|
```
|
|
259
275
|
|
|
260
|
-
### Alert
|
|
276
|
+
### Alert (soft style)
|
|
261
277
|
|
|
262
278
|
```css
|
|
279
|
+
/* Replace {name} with: success | danger | warning | info */
|
|
263
280
|
.alert-success {
|
|
264
281
|
background: var(--xz-color-success-soft-100);
|
|
265
282
|
color: var(--xz-color-success-text-100);
|
|
266
283
|
border: 1px solid var(--xz-color-success-line-100);
|
|
267
284
|
}
|
|
285
|
+
.alert-danger {
|
|
286
|
+
background: var(--xz-color-danger-soft-100);
|
|
287
|
+
color: var(--xz-color-danger-text-100);
|
|
288
|
+
border: 1px solid var(--xz-color-danger-line-100);
|
|
289
|
+
}
|
|
290
|
+
.alert-warning {
|
|
291
|
+
background: var(--xz-color-warning-soft-100);
|
|
292
|
+
color: var(--xz-color-warning-text-100);
|
|
293
|
+
border: 1px solid var(--xz-color-warning-line-100);
|
|
294
|
+
}
|
|
295
|
+
.alert-info {
|
|
296
|
+
background: var(--xz-color-info-soft-100);
|
|
297
|
+
color: var(--xz-color-info-text-100);
|
|
298
|
+
border: 1px solid var(--xz-color-info-line-100);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Badge — Soft
|
|
303
|
+
|
|
304
|
+
```css
|
|
305
|
+
.badge-success {
|
|
306
|
+
background: var(--xz-color-success-soft-100);
|
|
307
|
+
color: var(--xz-color-success-text-100);
|
|
308
|
+
}
|
|
309
|
+
```
|
|
268
310
|
|
|
269
|
-
|
|
311
|
+
### Badge — Solid
|
|
312
|
+
|
|
313
|
+
```css
|
|
314
|
+
.badge-danger-solid {
|
|
270
315
|
background: var(--xz-color-danger-bg-100);
|
|
271
|
-
color: var(--xz-color-danger-fg-100);
|
|
316
|
+
color: var(--xz-color-danger-fg-100);
|
|
272
317
|
}
|
|
273
318
|
```
|
|
274
319
|
|
|
275
|
-
### Form
|
|
320
|
+
### Form Input
|
|
276
321
|
|
|
277
322
|
```css
|
|
278
323
|
.input {
|
|
279
324
|
background: var(--xz-color-surface-100);
|
|
280
325
|
color: var(--xz-color-text-100);
|
|
281
326
|
border: 1px solid var(--xz-color-line-200);
|
|
282
|
-
|
|
327
|
+
}
|
|
328
|
+
.input::placeholder {
|
|
329
|
+
color: var(--xz-color-text-300);
|
|
283
330
|
}
|
|
284
331
|
.input:focus {
|
|
285
332
|
border-color: var(--xz-color-primary-line-200);
|
|
286
333
|
box-shadow: 0 0 0 3px var(--xz-color-primary-soft-100);
|
|
334
|
+
outline: none;
|
|
335
|
+
}
|
|
336
|
+
.input.error {
|
|
337
|
+
border-color: var(--xz-color-danger-line-200);
|
|
338
|
+
box-shadow: 0 0 0 3px var(--xz-color-danger-soft-100);
|
|
287
339
|
}
|
|
288
340
|
```
|
|
289
341
|
|
|
290
|
-
###
|
|
342
|
+
### Text Hierarchy
|
|
291
343
|
|
|
292
344
|
```css
|
|
293
|
-
.text-
|
|
294
|
-
.text-
|
|
345
|
+
.text-primary { color: var(--xz-color-text-100); }
|
|
346
|
+
.text-muted { color: var(--xz-color-text-200); }
|
|
347
|
+
.text-disabled { color: var(--xz-color-text-300); }
|
|
348
|
+
.text-link { color: var(--xz-color-primary-text-100); }
|
|
349
|
+
.text-danger { color: var(--xz-color-danger-text-100); }
|
|
350
|
+
.text-success { color: var(--xz-color-success-text-100); }
|
|
295
351
|
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Figma Variables Guide
|
|
356
|
+
|
|
357
|
+
Figma variables mirror the CSS token system exactly. Every CSS variable has a corresponding Figma variable in the same collection.
|
|
358
|
+
|
|
359
|
+
### Collection Structure
|
|
360
|
+
|
|
361
|
+
- **Collection name**: `colors`
|
|
362
|
+
- **Modes**: `Light` and `Dark`
|
|
363
|
+
- **Total variables**: ~160 color variables
|
|
364
|
+
|
|
365
|
+
### Naming Pattern
|
|
366
|
+
|
|
367
|
+
Figma uses slash-separated paths. The mapping to CSS is direct:
|
|
368
|
+
|
|
369
|
+
| Variable type | Figma path | CSS variable |
|
|
370
|
+
|---|---|---|
|
|
371
|
+
| Base theme token | `theme/base/{property}/{scale}` | `--xz-color-{property}-{scale}` |
|
|
372
|
+
| Semantic theme token | `theme/{category}/{property}/{scale}` | `--xz-color-{category}-{property}-{scale}` |
|
|
373
|
+
| Alpha token | `theme/blackAlpha/{scale}` | `--xz-color-black-alpha-{scale}` |
|
|
374
|
+
| Alpha token | `theme/whiteAlpha/{scale}` | `--xz-color-white-alpha-{scale}` |
|
|
375
|
+
| Overlay token | `theme/overlay/{scale}` | `--xz-color-overlay-{scale}` |
|
|
376
|
+
| Palette primitive | `palette/{name}` | `--xz-color-{name}` |
|
|
377
|
+
|
|
378
|
+
### Complete Figma → CSS Mapping
|
|
379
|
+
|
|
380
|
+
#### Base (16 variables)
|
|
381
|
+
|
|
382
|
+
| Figma Variable | CSS Variable |
|
|
383
|
+
|---|---|
|
|
384
|
+
| `theme/base/bg/100` | `--xz-color-bg-100` |
|
|
385
|
+
| `theme/base/bg/200` | `--xz-color-bg-200` |
|
|
386
|
+
| `theme/base/surface/50` | `--xz-color-surface-50` |
|
|
387
|
+
| `theme/base/surface/100` | `--xz-color-surface-100` |
|
|
388
|
+
| `theme/base/surface/200` | `--xz-color-surface-200` |
|
|
389
|
+
| `theme/base/surface/300` | `--xz-color-surface-300` |
|
|
390
|
+
| `theme/base/surface/400` | `--xz-color-surface-400` |
|
|
391
|
+
| `theme/base/fg/100` | `--xz-color-fg-100` |
|
|
392
|
+
| `theme/base/soft/100` | `--xz-color-soft-100` |
|
|
393
|
+
| `theme/base/soft/200` | `--xz-color-soft-200` |
|
|
394
|
+
| `theme/base/text/100` | `--xz-color-text-100` |
|
|
395
|
+
| `theme/base/text/200` | `--xz-color-text-200` |
|
|
396
|
+
| `theme/base/text/300` | `--xz-color-text-300` |
|
|
397
|
+
| `theme/base/line/100` | `--xz-color-line-100` |
|
|
398
|
+
| `theme/base/line/200` | `--xz-color-line-200` |
|
|
399
|
+
| `theme/base/line/300` | `--xz-color-line-300` |
|
|
400
|
+
|
|
401
|
+
#### Semantic Categories (11 variables each; neutral has 12)
|
|
402
|
+
|
|
403
|
+
Same pattern for all 8 categories: `primary`, `danger`, `success`, `warning`, `info`, `neutral`, `orange`, `purple`.
|
|
404
|
+
|
|
405
|
+
| Figma Variable | CSS Variable |
|
|
406
|
+
|---|---|
|
|
407
|
+
| `theme/{name}/soft/100` | `--xz-color-{name}-soft-100` |
|
|
408
|
+
| `theme/{name}/soft/200` | `--xz-color-{name}-soft-200` |
|
|
409
|
+
| `theme/{name}/softSolid/100` | `--xz-color-{name}-soft-solid-100` |
|
|
410
|
+
| `theme/{name}/softSolid/200` | `--xz-color-{name}-soft-solid-200` |
|
|
411
|
+
| `theme/{name}/line/100` | `--xz-color-{name}-line-100` |
|
|
412
|
+
| `theme/{name}/line/200` | `--xz-color-{name}-line-200` |
|
|
413
|
+
| `theme/{name}/line/300` | `--xz-color-{name}-line-300` |
|
|
414
|
+
| `theme/{name}/bg/100` | `--xz-color-{name}-bg-100` |
|
|
415
|
+
| `theme/{name}/bg/200` | `--xz-color-{name}-bg-200` |
|
|
416
|
+
| `theme/{name}/fg/100` | `--xz-color-{name}-fg-100` |
|
|
417
|
+
| `theme/{name}/text/100` | `--xz-color-{name}-text-100` |
|
|
418
|
+
|
|
419
|
+
> **`neutral` exception:** also includes `theme/neutral/text/200` → `--xz-color-neutral-text-200`.
|
|
420
|
+
|
|
421
|
+
#### Black Alpha (10 variables)
|
|
422
|
+
|
|
423
|
+
| Figma Variable | CSS Variable |
|
|
424
|
+
|---|---|
|
|
425
|
+
| `theme/blackAlpha/100` | `--xz-color-black-alpha-100` |
|
|
426
|
+
| `theme/blackAlpha/200` | `--xz-color-black-alpha-200` |
|
|
427
|
+
| `theme/blackAlpha/300` | `--xz-color-black-alpha-300` |
|
|
428
|
+
| `theme/blackAlpha/400` | `--xz-color-black-alpha-400` |
|
|
429
|
+
| `theme/blackAlpha/500` | `--xz-color-black-alpha-500` |
|
|
430
|
+
| `theme/blackAlpha/600` | `--xz-color-black-alpha-600` |
|
|
431
|
+
| `theme/blackAlpha/700` | `--xz-color-black-alpha-700` |
|
|
432
|
+
| `theme/blackAlpha/800` | `--xz-color-black-alpha-800` |
|
|
433
|
+
| `theme/blackAlpha/900` | `--xz-color-black-alpha-900` |
|
|
434
|
+
| `theme/blackAlpha/1000` | `--xz-color-black-alpha-1000` |
|
|
435
|
+
|
|
436
|
+
#### White Alpha (10 variables)
|
|
437
|
+
|
|
438
|
+
| Figma Variable | CSS Variable |
|
|
439
|
+
|---|---|
|
|
440
|
+
| `theme/whiteAlpha/100` | `--xz-color-white-alpha-100` |
|
|
441
|
+
| `theme/whiteAlpha/200` | `--xz-color-white-alpha-200` |
|
|
442
|
+
| `theme/whiteAlpha/300` | `--xz-color-white-alpha-300` |
|
|
443
|
+
| `theme/whiteAlpha/400` | `--xz-color-white-alpha-400` |
|
|
444
|
+
| `theme/whiteAlpha/500` | `--xz-color-white-alpha-500` |
|
|
445
|
+
| `theme/whiteAlpha/600` | `--xz-color-white-alpha-600` |
|
|
446
|
+
| `theme/whiteAlpha/700` | `--xz-color-white-alpha-700` |
|
|
447
|
+
| `theme/whiteAlpha/800` | `--xz-color-white-alpha-800` |
|
|
448
|
+
| `theme/whiteAlpha/900` | `--xz-color-white-alpha-900` |
|
|
449
|
+
| `theme/whiteAlpha/1000` | `--xz-color-white-alpha-1000` |
|
|
450
|
+
|
|
451
|
+
#### Overlay (10 variables)
|
|
452
|
+
|
|
453
|
+
| Figma Variable | CSS Variable |
|
|
454
|
+
|---|---|
|
|
455
|
+
| `theme/overlay/100` | `--xz-color-overlay-100` |
|
|
456
|
+
| `theme/overlay/200` | `--xz-color-overlay-200` |
|
|
457
|
+
| `theme/overlay/300` | `--xz-color-overlay-300` |
|
|
458
|
+
| `theme/overlay/400` | `--xz-color-overlay-400` |
|
|
459
|
+
| `theme/overlay/500` | `--xz-color-overlay-500` |
|
|
460
|
+
| `theme/overlay/600` | `--xz-color-overlay-600` |
|
|
461
|
+
| `theme/overlay/700` | `--xz-color-overlay-700` |
|
|
462
|
+
| `theme/overlay/800` | `--xz-color-overlay-800` |
|
|
463
|
+
| `theme/overlay/900` | `--xz-color-overlay-900` |
|
|
464
|
+
| `theme/overlay/1000` | `--xz-color-overlay-1000` |
|
|
465
|
+
|
|
466
|
+
#### Palette (8 variables)
|
|
467
|
+
|
|
468
|
+
| Figma Variable | CSS Variable |
|
|
469
|
+
|---|---|
|
|
470
|
+
| `palette/fastwork` | `--xz-color-fastwork` |
|
|
471
|
+
| `palette/gray` | `--xz-color-gray` |
|
|
472
|
+
| `palette/green` | `--xz-color-green` |
|
|
473
|
+
| `palette/yellow` | `--xz-color-yellow` |
|
|
474
|
+
| `palette/red` | `--xz-color-red` |
|
|
475
|
+
| `palette/orange` | `--xz-color-orange` |
|
|
476
|
+
| `palette/purple` | `--xz-color-purple` |
|
|
477
|
+
| `palette/cyan` | `--xz-color-cyan` |
|
|
478
|
+
|
|
479
|
+
### How to Use Figma Variables in Designs
|
|
480
|
+
|
|
481
|
+
1. Select a layer in Figma (frame, text, shape, etc.)
|
|
482
|
+
2. In the Fill or Stroke panel, click the color swatch
|
|
483
|
+
3. Switch to the **Variables** tab in the color picker
|
|
484
|
+
4. Pick from the `colors` collection
|
|
485
|
+
|
|
486
|
+
**Rules for Figma:**
|
|
487
|
+
- Always use `theme/*` variables for component fills, text colors, and stroke colors
|
|
488
|
+
- Use `palette/*` variables only as references — not directly on components
|
|
489
|
+
- Use `theme/base/surface/100` for page backgrounds, `theme/base/surface/200` for cards
|
|
490
|
+
- Use `theme/{name}/bg/100` for solid-filled elements and `theme/{name}/fg/100` for text on top of them
|
|
491
|
+
- Switch between Light/Dark previews using the **Mode** toggle on the variable collection
|
|
492
|
+
|
|
493
|
+
### Keeping Figma in Sync with Code
|
|
494
|
+
|
|
495
|
+
Variables are synced from the npm package via the **XOSMOZ Theme Sync** plugin:
|
|
496
|
+
|
|
497
|
+
1. Open **Plugins → Development → XOSMOZ Theme Sync** in Figma
|
|
498
|
+
2. Select your variable collection from the dropdown
|
|
499
|
+
3. Click **"Check for Updates"** to see if any colors changed
|
|
500
|
+
4. Click **"Update Variables"** to apply changes to both Light and Dark modes at once
|
|
501
|
+
|
|
502
|
+
If starting a new Figma file, use **"Create New Collection"** to generate all variables from scratch.
|