@soybeanjs/shadcn-theme 0.0.11 → 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/README.en_US.md +305 -122
- package/README.md +315 -124
- package/dist/index.d.ts +102 -78
- package/dist/index.js +1 -1
- package/package.json +26 -25
package/README.en_US.md
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
# @soybeanjs/shadcn-theme
|
|
2
2
|
|
|
3
|
-
A powerful and flexible shadcn/ui theme generator with
|
|
3
|
+
A powerful and flexible shadcn/ui theme CSS variables generator with preset color schemes, light/dark output, and optional custom preset extension.
|
|
4
4
|
|
|
5
5
|
[中文 README](README.md)
|
|
6
6
|
|
|
7
7
|
## ✨ Features
|
|
8
8
|
|
|
9
|
-
- 🎨 **Rich Preset Themes** -
|
|
10
|
-
- 🌗 **Light/Dark
|
|
11
|
-
- 🎯 **Flexible Color
|
|
12
|
-
- 🔧 **
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- 🌈 **Color Palette Generation** - Automatically generates gradient palettes (50-950) for primary colors
|
|
9
|
+
- 🎨 **Rich Preset Themes** - Built-in base / primary / feedback preset combinations
|
|
10
|
+
- 🌗 **Light/Dark Output** - Supports `.dark` / `@media (prefers-color-scheme: dark)` / custom selector
|
|
11
|
+
- 🎯 **Flexible Color Formats** - Supports `hsl` and `oklch` output
|
|
12
|
+
- 🔧 **Extensible** - Add custom colors via `preset` (including sidebar / chart fields)
|
|
13
|
+
- 🌈 **Palette Variables** - Generates 50-950 palette vars for primary/destructive/success/warning/info/carbon
|
|
14
|
+
- 📦 **Lightweight Dependency** - Only depends on `@soybeanjs/colord`
|
|
15
|
+
- 🧩 **Pure Generator** - Returns CSS strings only; does not automatically mutate the DOM
|
|
17
16
|
|
|
18
17
|
## 📦 Installation
|
|
19
18
|
|
|
@@ -28,97 +27,238 @@ pnpm add @soybeanjs/shadcn-theme
|
|
|
28
27
|
```typescript
|
|
29
28
|
import { createShadcnTheme } from '@soybeanjs/shadcn-theme';
|
|
30
29
|
|
|
31
|
-
// Use default presets (
|
|
32
|
-
createShadcnTheme();
|
|
30
|
+
// Use default presets (gray + indigo + classic + extended)
|
|
31
|
+
const theme = createShadcnTheme();
|
|
32
|
+
const css = theme.getCss();
|
|
33
33
|
|
|
34
34
|
// Custom preset combination
|
|
35
|
-
createShadcnTheme({
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
format: 'hsl' // Color format: 'hsl' | 'oklch'
|
|
35
|
+
const custom = createShadcnTheme({
|
|
36
|
+
base: 'zinc',
|
|
37
|
+
primary: 'blue',
|
|
38
|
+
feedback: 'vivid',
|
|
39
|
+
sidebar: 'extended',
|
|
40
|
+
radius: '0.5rem',
|
|
41
|
+
darkSelector: 'class',
|
|
42
|
+
format: 'hsl'
|
|
44
43
|
});
|
|
44
|
+
|
|
45
|
+
const customCss = custom.getCss();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### (Optional) Inject into the DOM
|
|
49
|
+
|
|
50
|
+
This library generates CSS strings. If you want runtime theme switching, you can inject the result yourself:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { createShadcnTheme } from '@soybeanjs/shadcn-theme';
|
|
54
|
+
|
|
55
|
+
const theme = createShadcnTheme({ primary: 'indigo' });
|
|
56
|
+
|
|
57
|
+
function applyTheme(cssText: string, styleId = 'SHADCN_THEME_STYLE') {
|
|
58
|
+
const el = document.getElementById(styleId) ?? document.createElement('style');
|
|
59
|
+
el.id = styleId;
|
|
60
|
+
el.textContent = cssText;
|
|
61
|
+
document.head.appendChild(el);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
applyTheme(theme.getCss());
|
|
65
|
+
applyTheme(theme.getCss({ primary: 'emerald' }));
|
|
45
66
|
```
|
|
46
67
|
|
|
47
|
-
### Custom
|
|
68
|
+
### Custom Preset
|
|
69
|
+
|
|
70
|
+
Using the `preset` parameter, you can provide a complete custom color configuration that overrides the built-in base/primary/feedback/sidebar presets. When using a custom preset, you need to provide complete color definitions.
|
|
71
|
+
|
|
72
|
+
#### 1) When to use custom preset
|
|
73
|
+
|
|
74
|
+
- Use `preset` to provide a complete custom color configuration when built-in preset combinations cannot meet your design requirements.
|
|
75
|
+
- When using a custom preset, all base/primary/feedback/sidebar related parameters will be ignored, only the `preset` configuration is used.
|
|
76
|
+
|
|
77
|
+
#### 2) Color values and `format`
|
|
78
|
+
|
|
79
|
+
- Each color value supports: Tailwind palette reference (e.g. `slate.500`), `hsl(...)`, `oklch(...)`, or the builtin permitted color names (`inherit`, `currentColor`, `transparent`, `black`, `white`).
|
|
80
|
+
- `format: 'hsl'`: outputs `h s l [/ alpha]` (no outer `hsl(...)`); `oklch(...)` inputs are converted to HSL.
|
|
81
|
+
- `format: 'oklch'`: outputs values with the outer `oklch(...)`; `hsl(...)` inputs are converted to OKLCH.
|
|
82
|
+
|
|
83
|
+
#### Quick example: Complete custom preset
|
|
48
84
|
|
|
49
85
|
```typescript
|
|
50
|
-
createShadcnTheme({
|
|
51
|
-
|
|
86
|
+
const theme = createShadcnTheme({
|
|
87
|
+
preset: {
|
|
52
88
|
light: {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
89
|
+
// Base colors
|
|
90
|
+
background: 'white',
|
|
91
|
+
foreground: 'slate.950',
|
|
92
|
+
card: 'white',
|
|
93
|
+
cardForeground: 'slate.950',
|
|
94
|
+
popover: 'white',
|
|
95
|
+
popoverForeground: 'slate.950',
|
|
96
|
+
primaryForeground: 'slate.50',
|
|
97
|
+
secondary: 'slate.100',
|
|
98
|
+
secondaryForeground: 'slate.900',
|
|
99
|
+
muted: 'slate.100',
|
|
100
|
+
mutedForeground: 'slate.500',
|
|
101
|
+
accent: 'slate.100',
|
|
102
|
+
accentForeground: 'slate.900',
|
|
103
|
+
destructiveForeground: 'slate.50',
|
|
104
|
+
successForeground: 'slate.50',
|
|
105
|
+
warningForeground: 'slate.50',
|
|
106
|
+
infoForeground: 'slate.50',
|
|
107
|
+
carbon: 'slate.800',
|
|
108
|
+
carbonForeground: 'slate.50',
|
|
109
|
+
border: 'slate.200',
|
|
110
|
+
input: 'slate.200',
|
|
111
|
+
// Theme colors
|
|
112
|
+
primary: 'blue.600',
|
|
113
|
+
destructive: 'red.500',
|
|
114
|
+
success: 'green.500',
|
|
115
|
+
warning: 'amber.500',
|
|
116
|
+
info: 'blue.500',
|
|
117
|
+
ring: 'blue.400',
|
|
118
|
+
// Chart colors
|
|
119
|
+
chart1: 'orange.600',
|
|
120
|
+
chart2: 'teal.600',
|
|
121
|
+
chart3: 'cyan.900',
|
|
122
|
+
chart4: 'amber.400',
|
|
123
|
+
chart5: 'amber.500',
|
|
124
|
+
// Sidebar colors
|
|
125
|
+
sidebar: 'slate.50',
|
|
126
|
+
sidebarForeground: 'slate.900',
|
|
127
|
+
sidebarPrimary: 'blue.600',
|
|
128
|
+
sidebarPrimaryForeground: 'slate.50',
|
|
129
|
+
sidebarAccent: 'slate.100',
|
|
130
|
+
sidebarAccentForeground: 'slate.900',
|
|
131
|
+
sidebarBorder: 'slate.200',
|
|
132
|
+
sidebarRing: 'blue.400'
|
|
58
133
|
},
|
|
59
134
|
dark: {
|
|
60
|
-
//
|
|
61
|
-
background: '
|
|
62
|
-
foreground: '
|
|
63
|
-
|
|
135
|
+
// Base colors
|
|
136
|
+
background: 'slate.950',
|
|
137
|
+
foreground: 'slate.50',
|
|
138
|
+
card: 'slate.900',
|
|
139
|
+
cardForeground: 'slate.50',
|
|
140
|
+
popover: 'slate.900',
|
|
141
|
+
popoverForeground: 'slate.50',
|
|
142
|
+
primaryForeground: 'slate.900',
|
|
143
|
+
secondary: 'slate.800',
|
|
144
|
+
secondaryForeground: 'slate.50',
|
|
145
|
+
muted: 'slate.800',
|
|
146
|
+
mutedForeground: 'slate.400',
|
|
147
|
+
accent: 'slate.800',
|
|
148
|
+
accentForeground: 'slate.50',
|
|
149
|
+
destructiveForeground: 'slate.900',
|
|
150
|
+
successForeground: 'slate.900',
|
|
151
|
+
warningForeground: 'slate.900',
|
|
152
|
+
infoForeground: 'slate.900',
|
|
153
|
+
carbon: 'slate.100',
|
|
154
|
+
carbonForeground: 'slate.900',
|
|
155
|
+
border: 'oklch(100% 0 0 / 0.1)',
|
|
156
|
+
input: 'oklch(100% 0 0 / 0.15)',
|
|
157
|
+
// Theme colors
|
|
158
|
+
primary: 'blue.400',
|
|
159
|
+
destructive: 'red.400',
|
|
160
|
+
success: 'green.400',
|
|
161
|
+
warning: 'amber.400',
|
|
162
|
+
info: 'blue.400',
|
|
163
|
+
ring: 'blue.500',
|
|
164
|
+
// Chart colors
|
|
165
|
+
chart1: 'orange.500',
|
|
166
|
+
chart2: 'teal.500',
|
|
167
|
+
chart3: 'cyan.400',
|
|
168
|
+
chart4: 'amber.500',
|
|
169
|
+
chart5: 'amber.600',
|
|
170
|
+
// Sidebar colors
|
|
171
|
+
sidebar: 'slate.950',
|
|
172
|
+
sidebarForeground: 'slate.50',
|
|
173
|
+
sidebarPrimary: 'blue.400',
|
|
174
|
+
sidebarPrimaryForeground: 'slate.950',
|
|
175
|
+
sidebarAccent: 'slate.900',
|
|
176
|
+
sidebarAccentForeground: 'slate.50',
|
|
177
|
+
sidebarBorder: 'slate.800',
|
|
178
|
+
sidebarRing: 'blue.500'
|
|
64
179
|
}
|
|
65
180
|
}
|
|
66
181
|
});
|
|
182
|
+
|
|
183
|
+
const css = theme.getCss();
|
|
67
184
|
```
|
|
68
185
|
|
|
186
|
+
#### Notes
|
|
187
|
+
|
|
188
|
+
- When providing the `preset` parameter, the `base`, `primary`, `feedback`, and `sidebar` parameters will be ignored.
|
|
189
|
+
- The preset must include complete color definitions for both `light` and `dark` modes.
|
|
190
|
+
- It is recommended to start from the structure of built-in presets and modify according to your design needs.
|
|
191
|
+
|
|
69
192
|
## 📖 API Documentation
|
|
70
193
|
|
|
71
194
|
### `createShadcnTheme(options?: ThemeOptions)`
|
|
72
195
|
|
|
73
|
-
Main function to create
|
|
196
|
+
Main function to create a theme CSS generator.
|
|
197
|
+
|
|
198
|
+
Return value:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
const theme = createShadcnTheme();
|
|
202
|
+
|
|
203
|
+
theme.getCss(config?: PresetConfig, radius?: string): string
|
|
204
|
+
theme.getColorCss(config: PresetConfig): string
|
|
205
|
+
theme.getRadiusCss(radius?: string): string
|
|
206
|
+
```
|
|
74
207
|
|
|
75
208
|
#### ThemeOptions
|
|
76
209
|
|
|
77
|
-
| Parameter
|
|
78
|
-
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
210
|
+
| Parameter | Type | Default | Description |
|
|
211
|
+
| -------------- | ------------------------------ | ------------ | --------------------------------------------------------------------------------------- |
|
|
212
|
+
| `base` | `BuiltinBasePresetKey` | `'neutral'` | Base preset key |
|
|
213
|
+
| `primary` | `BuiltinPrimaryPresetKey` | `'indigo'` | Primary preset key |
|
|
214
|
+
| `feedback` | `BuiltinFeedbackPresetKey` | `'classic'` | Feedback preset key |
|
|
215
|
+
| `sidebar` | `'extended'` | `'extended'` | Sidebar mode; `extended` derives from base/primary |
|
|
216
|
+
| `preset` | `ThemeColorPresetItem` | - | Complete custom color preset (when provided, base/primary/feedback/sidebar are ignored) |
|
|
217
|
+
| `radius` | `string` | `'0.625rem'` | Global border radius |
|
|
218
|
+
| `styleTarget` | `'html' \| ':root'` | `':root'` | CSS variables mount selector |
|
|
219
|
+
| `darkSelector` | `'class' \| 'media' \| string` | `'class'` | Dark mode selector (custom string supported) |
|
|
220
|
+
| `format` | `'hsl' \| 'oklch'` | `'hsl'` | Output color format |
|
|
86
221
|
|
|
87
222
|
### Preset Configuration (PresetConfig)
|
|
88
223
|
|
|
89
224
|
```typescript
|
|
90
225
|
interface PresetConfig {
|
|
91
|
-
base?:
|
|
92
|
-
|
|
93
|
-
feedback?:
|
|
226
|
+
base?: BuiltinBasePresetKey | 'custom';
|
|
227
|
+
primary?: BuiltinPrimaryPresetKey | 'custom';
|
|
228
|
+
feedback?: BuiltinFeedbackPresetKey | 'custom';
|
|
229
|
+
sidebar?: 'extended' | 'custom';
|
|
230
|
+
preset?: ThemeColorPresetItem;
|
|
94
231
|
}
|
|
95
232
|
```
|
|
96
233
|
|
|
234
|
+
When using the `preset` parameter, other configuration parameters (base/primary/feedback/sidebar) will be ignored.
|
|
235
|
+
|
|
97
236
|
#### Feedback Palette Key (FeedbackPaletteKey)
|
|
98
237
|
|
|
99
|
-
| Style
|
|
100
|
-
|
|
101
|
-
| `classic`
|
|
102
|
-
| `vivid`
|
|
103
|
-
| `subtle`
|
|
104
|
-
| `warm`
|
|
105
|
-
| `cool`
|
|
106
|
-
| `nature`
|
|
107
|
-
| `modern`
|
|
108
|
-
| `vibrant`
|
|
109
|
-
| `professional` | Business Professional | Stable and dignified, suitable for enterprise applications and B2B products
|
|
110
|
-
| `soft`
|
|
111
|
-
| `bold`
|
|
112
|
-
| `calm`
|
|
113
|
-
| `candy`
|
|
114
|
-
| `deep`
|
|
115
|
-
| `light`
|
|
238
|
+
| Style | Description | Use Cases |
|
|
239
|
+
| -------------- | --------------------- | ------------------------------------------------------------------------------- |
|
|
240
|
+
| `classic` | Classic Standard | Most common combination, suitable for most scenarios |
|
|
241
|
+
| `vivid` | Vivid & Energetic | High saturation, suitable for youth-oriented products and creative applications |
|
|
242
|
+
| `subtle` | Soft & Elegant | Low contrast, suitable for premium brands and elegant interfaces |
|
|
243
|
+
| `warm` | Warm & Welcoming | Warm color tones, creates a friendly and warm atmosphere |
|
|
244
|
+
| `cool` | Cool & Professional | Cool color tones, suitable for tech and professional applications |
|
|
245
|
+
| `nature` | Natural & Fresh | Natural colors, suitable for eco-friendly and health products |
|
|
246
|
+
| `modern` | Modern & Minimalist | Strong modern feel, suitable for tech products and SaaS applications |
|
|
247
|
+
| `vibrant` | Vibrant & Dynamic | High-energy colors, suitable for sports and gaming applications |
|
|
248
|
+
| `professional` | Business Professional | Stable and dignified, suitable for enterprise applications and B2B products |
|
|
249
|
+
| `soft` | Dreamy & Soft | Soft tones, suitable for design tools and creative platforms |
|
|
250
|
+
| `bold` | Bold & Eye-catching | High contrast, suitable for scenarios requiring strong visual impact |
|
|
251
|
+
| `calm` | Calm & Soothing | Low saturation, suitable for long-term use applications |
|
|
252
|
+
| `candy` | Candy Colors | Bright and cute, suitable for children's products and fun applications |
|
|
253
|
+
| `deep` | Deep & Mysterious | Deep tones, suitable for dark themes and mysterious styles |
|
|
254
|
+
| `light` | Fresh & Light | Light tones, suitable for clean and refreshing interfaces |
|
|
116
255
|
|
|
117
256
|
### Theme Color Configuration (ThemeColors)
|
|
118
257
|
|
|
119
258
|
Supports configuration of the following color variables:
|
|
120
259
|
|
|
121
260
|
#### Base Colors
|
|
261
|
+
|
|
122
262
|
- `background` - Background color
|
|
123
263
|
- `foreground` - Foreground color (text)
|
|
124
264
|
- `card` - Card background
|
|
@@ -140,12 +280,14 @@ Supports configuration of the following color variables:
|
|
|
140
280
|
- `ring` - Focus ring color
|
|
141
281
|
|
|
142
282
|
#### Extended Colors
|
|
283
|
+
|
|
143
284
|
- `success` / `successForeground` - Success state
|
|
144
285
|
- `warning` / `warningForeground` - Warning state
|
|
145
286
|
- `info` / `infoForeground` - Info state
|
|
146
287
|
- `carbon` / `carbonForeground` - Carbon color (additional dark scheme)
|
|
147
288
|
|
|
148
289
|
#### Sidebar Colors
|
|
290
|
+
|
|
149
291
|
- `sidebar` - Sidebar background
|
|
150
292
|
- `sidebarForeground` - Sidebar foreground
|
|
151
293
|
- `sidebarPrimary` - Sidebar primary color
|
|
@@ -156,6 +298,7 @@ Supports configuration of the following color variables:
|
|
|
156
298
|
- `sidebarRing` - Sidebar focus ring
|
|
157
299
|
|
|
158
300
|
#### Chart Colors
|
|
301
|
+
|
|
159
302
|
- `chart1` ~ `chart5` - Chart colors
|
|
160
303
|
|
|
161
304
|
### Color Value Format (ColorValue)
|
|
@@ -163,22 +306,25 @@ Supports configuration of the following color variables:
|
|
|
163
306
|
Supports three color value formats:
|
|
164
307
|
|
|
165
308
|
1. **HSL Format**
|
|
309
|
+
|
|
166
310
|
```typescript
|
|
167
|
-
'hsl(0 0% 100%)'
|
|
168
|
-
'hsl(0 0% 100% / 0.5)' // with opacity
|
|
311
|
+
'hsl(0 0% 100%)';
|
|
312
|
+
'hsl(0 0% 100% / 0.5)'; // with opacity
|
|
169
313
|
```
|
|
170
314
|
|
|
171
315
|
2. **OKLCH Format**
|
|
316
|
+
|
|
172
317
|
```typescript
|
|
173
|
-
'oklch(100% 0 0)'
|
|
174
|
-
'oklch(100% 0 0 / 0.5)' // with opacity
|
|
318
|
+
'oklch(100% 0 0)';
|
|
319
|
+
'oklch(100% 0 0 / 0.5)'; // with opacity
|
|
175
320
|
```
|
|
176
321
|
|
|
177
322
|
3. **Tailwind Palette Reference**
|
|
323
|
+
|
|
178
324
|
```typescript
|
|
179
|
-
'slate.500'
|
|
180
|
-
'blue.600'
|
|
181
|
-
'red.50'
|
|
325
|
+
'slate.500';
|
|
326
|
+
'blue.600';
|
|
327
|
+
'red.50';
|
|
182
328
|
```
|
|
183
329
|
|
|
184
330
|
## 🎨 Usage Examples
|
|
@@ -186,78 +332,75 @@ Supports three color value formats:
|
|
|
186
332
|
### Example 1: Classic Blue Theme
|
|
187
333
|
|
|
188
334
|
```typescript
|
|
189
|
-
createShadcnTheme({
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
feedback: 'classic'
|
|
194
|
-
},
|
|
335
|
+
const theme = createShadcnTheme({
|
|
336
|
+
base: 'slate',
|
|
337
|
+
primary: 'blue',
|
|
338
|
+
feedback: 'classic',
|
|
195
339
|
radius: '0.5rem',
|
|
196
340
|
darkSelector: 'class'
|
|
197
341
|
});
|
|
342
|
+
|
|
343
|
+
const css = theme.getCss();
|
|
198
344
|
```
|
|
199
345
|
|
|
200
346
|
### Example 2: Modern Purple Theme
|
|
201
347
|
|
|
202
348
|
```typescript
|
|
203
|
-
createShadcnTheme({
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
feedback: 'modern'
|
|
208
|
-
},
|
|
349
|
+
const theme = createShadcnTheme({
|
|
350
|
+
base: 'zinc',
|
|
351
|
+
primary: 'violet',
|
|
352
|
+
feedback: 'modern',
|
|
209
353
|
radius: '0.75rem',
|
|
210
354
|
darkSelector: 'class',
|
|
211
355
|
format: 'oklch'
|
|
212
356
|
});
|
|
357
|
+
|
|
358
|
+
const css = theme.getCss();
|
|
213
359
|
```
|
|
214
360
|
|
|
215
|
-
### Example 3:
|
|
361
|
+
### Example 3: Override Per Generation
|
|
216
362
|
|
|
217
363
|
```typescript
|
|
218
|
-
createShadcnTheme({
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
foreground: 'oklch(20% 0 0)',
|
|
223
|
-
primary: 'oklch(50% 0.25 280)', // Custom brand purple
|
|
224
|
-
primaryForeground: 'oklch(100% 0 0)',
|
|
225
|
-
secondary: 'oklch(95% 0.01 280)',
|
|
226
|
-
secondaryForeground: 'oklch(30% 0 0)',
|
|
227
|
-
// ... other colors
|
|
228
|
-
}
|
|
229
|
-
// dark is optional, will be auto-generated if not provided
|
|
230
|
-
}
|
|
231
|
-
});
|
|
364
|
+
const theme = createShadcnTheme({ base: 'slate', primary: 'indigo', feedback: 'classic' });
|
|
365
|
+
|
|
366
|
+
const css1 = theme.getCss();
|
|
367
|
+
const css2 = theme.getCss({ primary: 'emerald', feedback: 'vivid' });
|
|
232
368
|
```
|
|
233
369
|
|
|
234
370
|
### Example 4: Media Query Dark Mode
|
|
235
371
|
|
|
236
372
|
```typescript
|
|
237
|
-
createShadcnTheme({
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
theme: 'indigo'
|
|
241
|
-
},
|
|
373
|
+
const theme = createShadcnTheme({
|
|
374
|
+
base: 'slate',
|
|
375
|
+
primary: 'indigo',
|
|
242
376
|
darkSelector: 'media' // Use system preference
|
|
243
377
|
});
|
|
378
|
+
|
|
379
|
+
const css = theme.getCss();
|
|
244
380
|
```
|
|
245
381
|
|
|
246
382
|
### Example 5: Custom Dark Mode Selector
|
|
247
383
|
|
|
248
384
|
```typescript
|
|
249
|
-
createShadcnTheme({
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
theme: 'emerald'
|
|
253
|
-
},
|
|
385
|
+
const theme = createShadcnTheme({
|
|
386
|
+
base: 'slate',
|
|
387
|
+
primary: 'emerald',
|
|
254
388
|
darkSelector: '[data-theme="dark"]' // Custom selector
|
|
255
389
|
});
|
|
390
|
+
|
|
391
|
+
const css = theme.getCss();
|
|
256
392
|
```
|
|
257
393
|
|
|
258
394
|
## 🎯 Generated CSS Variables
|
|
259
395
|
|
|
260
|
-
|
|
396
|
+
`getCss()` returns a CSS string containing variables like the following.
|
|
397
|
+
|
|
398
|
+
When `format: 'hsl'`, variable values are `h s l [/ alpha]` (without the outer `hsl(...)` wrapper):
|
|
399
|
+
|
|
400
|
+
Notes:
|
|
401
|
+
|
|
402
|
+
- When `format: 'hsl'` and the color key is `border`, `input`, or `sidebarBorder`, if the value includes opacity (e.g. `hsl(... / 0.1)` or `oklch(... / 0.1)`), the library also emits alpha variables: `--border-alpha`, `--input-alpha`, `--sidebar-border-alpha`. Meanwhile `--border` / `--input` / `--sidebar-border` keep only the `h s l` part (without the `/ alpha`).
|
|
403
|
+
- It generates 11 palette variables (50-950) for `primary`, `destructive`, `success`, `warning`, `info`, and `carbon`: `50/100/200/300/400/500/600/700/800/900/950`.
|
|
261
404
|
|
|
262
405
|
```css
|
|
263
406
|
:root {
|
|
@@ -265,9 +408,13 @@ After calling `createShadcnTheme()`, a `<style>` tag containing the following va
|
|
|
265
408
|
--background: 0 0% 100%;
|
|
266
409
|
--foreground: 222.2 84% 4.9%;
|
|
267
410
|
--primary: 221.2 83.2% 53.3%;
|
|
411
|
+
|
|
412
|
+
/* In hsl mode: border/input/sidebarBorder also output alpha vars */
|
|
413
|
+
--border: 214.3 31.8% 91.4%;
|
|
414
|
+
--border-alpha: 0.1;
|
|
268
415
|
/* ... more variables */
|
|
269
416
|
|
|
270
|
-
/* Auto-generated palettes */
|
|
417
|
+
/* Auto-generated palettes (11 levels: 50-950) */
|
|
271
418
|
--primary-50: 239 84% 97%;
|
|
272
419
|
--primary-100: 237 84% 94%;
|
|
273
420
|
/* ... primary-200 to primary-950 */
|
|
@@ -287,23 +434,36 @@ After calling `createShadcnTheme()`, a `<style>` tag containing the following va
|
|
|
287
434
|
}
|
|
288
435
|
```
|
|
289
436
|
|
|
437
|
+
When `format: 'oklch'`, variable values include the outer `oklch(...)` wrapper:
|
|
438
|
+
|
|
439
|
+
```css
|
|
440
|
+
:root {
|
|
441
|
+
--background: oklch(100% 0 0);
|
|
442
|
+
--foreground: oklch(20% 0 0);
|
|
443
|
+
--border: oklch(100% 0 0 / 0.1);
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
290
447
|
## 💡 Advanced Usage
|
|
291
448
|
|
|
292
449
|
### Dynamic Theme Switching
|
|
293
450
|
|
|
294
451
|
```typescript
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
452
|
+
const theme = createShadcnTheme();
|
|
453
|
+
|
|
454
|
+
function apply(cssText: string) {
|
|
455
|
+
const id = 'SHADCN_THEME_STYLE';
|
|
456
|
+
const el = document.getElementById(id) ?? document.createElement('style');
|
|
457
|
+
el.id = id;
|
|
458
|
+
el.textContent = cssText;
|
|
459
|
+
document.head.appendChild(el);
|
|
460
|
+
}
|
|
299
461
|
|
|
300
|
-
|
|
301
|
-
|
|
462
|
+
apply(theme.getCss());
|
|
463
|
+
apply(theme.getCss({ base: 'zinc', primary: 'purple' }));
|
|
302
464
|
|
|
303
|
-
//
|
|
304
|
-
|
|
305
|
-
presets: { base: 'zinc', theme: 'purple' }
|
|
306
|
-
});
|
|
465
|
+
// Dark mode switching is controlled by your darkSelector (e.g. default is adding .dark)
|
|
466
|
+
document.documentElement.classList.add('dark');
|
|
307
467
|
```
|
|
308
468
|
|
|
309
469
|
### Using with Tailwind CSS
|
|
@@ -321,19 +481,42 @@ module.exports = {
|
|
|
321
481
|
DEFAULT: 'hsl(var(--primary))',
|
|
322
482
|
foreground: 'hsl(var(--primary-foreground))',
|
|
323
483
|
50: 'hsl(var(--primary-50))',
|
|
324
|
-
100: 'hsl(var(--primary-100))'
|
|
484
|
+
100: 'hsl(var(--primary-100))'
|
|
325
485
|
// ... more shades
|
|
326
|
-
}
|
|
486
|
+
}
|
|
327
487
|
// ... other colors
|
|
328
488
|
},
|
|
329
489
|
borderRadius: {
|
|
330
490
|
lg: 'var(--radius)',
|
|
331
491
|
md: 'calc(var(--radius) - 2px)',
|
|
332
|
-
sm: 'calc(var(--radius) - 4px)'
|
|
492
|
+
sm: 'calc(var(--radius) - 4px)'
|
|
333
493
|
}
|
|
334
494
|
}
|
|
335
495
|
}
|
|
336
|
-
}
|
|
496
|
+
};
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
When you use `format: 'hsl'`, opacity must be handled separately, especially for `border` / `input` / `sidebarBorder`:
|
|
500
|
+
|
|
501
|
+
- These variables output `h s l` (without `/ alpha`). If opacity is present, the library also emits `--border-alpha` / `--input-alpha` / `--sidebar-border-alpha`.
|
|
502
|
+
- In Tailwind, you can compose them using the slash syntax:
|
|
503
|
+
|
|
504
|
+
```js
|
|
505
|
+
// Use the generated alpha value
|
|
506
|
+
border: 'hsl(var(--border) / var(--border-alpha))';
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
If you want Tailwind opacity modifiers to work (e.g. `border-border/50`), use the `<alpha-value>` placeholder (in this case you typically don't use `--border-alpha`):
|
|
510
|
+
|
|
511
|
+
```js
|
|
512
|
+
// Let Tailwind inject opacity
|
|
513
|
+
border: 'hsl(var(--border) / <alpha-value>)';
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
If you use `format: 'oklch'`, since the variable value already contains `oklch(...)`, use `var(--xxx)` directly in Tailwind (no extra `oklch(...)` wrapper needed):
|
|
517
|
+
|
|
518
|
+
```js
|
|
519
|
+
background: 'var(--background)';
|
|
337
520
|
```
|
|
338
521
|
|
|
339
522
|
### Using in CSS
|