@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
|
+
# 主题系统开发指南
|
|
2
|
+
|
|
3
|
+
## 目录
|
|
4
|
+
|
|
5
|
+
1. [主题系统概述](#主题系统概述)
|
|
6
|
+
2. [主题变量和样式系统](#主题变量和样式系统)
|
|
7
|
+
3. [组件主题实现](#组件主题实现)
|
|
8
|
+
4. [主题切换和状态管理](#主题切换和状态管理)
|
|
9
|
+
5. [最佳实践和示例](#最佳实践和示例)
|
|
10
|
+
|
|
11
|
+
## 主题系统概述
|
|
12
|
+
|
|
13
|
+
### 1. 主题架构
|
|
14
|
+
|
|
15
|
+
项目采用分层的主题系统设计:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
样式层 组件层
|
|
19
|
+
┌──────────────┐ ┌──────────────┐
|
|
20
|
+
│ CSS 变量 │ │ 主题提供者 │
|
|
21
|
+
├──────────────┤ ├──────────────┤
|
|
22
|
+
│ 主题样式 │ ◄─────┤ 主题消费者 │
|
|
23
|
+
├──────────────┤ ├──────────────┤
|
|
24
|
+
│ 组件样式 │ │ 主题切换器 │
|
|
25
|
+
└──────────────┘ └──────────────┘
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. 主题类型
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// config/theme.ts
|
|
32
|
+
export const themeConfig = {
|
|
33
|
+
// 支持的主题
|
|
34
|
+
supportedThemes: ['light', 'dark', 'pink'] as const,
|
|
35
|
+
defaultTheme: 'system',
|
|
36
|
+
|
|
37
|
+
// DOM 属性
|
|
38
|
+
domAttribute: 'data-theme',
|
|
39
|
+
|
|
40
|
+
// 存储键
|
|
41
|
+
storageKey: 'theme'
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// 主题类型定义
|
|
45
|
+
export type ThemeMode = (typeof themeConfig.supportedThemes)[number];
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 主题变量和样式系统
|
|
49
|
+
|
|
50
|
+
### 1. 基础变量定义
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
/* styles/css/antd-themes/_common/_default.css */
|
|
54
|
+
html,
|
|
55
|
+
.fe-theme {
|
|
56
|
+
/* 主色调相关变量 */
|
|
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
|
+
/* 状态色 */
|
|
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
|
+
/* 基础变量 */
|
|
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. 暗色主题变量
|
|
79
|
+
|
|
80
|
+
```css
|
|
81
|
+
/* styles/css/antd-themes/_common/dark.css */
|
|
82
|
+
[data-theme='dark'],
|
|
83
|
+
[data-theme='dark'] .fe-theme {
|
|
84
|
+
/* 主色调 - 紫色主题 */
|
|
85
|
+
--fe-color-primary: #9333ea;
|
|
86
|
+
--fe-color-primary-hover: #a855f7;
|
|
87
|
+
--fe-color-primary-active: #7e22ce;
|
|
88
|
+
|
|
89
|
+
/* 基础变量覆盖 */
|
|
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. 粉色主题变量
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
/* styles/css/antd-themes/_common/pink.css */
|
|
102
|
+
[data-theme='pink'],
|
|
103
|
+
[data-theme='pink'] .fe-theme {
|
|
104
|
+
/* 主色调 - 玫瑰色主题 */
|
|
105
|
+
--fe-color-primary: #f472b6;
|
|
106
|
+
--fe-color-primary-hover: #ec4899;
|
|
107
|
+
--fe-color-primary-active: #db2777;
|
|
108
|
+
|
|
109
|
+
/* 基础变量覆盖 */
|
|
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 主题系统
|
|
118
|
+
|
|
119
|
+
### 1. 基础主题变量
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
/* styles/css/antd-themes/_common/_default.css */
|
|
123
|
+
html,
|
|
124
|
+
.fe-theme {
|
|
125
|
+
/* Antd 主色调相关变量 - 浅蓝色主题 */
|
|
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
|
+
/* 状态色 */
|
|
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 基础变量 */
|
|
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 组件通用变量 */
|
|
145
|
+
--fe-line-width: 1px;
|
|
146
|
+
--fe-border-radius: 6px;
|
|
147
|
+
--fe-motion-duration-mid: 0.2s;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 2. 暗色主题组件变量
|
|
152
|
+
|
|
153
|
+
```css
|
|
154
|
+
/* styles/css/antd-themes/_common/dark.css */
|
|
155
|
+
[data-theme='dark'] {
|
|
156
|
+
/* Input 组件变量 */
|
|
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 组件变量 */
|
|
165
|
+
.ant-btn-css-var {
|
|
166
|
+
/* 紫色主题 */
|
|
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
|
+
/* 默认按钮 */
|
|
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 组件变量 */
|
|
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. 粉色主题组件变量
|
|
187
|
+
|
|
188
|
+
```css
|
|
189
|
+
/* styles/css/antd-themes/_common/pink.css */
|
|
190
|
+
[data-theme='pink'] {
|
|
191
|
+
/* 主色调 */
|
|
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
|
+
/* 状态色 */
|
|
197
|
+
--fe-color-error: #fb7185; /* rose-400 */
|
|
198
|
+
--fe-color-warning-bg: #fff7e6;
|
|
199
|
+
--fe-color-warning-border: #ffd591;
|
|
200
|
+
|
|
201
|
+
/* 基础变量 */
|
|
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 组件覆盖
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// 1. 配置主题令牌
|
|
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 // 启用算法
|
|
224
|
+
},
|
|
225
|
+
Input: {
|
|
226
|
+
colorBgContainer: '#ffffff',
|
|
227
|
+
activeBorderColor: '#60a5fa'
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// 2. 使用主题提供者
|
|
233
|
+
export function AntdProvider({ children }: PropsWithChildren) {
|
|
234
|
+
return (
|
|
235
|
+
<ConfigProvider theme={theme}>
|
|
236
|
+
{children}
|
|
237
|
+
</ConfigProvider>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## 组件主题实现
|
|
243
|
+
|
|
244
|
+
### 1. 菜单组件主题
|
|
245
|
+
|
|
246
|
+
```css
|
|
247
|
+
/* styles/css/antd-themes/menu/_default.css */
|
|
248
|
+
.fe-theme {
|
|
249
|
+
&.ant-menu-css-var {
|
|
250
|
+
/* 基础尺寸 */
|
|
251
|
+
--fe-menu-item-height: 40px;
|
|
252
|
+
--fe-menu-item-padding-inline: 16px;
|
|
253
|
+
--fe-menu-radius-item: 8px;
|
|
254
|
+
|
|
255
|
+
/* 文字颜色 */
|
|
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
|
+
/* 选中和激活状态 */
|
|
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
|
+
/* 背景颜色 */
|
|
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. 表格组件主题
|
|
272
|
+
|
|
273
|
+
```css
|
|
274
|
+
/* styles/css/antd-themes/table/_default.css */
|
|
275
|
+
.fe-theme {
|
|
276
|
+
&.ant-table-css-var {
|
|
277
|
+
/* 表格样式变量 */
|
|
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. 组件主题使用
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
// 1. 在组件中使用主题变量
|
|
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. 主题感知组件
|
|
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
|
+
## 主题切换和状态管理
|
|
327
|
+
|
|
328
|
+
### 1. 主题提供者
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// 1. 主题配置提供者
|
|
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. 主题切换器
|
|
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. 主题状态管理
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
// 1. 主题 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
|
+
// 监听系统主题变化
|
|
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. 在组件中使用
|
|
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
|
+
{/* 组件内容 */}
|
|
410
|
+
</div>
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## 最佳实践和示例
|
|
416
|
+
|
|
417
|
+
### 1. 主题变量命名规范
|
|
418
|
+
|
|
419
|
+
```css
|
|
420
|
+
/* ✅ 好的命名规范 */
|
|
421
|
+
--fe-color-primary
|
|
422
|
+
--fe-color-text
|
|
423
|
+
--fe-spacing-lg
|
|
424
|
+
--fe-radius-sm
|
|
425
|
+
|
|
426
|
+
/* ❌ 不好的命名规范 */
|
|
427
|
+
--primary
|
|
428
|
+
--text
|
|
429
|
+
--large-spacing
|
|
430
|
+
--small-radius
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 2. 主题样式组织
|
|
434
|
+
|
|
435
|
+
```
|
|
436
|
+
styles/
|
|
437
|
+
css/
|
|
438
|
+
antd-themes/ # Ant Design 主题
|
|
439
|
+
_common/ # 通用变量
|
|
440
|
+
_default.css # 默认主题
|
|
441
|
+
dark.css # 暗色主题
|
|
442
|
+
pink.css # 粉色主题
|
|
443
|
+
menu/ # 菜单组件主题
|
|
444
|
+
table/ # 表格组件主题
|
|
445
|
+
themes/ # 自定义主题
|
|
446
|
+
default.css
|
|
447
|
+
dark.css
|
|
448
|
+
pink.css
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### 3. 响应式主题
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
454
|
+
// 1. 使用 Tailwind 的响应式主题
|
|
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
|
+
{/* 卡片内容 */}
|
|
467
|
+
</div>
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// 2. 使用媒体查询
|
|
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. 主题切换动画
|
|
490
|
+
|
|
491
|
+
```css
|
|
492
|
+
/* 添加主题切换动画 */
|
|
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
|
+
/* 禁用特定元素的过渡效果 */
|
|
505
|
+
.no-theme-transition {
|
|
506
|
+
transition: none !important;
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## 总结
|
|
511
|
+
|
|
512
|
+
项目的主题系统遵循以下原则:
|
|
513
|
+
|
|
514
|
+
1. **变量系统**:
|
|
515
|
+
- 统一的变量命名规范
|
|
516
|
+
- 层次化的变量组织
|
|
517
|
+
- 完整的类型定义
|
|
518
|
+
|
|
519
|
+
2. **组件支持**:
|
|
520
|
+
- 组件级别的主题变量
|
|
521
|
+
- 响应式的主题支持
|
|
522
|
+
- 平滑的主题切换
|
|
523
|
+
|
|
524
|
+
3. **可扩展性**:
|
|
525
|
+
- 支持自定义主题
|
|
526
|
+
- 插件化的主题系统
|
|
527
|
+
- 组件级别的主题扩展
|
|
528
|
+
|
|
529
|
+
4. **最佳实践**:
|
|
530
|
+
- 清晰的文件组织
|
|
531
|
+
- 响应式设计
|
|
532
|
+
- 性能优化
|