Files
cc-web/.codex/skills/create-cc-web-theme/references/cc-web-theme-architecture.md
2026-07-18 10:14:38 +08:00

5.3 KiB
Raw Blame History

cc-web 主题架构与修改边界

目录

  1. 代码定位顺序
  2. 主题运行链路
  3. CSS 分层
  4. DOM 双路径
  5. 资产与回归
  6. 脏工作树与服务约束

1. 代码定位顺序

不要依赖固定行号。按符号和稳定文本定位:

  1. public/app.js
    • THEME_OPTIONS
    • normalizeTheme
    • applyTheme
    • buildThemePickerHtml / mountThemePicker
    • buildWelcomeMarkup
  2. public/index.html
    • CSS 加载前的主题 bootstrap
    • 静态 welcome DOM
    • CSS/JS cache-busting query
  3. public/style.css
    • html[data-theme='<id>'] 语义变量
    • 共享暗色 :is(...) completion selectors
    • 文件后部的主题专属组件层
    • 响应式与 prefers-reduced-motion
  4. scripts/regression.js
    • assertFrontend<Theme>ThemeContract
    • --target <theme>-theme
    • 全量回归入口
  5. public/assets/themes/<id>/
    • background、frames、icons、textures、manifest

先用 codebase-memory 找符号和调用关系,再用 rg 核对资源文本与最终位置。

2. 主题运行链路

THEME_OPTIONS
    ├── 设置页主题候选 / label / desc / swatches
    ├── normalizeTheme() 判断持久化值是否合法
    └── applyTheme()
          ├── document.documentElement.dataset.theme
          └── localStorage['cc-web-theme']

index.html bootstrap
    └── CSS 加载前写入 data-theme避免首屏闪烁

html[data-theme='<id>']
    └── 语义变量 → 共享组件 → 主题专属组件层

主题列表只维护一份。不要在设置页或其他弹层硬编码第二份主题候选。

新主题 ID

  • 使用稳定、小写、可长期保留的 ID。
  • 新主题默认新建 ID不要借用隐藏主题、历史主题或另一个风格的 ID。
  • 保留旧主题用于对比时,不修改其 label、资产和 selector。
  • 如需迁移旧 ID明确写出 旧值 → 新值,并增加回归断言。

3. CSS 分层

按以下层次组织:

  1. 语义变量层:背景、文字、边线、强调色、面板色。
  2. 共享 completion 层:只放多个暗色主题确实共用的组件补齐。
  3. 基础 UI 层:不因单个主题改变业务布局或交互。
  4. 主题专属层背景、边框、图标、welcome、特殊响应式。

专属层应放在共享规则之后,并限定 html[data-theme='<id>']。当后置规则仍无效时,检查 specificity而不是继续追加更宽泛的选择器。

:is() 风险

:is() 的 specificity 取参数中最高值。共享规则例如:

:is(
  html[data-theme='a'] .msg.assistant .msg-bubble,
  html[data-theme='b'] .msg.system .msg-bubble[data-tone='info']
) { ... }

可能比后面的普通主题规则更强。出现“backdrop-filter 变了但 background 没变”时,必须查看 computed style 的规则来源;必要时使用同级 specificity 或只对冲突声明使用精确 !important

4. DOM 双路径

welcome 页面同时存在:

  • public/index.html 的静态首屏结构。
  • public/app.jsbuildWelcomeMarkup() 动态结构。

新增图层、class、无障碍属性、文案节点或图片时必须同步两处。

动态数据必须由 JS 统一填充,例如:

  • 当前项目名称来自 cwd
  • 当前 Agent 名称来自运行时状态。
  • 当前会话标题来自 snapshot。

静态 HTML 只保留可定位的空节点或不依赖运行时的数据。回归必须断言静态模板没有写死动态名称。

重复视觉来源

实现主题图标前检查实际 DOM

  • 文本 +
  • 内联 SVG。
  • <img> 头像。
  • 基础主题已有的 ::before / ::after
  • 新主题 background/mask。

同一语义只保留一个可见来源,并只在当前主题下隐藏旧来源。

5. 资产与回归

推荐目录:

public/assets/themes/<theme-id>/
├── background.webp
├── frames/
│   ├── manifest.json
│   └── *.png
├── icons/
│   ├── manifest.json
│   └── *.png
└── textures/
    └── *.webp

专项回归至少覆盖:

  • 主题注册、可见性和迁移策略。
  • 变量块和专属组件层存在。
  • 新主题加入必要共享 selectors。
  • 静态/动态 welcome 同步。
  • 本地资产格式、尺寸、hash 或 manifest。
  • 禁止远程 URL。
  • 动态组件的结构契约,例如可伸缩输入框不依赖固定伪元素。
  • 响应式、reduced-motion、文字对比度。
  • cache bust 与在线加载版本一致。
  • 旧主题专项回归继续通过。

回归验证结构和不变量,不替代像素与构图验收。

6. 脏工作树与服务约束

  • 实施前执行 git status --short 和主题相关精确 diff。
  • 记录相关文件的起始状态;只修改目标区块。
  • 不使用 git reset --hardgit checkout -- 或整文件还原保护自己生成的改动。
  • 多会话可能同时修改 app.jsstyle.cssindex.htmlregression.js。发现反复回写时停止覆盖,先协调写入边界。
  • 修改静态文件通常不需要重启服务。需要重启 cc-web 时,严格执行仓库 AGENTS.md 的运行会话检查。
  • 浏览器访问失败时先用 curl http://127.0.0.1:<port> 检查本地服务,再按 hostname -I 使用 11.144.144.* 地址排除网络命名空间问题。