|
| 1 | +import { colord, generateColorPalette } from '@soybean-react-ui/color'; |
1 | 2 | import { mergeDeep } from '@unocss/core'; |
2 | 3 |
|
3 | 4 | import themes from './theme.json'; |
4 | 5 | import type { |
5 | 6 | ColorOptions, |
| 7 | + FeedbackColorOfThemeCssVarKey, |
| 8 | + FeedbackColorOfThemeCssVars, |
6 | 9 | FeedbackColorOfThemeCssVarsVariant, |
7 | 10 | PresetShadcnOptions, |
| 11 | + SidebarColorOfThemeCssVarKey, |
8 | 12 | SidebarColorOfThemeCssVarsVariant, |
| 13 | + ThemeCSSVarKey, |
9 | 14 | ThemeCSSVars, |
10 | 15 | ThemeCSSVarsVariant, |
11 | 16 | ThemeConfig |
12 | 17 | } from './types'; |
13 | 18 |
|
14 | 19 | const builtinThemes = themes as ThemeConfig[]; |
15 | 20 |
|
| 21 | +type CSSVarKey = ThemeCSSVarKey | FeedbackColorOfThemeCssVarKey | SidebarColorOfThemeCssVarKey; |
| 22 | + |
| 23 | +const themeCSSVarKeys: CSSVarKey[] = [ |
| 24 | + 'background', |
| 25 | + 'foreground', |
| 26 | + 'card', |
| 27 | + 'card-foreground', |
| 28 | + 'popover', |
| 29 | + 'popover-foreground', |
| 30 | + 'primary', |
| 31 | + 'primary-foreground', |
| 32 | + 'destructive', |
| 33 | + 'destructive-foreground', |
| 34 | + 'success', |
| 35 | + 'success-foreground', |
| 36 | + 'warning', |
| 37 | + 'warning-foreground', |
| 38 | + 'info', |
| 39 | + 'info-foreground', |
| 40 | + 'secondary', |
| 41 | + 'secondary-foreground', |
| 42 | + 'carbon', |
| 43 | + 'carbon-foreground', |
| 44 | + 'muted', |
| 45 | + 'muted-foreground', |
| 46 | + 'accent', |
| 47 | + 'accent-foreground', |
| 48 | + 'border', |
| 49 | + 'input', |
| 50 | + 'ring', |
| 51 | + 'sidebar-background', |
| 52 | + 'sidebar-foreground', |
| 53 | + 'sidebar-border', |
| 54 | + 'sidebar-ring', |
| 55 | + 'sidebar-primary', |
| 56 | + 'sidebar-primary-foreground', |
| 57 | + 'sidebar-accent', |
| 58 | + 'sidebar-accent-foreground' |
| 59 | +]; |
| 60 | + |
| 61 | +const themeColorKeys: CSSVarKey[] = ['primary', 'destructive', 'success', 'warning', 'info', 'carbon']; |
| 62 | + |
16 | 63 | function getRadiusCSSVars(radius: number) { |
17 | 64 | return `--radius: ${radius}rem;`; |
18 | 65 | } |
@@ -73,51 +120,79 @@ function getColorTheme(color: ColorOptions): ThemeCSSVarsVariant { |
73 | 120 | function createBuiltinFeedbackColorTheme() { |
74 | 121 | const feedbackColor: FeedbackColorOfThemeCssVarsVariant = { |
75 | 122 | dark: { |
76 | | - '--carbon': '220 14.3% 95.9%', |
77 | | - '--carbon-foreground': '220.9 39.3% 11%', |
78 | | - '--info': '215 100% 54%', |
79 | | - '--info-foreground': '0 0% 100%', |
80 | | - '--success': '140 79% 45%', |
81 | | - '--success-foreground': '0 0% 100%', |
82 | | - '--warning': '37 91% 55%', |
83 | | - '--warning-foreground': '0 0% 100%' |
| 123 | + carbon: '220 14.3% 95.9%', |
| 124 | + 'carbon-foreground': '220.9 39.3% 11%', |
| 125 | + info: '215 100% 54%', |
| 126 | + 'info-foreground': '0 0% 100%', |
| 127 | + success: '140 79% 45%', |
| 128 | + 'success-foreground': '0 0% 100%', |
| 129 | + warning: '37 91% 55%', |
| 130 | + 'warning-foreground': '0 0% 100%' |
84 | 131 | }, |
85 | 132 | light: { |
86 | | - '--carbon': '240 4% 16%', |
87 | | - '--carbon-foreground': '0 0% 98%', |
88 | | - '--info': '215 100% 54%', |
89 | | - '--info-foreground': '0 0% 100%', |
90 | | - '--success': '140 79% 45%', |
91 | | - '--success-foreground': '0 0% 100%', |
92 | | - '--warning': '37 91% 55%', |
93 | | - '--warning-foreground': '0 0% 100%' |
| 133 | + carbon: '240 4% 16%', |
| 134 | + 'carbon-foreground': '0 0% 98%', |
| 135 | + info: '215 100% 54%', |
| 136 | + 'info-foreground': '0 0% 100%', |
| 137 | + success: '140 79% 45%', |
| 138 | + 'success-foreground': '0 0% 100%', |
| 139 | + warning: '37 91% 55%', |
| 140 | + 'warning-foreground': '0 0% 100%' |
94 | 141 | } |
95 | 142 | }; |
96 | 143 |
|
97 | 144 | return feedbackColor; |
98 | 145 | } |
99 | 146 |
|
| 147 | +function getColorCSSVars(color: FeedbackColorOfThemeCssVars): Record<string, string> { |
| 148 | + const result: Record<string, string> = {}; |
| 149 | + |
| 150 | + for (const [item, value] of Object.entries(color)) { |
| 151 | + const key = item as CSSVarKey; |
| 152 | + |
| 153 | + if (!themeCSSVarKeys.includes(key)) { |
| 154 | + continue; |
| 155 | + } |
| 156 | + |
| 157 | + result[`--${key}`] = value; // 原始变量,如 "--primary": "220 90% 55%" |
| 158 | + |
| 159 | + |
| 160 | + if (themeColorKeys.includes(key)) { |
| 161 | + const hsl = `hsl(${value.split(' ').join(', ')})`; |
| 162 | + |
| 163 | + const colorPalette = generateColorPalette(hsl); // { 100: "#f0f", 200: "#e0e", ... } |
| 164 | + |
| 165 | + for (const [num, hex] of Object.entries(colorPalette)) { |
| 166 | + const { h, l, s } = colord(hex).toHsl(); |
| 167 | + result[`--${key}-${num}`] = `${h} ${s}% ${l}%`; // "--primary-100": "220 90% 95%" |
| 168 | + } |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + return result; |
| 173 | +} |
| 174 | + |
100 | 175 | function createBuiltinSidebarColorTheme() { |
101 | 176 | const sidebarColor: SidebarColorOfThemeCssVarsVariant = { |
102 | 177 | dark: { |
103 | | - '--sidebar-accent': '240 3.7% 15.9%', |
104 | | - '--sidebar-accent-foreground': '240 4.8% 95.9%', |
105 | | - '--sidebar-background': '240 5.9% 10%', |
106 | | - '--sidebar-border': '240 3.7% 15.9%', |
107 | | - '--sidebar-foreground': '240 4.8% 95.9%', |
108 | | - '--sidebar-primary': '236.9 100% 69.61%', |
109 | | - '--sidebar-primary-foreground': '0 0% 100%', |
110 | | - '--sidebar-ring': '217.2 91.2% 59.8%' |
| 178 | + 'sidebar-accent': '240 3.7% 15.9%', |
| 179 | + 'sidebar-accent-foreground': '240 4.8% 95.9%', |
| 180 | + 'sidebar-background': '240 5.9% 10%', |
| 181 | + 'sidebar-border': '240 3.7% 15.9%', |
| 182 | + 'sidebar-foreground': '240 4.8% 95.9%', |
| 183 | + 'sidebar-primary': '236.9 100% 69.61%', |
| 184 | + 'sidebar-primary-foreground': '0 0% 100%', |
| 185 | + 'sidebar-ring': '217.2 91.2% 59.8%' |
111 | 186 | }, |
112 | 187 | light: { |
113 | | - '--sidebar-accent': '240 4.8% 95.9%', |
114 | | - '--sidebar-accent-foreground': '240 5.9% 10%', |
115 | | - '--sidebar-background': '0 0% 98%', |
116 | | - '--sidebar-border': '220 13% 91%', |
117 | | - '--sidebar-foreground': '240 5.3% 26.1%', |
118 | | - '--sidebar-primary': '236.9 100% 69.61%', |
119 | | - '--sidebar-primary-foreground': '0 0% 98%', |
120 | | - '--sidebar-ring': '217.2 91.2% 59.8%' |
| 188 | + 'sidebar-accent': '240 4.8% 95.9%', |
| 189 | + 'sidebar-accent-foreground': '240 5.9% 10%', |
| 190 | + 'sidebar-background': '0 0% 98%', |
| 191 | + 'sidebar-border': '220 13% 91%', |
| 192 | + 'sidebar-foreground': '240 5.3% 26.1%', |
| 193 | + 'sidebar-primary': '236.9 100% 69.61%', |
| 194 | + 'sidebar-primary-foreground': '0 0% 98%', |
| 195 | + 'sidebar-ring': '217.2 91.2% 59.8%' |
121 | 196 | } |
122 | 197 | }; |
123 | 198 |
|
@@ -154,17 +229,18 @@ export function generateCSSVars(theme: PresetShadcnOptions, onlyOne = true): obj |
154 | 229 |
|
155 | 230 | const darkThemeSelector = addThemeName ? `.theme-${themeName}${darkSelector}` : darkSelector; |
156 | 231 |
|
| 232 | + |
| 233 | + const darkThemeCSSVars = getColorCSSVars({ ...feedbackColor.dark, ...dark, ...sidebar.dark }); |
| 234 | + |
| 235 | + const lightThemeCSSVars = getColorCSSVars({ ...feedbackColor.light, ...light, ...sidebar.light }); |
| 236 | + |
157 | 237 | return { |
158 | | - [darkThemeSelector]: { |
159 | | - ...sidebar.dark, |
160 | | - ...feedbackColor.dark, |
161 | | - ...dark |
162 | | - }, |
163 | 238 | [themeSelector]: { |
164 | | - ...sidebar.light, |
165 | | - ...feedbackColor.light, |
166 | | - ...light, |
| 239 | + ...lightThemeCSSVars, |
167 | 240 | '--radius': `${radius}rem` |
| 241 | + }, |
| 242 | + [darkThemeSelector]: { |
| 243 | + ...darkThemeCSSVars, |
168 | 244 | } |
169 | 245 | }; |
170 | 246 | } |
|
0 commit comments