@nebutra/theme 0.1.0 → 0.2.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/.turbo/turbo-build.log +9 -176
- package/.turbo/turbo-typecheck.log +1 -1
- package/AGENTS.md +18 -31
- package/CHANGELOG.md +7 -0
- package/DESIGN.md +73 -152
- package/LICENSE +21 -676
- package/README.md +73 -27
- package/keyframes.css +147 -0
- package/package.json +20 -9
- package/scripts/sync-languages.mjs +189 -0
- package/scripts/sync-skins.mjs +83 -0
- package/scripts/sync-themes.mjs +40 -0
- package/skins.css +1844 -0
- package/src/__tests__/apply-language.test.ts +70 -0
- package/src/__tests__/languages.test.ts +100 -0
- package/src/__tests__/theme-registry.test.ts +18 -40
- package/src/apply-language.ts +87 -0
- package/src/brand-package-surface.ts +30 -0
- package/src/built-in-packages.generated.ts +39 -0
- package/src/built-in-packages.ts +14 -0
- package/src/client.ts +35 -0
- package/src/index.ts +51 -18
- package/src/languages.json +188 -0
- package/src/languages.meta.json +62 -0
- package/src/languages.ts +70 -0
- package/src/registry.json +4 -196
- package/themes.css +3 -384
- package/turbo.json +25 -0
- package/.turbo/turbo-test.log +0 -14
- package/src/registry.ts +0 -56
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,177 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
> @nebutra/theme@0.
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
css
|
|
11
|
-
- build/css/light.css
|
|
12
|
-
|
|
13
|
-
ts
|
|
14
|
-
- build/ts/light.ts
|
|
15
|
-
- build/ts/light.d.ts
|
|
16
|
-
|
|
17
|
-
tailwind
|
|
18
|
-
- build/tailwind/light.preset.cjs
|
|
19
|
-
|
|
20
|
-
css
|
|
21
|
-
✔︎ build/css/light.css
|
|
22
|
-
|
|
23
|
-
ts
|
|
24
|
-
✔︎ build/ts/light.ts
|
|
25
|
-
✔︎ build/ts/light.d.ts
|
|
26
|
-
|
|
27
|
-
tailwind
|
|
28
|
-
✔︎ build/tailwind/light.preset.cjs
|
|
29
|
-
|
|
30
|
-
css
|
|
31
|
-
- build/css/dark.css
|
|
32
|
-
|
|
33
|
-
ts
|
|
34
|
-
- build/ts/dark.ts
|
|
35
|
-
- build/ts/dark.d.ts
|
|
36
|
-
|
|
37
|
-
tailwind
|
|
38
|
-
- build/tailwind/dark.preset.cjs
|
|
39
|
-
|
|
40
|
-
css
|
|
41
|
-
✔︎ build/css/dark.css
|
|
42
|
-
|
|
43
|
-
ts
|
|
44
|
-
✔︎ build/ts/dark.ts
|
|
45
|
-
✔︎ build/ts/dark.d.ts
|
|
46
|
-
|
|
47
|
-
tailwind
|
|
48
|
-
✔︎ build/tailwind/dark.preset.cjs
|
|
49
|
-
|
|
50
|
-
css
|
|
51
|
-
- build/css/neon.css
|
|
52
|
-
|
|
53
|
-
ts
|
|
54
|
-
- build/ts/neon.ts
|
|
55
|
-
- build/ts/neon.d.ts
|
|
56
|
-
|
|
57
|
-
tailwind
|
|
58
|
-
- build/tailwind/neon.preset.cjs
|
|
59
|
-
|
|
60
|
-
css
|
|
61
|
-
✔︎ build/css/neon.css
|
|
62
|
-
|
|
63
|
-
ts
|
|
64
|
-
✔︎ build/ts/neon.ts
|
|
65
|
-
✔︎ build/ts/neon.d.ts
|
|
66
|
-
|
|
67
|
-
tailwind
|
|
68
|
-
✔︎ build/tailwind/neon.preset.cjs
|
|
69
|
-
|
|
70
|
-
css
|
|
71
|
-
- build/css/gradient.css
|
|
72
|
-
|
|
73
|
-
ts
|
|
74
|
-
- build/ts/gradient.ts
|
|
75
|
-
- build/ts/gradient.d.ts
|
|
76
|
-
|
|
77
|
-
tailwind
|
|
78
|
-
- build/tailwind/gradient.preset.cjs
|
|
79
|
-
|
|
80
|
-
css
|
|
81
|
-
✔︎ build/css/gradient.css
|
|
82
|
-
|
|
83
|
-
ts
|
|
84
|
-
✔︎ build/ts/gradient.ts
|
|
85
|
-
✔︎ build/ts/gradient.d.ts
|
|
86
|
-
|
|
87
|
-
tailwind
|
|
88
|
-
✔︎ build/tailwind/gradient.preset.cjs
|
|
89
|
-
|
|
90
|
-
css
|
|
91
|
-
- build/css/dark-dense.css
|
|
92
|
-
|
|
93
|
-
ts
|
|
94
|
-
- build/ts/dark-dense.ts
|
|
95
|
-
- build/ts/dark-dense.d.ts
|
|
96
|
-
|
|
97
|
-
tailwind
|
|
98
|
-
- build/tailwind/dark-dense.preset.cjs
|
|
99
|
-
|
|
100
|
-
css
|
|
101
|
-
✔︎ build/css/dark-dense.css
|
|
102
|
-
|
|
103
|
-
ts
|
|
104
|
-
✔︎ build/ts/dark-dense.ts
|
|
105
|
-
✔︎ build/ts/dark-dense.d.ts
|
|
106
|
-
|
|
107
|
-
tailwind
|
|
108
|
-
✔︎ build/tailwind/dark-dense.preset.cjs
|
|
109
|
-
|
|
110
|
-
css
|
|
111
|
-
- build/css/minimal.css
|
|
112
|
-
|
|
113
|
-
ts
|
|
114
|
-
- build/ts/minimal.ts
|
|
115
|
-
- build/ts/minimal.d.ts
|
|
116
|
-
|
|
117
|
-
tailwind
|
|
118
|
-
- build/tailwind/minimal.preset.cjs
|
|
119
|
-
|
|
120
|
-
css
|
|
121
|
-
✔︎ build/css/minimal.css
|
|
122
|
-
|
|
123
|
-
ts
|
|
124
|
-
✔︎ build/ts/minimal.ts
|
|
125
|
-
✔︎ build/ts/minimal.d.ts
|
|
126
|
-
|
|
127
|
-
tailwind
|
|
128
|
-
✔︎ build/tailwind/minimal.preset.cjs
|
|
129
|
-
|
|
130
|
-
css
|
|
131
|
-
- build/css/vibrant.css
|
|
132
|
-
|
|
133
|
-
ts
|
|
134
|
-
- build/ts/vibrant.ts
|
|
135
|
-
- build/ts/vibrant.d.ts
|
|
136
|
-
|
|
137
|
-
tailwind
|
|
138
|
-
- build/tailwind/vibrant.preset.cjs
|
|
139
|
-
|
|
140
|
-
css
|
|
141
|
-
✔︎ build/css/vibrant.css
|
|
142
|
-
|
|
143
|
-
ts
|
|
144
|
-
✔︎ build/ts/vibrant.ts
|
|
145
|
-
✔︎ build/ts/vibrant.d.ts
|
|
146
|
-
|
|
147
|
-
tailwind
|
|
148
|
-
✔︎ build/tailwind/vibrant.preset.cjs
|
|
149
|
-
|
|
150
|
-
css
|
|
151
|
-
- build/css/ocean.css
|
|
152
|
-
|
|
153
|
-
ts
|
|
154
|
-
- build/ts/ocean.ts
|
|
155
|
-
- build/ts/ocean.d.ts
|
|
156
|
-
|
|
157
|
-
tailwind
|
|
158
|
-
- build/tailwind/ocean.preset.cjs
|
|
159
|
-
|
|
160
|
-
css
|
|
161
|
-
✔︎ build/css/ocean.css
|
|
162
|
-
|
|
163
|
-
ts
|
|
164
|
-
✔︎ build/ts/ocean.ts
|
|
165
|
-
✔︎ build/ts/ocean.d.ts
|
|
166
|
-
|
|
167
|
-
tailwind
|
|
168
|
-
✔︎ build/tailwind/ocean.preset.cjs
|
|
169
|
-
|
|
170
|
-
[design-tokens] build complete
|
|
171
|
-
→ build/css/styles.generated.css (replaces packages/design/tokens/styles.css)
|
|
172
|
-
→ build/css/themes.generated.css (replaces packages/design/theme/themes.css)
|
|
173
|
-
|
|
174
|
-
> @nebutra/theme@0.1.0 build /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/design/theme
|
|
175
|
-
> node -e "require('node:fs').copyFileSync('../design-tokens/build/css/themes.generated.css', './themes.css'); console.log('themes.css regenerated from @nebutra/design-tokens')"
|
|
176
|
-
|
|
177
|
-
themes.css regenerated from @nebutra/design-tokens
|
|
2
|
+
> @nebutra/theme@0.2.0 build /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/design/theme
|
|
3
|
+
> node scripts/sync-languages.mjs && node ../tokens/scripts/emit-skins.mjs && node scripts/sync-skins.mjs
|
|
4
|
+
|
|
5
|
+
sync-languages:
|
|
6
|
+
languages.json: 8 languages (7 skins + factory)
|
|
7
|
+
built-in-packages.generated.ts: 7 packages
|
|
8
|
+
emit-skins: 7 skins from brand.json → skins/*.css
|
|
9
|
+
gsap, linear, notion, raycast, stripe, vanta, vercel
|
|
10
|
+
skins.css refreshed: 7 languages -> /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/design/theme/skins.css
|
package/AGENTS.md
CHANGED
|
@@ -1,41 +1,28 @@
|
|
|
1
|
-
# AGENTS.md — packages/theme
|
|
2
|
-
|
|
3
|
-
Execution contract for Nebutra's multi-theme preset package.
|
|
1
|
+
# AGENTS.md — packages/design/theme
|
|
4
2
|
|
|
5
3
|
## Scope
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
This package owns the named product-theme layer that sits above base runtime
|
|
10
|
-
tokens. It is CSS-first and intentionally small.
|
|
11
|
-
|
|
12
|
-
## Source Of Truth
|
|
13
|
-
|
|
14
|
-
- Public package surface and exports: `package.json`, `src/index.ts`
|
|
15
|
-
- Canonical named theme selectors and CSS theme payloads: `themes.css`
|
|
5
|
+
`@nebutra/theme` is the **design-language switch surface**.
|
|
16
6
|
|
|
17
|
-
##
|
|
7
|
+
## Do not reintroduce
|
|
18
8
|
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
defined in `themes.css`. Adding, renaming, or removing a theme requires
|
|
23
|
-
updating both in the same change.
|
|
24
|
-
- This package re-exports `next-themes` as a convenience boundary. Do not add
|
|
25
|
-
unrelated runtime policy, product gating, or token definitions here.
|
|
26
|
-
- Keep this package distinct from `@nebutra/tokens`. `@nebutra/theme` owns
|
|
27
|
-
named presets such as `ocean` or `minimal`; `@nebutra/tokens` owns the base
|
|
28
|
-
semantic token system.
|
|
9
|
+
- Multi-mood oklch `[data-theme]` catalogs (deleted 2026.07)
|
|
10
|
+
- Root `@theme { --color-primary: … }` dual-truth against `@nebutra/tokens`
|
|
11
|
+
- “Theme = recolor primary only” product thinking
|
|
29
12
|
|
|
30
|
-
##
|
|
13
|
+
## Source Of Truth
|
|
31
14
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
15
|
+
| Concern | Source |
|
|
16
|
+
|---------|--------|
|
|
17
|
+
| Product chrome (factory) | `@nebutra/tokens` |
|
|
18
|
+
| Design language catalog | `src/languages.json` |
|
|
19
|
+
| Brand Package fixtures | `packages/design/tokens/brands/*` |
|
|
20
|
+
| Multi-language CSS | `skins.css` (`html[data-brand]`) |
|
|
21
|
+
| Keyframes only | `keyframes.css` (`themes.css` = deprecated alias) |
|
|
35
22
|
|
|
36
23
|
## Validation
|
|
37
24
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
```bash
|
|
26
|
+
pnpm --filter @nebutra/theme test
|
|
27
|
+
pnpm --filter @nebutra/theme sync:skins
|
|
28
|
+
```
|
package/CHANGELOG.md
ADDED
package/DESIGN.md
CHANGED
|
@@ -1,203 +1,124 @@
|
|
|
1
1
|
# `@nebutra/theme` — Design Spec
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
> Part of the [root DESIGN.md](../../DESIGN.md). Spec format: `design-md@2026.
|
|
3
|
+
> Design-language catalog for **global product chrome swap**.
|
|
4
|
+
> Part of the [root DESIGN.md](../../DESIGN.md). Spec format: `design-md@2026.07`.
|
|
5
5
|
|
|
6
6
|
| Field | Value |
|
|
7
7
|
|------|------|
|
|
8
8
|
| Package | `@nebutra/theme` |
|
|
9
|
-
| Status |
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
9
|
+
| Status | Design languages only — oklch multi-mood catalog **deleted** |
|
|
10
|
+
| Primary catalog | `src/languages.json` + generated `skins.css` |
|
|
11
|
+
| Brand Package fixtures | `packages/design/tokens/brands/*` |
|
|
12
|
+
| keyframes.css | Keyframes only (no color moods); themes.css is a deprecated alias |
|
|
13
|
+
| Product SSOT | Always `@nebutra/tokens` |
|
|
13
14
|
|
|
14
15
|
---
|
|
15
16
|
|
|
16
17
|
## 1. Identity
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
**What users mean by “换主题” in Create Center** is swapping a full **design language**:
|
|
20
|
+
action vs brand-mark, button recipe, free elevation stacks, radii slots, type zones — not recoloring `--primary` alone.
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
That product surface lives here. The stress-test loop (Linear → GSAP → Raycast → Vercel → Vanta) is how we grow **carrier capacity**, not an infinite preset zoo.
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
**Not this package:** factory semantic HSL (tokens), VI logo lock (brand), component class strings (ui).
|
|
25
|
+
|
|
26
|
+
### 1.1 Single catalog
|
|
27
|
+
|
|
28
|
+
| Catalog | Attribute | Payload |
|
|
29
|
+
|---------|-----------|---------|
|
|
30
|
+
| **Design language** | `html[data-brand]` | Brand Package CSS |
|
|
31
|
+
|
|
32
|
+
Oklch multi-mood `[data-theme]` catalog was removed — dual-truth and weak design quality.
|
|
25
33
|
|
|
26
34
|
---
|
|
27
35
|
|
|
28
|
-
## 2.
|
|
36
|
+
## 2. Design language contract
|
|
29
37
|
|
|
30
|
-
Each
|
|
38
|
+
Each entry in `languages.json` maps to a Brand Package:
|
|
31
39
|
|
|
32
40
|
```
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Shadows: --shadow-{sm,md,lg,xl}
|
|
40
|
-
Transitions: --transition-{fast,normal,slow}
|
|
41
|
+
roles.action → --primary (CTA)
|
|
42
|
+
roles.brand → --brand-mark (logo / AI badge)
|
|
43
|
+
recipe → --btn-default-*, --badge-default-*, radii
|
|
44
|
+
elevationTokens → --elevation-card|control|raised (free CSS)
|
|
45
|
+
zones → product vs marketing type scales
|
|
46
|
+
typography.faces → @font-face
|
|
41
47
|
```
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
### 2.1 Theme catalogue
|
|
49
|
+
### 2.1 Fixture matrix (acceptance bar)
|
|
46
50
|
|
|
47
|
-
|
|
|
48
|
-
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
51
|
+
| id | Proves |
|
|
52
|
+
|----|--------|
|
|
53
|
+
| factory | No override — tokens SSOT |
|
|
54
|
+
| linear | Chromatic solid CTA + **dual-mode** dark/light |
|
|
55
|
+
| gsap | Non-solid CTA recipe + zones |
|
|
56
|
+
| raycast | action ≠ brand-mark + elev=key |
|
|
57
|
+
| vercel | Light mono + elev=hairline + **dual-mode** light/dark palettes |
|
|
58
|
+
| vanta | Chromatic action≠brand + elev=none + pills + dual fonts |
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
### 2.2 CSS modes
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
--color-secondary: oklch(0.715 0.143 215.2);
|
|
64
|
-
--color-accent: oklch(0.714 0.203 264.1);
|
|
65
|
-
--color-background: oklch(0.141 0.005 285.9);
|
|
66
|
-
--color-foreground: oklch(0.985 0 0);
|
|
67
|
-
--color-card: oklch(0.212 0.006 285.9);
|
|
68
|
-
--color-border: oklch(0.274 0.006 286);
|
|
69
|
-
--color-destructive: oklch(0.577 0.245 27.3);
|
|
70
|
-
--color-success: oklch(0.723 0.219 149.6);
|
|
71
|
-
--color-warning: oklch(0.769 0.189 70.1);
|
|
72
|
-
--color-info: oklch(0.623 0.214 259.1);
|
|
73
|
-
|
|
74
|
-
--color-primary-hover: color-mix(in oklch, oklch(0.452 0.313 264.1), white 15%);
|
|
75
|
-
--color-primary-active: color-mix(in oklch, oklch(0.452 0.313 264.1), black 10%);
|
|
76
|
-
|
|
77
|
-
--radius-md: 0.375rem;
|
|
78
|
-
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
|
|
79
|
-
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
80
|
-
}
|
|
81
|
-
```
|
|
62
|
+
| Emit mode | Selector | Use |
|
|
63
|
+
|-----------|----------|-----|
|
|
64
|
+
| `global` (darkDefault) | `:root, .dark, html[data-brand]` | Dark-first single-skin demos |
|
|
65
|
+
| `global` (light) | `:root, html[data-brand]` | Light packs — never bind `.dark` |
|
|
66
|
+
| `scoped` | `html[data-brand]` only | `skins.css` multi-language catalog |
|
|
82
67
|
|
|
83
68
|
---
|
|
84
69
|
|
|
85
70
|
## 3. Patterns
|
|
86
71
|
|
|
87
|
-
### 3.1
|
|
88
|
-
|
|
89
|
-
```tsx
|
|
90
|
-
// apps/{app}/src/app/globals.css
|
|
91
|
-
@import "tailwindcss";
|
|
92
|
-
@import "@nebutra/tokens/styles.css"; /* base tokens */
|
|
93
|
-
@import "@nebutra/theme/themes.css"; /* multi-theme overrides */
|
|
72
|
+
### 3.1 App wiring
|
|
94
73
|
|
|
95
|
-
|
|
96
|
-
import
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
{children}
|
|
100
|
-
</ThemeProvider>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### 3.2 Switching themes at runtime
|
|
104
|
-
|
|
105
|
-
```tsx
|
|
106
|
-
"use client";
|
|
107
|
-
import { useTheme } from "@nebutra/tokens";
|
|
108
|
-
|
|
109
|
-
function ThemeSwitch() {
|
|
110
|
-
const { theme, setTheme } = useTheme();
|
|
111
|
-
return (
|
|
112
|
-
<select value={theme} onChange={(e) => setTheme(e.target.value)}>
|
|
113
|
-
<option value="neon">Neon</option>
|
|
114
|
-
<option value="gradient">Gradient</option>
|
|
115
|
-
<option value="dark-dense">Dark Dense</option>
|
|
116
|
-
<option value="minimal">Minimal</option>
|
|
117
|
-
<option value="vibrant">Vibrant</option>
|
|
118
|
-
<option value="ocean">Ocean</option>
|
|
119
|
-
</select>
|
|
120
|
-
);
|
|
121
|
-
}
|
|
74
|
+
```css
|
|
75
|
+
@import "@nebutra/tokens/styles.css";
|
|
76
|
+
@import "@nebutra/tokens/recipe.css";
|
|
77
|
+
@import "@nebutra/theme/skins.css"; /* optional catalog */
|
|
122
78
|
```
|
|
123
79
|
|
|
124
|
-
|
|
80
|
+
```ts
|
|
81
|
+
import { applyLanguage, clearLanguage } from "@nebutra/theme";
|
|
125
82
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
4. Run `pnpm --filter @nebutra/design-tokens build` to regenerate theme CSS.
|
|
130
|
-
5. Validate with theme tests, preset tests, and the CLI smoke checks.
|
|
131
|
-
6. Add the playground/Storybook visual entry before publishing the theme.
|
|
132
|
-
7. Open a PR; design-system maintainer reviews perceptual coherence, contrast, and component coverage.
|
|
133
|
-
|
|
134
|
-
---
|
|
83
|
+
applyLanguage("vanta", { persist: true }); // built-in Brand Package
|
|
84
|
+
clearLanguage(); // factory
|
|
85
|
+
```
|
|
135
86
|
|
|
136
|
-
|
|
87
|
+
### 3.2 Compile pipeline
|
|
137
88
|
|
|
138
|
-
```
|
|
139
|
-
|
|
89
|
+
```bash
|
|
90
|
+
pnpm --filter @nebutra/tokens compile-brand -- ~/Desktop/Design-System/Foo --id foo
|
|
91
|
+
# edit languages.json
|
|
92
|
+
pnpm --filter @nebutra/theme sync:skins
|
|
140
93
|
```
|
|
141
94
|
|
|
142
|
-
|
|
143
|
-
Theme names are registry-derived; do not introduce new handwritten enums.
|
|
95
|
+
### 3.3 Light/dark
|
|
144
96
|
|
|
145
|
-
|
|
97
|
+
Independent of design-language **id**. Use `@nebutra/tokens` ThemeProvider (`class="dark"`).
|
|
146
98
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
99
|
+
| Pack shape | Emit behavior |
|
|
100
|
+
|------------|----------------|
|
|
101
|
+
| Single-mode (most fixtures) | One palette; `darkDefault` may bind `.dark` so dark shells keep the skin |
|
|
102
|
+
| Dual-mode (`modes.light` + `modes.dark`) | Light under `:root` / `html[data-brand]`; dark under `.dark` / `html.dark[data-brand]` (e.g. **vercel**) |
|
|
150
103
|
|
|
151
|
-
|
|
152
|
-
[data-theme="my-theme"] { --color-primary: oklch(…); /* missing background, etc. */ }
|
|
153
|
-
```
|
|
104
|
+
Recipe, typography, and zones are shared across modes; only color roles/semantic flip.
|
|
154
105
|
|
|
155
106
|
---
|
|
156
107
|
|
|
157
|
-
##
|
|
158
|
-
|
|
159
|
-
Light/dark and multi-theme are **orthogonal**:
|
|
108
|
+
## 4. Anti-goals
|
|
160
109
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
| (none) | `gradient` | gradient theme overrides |
|
|
166
|
-
| `dark` | `dark-dense` | dark-dense theme overrides (dark by design) |
|
|
167
|
-
|
|
168
|
-
Themes that define their own background/foreground supersede the `.dark` overrides for those tokens — designers should pick one mode per theme intent.
|
|
110
|
+
- Do not treat 78 oklch moods as the product roadmap.
|
|
111
|
+
- Do not dual-write root `@theme --color-primary` against tokens.
|
|
112
|
+
- Do not map brand-mark into `--primary` for “branded buttons”.
|
|
113
|
+
- Do not add a language that only changes hue without a new **capacity** proof.
|
|
169
114
|
|
|
170
115
|
---
|
|
171
116
|
|
|
172
|
-
##
|
|
173
|
-
|
|
174
|
-
| Surface | Status |
|
|
175
|
-
|--------|--------|
|
|
176
|
-
| Default theme name (`neon`) | **Locked** |
|
|
177
|
-
| Token *names* listed in §2 | **Locked** — every theme must define all of them |
|
|
178
|
-
| Adding a new theme preset | Extensible — design-system maintainer review |
|
|
179
|
-
| Renaming an existing theme | **Forbidden** without a migration alias |
|
|
180
|
-
| Per-theme oklch values | Extensible — adjust freely with PR + visual diff |
|
|
181
|
-
|
|
182
|
-
### Governance scripts
|
|
117
|
+
## 5. Validation
|
|
183
118
|
|
|
184
119
|
```bash
|
|
185
120
|
pnpm --filter @nebutra/theme test
|
|
186
|
-
pnpm --filter @nebutra/
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
pnpm --filter nebutra build
|
|
190
|
-
node packages/ops/cli/dist/index.js theme list --format json
|
|
191
|
-
pnpm tsx scripts/validate-ui-governance-policy.ts
|
|
121
|
+
pnpm --filter @nebutra/tokens test
|
|
122
|
+
nebutra theme list
|
|
123
|
+
nebutra theme inspect vanta
|
|
192
124
|
```
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## 7. Open questions / review notes
|
|
197
|
-
|
|
198
|
-
- Per-theme oklch tables are not enumerated here to avoid duplicating `themes.css`. Storybook's Foundation/Themes panel is the canonical visual reference — add it if missing.
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
← back to [root DESIGN.md](../../DESIGN.md) ·
|
|
203
|
-
peer specs: [brand](../brand/DESIGN.md) · [tokens](../tokens/DESIGN.md) · [ui](../ui/DESIGN.md)
|