@djangocfg/ui-core 2.1.363 → 2.1.365

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 CHANGED
@@ -101,10 +101,61 @@ const log = createLogger('MyComponent');
101
101
  log.info('user logged in', { userId: 123 });
102
102
  ```
103
103
 
104
- ## Styles
104
+ ## Styles & Theming
105
105
 
106
106
  ```css
107
- @import '@djangocfg/ui-core/styles/globals.css';
107
+ /* In your app's globals.css — import BEFORE @import "tailwindcss" */
108
+ @import '@djangocfg/ui-nextjs/styles'; /* re-exports ui-core styles */
109
+ ```
110
+
111
+ ### Semantic color tokens
112
+
113
+ All colors are CSS custom properties registered in `@theme` so Tailwind generates utility classes.
114
+ **Never use raw Tailwind color-scale classes** (`amber-500`, `green-100`) in components — use
115
+ semantic tokens that adapt to both light and dark themes automatically.
116
+
117
+ #### Status surfaces — banners and alerts
118
+
119
+ ```tsx
120
+ {/* Warning */}
121
+ <div className="flex gap-2 rounded-md border border-warning-border/40
122
+ bg-warning-background px-3 py-2 text-xs text-warning-foreground">
123
+ <Icon className="text-warning" />
124
+ <span>You're on a preview plan.</span>
125
+ </div>
126
+ ```
127
+
128
+ Each status (`warning` · `success` · `destructive` · `info`) exposes four classes:
129
+
130
+ | Class | Role |
131
+ |---|---|
132
+ | `bg-*-background` | Banner fill |
133
+ | `text-*-foreground` | Readable body text |
134
+ | `border-*-border` | Border ring |
135
+ | `text-*` / `bg-*` | Icon / accent color |
136
+
137
+ #### Code surface
138
+
139
+ `bg-code` · `text-code-foreground` · `border-code-border` — used by PrettyCode, MarkdownMessage code fences.
140
+ `bg-code-inline` · `text-code-inline-foreground` — for inline `<code>` chips.
141
+
142
+ ### Playground
143
+
144
+ ```bash
145
+ pnpm playground # opens component explorer with live theme preview
146
+ ```
147
+
148
+ The **Theme / Tokens** story shows every semantic token in both themes — use it to validate
149
+ changes before syncing CSS to consumers. See `src/styles/README.md` for the full token reference
150
+ and the manual sync workflow for local package development.
151
+
152
+ ### Programmatic colors (Canvas / SVG)
153
+
154
+ ```tsx
155
+ import { useThemePalette, alpha } from '@djangocfg/ui-core/styles/palette';
156
+
157
+ const palette = useThemePalette();
158
+ ctx.fillStyle = alpha(palette.primary, 0.3); // hex → rgba, updates on theme switch
108
159
  ```
109
160
 
110
161
  ## Requirements
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ui-core",
3
- "version": "2.1.363",
3
+ "version": "2.1.365",
4
4
  "description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
5
5
  "keywords": [
6
6
  "ui-components",
@@ -96,7 +96,7 @@
96
96
  "playground": "playground dev"
97
97
  },
98
98
  "peerDependencies": {
99
- "@djangocfg/i18n": "^2.1.363",
99
+ "@djangocfg/i18n": "^2.1.365",
100
100
  "consola": "^3.4.2",
101
101
  "lucide-react": "^0.545.0",
102
102
  "moment": "^2.30.1",
@@ -166,9 +166,9 @@
166
166
  "vaul": "1.1.2"
167
167
  },
168
168
  "devDependencies": {
169
- "@djangocfg/i18n": "^2.1.363",
169
+ "@djangocfg/i18n": "^2.1.365",
170
170
  "@djangocfg/playground": "workspace:*",
171
- "@djangocfg/typescript-config": "^2.1.363",
171
+ "@djangocfg/typescript-config": "^2.1.365",
172
172
  "@types/node": "^24.7.2",
173
173
  "@types/react": "^19.1.0",
174
174
  "@types/react-dom": "^19.1.0",
@@ -6,80 +6,134 @@ This directory contains the CSS architecture for `@djangocfg/ui-core` using **Ta
6
6
 
7
7
  ```
8
8
  styles/
