@soybeanjs/shadcn-theme 0.1.0 → 0.2.1

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
@@ -69,62 +69,115 @@ applyTheme(theme.getCss({ primary: 'emerald' }));
69
69
 
70
70
  ### 自定义预设
71
71
 
72
- `preset` 用于在内置预设的基础上“新增/覆盖”一组命名的配色方案。你可以只扩展某一类(例如只加一个 `primary` 预设),也可以同时扩展 `base / primary / feedback / sidebar`。
72
+ 通过 `preset` 参数,你可以使用完整的自定义颜色配置,覆盖内置的 base/primary/feedback/sidebar 预设。当使用自定义预设时,需要同时提供完整的颜色定义。
73
73
 
74
- #### 1) 预设结构与如何引用
74
+ #### 1) 何时使用自定义预设
75
75
 
76
- - `preset` 是一个对象,下面可包含 `base / primary / feedback / sidebar` 四个分组;每个分组都是 `{ [key: string]: PresetItem }`。
77
- - 想使用你新增的预设,只需要把对应的 `base` / `primary` / `feedback` / `sidebar` 设为你定义的 key。
78
- - 例:你在 `preset.primary` 里定义了 `brandPrimary`,那么传入 `primary: 'brandPrimary'` 就会选中它。
76
+ - 当内置预设组合无法满足设计需求时,可以使用 `preset` 传入完整的自定义颜色配置。
77
+ - 使用自定义预设时,所有 base/primary/feedback/sidebar 相关的参数将被忽略,仅使用 `preset` 中的配置。
79
78
 
80
- #### 2) 合并/覆盖规则
79
+ #### 2) 颜色值与 `format`
81
80
 
82
- 本库会把你的 `preset` 与内置预设做浅合并:
83
-
84
- - 同名 key 会被你的 `preset` 覆盖(例如你定义了 `primary.indigo`,会覆盖内置的 `indigo`)
85
- - 不同名 key 会作为新增预设加入(例如新增 `primary.brandPrimary`)
86
-
87
- #### 3) sidebar 的两个模式
88
-
89
- - `sidebar: 'extended'`(默认):不会读取 `preset.sidebar`,而是由 base/primary 的结果自动派生一套 sidebar 颜色。
90
- - `sidebar: '<yourKey>'`:会读取 `preset.sidebar[<yourKey>]` 作为 sidebar 配色。
91
-
92
- #### 4) 颜色值与 `format`
93
-
94
- - 预设里每个颜色值都支持三种写法:Tailwind 色板引用(如 `slate.500`)、`hsl(...)`、`oklch(...)`。
81
+ - 预设里每个颜色值都支持三种写法:Tailwind 色板引用(如 `slate.500`)、`hsl(...)`、`oklch(...)`、或内置允许的颜色名称(`inherit`、`currentColor`、`transparent`、`black`、`white`)。
95
82
  - `format: 'hsl'`:输出变量值为 `h s l [/ alpha]`(不含 `hsl(...)` 外层);如果输入是 `oklch(...)` 会转换为 hsl。
96
83
  - `format: 'oklch'`:输出变量值包含 `oklch(...)` 外层;如果输入是 `hsl(...)` 会转换为 oklch。
97
84
 
98
- #### 快速示例:只新增一个 primary 预设(推荐从小块开始)
99
-
100
- `primary` 预设只需要覆盖 `primary / ring / chart1~chart5`,字段相对最少:
85
+ #### 快速示例:完整的自定义预设
101
86
 
