feat(theme): implement comprehensive theme management system

Add full theme support with light, dark, and system modes, including:
- Theme store using Pinia for state management
- useTheme composable for reactive theme handling
- Theme setting UI in settings page
- Enhanced CSS variable system with Tailwind integration
- IPC communication for theme persistence
- Internationalization support for theme texts
- System theme detection and auto-switching

The implementation follows ClawX's architecture while adapting to Vue 3 and zn-ai's existing infrastructure.
This commit is contained in:
duanshuwen
2026-04-08 23:46:41 +08:00
parent 3ef3392808
commit a8bfbff0e9
12 changed files with 1450 additions and 326 deletions

View File

@@ -0,0 +1,697 @@
# ClawX主题设置功能分析报告与zn-ai迁移开发计划
## 一、ClawX项目主题设置功能全面分析报告
### 1. 架构概述
ClawX项目采用**现代化的主题管理系统**支持light、dark、system三种主题模式通过CSS变量、Tailwind CSS和状态管理实现灵活的主题切换功能。
### 2. 核心组件架构
| 组件 | 文件路径 | 功能描述 |
|------|----------|---------|
| **设置页面UI** | `src/pages/Settings/index.tsx` | 主题设置界面包含light/dark/system三个按钮 |
| **状态管理Store** | `src/stores/settings.ts` | Zustand状态管理包含theme状态和setTheme方法 |
| **主题应用逻辑** | `src/App.tsx` | 监听theme变化在html元素上应用对应的CSS类 |
| **CSS变量定义** | `src/styles/globals.css` | 定义:root和.dark类的CSS变量 |
| **Tailwind配置** | `tailwind.config.js` | 配置`darkMode: ['class']`支持CSS类切换 |
| **主进程API** | `electron/api/routes/settings.ts` | 提供`/api/settings/theme`接口处理主题设置 |
| **配置持久化** | `electron/utils/store.ts` | 使用electron-store持久化主题配置 |
| **国际化文本** | `src/i18n/locales/*/settings.json` | 主题设置的本地化文本 |
### 3. 技术实现细节
#### 3.1 状态管理 (Zustand)
```typescript
// src/stores/settings.ts 关键代码
interface SettingsState {
theme: 'light' | 'dark' | 'system';
// ...其他设置
setTheme: (theme: 'light' | 'dark' | 'system') => void;
}
export const useSettingsStore = create<SettingsState>()(
persist(
(set) => ({
theme: 'system',
setTheme: (theme) => {
set({ theme });
// 通知主进程更新配置
hostApiFetch('/api/settings/theme', { method: 'POST', body: JSON.stringify({ theme }) });
},
}),
{
name: 'settings-storage',
partialize: (state) => ({ theme: state.theme }),
}
)
);
```
#### 3.2 主题应用逻辑 (React Effect)
```typescript
// src/App.tsx 关键代码
export function App() {
const { theme } = useSettingsStore();
useEffect(() => {
const htmlEl = document.documentElement;
// 移除现有主题类
htmlEl.classList.remove('light', 'dark');
if (theme === 'system') {
// 系统主题检测
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const systemTheme = mediaQuery.matches ? 'dark' : 'light';
htmlEl.classList.add(systemTheme);
// 监听系统主题变化
const handler = (e: MediaQueryListEvent) => {
htmlEl.classList.remove('light', 'dark');
htmlEl.classList.add(e.matches ? 'dark' : 'light');
};
mediaQuery.addEventListener('change', handler);
return () => mediaQuery.removeEventListener('change', handler);
} else {
htmlEl.classList.add(theme);
}
}, [theme]);
return <Router />;
}
```
#### 3.3 CSS变量定义
```css
/* src/styles/globals.css 关键代码 */
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
/* ...更多变量 */
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 47.4% 11.2%;
/* ...深色模式变量 */
}
```
#### 3.4 Tailwind配置
```javascript
// tailwind.config.js 关键配置
module.exports = {
darkMode: ['class'], // 通过CSS类控制深色模式
theme: {
extend: {
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
card: 'hsl(var(--card))',
'card-foreground': 'hsl(var(--card-foreground))',
primary: 'hsl(var(--primary))',
'primary-foreground': 'hsl(var(--primary-foreground))',
// ...映射CSS变量到Tailwind颜色
},
},
},
};
```
#### 3.5 设置页面UI
```tsx
// src/pages/Settings/index.tsx 主题设置部分
const ThemeSection = () => {
const { t } = useTranslation();
const { theme, setTheme } = useSettingsStore();
const themes = [
{ id: 'light', label: t('settings.theme.light'), icon: Sun },
{ id: 'dark', label: t('settings.theme.dark'), icon: Moon },
{ id: 'system', label: t('settings.theme.system'), icon: Monitor },
] as const;
return (
<div className="space-y-4">
<h3 className="text-lg font-medium">{t('settings.theme.title')}</h3>
<p className="text-sm text-muted-foreground">
{t('settings.theme.description')}
</p>
<div className="flex gap-2">
{themes.map(({ id, label, icon: Icon }) => (
<Button
key={id}
variant={theme === id ? 'default' : 'outline'}
onClick={() => setTheme(id)}
className="flex-1 h-auto py-3"
>
<Icon className="h-5 w-5 mr-2" />
{label}
</Button>
))}
</div>
</div>
);
};
```
#### 3.6 主进程API
```typescript
// electron/api/routes/settings.ts 关键代码
router.post('/theme', async (req, res) => {
const { theme } = req.body;
// 验证主题值
if (!['light', 'dark', 'system'].includes(theme)) {
return res.status(400).json({ error: 'Invalid theme' });
}
try {
// 存储到electron-store
await store.set('settings.theme', theme);
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: 'Failed to save theme' });
}
});
```
### 4. 工作流程
#### 4.1 主题切换流程
```
用户点击主题按钮 → 调用setTheme更新Zustand状态 →
状态更新触发App.tsx中的useEffect → 在html元素上添加对应CSS类 →
同时调用hostApiFetch通知主进程 → 主进程存储配置到electron-store →
CSS变量和Tailwind样式自动应用新主题
```
#### 4.2 系统主题检测流程
```
用户选择system模式 → useEffect检测系统主题偏好 →
监听prefers-color-scheme媒体查询 → 系统主题变化时自动更新CSS类 →
用户无需手动切换,主题随系统设置变化
```
### 5. 设计模式与最佳实践
#### 5.1 关注点分离
- **UI层**:设置页面只负责显示和用户交互
- **状态层**Zustand管理主题状态和业务逻辑
- **样式层**CSS变量和Tailwind处理主题样式
- **持久化层**electron-store负责配置存储
- **系统集成层**主进程API处理进程间通信
#### 5.2 可扩展性设计
- **主题变量系统**CSS变量易于扩展新主题
- **插件化架构**:可轻松添加新的主题模式
- **响应式设计**:主题切换不影响应用功能
#### 5.3 用户体验优化
- **即时反馈**:主题切换无延迟
- **系统集成**:支持跟随系统主题
- **状态持久化**:记住用户偏好
- **无障碍支持**:高对比度主题选项
### 6. 技术栈总结
| 技术 | 用途 | 优势 |
|------|------|------|
| **Zustand** | 状态管理 | 轻量级、类型安全、支持持久化 |
| **Tailwind CSS** | 样式系统 | 实用优先、主题变量集成 |
| **CSS变量** | 主题变量 | 动态更新、性能优化 |
| **electron-store** | 配置存储 | 简单易用、跨平台 |
| **React Hooks** | 逻辑封装 | 响应式、可组合 |
| **TypeScript** | 类型安全 | 编译时检查、更好的开发体验 |
---
## 二、zn-ai项目现有主题实现分析
### 1. 现有架构
#### 1.1 核心组件
| 组件 | 文件路径 | 功能描述 |
|------|----------|---------|
| **主题服务** | `electron/service/theme-service/index.ts` | 主题切换服务处理IPC通信 |
| **配置服务** | `electron/service/config-service/index.ts` | 配置存储管理使用config.json文件 |
| **CSS变量系统** | `src/styles/theme/` | 包含light.css、dark.css、index.css |
| **主题常量** | `src/lib/constants.ts` | 定义CONFIG_KEYS.THEME_MODE等常量 |
| **样式入口** | `src/styles/index.css` | 导入主题样式 |
#### 1.2 现有实现特点
-**基础主题服务**theme-service处理主题切换IPC通信
-**配置管理**config-service提供配置存储
-**CSS变量系统**已定义light和dark主题的CSS变量
-**主题常量**定义了THEME_MODE等配置键
-**样式组织**:主题样式文件结构清晰
#### 1.3 缺失功能
-**系统主题支持**缺少system模式无法跟随系统主题
-**用户界面**没有主题设置UI组件
-**Tailwind集成**未与Tailwind CSS深度集成
-**状态管理**:缺少前端状态管理集成
-**国际化支持**:主题文本未国际化
-**完整工作流**:主题切换流程不完整
### 2. 技术差异分析
| 功能点 | ClawX实现 | zn-ai现状 | 迁移需求 |
|--------|-----------|-----------|----------|
| **状态管理** | Zustand + persist | 无前端状态管理 | 需要集成Zustand |
| **主题模式** | light/dark/system | light/dark | 需要添加system模式 |
| **CSS系统** | CSS变量 + Tailwind | CSS变量 | 需要Tailwind集成 |
| **UI组件** | 完整的设置界面 | 无主题设置UI | 需要开发设置组件 |
| **持久化** | electron-store | config.json文件 | 需统一存储方案 |
| **系统集成** | 系统主题检测 | 无系统检测 | 需要媒体查询支持 |
| **国际化** | 多语言文本 | 无主题文本 | 需要添加翻译 |
---
## 三、zn-ai主题设置迁移开发计划
### 1. 迁移目标
#### 1.1 核心目标
1. **完整功能迁移**实现ClawX的所有主题设置功能
2. **无缝集成**与zn-ai现有架构完美融合
3. **用户体验优化**:提供流畅的主题切换体验
4. **技术债务清理**:统一主题管理方案
#### 1.2 成功指标
- [ ] 支持light、dark、system三种主题模式
- [ ] 主题切换响应时间 < 100ms
- [ ] 配置持久化成功率 100%
- [ ] 系统主题检测准确率 100%
- [ ] 用户界面友好度评分 > 4.5/5
### 2. 技术选型与架构设计
#### 2.1 技术栈保持一致
| 技术 | 选型理由 | 实施计划 |
|------|----------|----------|
| **Zustand** | 与ClawX保持一致轻量高效 | 新增依赖创建theme store |
| **CSS变量** | 已存在,需扩展 | 优化现有CSS变量定义 |
| **Tailwind集成** | 提升开发效率 | 配置darkMode和颜色映射 |
| **Vue 3 Composition API** | 适配zn-ai技术栈 | 使用Vue替代React实现 |
#### 2.2 架构设计
```
zn-ai主题系统架构
├── 前端层 (Vue 3)
│ ├── 主题设置组件 (Settings/ThemeSetting.vue)
│ ├── 主题状态管理 (stores/theme.ts)
│ ├── 主题应用逻辑 (composables/useTheme.ts)
│ └── 国际化文本 (i18n/locales/*/settings.json)
├── 样式层
│ ├── CSS变量定义 (styles/theme/)
│ ├── Tailwind配置 (tailwind.config.js)
│ └── 全局样式 (styles/index.css)
├── 服务层
│ ├── 主题服务增强 (electron/service/theme-service/)
│ ├── 配置服务集成 (electron/service/config-service/)
│ └── IPC通信优化
└── 持久化层
├── 配置文件 (userData/config.json)
└── 状态持久化 (Zustand persist)
```
### 3. 核心功能模块
#### 3.1 主题状态管理 (Vue + Zustand)
```typescript
// src/stores/theme.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface ThemeState {
theme: 'light' | 'dark' | 'system';
systemTheme: 'light' | 'dark';
setTheme: (theme: 'light' | 'dark' | 'system') => Promise<void>;
detectSystemTheme: () => 'light' | 'dark';
}
export const useThemeStore = create<ThemeState>()(
persist(
(set, get) => ({
theme: 'system',
systemTheme: 'light',
setTheme: async (theme) => {
set({ theme });
// 调用主题服务更新配置
await window.api.theme.setThemeMode(theme);
},
detectSystemTheme: () => {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
},
}),
{
name: 'theme-storage',
partialize: (state) => ({ theme: state.theme }),
}
)
);
```
#### 3.2 主题应用Composable
```typescript
// src/composables/useTheme.ts
import { useThemeStore } from '@/stores/theme';
import { watch, onMounted, onUnmounted } from 'vue';
export function useTheme() {
const store = useThemeStore();
const applyTheme = () => {
const htmlEl = document.documentElement;
htmlEl.classList.remove('light', 'dark');
let themeToApply = store.theme;
if (themeToApply === 'system') {
themeToApply = store.detectSystemTheme();
}
htmlEl.classList.add(themeToApply);
};
// 监听主题变化
watch(() => store.theme, applyTheme, { immediate: true });
// 监听系统主题变化
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handleSystemThemeChange = (e: MediaQueryListEvent) => {
if (store.theme === 'system') {
store.setSystemTheme(e.matches ? 'dark' : 'light');
applyTheme();
}
};
onMounted(() => {
mediaQuery.addEventListener('change', handleSystemThemeChange);
});
onUnmounted(() => {
mediaQuery.removeEventListener('change', handleSystemThemeChange);
});
return {
theme: store.theme,
setTheme: store.setTheme,
availableThemes: ['light', 'dark', 'system'] as const,
};
}
```
#### 3.3 主题设置组件
```vue
<!-- src/pages/setting/components/ThemeSetting/index.vue -->
<template>
<div class="theme-setting">
<h3 class="text-lg font-medium mb-4">{{ t('settings.theme.title') }}</h3>
<p class="text-sm text-gray-500 mb-6">
{{ t('settings.theme.description') }}
</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<ThemeOption
v-for="option in themeOptions"
:key="option.id"
:option="option"
:selected="theme === option.id"
@select="setTheme(option.id)"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useTheme } from '@/composables/useTheme';
import ThemeOption from './ThemeOption.vue';
const { t } = useI18n();
const { theme, setTheme } = useTheme();
const themeOptions = computed(() => [
{
id: 'light',
label: t('settings.theme.light'),
icon: 'Sun',
description: t('settings.theme.lightDescription'),
},
{
id: 'dark',
label: t('settings.theme.dark'),
icon: 'Moon',
description: t('settings.theme.darkDescription'),
},
{
id: 'system',
label: t('settings.theme.system'),
icon: 'Monitor',
description: t('settings.theme.systemDescription'),
},
]);
</script>
```
#### 3.4 Tailwind配置优化
```javascript
// tailwind.config.js
module.exports = {
darkMode: ['class'], // 启用CSS类控制的深色模式
theme: {
extend: {
colors: {
// 映射CSS变量到Tailwind
background: 'var(--bg-color)',
'background-secondary': 'var(--bg-secondary)',
foreground: 'var(--text-primary)',
'foreground-secondary': 'var(--text-secondary)',
primary: 'var(--primary-color)',
border: 'var(--border-color)',
input: 'var(--input-bg)',
},
},
},
};
```
#### 3.5 主题服务增强
```typescript
// electron/service/theme-service/index.ts 增强
import { ipcMain, BrowserWindow } from 'electron';
import { IPC_EVENTS, CONFIG_KEYS } from '@lib/constants';
import { ConfigService } from '../config-service';
export class ThemeService {
private configService: ConfigService;
constructor() {
this.configService = ConfigService.getInstance();
this.setupIpcHandlers();
}
private setupIpcHandlers() {
// 获取当前主题
ipcMain.handle(IPC_EVENTS.GET_THEME_MODE, () => {
return this.configService.get(CONFIG_KEYS.THEME_MODE);
});
// 设置主题
ipcMain.handle(IPC_EVENTS.SET_THEME_MODE, (_, theme: string) => {
if (!['light', 'dark', 'system'].includes(theme)) {
throw new Error('Invalid theme mode');
}
this.configService.set(CONFIG_KEYS.THEME_MODE, theme);
// 通知所有窗口主题已更新
BrowserWindow.getAllWindows().forEach(win => {
win.webContents.send(IPC_EVENTS.THEME_MODE_UPDATED, theme);
});
return { success: true };
});
// 检查是否为深色主题
ipcMain.handle(IPC_EVENTS.IS_DARK_THEME, () => {
const theme = this.configService.get(CONFIG_KEYS.THEME_MODE);
if (theme === 'system') {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
return theme === 'dark';
});
}
}
```
### 4. 实施路线图
#### 第一阶段:基础框架搭建 (预计1-2周)
1. **依赖安装与配置**
- 安装zustand、zustand/middleware
- 配置Tailwind支持CSS类darkMode
- 更新TypeScript类型定义
2. **状态管理集成**
- 创建theme store (src/stores/theme.ts)
- 实现主题状态持久化
- 添加IPC通信集成
3. **Composable开发**
- 创建useTheme composable
- 实现主题应用逻辑
- 添加系统主题检测
#### 第二阶段:核心功能实现 (预计2-3周)
1. **UI组件开发**
- 创建ThemeSetting组件
- 开发ThemeOption子组件
- 集成到现有设置页面
2. **样式系统优化**
- 优化CSS变量定义
- 配置Tailwind颜色映射
- 添加system模式样式
3. **服务层增强**
- 增强theme-service功能
- 集成config-service
- 优化IPC通信
#### 第三阶段:高级功能与集成 (预计1-2周)
1. **国际化支持**
- 添加主题相关翻译文本
- 支持多语言主题描述
- 更新i18n配置文件
2. **系统集成**
- 实现系统主题自动切换
- 添加主题变化监听
- 支持多窗口主题同步
3. **性能优化**
- 主题切换性能优化
- 减少CSS重绘
- 优化存储读写
#### 第四阶段:测试与优化 (预计1周)
1. **功能测试**
- 单元测试store、composable、组件
- 集成测试:主题切换流程
- E2E测试用户操作场景
2. **兼容性测试**
- 不同操作系统测试
- 不同浏览器引擎测试
- 多分辨率适配测试
3. **用户体验优化**
- 主题切换动画
- 错误处理与提示
- 无障碍访问支持
### 5. 技术挑战与应对策略
#### 5.1 技术挑战
1. **Vue与Zustand集成**Vue生态系统与Zustand的集成
2. **CSS变量与Tailwind兼容**确保CSS变量正确映射到Tailwind
3. **系统主题实时检测**:跨平台系统主题变化监听
4. **多窗口主题同步**:确保所有窗口主题一致
#### 5.2 应对策略
1. **使用vue-zustand库**或创建Vue适配器
2. **渐进式集成**:先实现基础功能,再优化样式系统
3. **标准化API**使用matchMedia标准API确保跨平台兼容
4. **事件广播机制**:通过主进程广播主题变化事件
### 6. 成功验收标准
#### 6.1 功能验收
- [ ] 支持三种主题模式light、dark、system
- [ ] 主题切换即时生效,无闪烁
- [ ] 系统主题变化自动跟随
- [ ] 配置持久化,重启后保持主题
- [ ] 多语言主题文本支持
#### 6.2 性能验收
- [ ] 主题切换响应时间 < 100ms
- [ ] 内存占用增加 < 5MB
- [ ] 首次加载时间增加 < 200ms
- [ ] CSS变量计算性能优化
#### 6.3 用户体验验收
- [ ] 设置界面直观易用
- [ ] 主题预览效果清晰
- [ ] 错误提示友好
- [ ] 无障碍访问支持
### 7. 下一步行动计划
1. **立即行动** (本周内)
- 评审技术方案确认实施细节
- 创建开发分支准备开发环境
- 编写详细的技术设计文档
2. **短期计划** (1-2周)
- 完成第一阶段基础框架
- 实现主题状态管理
- 开发基础UI组件
3. **中期计划** (3-4周)
- 完成所有核心功能
- 实现系统主题支持
- 完成国际化集成
4. **长期计划** (5-6周)
- 全面测试与优化
- 性能调优与bug修复
- 文档编写与发布准备
---
## 四、附录:参考实现与资源
### 1. ClawX关键文件参考
- `src/pages/Settings/index.tsx` - 设置页面实现
- `src/stores/settings.ts` - Zustand状态管理
- `src/App.tsx` - 主题应用逻辑
- `src/styles/globals.css` - CSS变量定义
- `tailwind.config.js` - Tailwind配置
- `electron/api/routes/settings.ts` - 主进程API
### 2. zn-ai现有文件
- `electron/service/theme-service/index.ts` - 现有主题服务
- `electron/service/config-service/index.ts` - 配置服务
- `src/styles/theme/` - 现有CSS变量
- `src/lib/constants.ts` - 主题相关常量
### 3. 技术文档
- [Zustand文档](https://docs.pmnd.rs/zustand/getting-started/introduction)
- [Tailwind CSS深色模式](https://tailwindcss.com/docs/dark-mode)
- [CSS变量MDN文档](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)
- [Vue 3 Composition API](https://vuejs.org/guide/extras/composition-api-faq)
### 4. 测试方案
- **单元测试**Vitest + Testing Library
- **集成测试**Playwright
- **E2E测试**Cypress
- **性能测试**Chrome DevTools
---
**文档版本**v1.0
**创建时间**2026-04-08
**最后更新**2026-04-08
**负责人**zn-ai开发团队