9
- ├── index.css # Main entry point (import order is critical!)
10
- ├── theme.css # Theme imports
11
- ├── base.css # Base element styles
12
- ├── utilities.css # Custom utility classes
13
- ├── sources.css # Source detection for Tailwind v4 monorepo
14
- ├── palette/ # Theme palette hooks & utilities
15
- │ ├── index.ts # Exports
16
- │ ├── types.ts # ThemePalette, StylePresets, BoxColors interfaces
17
- │ ├── useThemePalette.ts # useThemePalette, useStylePresets, useBoxColors, alpha
18
- │ └── utils.ts # hslToHex, hslToRgbString, hslToRgba
9
+ ├── index.css # Main entry point (import order is critical!)
10
+ ├── theme.css # Theme imports
11
+ ├── base.css # Base element styles
12
+ ├── utilities.css # Custom utility classes
13
+ ├── sources.css # Source detection for Tailwind v4 monorepo
14
+ ├── palette/ # Theme palette hooks & utilities
15
+ │ ├── index.ts # Exports
16
+ │ ├── types.ts # ThemePalette, StylePresets, BoxColors interfaces
17
+ │ ├── useThemePalette.ts # useThemePalette, useStylePresets, useBoxColors, alpha
18
+ │ └── utils.ts # hslToHex, hslToRgbString, hslToRgba
19
19
  └── theme/
20
- ├── tokens.css # @theme block with CSS custom properties
21
- ├── light.css # Light theme variables
22
- ├── dark.css # Dark theme variables
23
- └── animations.css # Animation keyframes
20
+ ├── tokens.css # @theme block registers all CSS custom properties as Tailwind utilities
21
+ ├── light.css # :root — light theme HSL values
22
+ ├── dark.css # .dark — dark theme HSL values
23
+ ├── animations.css # Animation keyframes
24
+ └── theme-tokens.story.tsx # Playground story — visual reference for all tokens
24
25
  ```
25
26
 
26
- ## Key Changes in Tailwind v4
27
+ ## Semantic Color Token System
27
28
 
28
- 1. **CSS-First Configuration**: Theme is now defined using CSS custom properties in an `@theme` block instead of JavaScript
29
- 2. **New Import Syntax**: Use `@import "tailwindcss"` instead of `@tailwind` directives
30
- 3. **Simplified PostCSS Setup**: Use `@tailwindcss/postcss` plugin
31
- 4. **Performance Improvements**: 10x faster build times, significantly smaller CSS bundles
32
- 5. **Modern Browser Support**: Optimized for Safari 16.4+, Chrome 111+, Firefox 128+
33
- 6. **Source Detection Required**: Tailwind v4 requires explicit `@source` directives to scan files in monorepo packages
29
+ All colors are defined as HSL CSS custom properties in `light.css` / `dark.css` and
30
+ registered in `tokens.css` so Tailwind generates utility classes.
34
31
 
35
- ## App Setup (globals.css) - CRITICAL!
32
+ **Rule: never use raw Tailwind color-scale classes** (`amber-500`, `green-100`, etc.) in
33
+ components. Always use the semantic token classes — they adapt to both themes automatically.
34
+
35
+ ### Base tokens
36
+
37
+ | Tailwind class | Token | Description |
38
+ |---|---|---|
39
+ | `bg-background` | `--background` | Page background |
40
+ | `bg-foreground` | `--foreground` | Inverted fill (e.g. avatar bg) |
41
+ | `text-foreground` | `--foreground` | Primary body text |
42
+ | `text-muted-foreground` | `--muted-foreground` | Secondary / hint text |
43
+ | `bg-muted` | `--muted` | Subtle surface (inputs, chips) |
44
+ | `bg-card` | `--card` | Card surface |
45
+ | `bg-accent` | `--accent` | Hover surface |
46
+ | `bg-border` / `border-border` | `--border` | Dividers & rings |
47
+ | `bg-primary` / `text-primary` | `--primary` | Brand CTA color |
48
+ | `bg-destructive` / `text-destructive` | `--destructive` | Error / delete |
49
+
50
+ ### Status surface tokens
51
+
52
+ Each status has **4 tokens** for building banners and alerts:
53
+
54
+ | Role | Class | Token |
55
+ |---|---|---|
56
+ | Icon / accent | `text-warning` | `--warning` |
57
+ | Banner background | `bg-warning-background` | `--warning-background` |
58
+ | Readable text | `text-warning-foreground` | `--warning-foreground` |
59
+ | Border ring | `border-warning-border` | `--warning-border` |
60
+
61
+ Available statuses: **`warning`** · **`success`** · **`destructive`** · **`info`**
62
+
63
+ #### Banner pattern
64
+
65
+ ```tsx
66
+ <div className="flex items-center gap-3 rounded-md border border-warning-border/40
67
+ bg-warning-background px-3 py-2 text-xs text-warning-foreground">
68
+ <Icon className="h-4 w-4 text-warning" />
69
+ <span>You're on a preview plan.</span>
70
+ </div>
71
+ ```
72
+
73
+ Change `warning` → `success` / `destructive` / `info` for other states. No raw color classes needed.
74
+
75
+ ### Code surface tokens
76
+
77
+ | Class | Description |
78
+ |---|---|
79
+ | `bg-code` / `text-code-foreground` | Code block panel |
80
+ | `border-code-border` | Code block border |
81
+ | `bg-code-inline` / `text-code-inline-foreground` | Inline `<code>` chips |
82
+
83
+ ### Sidebar tokens
84
+
85
+ `bg-sidebar`, `text-sidebar-foreground`, `bg-sidebar-accent`, `text-sidebar-accent-foreground`,
86
+ `border-sidebar-border` — used by the app sidebar chrome, defined per-theme.
87
+
88
+ ## Playground Story
89
+
90
+ Run `pnpm playground` in the `ui-core` package to open the component explorer.
91
+ The **Theme / Tokens** story (`theme-tokens.story.tsx`) shows a live visual reference of every
92
+ semantic token — base colors, status surfaces, code surface, sidebar tokens, and typography —
93
+ in both light and dark mode. Use it to validate token changes before syncing to consumers.
94
+
95
+ ## App Setup (globals.css) — CRITICAL!
36
96
 
37
97
  When creating a new app that uses UI packages, your `globals.css` MUST follow this pattern:
38
98
 
39
99
  ```css
