video-shuoshan/docs/todo/亮色主题切换.md
seaislee1209 3da801d6e6 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>
2026-05-10 21:43:26 +08:00

12 KiB
Raw Blame History

亮色主题切换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 DesignCLAUDE.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

[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.htmldata-theme="light" 看一眼整页效果
  • 不要求完美,对比强烈一眼能看出"啊它确实是浅色了"就行
  • 列出"看着丑"的地方,进 Stage 4 修

预估0.5 天(人)/ 1 小时AI

Stage 3 — themeStore + 切换按钮 + 持久化

改动

  1. 新建 web/src/store/theme.tsZustand 风格,保持和其他 store 一致):

    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 变化重新 renderuseThemeStore((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不报错

参考资料


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