102
- ```ts
87
+ ```typescript
103
88
  const theme = createShadcnTheme({
104
- // 使用你新增的 primary key
105
- primary: 'brandPrimary',
106
89
  preset: {
107
- primary: {
108
- brandPrimary: {
109
- light: {
110
- primary: 'blue.600',
111
- ring: 'blue.400',
112
- chart1: 'orange.600',
113
- chart2: 'teal.600',
114
- chart3: 'cyan.900',
115
- chart4: 'amber.400',
116
- chart5: 'amber.500'
117
- },
118
- dark: {
119
- primary: 'blue.400',
120
- ring: 'blue.500',
121
- chart1: 'orange.500',
122
- chart2: 'teal.500',
123
- chart3: 'cyan.400',
124
- chart4: 'amber.500',
125
- chart5: 'amber.600'
126
- }
127
- }
90
+ light: {
91
+ // 基础颜色
92
+ background: 'white',
93
+ foreground: 'slate.950',
94
+ card: 'white',
95
+ cardForeground: 'slate.950',
96
+ popover: 'white',
97
+ popoverForeground: 'slate.950',
98
+ primaryForeground: 'slate.50',
99
+ secondary: 'slate.100',
100
+ secondaryForeground: 'slate.900',
101
+ muted: 'slate.100',
102
+ mutedForeground: 'slate.500',
103
+ accent: 'slate.100',
104
+ accentForeground: 'slate.900',
105
+ destructiveForeground: 'slate.50',
106
+ successForeground: 'slate.50',
107
+ warningForeground: 'slate.50',
108
+ infoForeground: 'slate.50',
109
+ carbon: 'slate.800',
110
+ carbonForeground: 'slate.50',
111
+ border: 'slate.200',
112
+ input: 'slate.200',
113
+ // 主题颜色
114
+ primary: 'blue.600',
115
+ destructive: 'red.500',
116
+ success: 'green.500',
117
+ warning: 'amber.500',
118
+ info: 'blue.500',
119
+ ring: 'blue.400',
120
+ // 图表颜色
121
+ chart1: 'orange.600',
122
+ chart2: 'teal.600',
123
+ chart3: 'cyan.900',
124
+ chart4: 'amber.400',
125
+ chart5: 'amber.500',
126
+ // 侧边栏颜色
127
+ sidebar: 'slate.50',
128
+ sidebarForeground: 'slate.900',
129
+ sidebarPrimary: 'blue.600',
130
+ sidebarPrimaryForeground: 'slate.50',
131
+ sidebarAccent: 'slate.100',
132
+ sidebarAccentForeground: 'slate.900',
133
+ sidebarBorder: 'slate.200',
134
+ sidebarRing: 'blue.400'
135
+ },
136
+ dark: {
137
+ // 基础颜色
138
+ background: 'slate.950',
139
+ foreground: 'slate.50',
140
+ card: 'slate.900',
141
+ cardForeground: 'slate.50',
142
+ popover: 'slate.900',
143
+ popoverForeground: 'slate.50',
144
+ primaryForeground: 'slate.900',
145
+ secondary: 'slate.800',
146
+ secondaryForeground: 'slate.50',
147
+ muted: 'slate.800',
148
+ mutedForeground: 'slate.400',
149
+ accent: 'slate.800',
150
+ accentForeground: 'slate.50',
151
+ destructiveForeground: 'slate.900',
152
+ successForeground: 'slate.900',
153
+ warningForeground: 'slate.900',
154
+ infoForeground: 'slate.900',
155
+ carbon: 'slate.100',
156
+ carbonForeground: 'slate.900',
157
+ border: 'oklch(100% 0 0 / 0.1)',
158
+ input: 'oklch(100% 0 0 / 0.15)',
159
+ // 主题颜色
160
+ primary: 'blue.400',
161
+ destructive: 'red.400',
162
+ success: 'green.400',
163
+ warning: 'amber.400',
164
+ info: 'blue.400',
165
+ ring: 'blue.500',
166
+ // 图表颜色
167
+ chart1: 'orange.500',
168
+ chart2: 'teal.500',
169
+ chart3: 'cyan.400',
170
+ chart4: 'amber.500',
171
+ chart5: 'amber.600',
172
+ // 侧边栏颜色
173
+ sidebar: 'slate.950',
174
+ sidebarForeground: 'slate.50',
175
+ sidebarPrimary: 'blue.400',
176
+ sidebarPrimaryForeground: 'slate.950',
177
+ sidebarAccent: 'slate.900',
178
+ sidebarAccentForeground: 'slate.50',
179
+ sidebarBorder: 'slate.800',
180
+ sidebarRing: 'blue.500'
128
181
  }
129
182
  }
130
183
  });
@@ -132,165 +185,11 @@ const theme = createShadcnTheme({
132
185
  const css = theme.getCss();
133
186
  ```
134
187
 
135
- #### 快速示例:新增一个 feedback 预设
188
+ #### 注意事项
136
189
 
137
- ```ts
138
- const theme = createShadcnTheme({
139
- feedback: 'brandFeedback',
140
- preset: {
141
- feedback: {
142
- brandFeedback: {
143
- light: {
144
- destructive: 'red.500',
145
- success: 'emerald.500',
146
- warning: 'amber.500',
147
- info: 'sky.500'
148
- },
149
- dark: {
150
- destructive: 'red.400',
151
- success: 'emerald.400',
152
- warning: 'amber.400',
153
- info: 'sky.400'
154
- }
155
- }
156
- }
157
- }
158
- });
159
- ```
160
-
161
- #### 快速示例:使用自定义 sidebar(非 extended)
162
-
163
- ```ts
164
- const theme = createShadcnTheme({
165
- sidebar: 'brandSidebar',
166
- preset: {
167
- sidebar: {
168
- brandSidebar: {
169
- light: {
170
- sidebar: 'slate.50',
171
- sidebarForeground: 'slate.900',
172
- sidebarPrimary: 'blue.600',
173
- sidebarPrimaryForeground: 'slate.50',
174
- sidebarAccent: 'slate.100',
175
- sidebarAccentForeground: 'slate.900',
176
- sidebarBorder: 'slate.200',
177
- sidebarRing: 'blue.400'
178
- },
179
- dark: {
180
- sidebar: 'slate.950',
181
- sidebarForeground: 'slate.50',
182
- sidebarPrimary: 'blue.400',
183
- sidebarPrimaryForeground: 'slate.950',
184
- sidebarAccent: 'slate.900',
185
- sidebarAccentForeground: 'slate.50',
186
- sidebarBorder: 'slate.800',
187
- sidebarRing: 'blue.500'
188
- }
189
- }
190
- }
191
- }
192
- });
193
- ```
194
-
195
- #### 完整示例(自定义 base + primary + feedback)
196
-
197
- ```typescript
198
- createShadcnTheme({
199
- base: 'demoBase',
200
- primary: 'demoPrimary',
201
- feedback: 'demoFeedback',
202
- preset: {
203
- base: {
204
- demoBase: {
205
- light: {
206
- background: 'oklch(100% 0 0)',
207
- foreground: 'stone.950',
208
- card: 'oklch(100% 0 0)',
209
- cardForeground: 'stone.950',
210
- popover: 'oklch(100% 0 0)',
211
- popoverForeground: 'stone.950',
212
- primaryForeground: 'stone.50',
213
- secondary: 'stone.100',
214
- secondaryForeground: 'stone.900',
215
- muted: 'stone.100',
216
- mutedForeground: 'stone.500',
217
- accent: 'stone.100',
218
- accentForeground: 'stone.900',
219
- destructiveForeground: 'stone.50',
220
- successForeground: 'stone.50',
221
- warningForeground: 'stone.50',
222
- infoForeground: 'stone.50',
223
- carbon: 'stone.800',
224
- carbonForeground: 'stone.50',
225
- border: 'stone.200',
226
- input: 'stone.200'
227
- },
228
- dark: {
229
- background: 'stone.950',
230
- foreground: 'stone.50',
231
- card: 'stone.900',
232
- cardForeground: 'stone.50',
233
- popover: 'stone.900',
234
- popoverForeground: 'stone.50',
235
- primaryForeground: 'stone.900',
236
- secondary: 'stone.800',
237
- secondaryForeground: 'stone.50',
238
- muted: 'stone.800',
239
- mutedForeground: 'stone.400',
240
- accent: 'stone.800',
241
- accentForeground: 'stone.50',
242
- destructiveForeground: 'stone.900',
243
- successForeground: 'stone.900',
244
- warningForeground: 'stone.900',
245
- infoForeground: 'stone.900',
246
- carbon: 'stone.100',
247
- carbonForeground: 'stone.900',
248
- border: 'oklch(100% 0 0 / 0.1)',
249
- input: 'oklch(100% 0 0 / 0.15)'
250
- }
251
- }
252
- },
253
- primary: {
254
- demoPrimary: {
255
- light: {
256
- primary: 'stone.800',
257
- ring: 'stone.400',
258
- chart1: 'orange.600',
259
- chart2: 'teal.600',
260
- chart3: 'cyan.900',
261
- chart4: 'amber.400',
262
- chart5: 'amber.500'
263
- },
264
- dark: {
265
- primary: 'stone.200',
266
- ring: 'stone.500',
267
- chart1: 'blue.700',
268
- chart2: 'emerald.500',
269
- chart3: 'amber.500',
270
- chart4: 'purple.500',
271
- chart5: 'rose.500'
272
- }
273
- }
274
- },
275
- feedback: {
276
- demoFeedback: {
277
- light: {
278
- destructive: 'red.500',
279
- success: 'green.500',
280
- warning: 'yellow.500',
281
- info: 'blue.500'
282
- },
283
- dark: {
284
- destructive: 'red.400',
285
- success: 'green.400',
286
- warning: 'yellow.400',
287
- info: 'blue.400'
288
- }
289
- }
290
- }
291
- }
292
- });
293
- ```
190
+ - 当提供 `preset` 参数时,`base`、`primary`、`feedback`、`sidebar` 参数将被忽略。
191
+ - 预设必须包含 `light` 和 `dark` 两个模式的完整色值定义。
192
+ - 建议从内置预设的结构开始,根据设计需求进行修改。
294
193
 
295
194
  ## 📖 API 文档
296
195
 
@@ -310,54 +209,58 @@ theme.getRadiusCss(radius?: string): string
310
209
 
311
210
  #### ThemeOptions
312
211
 
313
- | 参数 | 类型 | 默认值 | 描述 |
314
- |------|------|--------|------|
315
- | `base` | `BuiltinBasePresetKey \| string` | `'gray'` | base 预设 key |
316
- | `primary` | `BuiltinPrimaryPresetKey \| string` | `'indigo'` | primary 预设 key |
317
- | `feedback` | `BuiltinFeedbackPresetKey \| string` | `'classic'` | feedback 预设 key |
318
- | `sidebar` | `'extended' \| string` | `'extended'` | 侧边栏模式;`extended` 表示由 base/primary 自动派生 |
319
- | `preset` | `CustomPreset` | - | 自定义预设集合(可扩展 base/primary/feedback/sidebar) |
320
- | `radius` | `string` | `'0.625rem'` | 全局圆角 |
321
- | `styleTarget` | `'html' \| ':root'` | `':root'` | CSS 变量挂载目标选择器 |
322
- | `darkSelector` | `'class' \| 'media' \| string` | `'class'` | 深色模式选择器(支持自定义字符串) |
323
- | `format` | `'hsl' \| 'oklch'` | `'hsl'` | 颜色输出格式 |
212
+ | 参数 | 类型 | 默认值 | 描述 |
213
+ | -------------- | ------------------------------ | ------------ | ---------------------------------------------------------------- |
214
+ | `base` | `BuiltinBasePresetKey` | `'neutral'` | base 预设 key |
215
+ | `primary` | `BuiltinPrimaryPresetKey` | `'indigo'` | primary 预设 key |
216
+ | `feedback` | `BuiltinFeedbackPresetKey` | `'classic'` | feedback 预设 key |
217
+ | `sidebar` | `'extended'` | `'extended'` | 侧边栏模式;`extended` 表示由 base/primary 自动派生 |
218
+ | `preset` | `ThemeColorPresetItem` | - | 自定义完整颜色预设(提供时将忽略 base/primary/feedback/sidebar) |
219
+ | `radius` | `string` | `'0.625rem'` | 全局圆角 |
220
+ | `styleTarget` | `'html' \| ':root'` | `':root'` | CSS 变量挂载目标选择器 |
221
+ | `darkSelector` | `'class' \| 'media' \| string` | `'class'` | 深色模式选择器(支持自定义字符串) |
222
+ | `format` | `'hsl' \| 'oklch'` | `'hsl'` | 颜色输出格式 |
324
223
 
325
224
  ### 预设配置(PresetConfig)
326
225
 
327
226
  ```typescript
328
227
  interface PresetConfig {
329
- base?: string;
330
- primary?: string;
331
- feedback?: string;
332
- sidebar?: 'extended' | string;
228
+ base?: BuiltinBasePresetKey | 'custom';
229
+ primary?: BuiltinPrimaryPresetKey | 'custom';
230
+ feedback?: BuiltinFeedbackPresetKey | 'custom';
231
+ sidebar?: 'extended' | 'custom';
232
+ preset?: ThemeColorPresetItem;
333
233
  }
334
234
  ```
335
235
 
236
+ 当使用 `preset` 参数时,其他配置参数(base/primary/feedback/sidebar)将被忽略。
237
+
336
238
  #### 反馈色风格(FeedbackPaletteKey)
337
239
 
338
- | 风格 | 描述 | 适用场景 |
339
- |------|------|----------|
340
- | `classic` | 经典标准 | 最常见的组合,适用于大多数场景 |
341
- | `vivid` | 鲜艳活力 | 高饱和度,适合年轻化产品和创意应用 |
342
- | `subtle` | 柔和优雅 | 低对比度,适合高端品牌和优雅界面 |
343
- | `warm` | 暖色温馨 | 暖色调为主,营造友好温暖的氛围 |
344
- | `cool` | 冷色专业 | 冷色调为主,适合科技和专业应用 |
345
- | `nature` | 自然清新 | 自然色系,适合环保、健康类产品 |
346
- | `modern` | 现代简约 | 现代感强,适合科技产品和 SaaS 应用 |
347
- | `vibrant` | 活力四射 | 高能量配色,适合运动、游戏类应用 |
348
- | `professional` | 商务专业 | 稳重大气,适合企业级应用和 B2B 产品 |
349
- | `soft` | 梦幻柔美 | 柔和色调,适合设计工具和创意平台 |
350
- | `bold` | 大胆醒目 | 高对比度,适合需要强烈视觉冲击的场景 |
351
- | `calm` | 平静舒缓 | 低饱和度,适合长时间使用的应用 |
352
- | `candy` | 糖果色彩 | 明快可爱,适合儿童产品和趣味应用 |
353
- | `deep` | 深邃神秘 | 深色调,适合暗黑主题和神秘风格 |
354
- | `light` | 清新淡雅 | 浅色调,适合简洁清爽的界面 |
240
+ | 风格 | 描述 | 适用场景 |
241
+ | -------------- | -------- | ------------------------------------ |
242
+ | `classic` | 经典标准 | 最常见的组合,适用于大多数场景 |
243
+ | `vivid` | 鲜艳活力 | 高饱和度,适合年轻化产品和创意应用 |
244
+ | `subtle` | 柔和优雅 | 低对比度,适合高端品牌和优雅界面 |
245
+ | `warm` | 暖色温馨 | 暖色调为主,营造友好温暖的氛围 |
246
+ | `cool` | 冷色专业 | 冷色调为主,适合科技和专业应用 |
247
+ | `nature` | 自然清新 | 自然色系,适合环保、健康类产品 |
248
+ | `modern` | 现代简约 | 现代感强,适合科技产品和 SaaS 应用 |
249
+ | `vibrant` | 活力四射 | 高能量配色,适合运动、游戏类应用 |
250
+ | `professional` | 商务专业 | 稳重大气,适合企业级应用和 B2B 产品 |
251
+ | `soft` | 梦幻柔美 | 柔和色调,适合设计工具和创意平台 |
252
+ | `bold` | 大胆醒目 | 高对比度,适合需要强烈视觉冲击的场景 |
253
+ | `calm` | 平静舒缓 | 低饱和度,适合长时间使用的应用 |
254
+ | `candy` | 糖果色彩 | 明快可爱,适合儿童产品和趣味应用 |
255
+ | `deep` | 深邃神秘 | 深色调,适合暗黑主题和神秘风格 |
256
+ | `light` | 清新淡雅 | 浅色调,适合简洁清爽的界面 |
355
257
 
356
258
  ### 主题颜色(ThemeColors)
357
259
 
358
260
  支持配置以下颜色变量:
359
261
 
360
262
  #### 基础颜色
263
+
361
264
  - `background` - 背景色
362
265
  - `foreground` - 前景色(文本)
363
266
  - `card` - 卡片背景
@@ -379,12 +282,14 @@ interface PresetConfig {
379
282
  - `ring` - 聚焦环颜色
380
283
 
381
284
  #### 扩展颜色
285
+
382
286
  - `success` / `successForeground` - 成功状态
383
287
  - `warning` / `warningForeground` - 警告状态
384
288
  - `info` / `infoForeground` - 信息状态
385
289
  - `carbon` / `carbonForeground` - 碳色(额外的深色系)
386
290
 
387
291
  #### 侧边栏颜色
292
+
388
293
  - `sidebar` - 侧边栏背景
389
294
  - `sidebarForeground` - 侧边栏前景
390
295
  - `sidebarPrimary` - 侧边栏主色
@@ -395,6 +300,7 @@ interface PresetConfig {
395
300
  - `sidebarRing` - 侧边栏聚焦环
396
301
 
397
302
  #### 图表颜色
303
+
398
304
  - `chart1` ~ `chart5` - 图表配色
399
305
 
400
306
  ### 颜色值格式(ColorValue)
@@ -402,22 +308,25 @@ interface PresetConfig {
402
308
  支持三种颜色值格式:
403
309
 
404
310
  1. **HSL 格式**
311
+
405
312
  ```typescript
406
- 'hsl(0 0% 100%)'
407
- 'hsl(0 0% 100% / 0.5)' // 带透明度
313
+ 'hsl(0 0% 100%)';
314
+ 'hsl(0 0% 100% / 0.5)'; // 带透明度
408
315
  ```
409
316
 
410
317
  2. **OKLCH 格式**
318
+
411
319
  ```typescript
412
- 'oklch(100% 0 0)'
413
- 'oklch(100% 0 0 / 0.5)' // 带透明度
320
+ 'oklch(100% 0 0)';
321
+ 'oklch(100% 0 0 / 0.5)'; // 带透明度
414
322
  ```
415
323
 
416
324
  3. **Tailwind 色板引用**
325
+
417
326
  ```typescript
418
- 'slate.500'
419
- 'blue.600'
420
- 'red.50'
327
+ 'slate.500';
328
+ 'blue.600';
329
+ 'red.50';
421
330
  ```
422
331
 
423
332
  ## 🎨 使用示例
@@ -580,19 +489,19 @@ module.exports = {
580
489
  DEFAULT: 'hsl(var(--primary))',
581
490
  foreground: 'hsl(var(--primary-foreground))',
582
491
  50: 'hsl(var(--primary-50))',
583
- 100: 'hsl(var(--primary-100))',
492
+ 100: 'hsl(var(--primary-100))'
584
493
  // ... 更多色阶
585
- },
494
+ }
586
495
  // ... 其他颜色
587
496
  },
588
497
  borderRadius: {
589
498
  lg: 'var(--radius)',
590
499
  md: 'calc(var(--radius) - 2px)',
591
- sm: 'calc(var(--radius) - 4px)',
500
+ sm: 'calc(var(--radius) - 4px)'
592
501
  }
593
502
  }
594
503
  }
595
- }
504
+ };
596
505
  ```
597
506
 
598
507
  当你使用 `format: 'hsl'` 时,“透明度需要单独处理”,尤其是 `border` / `input` / `sidebarBorder`:
@@ -602,20 +511,20 @@ module.exports = {
602
511
 
603
512
  ```js
604
513
  // 固定使用生成出来的 alpha
605
- border: 'hsl(var(--border) / var(--border-alpha))'
514
+ border: 'hsl(var(--border) / var(--border-alpha))';
606
515
  ```
607
516
 
608
517
  如果你希望 Tailwind 的透明度修饰符(例如 `border-border/50`)生效,可以使用 `<alpha-value>` 占位符(这种情况下通常不需要使用 `--border-alpha`):
609
518
 
610
519
  ```js
611
520
  // 让 Tailwind 注入透明度
612
- border: 'hsl(var(--border) / <alpha-value>)'
521
+ border: 'hsl(var(--border) / <alpha-value>)';
613
522
  ```
614
523
 
615
524
  如果你使用 `format: 'oklch'`,由于变量值本身已经是 `oklch(...)`,在 Tailwind 中直接使用 `var(--xxx)` 即可(不需要再包一层 `oklch(...)`):
616
525
 
617
526
  ```js
618
- background: 'var(--background)'
527
+ background: 'var(--background)';
619
528
  ```
620
529
 
621
530
  ### 在 CSS 中使用