40
- /**
41
- * CRITICAL: Import order matters for Tailwind CSS v4!
42
- * 1. Theme variables MUST come BEFORE @import "tailwindcss"
43
- * 2. @source directives MUST be added for each package with Tailwind classes
44
- */
45
-
46
100
  /* 1. Import UI package styles FIRST (contains @theme variables) */
47
101
  @import "@djangocfg/ui-nextjs/styles";
48
102
 
49
- /* 2. Import other package styles (layouts, etc.) */
103
+ /* 2. Import other package styles (layouts, tools, etc.) */
50
104
  @import "@djangocfg/layouts/styles";
105
+ @import "@djangocfg/ui-tools/styles";
51
106
 
52
107
  /* 3. Import Tailwind CSS v4 (AFTER theme variables!) */
53
108
  @import "tailwindcss";
54
109
 
55
110
  /* 4. Load plugins */
56
111
  @plugin "tailwindcss-animate";
57
-
58
- /* 5. Source detection for packages NOT included in ui-nextjs/styles */
59
- /* This tells Tailwind where to scan for utility classes */
60
- @source "../../../packages/your-package/src/**/*.{ts,tsx}";
61
112
  ```
62
113
 
63
114
  ### Why @source is Required
64
115
 
65
- In Tailwind v4 monorepo, automatic class detection doesn't work across packages. Each package with Tailwind classes needs:
116
+ In a Tailwind v4 monorepo, automatic class detection doesn't work across packages.
117
+ Each package with Tailwind classes needs either:
66
118
 
67
- 1. **Either** a `@source` directive in the consuming app's `globals.css`
68
- 2. **Or** a `sources.css` file in the package that's imported via the styles entry point
119
+ 1. A `@source` directive in the consuming app's `globals.css`
120
+ 2. Or a `sources.css` file in the package imported via the styles entry point
69
121
 
70
- **Example**: If you have `playground-ui` package with components using `pb-20`, `grid-cols-5`, etc., and these classes don't work:
122
+ ## Syncing Local Packages to Consumer
71
123
 
72
- ```css
73
- /* Add this to your app's globals.css */
74
- @source "../../../packages/playground-ui/src/**/*.{ts,tsx}";
75
- ```
124
+ These packages are consumed via pinned npm versions — edits to `src/` don't automatically
125
+ reach the consumer. After changing theme files, copy them manually:
76
126
 
77
- ### Common Symptoms of Missing @source
127
+ ```bash
128
+ CONSUMER=/path/to/carapis/solution/projects/frontend
129
+ SRC=./src/styles/theme
130
+
131
+ cp "$SRC/light.css" "$CONSUMER/node_modules/@djangocfg/ui-core/src/styles/theme/light.css"
132
+ cp "$SRC/dark.css" "$CONSUMER/node_modules/@djangocfg/ui-core/src/styles/theme/dark.css"
133
+ cp "$SRC/tokens.css" "$CONSUMER/node_modules/@djangocfg/ui-core/src/styles/theme/tokens.css"
134
+ ```
78
135
 
79
- - Tailwind classes don't apply (but inline styles work)
80
- - Grid classes like `grid-cols-3`, `grid-cols-5` don't work
81
- - Spacing classes like `pb-20`, `mt-10` have no effect
82
- - Classes work in some packages but not others
136
+ Then restart the consumer's dev server (Next.js caches module resolution).
83
137
 
84
138
  ## Import Order (Critical!)
85
139
 
@@ -97,121 +151,45 @@ In Tailwind v4 monorepo, automatic class detection doesn't work across packages.
97
151
  @import "./utilities.css";
98
152
  ```
