|
@@ -0,0 +1,250 @@
|
|
|
+# 主题管理使用指南
|
|
|
+
|
|
|
+## 概述
|
|
|
+
|
|
|
+主题信息已集成到 Redux 状态管理中,可以在任何组件中访问当前主题类型和主题配置。
|
|
|
+
|
|
|
+## 文件结构
|
|
|
+
|
|
|
+```
|
|
|
+src/
|
|
|
+├── states/
|
|
|
+│ └── themeSlice.ts # 主题状态管理
|
|
|
+├── themes/
|
|
|
+│ ├── lightTheme.ts # 浅色主题配置
|
|
|
+│ ├── darkTheme.ts # 深色主题配置
|
|
|
+│ └── index.ts # 主题导出
|
|
|
+└── app.tsx # 主题应用入口
|
|
|
+```
|
|
|
+
|
|
|
+## 功能特性
|
|
|
+
|
|
|
+### 1. 主题持久化
|
|
|
+
|
|
|
+- 主题选择自动保存到 `localStorage`
|
|
|
+- 刷新页面后保持用户的主题选择
|
|
|
+- 默认主题:深色主题 (dark)
|
|
|
+
|
|
|
+### 2. 全局访问
|
|
|
+
|
|
|
+- 任何组件都可以通过 Redux 访问主题信息
|
|
|
+- 支持获取主题类型 (`'light'` | `'dark'`)
|
|
|
+- 支持获取完整的主题配置对象
|
|
|
+
|
|
|
+### 3. 主题切换
|
|
|
+
|
|
|
+- 提供 `setTheme` action 设置特定主题
|
|
|
+- 提供 `toggleTheme` action 在两个主题间切换
|
|
|
+
|
|
|
+## 在组件中使用主题
|
|
|
+
|
|
|
+### 方式 1: 获取主题类型(推荐用于条件渲染)
|
|
|
+
|
|
|
+```tsx
|
|
|
+import { useAppSelector } from '@/states/store';
|
|
|
+
|
|
|
+function MyComponent() {
|
|
|
+ // 获取当前主题类型
|
|
|
+ const themeType = useAppSelector((state) => state.theme.themeType);
|
|
|
+
|
|
|
+ // 根据主题类型动态加载图标
|
|
|
+ const iconPath =
|
|
|
+ themeType === 'dark' ? '/icons/dark/report.svg' : '/icons/light/report.svg';
|
|
|
+
|
|
|
+ return <img src={iconPath} alt="report" />;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 方式 2: 获取完整主题配置(推荐用于样式定制)
|
|
|
+
|
|
|
+```tsx
|
|
|
+import { useAppSelector } from '@/states/store';
|
|
|
+
|
|
|
+function MyComponent() {
|
|
|
+ // 获取完整的主题配置
|
|
|
+ const currentTheme = useAppSelector((state) => state.theme.currentTheme);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ backgroundColor: currentTheme.token.colorBgContainer,
|
|
|
+ color: currentTheme.token.colorText,
|
|
|
+ borderColor: currentTheme.token.colorPrimary,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 内容区域
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 方式 3: 同时获取主题类型和配置
|
|
|
+
|
|
|
+```tsx
|
|
|
+import { useAppSelector } from '@/states/store';
|
|
|
+
|
|
|
+function MyComponent() {
|
|
|
+ const { themeType, currentTheme } = useAppSelector((state) => state.theme);
|
|
|
+
|
|
|
+ const isDark = themeType === 'dark';
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <p>当前主题: {isDark ? '深色' : '浅色'}</p>
|
|
|
+ <div style={{ color: currentTheme.token.colorPrimary }}>主题色文字</div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 切换主题
|
|
|
+
|
|
|
+### 方式 1: 设置特定主题
|
|
|
+
|
|
|
+```tsx
|
|
|
+import { useAppDispatch } from '@/states/store';
|
|
|
+import { setTheme } from '@/states/themeSlice';
|
|
|
+
|
|
|
+function ThemeSelector() {
|
|
|
+ const dispatch = useAppDispatch();
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <button onClick={() => dispatch(setTheme('light'))}>浅色主题</button>
|
|
|
+ <button onClick={() => dispatch(setTheme('dark'))}>深色主题</button>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 方式 2: 切换主题
|
|
|
+
|
|
|
+```tsx
|
|
|
+import { useAppDispatch } from '@/states/store';
|
|
|
+import { toggleTheme } from '@/states/themeSlice';
|
|
|
+
|
|
|
+function ThemeToggle() {
|
|
|
+ const dispatch = useAppDispatch();
|
|
|
+
|
|
|
+ return <button onClick={() => dispatch(toggleTheme())}>切换主题</button>;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 实际应用场景
|
|
|
+
|
|
|
+### 场景 1: 根据主题动态加载图标
|
|
|
+
|
|
|
+```tsx
|
|
|
+import { useAppSelector } from '@/states/store';
|
|
|
+
|
|
|
+function ReportIcon() {
|
|
|
+ const themeType = useAppSelector((state) => state.theme.themeType);
|
|
|
+
|
|
|
+ // 根据主题类型选择对应的图标路径
|
|
|
+ const iconBasePath = `src/assets/Icons/base/module-patient/theme-${themeType}`;
|
|
|
+
|
|
|
+ return (
|
|
|
+ <img src={`${iconBasePath}/1x/report.svg`} alt="report" className="icon" />
|
|
|
+ );
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 场景 2: 主题感知的组件样式
|
|
|
+
|
|
|
+```tsx
|
|
|
+import { useAppSelector } from '@/states/store';
|
|
|
+
|
|
|
+function Card({ children }) {
|
|
|
+ const { themeType, currentTheme } = useAppSelector((state) => state.theme);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div
|
|
|
+ className={`card card-${themeType}`}
|
|
|
+ style={{
|
|
|
+ backgroundColor: currentTheme.token.colorBgContainer,
|
|
|
+ borderColor: currentTheme.token.colorPrimary,
|
|
|
+ color: currentTheme.token.colorText,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {children}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 场景 3: 条件渲染不同的组件
|
|
|
+
|
|
|
+```tsx
|
|
|
+import { useAppSelector } from '@/states/store';
|
|
|
+
|
|
|
+function ThemedLogo() {
|
|
|
+ const themeType = useAppSelector((state) => state.theme.themeType);
|
|
|
+
|
|
|
+ return themeType === 'dark' ? <DarkLogo /> : <LightLogo />;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 可用的主题 Token
|
|
|
+
|
|
|
+### 常用颜色 Token
|
|
|
+
|
|
|
+```typescript
|
|
|
+currentTheme.token.colorPrimary; // 主色调
|
|
|
+currentTheme.token.colorBgContainer; // 容器背景色
|
|
|
+currentTheme.token.colorBgLayout; // 全局背景色
|
|
|
+currentTheme.token.colorText; // 文字颜色
|
|
|
+currentTheme.token.buttonBgHover; // 按钮悬停背景色
|
|
|
+```
|
|
|
+
|
|
|
+### 浅色主题 (lightTheme)
|
|
|
+
|
|
|
+- `colorPrimary`: `#1DA57A`
|
|
|
+- `colorBgContainer`: `#FFFFFF`
|
|
|
+- `colorText`: `#000000`
|
|
|
+- `colorBgLayout`: `#FAFAFA`
|
|
|
+
|
|
|
+### 深色主题 (darkTheme)
|
|
|
+
|
|
|
+- `colorPrimary`: `#1DA57A`
|
|
|
+- `colorBgContainer`: `#1F1F1F`
|
|
|
+- `colorText`: `#E0E0E0`
|
|
|
+- `colorBgLayout`: `#121212`
|
|
|
+
|
|
|
+## 类型定义
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 主题类型
|
|
|
+type ThemeType = 'light' | 'dark';
|
|
|
+
|
|
|
+// 主题配置类型
|
|
|
+type ThemeConfig = typeof lightTheme;
|
|
|
+
|
|
|
+// Redux 状态中的主题状态
|
|
|
+interface ThemeState {
|
|
|
+ themeType: ThemeType;
|
|
|
+ currentTheme: ThemeConfig;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 最佳实践
|
|
|
+
|
|
|
+1. **优先使用主题类型判断**: 对于简单的条件渲染(如图标切换),直接使用 `themeType` 即可
|
|
|
+2. **使用主题配置定制样式**: 需要精确控制样式时,使用 `currentTheme.token` 中的值
|
|
|
+3. **避免硬编码颜色**: 所有颜色都应该从主题配置中获取,确保主题切换时样式一致
|
|
|
+4. **组件解耦**: 不要在组件内部导入 `lightTheme` 或 `darkTheme`,始终从 Redux 获取
|
|
|
+
|
|
|
+## 注意事项
|
|
|
+
|
|
|
+- 主题切换是全局的,会影响所有使用 Ant Design `ConfigProvider` 的组件
|
|
|
+- CSS 变量已自动注入到 `:root`,可在 Tailwind CSS 中使用
|
|
|
+- 主题信息会自动保存到 localStorage,无需手动处理
|
|
|
+- 默认主题为深色主题 (dark)
|
|
|
+
|
|
|
+## 调试技巧
|
|
|
+
|
|
|
+在浏览器控制台中查看当前主题状态:
|
|
|
+
|
|
|
+```javascript
|
|
|
+// 在开发环境中,store 已暴露到 window
|
|
|
+window.store.getState().theme;
|
|
|
+```
|