@nebutra/theme 0.1.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 +177 -0
- package/.turbo/turbo-test.log +14 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/AGENTS.md +41 -0
- package/DESIGN.md +203 -0
- package/LICENSE +676 -0
- package/README.md +46 -0
- package/package.json +46 -0
- package/src/__tests__/theme-registry.test.ts +49 -0
- package/src/index.ts +20 -0
- package/src/registry.json +199 -0
- package/src/registry.ts +56 -0
- package/themes.css +386 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
|
|
2
|
+
> @nebutra/theme@0.1.0 prebuild /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/design/theme
|
|
3
|
+
> corepack pnpm --filter @nebutra/design-tokens build
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
> @nebutra/design-tokens@0.1.0 build /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/design/design-tokens
|
|
7
|
+
> node style-dictionary.config.mjs
|
|
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
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
> @nebutra/theme@0.1.0 test /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/design/theme
|
|
3
|
+
> vitest run
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.4 [39m[90m/home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/design/theme[39m
|
|
7
|
+
|
|
8
|
+
[32m✓[39m src/__tests__/theme-registry.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 87[2mms[22m[39m
|
|
9
|
+
|
|
10
|
+
[2m Test Files [22m [1m[32m1 passed[39m[22m[90m (1)[39m
|
|
11
|
+
[2m Tests [22m [1m[32m4 passed[39m[22m[90m (4)[39m
|
|
12
|
+
[2m Start at [22m 16:50:59
|
|
13
|
+
[2m Duration [22m 1.40s[2m (transform 329ms, setup 0ms, import 481ms, tests 87ms, environment 0ms)[22m
|
|
14
|
+
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# AGENTS.md — packages/theme
|
|
2
|
+
|
|
3
|
+
Execution contract for Nebutra's multi-theme preset package.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
Applies to everything under `packages/design/theme/`.
|
|
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`
|
|
16
|
+
|
|
17
|
+
## Contract Boundaries
|
|
18
|
+
|
|
19
|
+
- Treat `themes.css` as the canonical source for theme-specific CSS behavior.
|
|
20
|
+
Do not duplicate theme selector logic in apps.
|
|
21
|
+
- Keep `THEME_IDS` in `src/index.ts` aligned with the `[data-theme]` selectors
|
|
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.
|
|
29
|
+
|
|
30
|
+
## Generated And Derived Files
|
|
31
|
+
|
|
32
|
+
- `tsconfig.tsbuildinfo` and similar compiler artifacts are derived files.
|
|
33
|
+
- Treat consumer app theme state and compiled CSS output as derived from
|
|
34
|
+
`themes.css` and `src/index.ts`.
|
|
35
|
+
|
|
36
|
+
## Validation
|
|
37
|
+
|
|
38
|
+
- Theme surface or type changes:
|
|
39
|
+
`pnpm --filter @nebutra/theme typecheck`
|
|
40
|
+
- When selector changes matter, verify a consumer imports `@nebutra/theme/themes.css`
|
|
41
|
+
instead of patching compiled output.
|
package/DESIGN.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# `@nebutra/theme` — Design Spec
|
|
2
|
+
|
|
3
|
+
> Multi-theme engine of the Nebutra-Sailor design system.
|
|
4
|
+
> Part of the [root DESIGN.md](../../DESIGN.md). Spec format: `design-md@2026.05`.
|
|
5
|
+
|
|
6
|
+
| Field | Value |
|
|
7
|
+
|------|------|
|
|
8
|
+
| Package | `@nebutra/theme` |
|
|
9
|
+
| Status | Stable — 6 themes shipped, more allowed via governance |
|
|
10
|
+
| Source files | `packages/design/theme/src/registry.json` and generated `packages/design/theme/themes.css` |
|
|
11
|
+
| Activation | `[data-theme="…"]` attribute on `<html>` |
|
|
12
|
+
| Default theme | `neon` (no `data-theme` attribute) |
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Identity
|
|
17
|
+
|
|
18
|
+
A **product feature**: the SaaS preset system (`@nebutra/preset`) lets end customers and self-hosters choose a theme that matches their product mood. Switching is CSS-only (no JS rebuild) — token values are overridden per `[data-theme]` selector.
|
|
19
|
+
|
|
20
|
+
**Boundary**: this package is for the multi-theme product feature. For light/dark of the *base* `neon` look, use `class="dark"` from `next-themes`. The two systems compose.
|
|
21
|
+
|
|
22
|
+
The theme catalogue is governed through `src/registry.json`. Consumers must import from
|
|
23
|
+
`@nebutra/theme/registry` instead of copying theme names. The Style Dictionary pipeline,
|
|
24
|
+
`@nebutra/preset`, CLI commands, docs, and future Figma/playground publishing all use this registry.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Tokens (per theme)
|
|
29
|
+
|
|
30
|
+
Each preset overrides the same set of tokens; only values differ. The base set:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Brand: --color-primary, --color-secondary, --color-accent (+ -foreground each)
|
|
34
|
+
Surfaces: --color-background, --color-foreground, --color-card, --color-popover, --color-muted, --color-border, --color-input, --color-ring
|
|
35
|
+
Status: --color-destructive, --color-success, --color-warning, --color-info (+ -foreground each)
|
|
36
|
+
Derived: --color-primary-hover, --color-primary-active (via color-mix in oklch)
|
|
37
|
+
Radius: --radius-{sm,md,lg,xl,full}
|
|
38
|
+
Typography: --font-sans, --font-mono, --font-heading
|
|
39
|
+
Shadows: --shadow-{sm,md,lg,xl}
|
|
40
|
+
Transitions: --transition-{fast,normal,slow}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
All color values are **oklch** for perceptual uniformity. Hover/active states are derived via `color-mix(in oklch, …)` — no JS.
|
|
44
|
+
|
|
45
|
+
### 2.1 Theme catalogue
|
|
46
|
+
|
|
47
|
+
| `data-theme` | Mood | Background | Primary | Use case |
|
|
48
|
+
|------|------|-----------|---------|----------|
|
|
49
|
+
| `neon` *(default)* | Vibrant dark, electric blue | `oklch(0.141 0.005 285.9)` ≈ #09090b | `oklch(0.452 0.313 264.1)` ≈ vivid blue | AI SaaS dashboards |
|
|
50
|
+
| `gradient` | Soft light, blue spectrum | `oklch(1 0 0)` (white) | `oklch(0.546 0.245 262.9)` | Marketing / growth |
|
|
51
|
+
| `dark-dense` | High-density dark | near-black | desaturated blue | Pro tools, terminals |
|
|
52
|
+
| `minimal` | Neutral, low chroma | white / off-white | low-chroma blue | Document apps |
|
|
53
|
+
| `vibrant` | Saturated multicolor | white | vivid magenta-blue | Creator / consumer |
|
|
54
|
+
| `ocean` | Cool teal/blue | white | teal | B2B finance, infra |
|
|
55
|
+
|
|
56
|
+
> Exact oklch tuples for every theme are in `packages/design/theme/themes.css`. Designer-readable per-theme tables are deferred to Storybook (Foundation/Themes) — adding them here would duplicate the source of truth.
|
|
57
|
+
|
|
58
|
+
### 2.2 Default (neon) — illustrative
|
|
59
|
+
|
|
60
|
+
```css
|
|
61
|
+
@theme {
|
|
62
|
+
--color-primary: oklch(0.452 0.313 264.1);
|
|
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
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 3. Patterns
|
|
86
|
+
|
|
87
|
+
### 3.1 Wiring up a Next.js app
|
|
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 */
|
|
94
|
+
|
|
95
|
+
// apps/{app}/src/app/layout.tsx
|
|
96
|
+
import { ThemeProvider } from "@nebutra/tokens";
|
|
97
|
+
|
|
98
|
+
<ThemeProvider attribute="data-theme" defaultTheme="neon" themes={["neon","gradient","dark-dense","minimal","vibrant","ocean"]}>
|
|
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
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 3.3 Adding a new theme
|
|
125
|
+
|
|
126
|
+
1. Add the DTCG file under `packages/design/design-tokens/tokens/themes/my-theme.json`.
|
|
127
|
+
2. Add the registry entry to `packages/design/theme/src/registry.json`.
|
|
128
|
+
3. Provide every token defined in §2.
|
|
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
|
+
---
|
|
135
|
+
|
|
136
|
+
## 4. Imports & Conventions
|
|
137
|
+
|
|
138
|
+
```css
|
|
139
|
+
@import "@nebutra/theme/themes.css";
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Themes are CSS at runtime, but their catalogue metadata is exported from `@nebutra/theme/registry`.
|
|
143
|
+
Theme names are registry-derived; do not introduce new handwritten enums.
|
|
144
|
+
|
|
145
|
+
### Forbidden
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
// ❌ Hardcoding theme-specific colors in components
|
|
149
|
+
<div className="bg-[#7C3AED]" />
|
|
150
|
+
|
|
151
|
+
// ❌ Skipping a token override when defining a new theme
|
|
152
|
+
[data-theme="my-theme"] { --color-primary: oklch(…); /* missing background, etc. */ }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 5. Theming (composition with light/dark)
|
|
158
|
+
|
|
159
|
+
Light/dark and multi-theme are **orthogonal**:
|
|
160
|
+
|
|
161
|
+
| `class` (next-themes) | `data-theme` (preset) | Result |
|
|
162
|
+
|-----------------------|----------------------|--------|
|
|
163
|
+
| (none) | (none) | base tokens from `@nebutra/tokens`, light |
|
|
164
|
+
| `dark` | (none) | base tokens, dark variant |
|
|
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.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 6. Versioning & Governance
|
|
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
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
pnpm --filter @nebutra/theme test
|
|
186
|
+
pnpm --filter @nebutra/theme typecheck
|
|
187
|
+
pnpm --filter @nebutra/design-tokens build
|
|
188
|
+
pnpm --filter @nebutra/preset test
|
|
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
|
|
192
|
+
```
|
|
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)
|