99
153
 
100
- ## Best Practices
154
+ ## Gotchas
101
155
 
102
- ### Spacing & Sizing
156
+ ### Opacity with HSL colors
103
157
 
104
- - Use standard Tailwind classes: `py-16 sm:py-20 md:py-24 lg:py-32`
105
- - Responsive patterns: `px-4 sm:px-6 lg:px-8`
106
- - Container pattern: `container max-w-7xl mx-auto`
107
-
108
- ### Arbitrary Values
109
-
110
- **IMPORTANT**: Arbitrary values like `h-[80px]`, `z-[100]` may NOT work in v4!
158
+ `bg-background/80` does **not** work with HSL tokens in Tailwind v4. Use inline styles:
111
159
 
112
160
  ```tsx
113
- // ❌ May not work in Tailwind v4
114
- <div className="h-[80px] z-[100]">
115
-
116
- // ✅ Define tokens in @theme instead
117
- @theme {
118
- --spacing-80: 20rem;
119
- --z-index-100: 100;
120
- }
121
-
122
- // ✅ Or use inline styles (always reliable)
123
- <div style={{ height: '80px', zIndex: 100 }}>
124
- ```
125
-
126
- ### Opacity with HSL Colors
161
+ // ❌ Broken
162
+ <nav className="bg-background/80">
127
163
 
128
- **CRITICAL**: `bg-background/80` does NOT work with HSL colors in v4!
129
-
130
- ```tsx
131
- // ❌ BROKEN - does not work in Tailwind v4
132
- <nav className="bg-background/80 border-border/30">
133
-
134
- // ✅ WORKING - use inline styles for opacity
135
- <nav
136
- className="sticky top-0 z-100 backdrop-blur-xl"
137
- style={{
138
- backgroundColor: 'hsl(var(--background) / 0.8)',
139
- borderColor: 'hsl(var(--border) / 0.3)'
140
- }}
141
- >
164
+ // Works
165
+ <nav style={{ backgroundColor: 'hsl(var(--background) / 0.8)' }}>
142
166
  ```
143
167
 
144
- ### Fixed Sizes
145
-
146
- ```tsx
147
- // ✅ Inline styles for fixed sizes (always reliable)
148
- <Avatar
149
- className="aspect-square rounded-full overflow-hidden"
150
- style={{ width: '80px', height: '80px' }}
151
- >
152
- <AvatarImage src={avatar} alt="User" />
153
- </Avatar>
154
- ```
168
+ **Exception**: `border-warning-border/40` works because `--color-warning-border` is resolved
169
+ to a full `hsl()` value, making the `/` opacity modifier valid.
155
170
 
156
- ### Spacing Requirements
171
+ ### Arbitrary values
157
172
 
158
- Spacing utilities (`h-20`, `p-4`, etc.) require `--spacing-*` variables defined in `@theme` block:
173
+ Arbitrary values like `h-[80px]`, `z-[100]` may not work in v4. Prefer tokens:
159
174
 
