docs: 亮色主题切换开发计划 (P3, AI 自主完成预备)

5 个 Stage 分阶段推进:
- Stage 1: 109 处 inline hex/rgba 颜色替换为 var(--color-*)
- Stage 2: :root 拆 [data-theme="dark/light"] 两套, 浅色色板抄 Linear/Vercel
- Stage 3: themeStore + 切换按钮 + localStorage 持久化
- Stage 4: 浅色色板调试 + 半透明色反相 / ECharts 重渲染 / AuroraCanvas 处理
- Stage 5: vitest + Playwright 本地无头浏览器深/浅截图回归

预期 AI 连续工时 7-9 小时, 人工 3.5-5 天。
关键发现: 项目未实际使用 Arco (CLAUDE.md 写错), 颜色高度集中
(Top 4 文件占 75%, Top 10 颜色占 60%+ 已有对应 var)。

待用户启动 /loop 后 AI 自主完成, 完成时输出截图 + 完成报告。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209 2026-05-10 21:43:26 +08:00
parent c2c811a8fe
commit 3da801d6e6

View File

@ -0,0 +1,313 @@
# 亮色主题切换dark / light theme toggle
**状态**:待开发
**创建日期**2026-04-28
**优先级**P3影视工具默认深色更专业浅色主要服务非影视用户 / 白天强光环境 / 投资人 demo
---
## 需求背景
当前界面是深色固定主题(参考 Linear / Vercel 风格)。部分用户在强光环境 / 白天工作 / 习惯亮色的场景下希望能切换。
不走传统"产品+设计师"流程,直接由 AI 从代码层做改造。
---
## 现状分析(关键发现)
### ✅ 基础设施已就位
- `web/src/index.css` `:root` 集中定义了 **35 个 CSS variable**`--color-bg-page``--color-text-primary` 等)
- 全项目 **525 处** 引用了 `var(--color-*)`,集中可控
- **未使用 Arco Design**CLAUDE.md 写错了,实际 `grep @arco-design = 0`)→ 不需要适配第三方 UI 库主题,少了一大块工作量
### ⚠️ 109 处 inline 颜色散落在 `.tsx`
热点文件(占 75%
| 文件 | inline 颜色数 |
|---|---|
| `pages/DashboardPage.tsx` | 31 |
| `pages/TeamDashboardPage.tsx` | 21 |
| `components/RecordDetailModal.tsx` | 17 |
| `components/ReferenceList.tsx` | 12 |
| 其他 | 28 |
颜色种类高度收敛(前 10 高频占 60%+
```
17次 #8b8ea8 ← 已有 var: --color-text-secondary
10次 #888 ← 同上语义
6次 rgba(255,255,255,0.06) ← 已有 var: --color-bg-card / --color-bg-input-bar
5次 rgba(255,255,255,0.08) ← 已有 var: --color-bg-hover
5次 #f1f0ff ← 已有 var: --color-text-primary
6次 #6c63ff ← 已有 var: --color-primary
```
→ 大部分是机械性 grep+replace不是创造性设计。
---
## 浅色主题色板设计
直接抄 Linear / Vercel 的浅色方案(这俩就是当前深色主题模仿的对象,他们都有官方浅色版)。
### 核心规则
| 类别 | 深色(现状) | 浅色(新增) | 说明 |
|---|---|---|---|
| 页面背景 | `#07070f` | `#fafafa` | 主背景,深色近黑/浅色近白 |
| 卡片背景 | `rgba(255,255,255,0.06)` | `rgba(0,0,0,0.04)` | **半透明色反相**:白半透明 → 黑半透明 |
| Hover | `rgba(255,255,255,0.08)` | `rgba(0,0,0,0.06)` | 同上 |
| 输入框背景 | `rgba(255,255,255,0.06)` | `#ffffff` | 浅色下输入框直接给纯白更醒目 |
| 主文字 | `#f1f0ff`(亮紫白)| `#171823`(深紫黑)| 反相,保留紫调一致性 |
| 次文字 | `#8b8ea8` | `#6b6e85` | 同上 |
| 边框 | `rgba(255,255,255,0.10)` | `rgba(0,0,0,0.08)` | 半透明反相 |
| 主色(按钮)| `#6c63ff` | `#5048cc` | 浅色背景下加深 18%,对比度足 |
| 强调色 | `#00b8e6` | `#0099cc` | 同上原则 |
| 成功 | `#00b894` | `#00a37e` | 浅色下加深 |
| 危险 | `#e74c3c` | `#d63a2a` | 同上 |
| 警告 | `#f39c12` | `#d4860a` | 同上 |
| Modal 阴影 | `rgba(0,0,0,0.6)` | `rgba(0,0,0,0.15)` | 浅色下阴影减弱 |
### 切换机制
- 用 `<html data-theme="dark">` / `<html data-theme="light">` 切换
- CSS 选择器 `[data-theme="dark"] :root { ... }` / `[data-theme="light"] :root { ... }` 各定义一套
- 默认 `data-theme="dark"`(保留现有体验)
- 用户切换后 localStorage 持久化,下次访问保持
---
## 改造步骤(分阶段,每阶段一次提交,不做大 PR
### Stage 1 — inline 颜色全部替换为 var不破坏现有体验
**目标**:所有 `style={{ color: '#xxx' }}` / `background: 'rgba(...)'` 改成 `style={{ color: 'var(--color-xxx)' }}`,深色继续工作不变。
**具体改动**
1. **DashboardPage.tsx** — 31 处
- 大部分是图表 axis / legend / tooltip 颜色,对照现有 var 替换
- ECharts 配置里的 `axisLine.lineStyle.color` / `tooltip.backgroundColor` 等改用 `getComputedStyle(document.documentElement).getPropertyValue('--color-xxx')` 动态读取(支持主题切换实时刷新图表)
2. **TeamDashboardPage.tsx** — 21 处(类似 DashboardPage
3. **RecordDetailModal.tsx** — 17 处(弹窗各 section 标题 / 边框 / 背景)
4. **ReferenceList.tsx** — 12 处
5. **VideoGenerationPage / VideoDetailModal / ProfilePage / AuroraCanvas** — 共 ~28 处
**新增的 var**(覆盖现有 `:root` 没有的颜色):
- `--color-modal-overlay`(替代各处 `rgba(0,0,0,0.6)` / `rgba(0,0,0,0.7)`
- `--color-text-tertiary`(替代各处 `#888` / `#555`
- `--color-bg-modal`(替代各处 `#1a1a2e` / `#111118`
- `--color-shadow`(替代各处 `rgba(0,0,0,0.4)` 之类)
**验收**
- `git diff` 看 109 处全部 `style={{ ... '#xxx' ... }}``var(--color-xxx)`
- 浏览器跑起来,肉眼对比改前改后无变化(因为 var 值还是原来的深色值)
**预估**1-1.5 天(人)/ 2-3 小时AI 连续 grep+sed+verify
### Stage 2 — `:root` 拆 dark / light 两套
**目标**CSS 层面准备好两套值,但不切换(默认 dark等 Stage 3 切按钮)。
**改动**`web/src/index.css`
```css
[data-theme="dark"] {
--color-bg-page: #07070f;
--color-text-primary: #f1f0ff;
/* ... 35 个 var 全部 */
}
[data-theme="light"] {
--color-bg-page: #fafafa;
--color-text-primary: #171823;
/* ... 同样 35 个 var 的浅色版本 */
}
```
`<html data-theme="dark">` 默认值在 `index.html` 写死,等 Stage 3 才动。
**验收**
- 手动改 `index.html``data-theme="light"` 看一眼整页效果
- 不要求完美,对比强烈一眼能看出"啊它确实是浅色了"就行
- 列出"看着丑"的地方,进 Stage 4 修
**预估**0.5 天(人)/ 1 小时AI
### Stage 3 — themeStore + 切换按钮 + 持久化
**改动**
1. 新建 `web/src/store/theme.ts`Zustand 风格,保持和其他 store 一致):
```typescript
import { create } from 'zustand';
type Theme = 'dark' | 'light';
interface ThemeState {
theme: Theme;
toggleTheme: () => void;
}
const STORAGE_KEY = 'airdrama-theme';
const initialTheme: Theme =
(localStorage.getItem(STORAGE_KEY) as Theme) || 'dark';
document.documentElement.dataset.theme = initialTheme;
export const useThemeStore = create<ThemeState>((set, get) => ({
theme: initialTheme,
toggleTheme: () => {
const next = get().theme === 'dark' ? 'light' : 'dark';
document.documentElement.dataset.theme = next;
localStorage.setItem(STORAGE_KEY, next);
set({ theme: next });
},
}));
```
2. 顶部加切换按钮(建议放 `Sidebar.tsx` 底部 / 用户头像旁,月亮/太阳 SVG 图标)
3. ECharts 等动态依赖 CSS var 的图表,订阅 theme 变化重新 render`useThemeStore((s) => s.theme)` 作为 key 触发重渲染)
**验收**
- 点击按钮深↔浅切换流畅
- 刷新页面保持上次选择
- 登录页 / 错误页等所有路由都生效
**预估**0.5 天(人)/ 1 小时AI
### Stage 4 — 浅色色板调试 / 边角料修复
切完之后**一定**会发现:
- 某个按钮文字不可见(对比度不足)
- 某个磁玻璃 backdrop 太透看不清
- 某个图表的 grid line 浅色下消失
- ECharts tooltip 颜色没跟着切
**做法**:每页跑一遍,列 bug 表,逐个调整 `[data-theme="light"]` 块里的具体值。
**预估**1-1.5 天(人)/ 2-3 小时AI 配合用户截图反馈)
### Stage 5 — 回归 vitest + 手测
- vitest 跑一遍(不会因为颜色变化挂,主要看依赖 DOM 结构的 snapshot test 没崩)
- 每个页面深 / 浅各走一遍:登录页 / 生成页 / 个人中心 / 7 个 admin 页 / 视频详情弹窗 / 任务详情弹窗 / 公告弹窗 / Toast
**预估**0.5-1 天(人)/ 1 小时AI 跑测试 + 用户走手测)
---
## 关键技术点(容易踩坑)
### 1. 半透明色反相不能简单替换
`rgba(255,255,255, 0.06)` 不是变成 `rgba(0,0,0, 0.06)`**透明度也要调整**。白半透明在深色背景下肉眼看是"浅色卡片";黑半透明在浅色背景下看是"深色卡片",但人眼对深色对比的敏感度不同。
**经验值**:浅色透明度通常比深色 -20%~-40%。比如深色 0.06 对应浅色 0.04。
### 2. ECharts 等图表的颜色需要 JS 同步切换
CSS variable 改了,但 ECharts 已经渲染的图表不会自动重新读 var。两种方案
- **方案 A**:图表内部颜色用 `getComputedStyle(document.documentElement).getPropertyValue('--color-xxx').trim()`,且组件内 `useEffect(theme => render)` 触发重渲染。
- **方案 B**:所有图表配置传入颜色直接读 themeStore 的 theme 值,动态返回不同 hex。
推荐 A保持单一颜色源
### 3. AuroraCanvas 极光动效
登录页 `AuroraCanvas.tsx` 是 canvas 画的极光渐变,硬编码紫色调。
- **暗色**:紫蓝极光好看
- **浅色**:极光放在白底上会刺眼
方案:浅色模式下整个 AuroraCanvas 直接 `display: none`,背景换成 `#fafafa` 纯净白,反而更"高级"。
### 4. 玻璃效果 backdrop-filter
不少地方用 `backdrop-filter: blur(24px)` + 白半透明做磨砂玻璃。浅色下 backdrop-filter 仍然有效,但底层颜色要换成黑半透明(`rgba(0,0,0,0.04)`)。
### 5. 主色对比度WCAG AA
`#6c63ff` 紫色按钮:
- 深色背景 + 白字:对比度 ~7.1AAA 级别)✓
- 浅色背景 + 白字:对比度 ~4.4(接近 AA 边界,但按钮上的小字可能不够)
- 解决:浅色模式 `--color-primary: #5048cc`(加深 18%),按钮上白字对比度 ~6.8AAA
---
## 验证清单
切换前后两种主题下都要看:
- [ ] 登录页(含 AuroraCanvas 切换)
- [ ] 生成页(卡片 / 输入框 / @ 标签 / 滚动条)
- [ ] 提示词标签(缩略图 / 文字)
- [ ] 任务卡片各种状态(生成中 / 完成 / 失败)
- [ ] 个人中心(消费图表)
- [ ] 公告弹窗HTML 渲染)
- [ ] Toast / 各种 Modal / Dropdown
- [ ] 7 个 admin 页Dashboard / Users / Records / Settings / Security / Logs / Assets
- [ ] 团管 4 个页TeamDashboard / TeamMembers / TeamRecords / TeamAssets
- [ ] 火山 EP / 任务详情 / 录像弹窗
---
## 工作量预估
| Stage | 描述 | 人工时 | AI 工时 |
|---|---|---|---|
| 1 | inline 颜色 → var | 1-1.5 天 | 2-3 小时 |
| 2 | dark/light 两套 var | 0.5 天 | 1 小时 |
| 3 | themeStore + 切换按钮 | 0.5 天 | 1 小时 |
| 4 | 浅色色板调试 | 1-1.5 天 | 2-3 小时 |
| 5 | 回归测试 | 0.5-1 天 | 1 小时 |
| **总计** | | **3.5-5 天** | **7-9 小时AI 连续)** |
---
## 不做的
- **跟随系统主题**`prefers-color-scheme: light`):以后再加,初版手动切换就够
- **多套主题**(如 sepia 米色 / 高对比度无障碍模式):用户没要求
- **管理后台和用户端独立主题**:保持一致更简单
- **每个团队管理员可定制配色**:复杂度爆炸,不做
---
## 风险点
1. **改 `:root` 默认 hex 写法 → 改成 `[data-theme]` 选择器后,原来组件的 var 引用都还能正确解析**CSS 优先级要确认。`[data-theme="dark"]` 选择器优先级 0,1,0`:root` 优先级 0,0,1。前者会胜出 ✓)
2. **AuroraCanvas 在浅色下隐藏** 的产品决策需要用户确认(也可以保留,但调淡)
3. **ECharts 重渲染开销**:每次切主题所有图表 re-render 一遍,仪表盘 6 个图表加起来 ~200ms 卡顿可接受
4. **localStorage 在隐身模式 / 用户禁用时**fallback 到 dark不报错
---
## 参考资料
- Linear 浅色主题色板https://linear.app直接 toggle 看)
- Vercel 浅色主题https://vercel.com同上
- WCAG 对比度计算https://webaim.org/resources/contrastchecker/
- `prefers-color-scheme` MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
---
## Critical Files
修改:
- `web/src/index.css``:root``[data-theme="dark/light]` 两套
- `web/src/store/theme.ts` — **新建**
- `web/src/pages/DashboardPage.tsx` — 31 处颜色替换
- `web/src/pages/TeamDashboardPage.tsx` — 21 处
- `web/src/components/RecordDetailModal.tsx` — 17 处
- `web/src/components/ReferenceList.tsx` — 12 处
- `web/src/components/Sidebar.tsx` — 加切换按钮(位置待定)
- 其余 ~28 处 inline 颜色散落的组件
不动:
- 后端代码(纯前端改造)
- DB schema
- 现有路由 / API