@qlover/create-app 0.7.14 → 0.7.15
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/CHANGELOG.md +23 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/next-app/README.en.md +131 -0
- package/dist/templates/next-app/README.md +115 -20
- package/dist/templates/next-app/docs/en/api.md +387 -0
- package/dist/templates/next-app/docs/en/component.md +544 -0
- package/dist/templates/next-app/docs/en/database.md +496 -0
- package/dist/templates/next-app/docs/en/development-guide.md +727 -0
- package/dist/templates/next-app/docs/en/env.md +563 -0
- package/dist/templates/next-app/docs/en/i18n.md +287 -0
- package/dist/templates/next-app/docs/en/index.md +166 -0
- package/dist/templates/next-app/docs/en/page.md +457 -0
- package/dist/templates/next-app/docs/en/project-structure.md +177 -0
- package/dist/templates/next-app/docs/en/router.md +427 -0
- package/dist/templates/next-app/docs/en/theme.md +532 -0
- package/dist/templates/next-app/docs/en/validator.md +478 -0
- package/dist/templates/next-app/docs/zh/api.md +387 -0
- package/dist/templates/next-app/docs/zh/component.md +544 -0
- package/dist/templates/next-app/docs/zh/database.md +496 -0
- package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
- package/dist/templates/next-app/docs/zh/env.md +563 -0
- package/dist/templates/next-app/docs/zh/i18n.md +287 -0
- package/dist/templates/next-app/docs/zh/index.md +166 -0
- package/dist/templates/next-app/docs/zh/page.md +457 -0
- package/dist/templates/next-app/docs/zh/project-structure.md +177 -0
- package/dist/templates/next-app/docs/zh/router.md +427 -0
- package/dist/templates/next-app/docs/zh/theme.md +532 -0
- package/dist/templates/next-app/docs/zh/validator.md +476 -0
- package/package.json +1 -1
- package/dist/templates/next-app/docs/env.md +0 -94
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
# Theme System Development Guide
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
1. [Theme System Overview](#theme-system-overview)
|
|
6
|
+
2. [Theme Variables and Style System](#theme-variables-and-style-system)
|
|
7
|
+
3. [Component Theme Implementation](#component-theme-implementation)
|
|
8
|
+
4. [Theme Switching and State Management](#theme-switching-and-state-management)
|
|
9
|
+
5. [Best Practices and Examples](#best-practices-and-examples)
|
|
10
|
+
|
|
11
|
+
## Theme System Overview
|
|
12
|
+
|
|
13
|
+
### 1. Theme Architecture
|
|
14
|
+
|
|
15
|
+
The project adopts a layered theme system design:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Style Layer Component Layer
|
|
19
|
+
┌──────────────┐ ┌──────────────┐
|
|
20
|
+
│ CSS Variables│ │Theme Provider│
|
|
21
|
+
├──────────────┤ ├──────────────┤
|
|
22
|
+
│Theme Styles │ ◄─────┤Theme Consumer│
|
|
23
|
+
├──────────────┤ ├──────────────┤
|
|
24
|
+
│Component Style│ │Theme Switcher│
|
|
25
|
+
└──────────────┘ └──────────────┘
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. Theme Types
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// config/theme.ts
|
|
32
|
+
export const themeConfig = {
|
|
33
|
+
// Supported themes
|
|
34
|
+
supportedThemes: ['light', 'dark', 'pink'] as const,
|
|
35
|
+
defaultTheme: 'system',
|
|
36
|
+
|
|
37
|
+
// DOM attribute
|
|
38
|
+
domAttribute: 'data-theme',
|
|
39
|
+
|
|
40
|
+
// Storage key
|
|
41
|
+
storageKey: 'theme'
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Theme type definition
|
|
45
|
+
export type ThemeMode = (typeof themeConfig.supportedThemes)[number];
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Theme Variables and Style System
|
|
49
|
+
|
|
50
|
+
### 1. Base Variable Definitions
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
/* styles/css/antd-themes/_common/_default.css */
|
|
54
|
+
html,
|
|
55
|
+
.fe-theme {
|
|
56
|
+
/* Primary color related variables */
|
|
57
|
+
--fe-color-primary: #60a5fa;
|
|
58
|
+
--fe-color-primary-hover: #3b82f6;
|
|
59
|
+
--fe-color-primary-active: #2563eb;
|
|
60
|
+
--fe-color-primary-bg: rgba(96, 165, 250, 0.1);
|
|
61
|
+
|
|
62
|
+
/* Status colors */
|
|
63
|
+
--fe-color-success: #52c41a;
|
|
64
|
+
--fe-color-warning: #faad14;
|
|
65
|
+
--fe-color-error: #ff4d4f;
|
|
66
|
+
--fe-color-info: var(--fe-color-primary);
|
|
67
|
+
|
|
68
|
+
/* Base variables */
|
|
69
|
+
--fe-color-bg-container: rgb(255 255 255);
|
|
70
|
+
--fe-color-bg-elevated: rgb(248 250 252);
|
|
71
|
+
--fe-color-text-heading: rgb(15 23 42);
|
|
72
|
+
--fe-color-text: rgba(15 23 42 / 0.85);
|
|
73
|
+
--fe-color-text-secondary: rgba(15 23 42 / 0.45);
|
|
74
|
+
--fe-color-border: rgb(226 232 240);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 2. Dark Theme Variables
|
|
79
|
+
|
|
80
|
+
```css
|
|
81
|
+
/* styles/css/antd-themes/_common/dark.css */
|
|
82
|
+
[data-theme='dark'],
|
|
83
|
+
[data-theme='dark'] .fe-theme {
|
|
84
|
+
/* Primary color - Purple theme */
|
|
85
|
+
--fe-color-primary: #9333ea;
|
|
86
|
+
--fe-color-primary-hover: #a855f7;
|
|
87
|
+
--fe-color-primary-active: #7e22ce;
|
|
88
|
+
|
|
89
|
+
/* Base variable overrides */
|
|
90
|
+
--fe-color-bg-container: rgb(30 41 59);
|
|
91
|
+
--fe-color-bg-elevated: rgb(51 65 85);
|
|
92
|
+
--fe-color-text-heading: rgb(241 245 249);
|
|
93
|
+
--fe-color-text: rgba(255, 255, 255, 0.85);
|
|
94
|
+
--fe-color-border: rgb(51 65 85);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 3. Pink Theme Variables
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
/* styles/css/antd-themes/_common/pink.css */
|
|
102
|
+
[data-theme='pink'],
|
|
103
|
+
[data-theme='pink'] .fe-theme {
|
|
104
|
+
/* Primary color - Rose theme */
|
|
105
|
+
--fe-color-primary: #f472b6;
|
|
106
|
+
--fe-color-primary-hover: #ec4899;
|
|
107
|
+
--fe-color-primary-active: #db2777;
|
|
108
|
+
|
|
109
|
+
/* Base variable overrides */
|
|
110
|
+
--ant-color-bg-container: rgb(255 241 242);
|
|
111
|
+
--ant-color-bg-elevated: rgb(254 205 211);
|
|
112
|
+
--fe-color-text-heading: rgb(159 18 57);
|
|
113
|
+
--fe-color-text: rgba(190 18 60 / 0.85);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Ant Design Theme System
|
|
118
|
+
|
|
119
|
+
### 1. Base Theme Variables
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
/* styles/css/antd-themes/_common/_default.css */
|
|
123
|
+
html,
|
|
124
|
+
.fe-theme {
|
|
125
|
+
/* Antd primary color related variables - Light blue theme */
|
|
126
|
+
--fe-color-primary: #60a5fa; /* blue-400 */
|
|
127
|
+
--fe-color-primary-hover: #3b82f6; /* blue-500 */
|
|
128
|
+
--fe-color-primary-active: #2563eb; /* blue-600 */
|
|
129
|
+
--fe-color-primary-bg: rgba(96, 165, 250, 0.1);
|
|
130
|
+
|
|
131
|
+
/* Status colors */
|
|
132
|
+
--fe-color-success: #52c41a;
|
|
133
|
+
--fe-color-warning: #faad14;
|
|
134
|
+
--fe-color-error: #ff4d4f;
|
|
135
|
+
--fe-color-info: var(--fe-color-primary);
|
|
136
|
+
|
|
137
|
+
/* Antd base variables */
|
|
138
|
+
--fe-color-bg-container: rgb(255 255 255);
|
|
139
|
+
--fe-color-bg-elevated: rgb(248 250 252);
|
|
140
|
+
--fe-color-text-heading: rgb(15 23 42);
|
|
141
|
+
--fe-color-text: rgba(15 23 42 / 0.85);
|
|
142
|
+
--fe-color-border: rgb(226 232 240);
|
|
143
|
+
|
|
144
|
+
/* Antd common component variables */
|
|
145
|
+
--fe-line-width: 1px;
|
|
146
|
+
--fe-border-radius: 6px;
|
|
147
|
+
--fe-motion-duration-mid: 0.2s;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 2. Dark Theme Component Variables
|
|
152
|
+
|
|
153
|
+
```css
|
|
154
|
+
/* styles/css/antd-themes/_common/dark.css */
|
|
155
|
+
[data-theme='dark'] {
|
|
156
|
+
/* Input component variables */
|
|
157
|
+
.ant-input-css-var {
|
|
158
|
+
--fe-input-hover-border-color: #4096ff;
|
|
159
|
+
--fe-input-active-border-color: #1677ff;
|
|
160
|
+
--fe-input-hover-bg: rgb(51 65 85);
|
|
161
|
+
--fe-input-active-bg: rgb(51 65 85);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Button component variables */
|
|
165
|
+
.ant-btn-css-var {
|
|
166
|
+
/* Purple theme */
|
|
167
|
+
--fe-button-primary-color: #fff;
|
|
168
|
+
--fe-button-primary-bg: #8b5cf6;
|
|
169
|
+
--fe-button-primary-hover-bg: #7c3aed;
|
|
170
|
+
--fe-button-primary-active-bg: #6d28d9;
|
|
171
|
+
|
|
172
|
+
/* Default button */
|
|
173
|
+
--fe-button-default-color: rgba(255, 255, 255, 0.85);
|
|
174
|
+
--fe-button-default-bg: rgb(30 41 59);
|
|
175
|
+
--fe-button-default-border-color: rgb(51 65 85);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Select component variables */
|
|
179
|
+
.ant-select-css-var {
|
|
180
|
+
--fe-select-dropdown-bg: rgb(30 41 59);
|
|
181
|
+
--fe-select-item-selected-bg: rgba(147, 51, 234, 0.1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 3. Pink Theme Component Variables
|
|
187
|
+
|
|
188
|
+
```css
|
|
189
|
+
/* styles/css/antd-themes/_common/pink.css */
|
|
190
|
+
[data-theme='pink'] {
|
|
191
|
+
/* Primary color */
|
|
192
|
+
--fe-color-primary: #f472b6; /* pink-400 */
|
|
193
|
+
--fe-color-primary-hover: #ec4899; /* pink-500 */
|
|
194
|
+
--fe-color-primary-active: #db2777; /* pink-600 */
|
|
195
|
+
|
|
196
|
+
/* Status colors */
|
|
197
|
+
--fe-color-error: #fb7185; /* rose-400 */
|
|
198
|
+
--fe-color-warning-bg: #fff7e6;
|
|
199
|
+
--fe-color-warning-border: #ffd591;
|
|
200
|
+
|
|
201
|
+
/* Base variables */
|
|
202
|
+
--ant-color-bg-container: rgb(255 241 242);
|
|
203
|
+
--ant-color-bg-elevated: rgb(254 205 211);
|
|
204
|
+
--fe-color-text-heading: rgb(159 18 57);
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 4. Ant Design Component Override
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// 1. Configure theme tokens
|
|
212
|
+
const theme = {
|
|
213
|
+
token: {
|
|
214
|
+
colorPrimary: '#60a5fa',
|
|
215
|
+
borderRadius: 6,
|
|
216
|
+
colorBgContainer: '#ffffff',
|
|
217
|
+
colorText: 'rgba(15, 23, 42, 0.85)',
|
|
218
|
+
colorBorder: 'rgb(226, 232, 240)'
|
|
219
|
+
},
|
|
220
|
+
components: {
|
|
221
|
+
Button: {
|
|
222
|
+
colorPrimary: '#60a5fa',
|
|
223
|
+
algorithm: true // Enable algorithm
|
|
224
|
+
},
|
|
225
|
+
Input: {
|
|
226
|
+
colorBgContainer: '#ffffff',
|
|
227
|
+
activeBorderColor: '#60a5fa'
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// 2. Use theme provider
|
|
233
|
+
export function AntdProvider({ children }: PropsWithChildren) {
|
|
234
|
+
return (
|
|
235
|
+
<ConfigProvider theme={theme}>
|
|
236
|
+
{children}
|
|
237
|
+
</ConfigProvider>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Component Theme Implementation
|
|
243
|
+
|
|
244
|
+
### 1. Menu Component Theme
|
|
245
|
+
|
|
246
|
+
```css
|
|
247
|
+
/* styles/css/antd-themes/menu/_default.css */
|
|
248
|
+
.fe-theme {
|
|
249
|
+
&.ant-menu-css-var {
|
|
250
|
+
/* Base dimensions */
|
|
251
|
+
--fe-menu-item-height: 40px;
|
|
252
|
+
--fe-menu-item-padding-inline: 16px;
|
|
253
|
+
--fe-menu-radius-item: 8px;
|
|
254
|
+
|
|
255
|
+
/* Text colors */
|
|
256
|
+
--fe-menu-color-item-text: rgb(var(--text-primary));
|
|
257
|
+
--fe-menu-color-item-text-hover: rgb(var(--text-primary));
|
|
258
|
+
--fe-menu-color-group-title: rgb(var(--text-secondary));
|
|
259
|
+
|
|
260
|
+
/* Selected and active states */
|
|
261
|
+
--fe-menu-color-item-text-selected: rgb(var(--color-brand));
|
|
262
|
+
--fe-menu-color-item-bg-selected: rgba(var(--color-brand), 0.1);
|
|
263
|
+
|
|
264
|
+
/* Background colors */
|
|
265
|
+
--fe-menu-color-item-bg: rgb(var(--color-bg-base));
|
|
266
|
+
--fe-menu-color-item-bg-hover: rgba(var(--text-primary), 0.06);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 2. Table Component Theme
|
|
272
|
+
|
|
273
|
+
```css
|
|
274
|
+
/* styles/css/antd-themes/table/_default.css */
|
|
275
|
+
.fe-theme {
|
|
276
|
+
&.ant-table-css-var {
|
|
277
|
+
/* Table style variables */
|
|
278
|
+
--fe-table-header-bg: var(--fe-color-bg-elevated);
|
|
279
|
+
--fe-table-row-hover-bg: var(--fe-color-primary-bg);
|
|
280
|
+
--fe-table-border-color: var(--fe-color-border);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 3. Component Theme Usage
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
// 1. Use theme variables in components
|
|
289
|
+
function ThemedButton({ children }: PropsWithChildren) {
|
|
290
|
+
return (
|
|
291
|
+
<button
|
|
292
|
+
className="
|
|
293
|
+
bg-primary
|
|
294
|
+
hover:bg-primary-hover
|
|
295
|
+
active:bg-primary-active
|
|
296
|
+
text-white
|
|
297
|
+
px-4
|
|
298
|
+
py-2
|
|
299
|
+
rounded
|
|
300
|
+
"
|
|
301
|
+
>
|
|
302
|
+
{children}
|
|
303
|
+
</button>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// 2. Theme-aware component
|
|
308
|
+
function ThemedCard({ children }: PropsWithChildren) {
|
|
309
|
+
return (
|
|
310
|
+
<div className="
|
|
311
|
+
bg-bg-container
|
|
312
|
+
dark:bg-bg-elevated
|
|
313
|
+
text-text
|
|
314
|
+
dark:text-text-light
|
|
315
|
+
border
|
|
316
|
+
border-border
|
|
317
|
+
rounded-lg
|
|
318
|
+
p-4
|
|
319
|
+
">
|
|
320
|
+
{children}
|
|
321
|
+
</div>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Theme Switching and State Management
|
|
327
|
+
|
|
328
|
+
### 1. Theme Provider
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// 1. Theme configuration provider
|
|
332
|
+
export function ThemeProvider({ children }: PropsWithChildren) {
|
|
333
|
+
return (
|
|
334
|
+
<NextThemesProvider
|
|
335
|
+
attribute={themeConfig.domAttribute}
|
|
336
|
+
defaultTheme={themeConfig.defaultTheme}
|
|
337
|
+
themes={themeConfig.supportedThemes}
|
|
338
|
+
enableSystem
|
|
339
|
+
>
|
|
340
|
+
<AntdThemeProvider theme={themeConfig.antdTheme}>
|
|
341
|
+
{children}
|
|
342
|
+
</AntdThemeProvider>
|
|
343
|
+
</NextThemesProvider>
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// 2. Theme switcher
|
|
348
|
+
export function ThemeSwitcher() {
|
|
349
|
+
const { theme, setTheme } = useTheme();
|
|
350
|
+
|
|
351
|
+
return (
|
|
352
|
+
<Select
|
|
353
|
+
value={theme}
|
|
354
|
+
onChange={setTheme}
|
|
355
|
+
options={[
|
|
356
|
+
{ value: 'light', label: t('theme.light') },
|
|
357
|
+
{ value: 'dark', label: t('theme.dark') },
|
|
358
|
+
{ value: 'pink', label: t('theme.pink') },
|
|
359
|
+
{ value: 'system', label: t('theme.system') }
|
|
360
|
+
]}
|
|
361
|
+
/>
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 2. Theme State Management
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
// 1. Theme Store
|
|
370
|
+
@injectable()
|
|
371
|
+
export class ThemeStore extends StoreInterface<ThemeState> {
|
|
372
|
+
constructor() {
|
|
373
|
+
super(() => ({
|
|
374
|
+
mode: themeConfig.defaultTheme,
|
|
375
|
+
systemTheme: 'light'
|
|
376
|
+
}));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
setTheme(mode: ThemeMode) {
|
|
380
|
+
this.emit({ ...this.state, mode });
|
|
381
|
+
localStorage.setItem(themeConfig.storageKey, mode);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Watch system theme changes
|
|
385
|
+
watchSystemTheme() {
|
|
386
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
387
|
+
const handler = (e: MediaQueryListEvent) => {
|
|
388
|
+
this.emit({
|
|
389
|
+
...this.state,
|
|
390
|
+
systemTheme: e.matches ? 'dark' : 'light'
|
|
391
|
+
});
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
mediaQuery.addEventListener('change', handler);
|
|
395
|
+
return () => mediaQuery.removeEventListener('change', handler);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// 2. Use in components
|
|
400
|
+
function ThemeAwareComponent() {
|
|
401
|
+
const themeStore = useIOC(ThemeStore);
|
|
402
|
+
const theme = useStore(themeStore, state => state.mode);
|
|
403
|
+
const systemTheme = useStore(themeStore, state => state.systemTheme);
|
|
404
|
+
|
|
405
|
+
const actualTheme = theme === 'system' ? systemTheme : theme;
|
|
406
|
+
|
|
407
|
+
return (
|
|
408
|
+
<div className={`theme-${actualTheme}`}>
|
|
409
|
+
{/* Component content */}
|
|
410
|
+
</div>
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Best Practices and Examples
|
|
416
|
+
|
|
417
|
+
### 1. Theme Variable Naming Conventions
|
|
418
|
+
|
|
419
|
+
```css
|
|
420
|
+
/* ✅ Good naming conventions */
|
|
421
|
+
--fe-color-primary
|
|
422
|
+
--fe-color-text
|
|
423
|
+
--fe-spacing-lg
|
|
424
|
+
--fe-radius-sm
|
|
425
|
+
|
|
426
|
+
/* ❌ Bad naming conventions */
|
|
427
|
+
--primary
|
|
428
|
+
--text
|
|
429
|
+
--large-spacing
|
|
430
|
+
--small-radius
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 2. Theme Style Organization
|
|
434
|
+
|
|
435
|
+
```
|
|
436
|
+
styles/
|
|
437
|
+
css/
|
|
438
|
+
antd-themes/ # Ant Design themes
|
|
439
|
+
_common/ # Common variables
|
|
440
|
+
_default.css # Default theme
|
|
441
|
+
dark.css # Dark theme
|
|
442
|
+
pink.css # Pink theme
|
|
443
|
+
menu/ # Menu component theme
|
|
444
|
+
table/ # Table component theme
|
|
445
|
+
themes/ # Custom themes
|
|
446
|
+
default.css
|
|
447
|
+
dark.css
|
|
448
|
+
pink.css
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### 3. Responsive Theme
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
454
|
+
// 1. Use Tailwind's responsive theme
|
|
455
|
+
function ResponsiveCard() {
|
|
456
|
+
return (
|
|
457
|
+
<div className="
|
|
458
|
+
bg-white
|
|
459
|
+
dark:bg-gray-800
|
|
460
|
+
md:p-6
|
|
461
|
+
lg:p-8
|
|
462
|
+
rounded-lg
|
|
463
|
+
shadow-sm
|
|
464
|
+
dark:shadow-gray-700
|
|
465
|
+
">
|
|
466
|
+
{/* Card content */}
|
|
467
|
+
</div>
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// 2. Use media queries
|
|
472
|
+
const styles = css`
|
|
473
|
+
@media (prefers-color-scheme: dark) {
|
|
474
|
+
:root {
|
|
475
|
+
--fe-color-bg: #1a1a1a;
|
|
476
|
+
--fe-color-text: #ffffff;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
@media (prefers-color-scheme: light) {
|
|
481
|
+
:root {
|
|
482
|
+
--fe-color-bg: #ffffff;
|
|
483
|
+
--fe-color-text: #1a1a1a;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
`;
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### 4. Theme Transition Animation
|
|
490
|
+
|
|
491
|
+
```css
|
|
492
|
+
/* Add theme transition animation */
|
|
493
|
+
:root {
|
|
494
|
+
--transition-duration: 200ms;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
* {
|
|
498
|
+
transition:
|
|
499
|
+
background-color var(--transition-duration) ease,
|
|
500
|
+
color var(--transition-duration) ease,
|
|
501
|
+
border-color var(--transition-duration) ease;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/* Disable transition for specific elements */
|
|
505
|
+
.no-theme-transition {
|
|
506
|
+
transition: none !important;
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## Summary
|
|
511
|
+
|
|
512
|
+
The project's theme system follows these principles:
|
|
513
|
+
|
|
514
|
+
1. **Variable System**:
|
|
515
|
+
- Unified variable naming conventions
|
|
516
|
+
- Hierarchical variable organization
|
|
517
|
+
- Complete type definitions
|
|
518
|
+
|
|
519
|
+
2. **Component Support**:
|
|
520
|
+
- Component-level theme variables
|
|
521
|
+
- Responsive theme support
|
|
522
|
+
- Smooth theme switching
|
|
523
|
+
|
|
524
|
+
3. **Extensibility**:
|
|
525
|
+
- Support for custom themes
|
|
526
|
+
- Plugin-based theme system
|
|
527
|
+
- Component-level theme extensions
|
|
528
|
+
|
|
529
|
+
4. **Best Practices**:
|
|
530
|
+
- Clear file organization
|
|
531
|
+
- Responsive design
|
|
532
|
+
- Performance optimization
|