160
175
  ```css
161
176
  @theme {
162
- --spacing: 0.25rem; /* Base unit: 4px */
163
- --spacing-0: 0;
164
- --spacing-1: 0.25rem; /* 4px */
165
- --spacing-2: 0.5rem; /* 8px */
166
- --spacing-4: 1rem; /* 16px */
167
- --spacing-8: 2rem; /* 32px */
168
- --spacing-13: 3.25rem; /* 52px - for min-h-13 */
169
- /* ... */
170
- }
171
- ```
172
-
173
- ### Z-Index Requirements
174
-
175
- Z-index utilities (`z-50`, `z-100`) require `--z-index-*` variables:
176
-
177
- ```css
178
- @theme {
179
- --z-index-50: 50;
177
+ --spacing-80: 20rem;
180
178
  --z-index-100: 100;
181
- --z-index-9999: 9999;
182
179
  }
183
180
  ```
184
181
 
185
- ## Common Patterns
186
-
187
- ### Responsive Design (Mobile-First)
188
-
189
- ```tsx
190
- <div className="px-4 sm:px-6 lg:px-8">
191
- <div className="py-16 sm:py-20 md:py-24 lg:py-32">
192
- Content
193
- </div>
194
- </div>
195
- ```
196
-
197
- ### Breakpoints
198
-
199
- - `sm:` - 640px (40rem)
200
- - `md:` - 768px (48rem)
201
- - `lg:` - 1024px (64rem)
202
- - `xl:` - 1280px (80rem)
203
- - `2xl:` - 1536px (96rem)
182
+ Or use inline styles for one-off fixed sizes.
204
183
 
205
- ### Circles
184
+ ### Spacing & z-index
206
185
 
207
- ```tsx
208
- // Perfect circle
209
- <div className="aspect-square rounded-full overflow-hidden w-10 h-10">
210
- ```
186
+ Spacing utilities (`h-20`, `p-4`) require `--spacing-*` in `@theme`.
187
+ Z-index utilities (`z-50`, `z-100`) require `--z-index-*` in `@theme`.
188
+ Both are already defined in `tokens.css`.
211
189
 
212
190
  ## Theme Palette (Programmatic Color Access)
213
191
 
214
- For Canvas, SVG, Mermaid, and other contexts that don't support CSS variables, use the palette hooks:
192
+ For Canvas, SVG, Mermaid, and other contexts that don't support CSS variables:
215
193
 
216
194
  ```tsx
217
195
  import {
@@ -221,59 +199,13 @@ import {
221
199
  alpha,
222
200
  } from '@djangocfg/ui-core/styles/palette';
223
201
 
224
- // Hex colors from CSS variables (updates on theme switch)
225
202
  const palette = useThemePalette();
226
- ctx.fillStyle = palette.primary; // '#a855f7'
227
- ctx.fillStyle = alpha(palette.primary, 0.3); // 'rgba(168, 85, 247, 0.3)'
203
+ ctx.fillStyle = palette.primary; // '#0989aa'
204
+ ctx.fillStyle = alpha(palette.warning, 0.15); // 'rgba(..., 0.15)'
228
205
 
229
- // Pre-built { fill, stroke, color } for diagrams
230
206
  const presets = useStylePresets();
231
- presets.success // { fill: '#22c55e', stroke: '#22c55e', color: '#fff' }
232
- presets.danger // { fill: '#ef4444', stroke: '#ef4444', color: '#fff' }
207
+ presets.success // { fill: '#...', stroke: '#...', color: '#fff' }
233
208
 
234
- // Semi-transparent backgrounds (adapts opacity to light/dark)
235
209
  const boxes = useBoxColors();
236
- boxes.primary // 'rgba(168, 85, 247, 0.15)' in light, 0.3 in dark
237
- ```
238
-
239
- ### `alpha(hex, opacity)`
240
-
241
- Convert any hex color to `rgba()` — works with any value from `ThemePalette`:
242
-
243
- ```tsx
244
- alpha(palette.primary, 0.3) // 'rgba(168, 85, 247, 0.3)'
245
- alpha(palette.destructive, 0.1) // useful for error backgrounds
246
- ```
247
-
248
- ### Raw HSL Utilities
249
-
250
- ```tsx
251
- import { hslToHex, hslToRgbString, hslToRgba } from '@djangocfg/ui-core/styles/palette';
252
-
253
- hslToHex('265 89% 78%') // '#c084fc'
254
- hslToRgba('265 89% 78%', 0.2) // 'rgba(192, 132, 252, 0.2)'
255
- ```
256
-
257
- ## What to Avoid
258
-
259
- - Custom utilities like: `section-padding`, `animate-*`, `shadow-brand`
260
- - Arbitrary values without checking if they work: `h-[53px]`, `min-h-[100px]`
261
- - Opacity modifiers with HSL colors: `bg-background/80`
262
- - Assuming spacing values exist without defining them in `@theme`
263
-
264
- ## CSS Variables
265
-
266
- Use CSS variables for dynamic values:
267
-
268
- ```tsx
269
- <div style={{ color: 'var(--color-primary)' }}>
270
- ```
271
-
272
- Or in CSS:
273
-
274
- ```css
275
- .my-class {
276
- background-color: hsl(var(--background));
277
- color: hsl(var(--foreground));
278
- }
210
+ boxes.primary // semi-transparent brand, adapts to light/dark
279
211
  ```
@@ -60,6 +60,34 @@
60
60
  --sidebar-border: 0 0% 15%;
61
61
  --sidebar-ring: 189 100% 50%;
62
62
 
63
+ /* ── Status surfaces (dark) ──────────────────────────────────────
64
+ * Dark variants: dim backgrounds (~8-12% lightness) so banners
65
+ * don't blow out against the near-black page. Foreground raised
66
+ * to ~70-80% lightness for contrast. Borders kept muted.
67
+ * ─────────────────────────────────────────────────────────────── */
68
+
69
+ /* Warning — amber */
70
+ --warning: 38 92% 50%;
71
+ --warning-background: 38 80% 10%;
72
+ --warning-foreground: 38 90% 75%;
73
+ --warning-border: 38 60% 30%;
74
+
75
+ /* Success — green */
76
+ --success: 142 60% 45%;
77
+ --success-background: 142 60% 8%;
78
+ --success-foreground: 142 70% 70%;
79
+ --success-border: 142 50% 25%;
80
+
81
+ /* Destructive surface */
82
+ --destructive-background: 0 80% 10%;
83
+ --destructive-border: 0 70% 30%;
84
+
85
+ /* Info — blue-cyan */
86
+ --info: 200 80% 55%;
87
+ --info-background: 200 80% 8%;
88
+ --info-foreground: 200 80% 75%;
89
+ --info-border: 200 60% 25%;
90
+
63
91
  /* Surface gradient dark */
64
92
  --surface-gradient: linear-gradient(to bottom, hsl(var(--background)), hsl(var(--background) / 0.8));
65
93
 
@@ -60,6 +60,35 @@
60
60
  --sidebar-border: 0 0% 90%;
61
61
  --sidebar-ring: 192 90% 35%;
62
62
 
63
+ /* ── Status surfaces ─────────────────────────────────────────────
64
+ * Each status has 4 tokens: icon/accent color, page background,
65
+ * readable foreground text, and border ring.
66
+ * Use bg-warning-background / text-warning-foreground / border-warning-border
67
+ * in components — never raw amber-* or green-* classes.
68
+ * ─────────────────────────────────────────────────────────────── */
69
+
70
+ /* Warning — amber */
71
+ --warning: 38 92% 50%;
72
+ --warning-background: 48 100% 96%;
73
+ --warning-foreground: 26 90% 25%;
74
+ --warning-border: 38 70% 65%;
75
+
76
+ /* Success — green */
77
+ --success: 142 71% 45%;
78
+ --success-background: 138 76% 97%;
79
+ --success-foreground: 140 60% 20%;
80
+ --success-border: 142 60% 65%;
81
+
82
+ /* Destructive surface (separate from the filled button token) */
83
+ --destructive-background: 0 100% 97%;
84
+ --destructive-border: 0 84% 70%;
85
+
86
+ /* Info — blue-cyan (brand-adjacent) */
87
+ --info: 200 90% 40%;
88
+ --info-background: 200 100% 97%;
89
+ --info-foreground: 200 80% 20%;
90
+ --info-border: 200 80% 65%;
91
+
63
92
  /* Surface gradient */
64
93
  --surface-gradient: linear-gradient(to bottom, hsl(var(--background)), hsl(var(--background) / 0.8));
65
94
 
@@ -0,0 +1,157 @@
1
+ import { defineStory } from '@djangocfg/playground';
2
+
3
+ export default defineStory({
4
+ title: 'Theme/Tokens',
5
+ description: 'Visual reference for all semantic CSS color tokens. Use these classes — never raw Tailwind color-scale classes (amber-500 etc).',
6
+ });
7
+
8
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
9
+
10
+ function TokenRow({ label, bg, text, border }: { label: string; bg: string; text: string; border: string }) {
11
+ return (
12
+ <div className={`flex items-center justify-between rounded-md border px-4 py-3 ${bg} ${border}`}>
13
+ <span className={`text-sm font-medium ${text}`}>{label}</span>
14
+ <div className="flex gap-2 font-mono text-xs opacity-70">
15
+ <code className={text}>{bg}</code>
16
+ <code className={text}>{text}</code>
17
+ <code className={text}>{border}</code>
18
+ </div>
19
+ </div>
20
+ );
21
+ }
22
+
23
+ function Section({ title, children }: { title: string; children: React.ReactNode }) {
24
+ return (
25
+ <div className="space-y-2">
26
+ <h3 className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">{title}</h3>
27
+ <div className="space-y-2">{children}</div>
28
+ </div>
29
+ );
30
+ }
31
+
32
+ function SwatchRow({ name, bgClass }: { name: string; bgClass: string }) {
33
+ return (
34
+ <div className="flex items-center gap-3">
35
+ <div className={`h-8 w-16 rounded border border-border ${bgClass}`} />
36
+ <code className="text-xs text-foreground">{name}</code>
37
+ </div>
38
+ );
39
+ }
40
+
41
+ // ─── Stories ──────────────────────────────────────────────────────────────────
42
+
43
+ export const StatusSurfaces = () => (
44
+ <div className="space-y-6 max-w-2xl">
45
+ <p className="text-sm text-muted-foreground">
46
+ Status banners — use <code className="text-xs bg-code text-code-foreground rounded px-1">bg-*-background</code>,{' '}
47
+ <code className="text-xs bg-code text-code-foreground rounded px-1">text-*-foreground</code>,{' '}
48
+ <code className="text-xs bg-code text-code-foreground rounded px-1">border-*-border</code>
49
+ </p>
50
+
51
+ <Section title="Warning">
52
+ <TokenRow
53
+ label="⚠ You're seeing a preview. Subscribe for full access."
54
+ bg="bg-warning-background"
55
+ text="text-warning-foreground"
56
+ border="border border-warning-border/50"
57
+ />
58
+ </Section>
59
+
60
+ <Section title="Success">
61
+ <TokenRow
62
+ label="✓ Operation completed successfully."
63
+ bg="bg-success-background"
64
+ text="text-success-foreground"
65
+ border="border border-success-border/50"
66
+ />
67
+ </Section>
68
+
69
+ <Section title="Destructive">
70
+ <TokenRow
71
+ label="✕ Something went wrong. Please try again."
72
+ bg="bg-destructive-background"
73
+ text="text-destructive"
74
+ border="border border-destructive-border/50"
75
+ />
76
+ </Section>
77
+
78
+ <Section title="Info">
79
+ <TokenRow
80
+ label="ℹ New features are available in your plan."
81
+ bg="bg-info-background"
82
+ text="text-info-foreground"
83
+ border="border border-info-border/50"
84
+ />
85
+ </Section>
86
+ </div>
87
+ );
88
+
89
+ export const BaseColors = () => (
90
+ <div className="space-y-6 max-w-xl">
91
+ <Section title="Base">
92
+ <div className="grid grid-cols-2 gap-3">
93
+ <SwatchRow name="bg-background" bgClass="bg-background" />
94
+ <SwatchRow name="bg-foreground" bgClass="bg-foreground" />
95
+ <SwatchRow name="bg-card" bgClass="bg-card" />
96
+ <SwatchRow name="bg-muted" bgClass="bg-muted" />
97
+ <SwatchRow name="bg-accent" bgClass="bg-accent" />
98
+ <SwatchRow name="bg-border" bgClass="bg-border" />
99
+ </div>
100
+ </Section>
101
+
102
+ <Section title="Brand">
103
+ <div className="grid grid-cols-2 gap-3">
104
+ <SwatchRow name="bg-primary" bgClass="bg-primary" />
105
+ <SwatchRow name="bg-secondary" bgClass="bg-secondary" />
106
+ </div>
107
+ </Section>
108
+
109
+ <Section title="Status accents (icon color)">
110
+ <div className="grid grid-cols-2 gap-3">
111
+ <SwatchRow name="bg-warning" bgClass="bg-warning" />
112
+ <SwatchRow name="bg-success" bgClass="bg-success" />
113
+ <SwatchRow name="bg-destructive" bgClass="bg-destructive" />
114
+ <SwatchRow name="bg-info" bgClass="bg-info" />
115
+ </div>
116
+ </Section>
117
+ </div>
118
+ );
119
+
120
+ export const CodeSurface = () => (
121
+ <div className="space-y-4 max-w-xl">
122
+ <Section title="Code tokens">
123
+ <div className="rounded-md border border-code-border bg-code text-code-foreground p-4 font-mono text-sm">
124
+ <div>bg-code / text-code-foreground / border-code-border</div>
125
+ <div className="mt-2 text-xs opacity-60">Used by PrettyCode, MarkdownMessage code fences</div>
126
+ </div>
127
+ <div className="text-sm">
128
+ Inline:{' '}
129
+ <code className="rounded bg-code-inline px-1.5 py-0.5 text-code-inline-foreground text-xs">
130
+ const x = 42
131
+ </code>
132
+ </div>
133
+ </Section>
134
+
135
+ <Section title="Sidebar tokens">
136
+ <div className="rounded-md border border-sidebar-border bg-sidebar p-4 space-y-1 text-sidebar-foreground text-sm">
137
+ <div className="font-semibold">bg-sidebar / text-sidebar-foreground</div>
138
+ <div className="text-xs opacity-60">Used by the app sidebar chrome</div>
139
+ <div className="mt-2 rounded bg-sidebar-accent px-2 py-1 text-sidebar-accent-foreground text-xs">
140
+ bg-sidebar-accent — hover state
141
+ </div>
142
+ </div>
143
+ </Section>
144
+ </div>
145
+ );
146
+
147
+ export const TypographyTokens = () => (
148
+ <div className="space-y-3 max-w-md">
149
+ <p className="text-foreground text-sm font-medium">text-foreground — primary body</p>
150
+ <p className="text-muted-foreground text-sm">text-muted-foreground — secondary / hints</p>
151
+ <p className="text-primary text-sm">text-primary — brand links / accents</p>
152
+ <p className="text-destructive text-sm">text-destructive — error messages</p>
153
+ <p className="text-warning text-sm">text-warning — warning labels</p>
154
+ <p className="text-success text-sm">text-success — success labels</p>
155
+ <p className="text-info text-sm">text-info — info labels</p>
156
+ </div>
157
+ );
@@ -35,7 +35,24 @@
35
35
  --color-ring: hsl(var(--ring));
36
36
  --color-black: #000000;
37
37
  --color-white: #ffffff;
38
+ /* Status surfaces — warning / success / destructive / info */
38
39
  --color-warning: hsl(var(--warning));
40
+ --color-warning-background: hsl(var(--warning-background));
41
+ --color-warning-foreground: hsl(var(--warning-foreground));
42
+ --color-warning-border: hsl(var(--warning-border));
43
+
44
+ --color-success: hsl(var(--success));
45
+ --color-success-background: hsl(var(--success-background));
46
+ --color-success-foreground: hsl(var(--success-foreground));
47
+ --color-success-border: hsl(var(--success-border));
48
+
49
+ --color-destructive-background: hsl(var(--destructive-background));
50
+ --color-destructive-border: hsl(var(--destructive-border));
51
+
52
+ --color-info: hsl(var(--info));
53
+ --color-info-background: hsl(var(--info-background));
54
+ --color-info-foreground: hsl(var(--info-foreground));
55
+ --color-info-border: hsl(var(--info-border));
39
56
 
40
57
  /* Code surface tokens — single source of truth for any "this is
41
58
  * code, not prose" panel (markdown fences, inline code, terminal