feat(themes): 添加可编辑的站点外观和皮肤主题(#408)

This commit is contained in:
Ray authored and GitHub committed 2026-09-03 21:13:41 +08:00
1 parent c768fccbc2
commit 5e66cb7c45
70 files changed
+3654 -327

No files matched your search

+39
View File
@@ -1152,3 +1152,42 @@
- 验证结果:目标文件定向 Prettier 与 `git diff --check` 通过;固定 Bun 1.3.13、提交的 `bun.lock` 和干净依赖环境运行外观、后台、对象存储与找回密码四组专项测试,23 项全部通过、194 个断言无失败,TypeScript `tsc --noEmit` 为 0 错误。生产 Docker 多阶段构建转换 13,499 个模块并成功生成镜像,只保留项目既有的大分块提示。独立前端烟测返回 200,确认初始 HTML 不含内置品牌与 `/logo.svg`,新尺寸选择器已进入打包 CSS;真实管理员页面的深浅主题截图仍按 `docs/content/docs/progress/pending-test.mdx` 保留为人工验证项,不伪造登录态或业务配置。
- 潜在影响:关闭外框后,宽或高较小、透明留白较多的 Logo 会在原容器范围内明显变大,但仍保持自身比例且不会溢出;如素材文件本身带有透明边距,视觉内容不会强制裁切到满边。开关仍属于外观页面草稿,需要点击原有“保存修改”才写入服务端;没有改成即时保存。
- 逐项回滚:先使用 `.local/ui-change-backups/batch-134/` 中对应原件逐项恢复本批六个源码/文档文件,再恢复本台账并执行其 `MANIFEST.sha256` 校验;恢复前如文件已包含后续批次,先复制当前版本。本批不依赖 Git 历史做本地回滚。
## 批次 135:站点及外观、全站皮肤、SEO/备案与品牌残留收口
- 日期时间:2026-09-03 12:45:00 +0800
- 目的:将“外观管理”扩展并更名为“站点及外观”,让自定义站点名贯穿邮件、诊断、导出、插件和协议说明;新增 SEO、版权、ICP备案与可扩展皮肤主题库,同时保证自定义品牌首屏不会闪现内置品牌或默认皮肤。
- 修改前状况:自定义站点名主要覆盖页面导航与登录场景,注册验证码和密码重置邮件仍写死内置品牌;SEO、页脚版权和备案没有统一配置;`skinId` 只保留占位且仅支持经典样式,颜色、控件状态和圆角散落在既有主题层。协议文档、诊断包、部分插件说明与画布导出仍存在可见内置品牌文案。
- 涉及范围:后端外观 schema/公开投影、邮件与密码重置、诊断/LibTV/工作流插件、协议文档及其断言;前端外观 API/store/bootstrap、主题入口、皮肤注册表、公共页脚、登录场景、后台导航/表单/样式、插件/画布展示;功能文档、设计合同和本台账。仓库名、镜像/升级器路径、剪贴板与 localStorage key、插件 API version、数据库校验值和对象存储既有默认前缀继续作为技术兼容标识保留。
- 具体改动:外观 schema 升级为 v4,新增 SEO 标题/描述/关键词、版权、备案开关/号码并对旧配置按当前品牌补全;邮件发件人留空或沿用历史内置名时自动继承当前站点名,注册与重置主题/正文动态品牌化。新增 `skin-themes.ts`,以 primitive、semantic、component 三层令牌定义经典黑白、创作室青橙、暖调柿棕、品牌紫蓝四套皮肤;经典皮肤覆盖表为空,三套扩展皮肤同时定义亮暗背景、文字、表面、边界、控件 hover/active/selected/focus、开关、管理端/登录页和三级圆角,并与 Ant Design token 合并。后台按品牌、登录内容与媒体、SEO、首页收尾与备案、皮肤主题五段排列,继续使用原保存/未保存保护;备案链接固定为工信部备案系统。动态 metadata 覆盖 title、description、可选 keywords、Open Graph、Twitter、theme-color、favicon 与 canonical;公共登录场景增加版权/备案页脚。协议和插件运行时说明改为中性“宿主”,默认品牌与“一键恢复影策默认”仍保留。
- 验证结果:`git diff --check` 通过;固定 Bun 1.3.13 专项测试 28 项、265 个断言全部通过;隔离干净依赖的 TypeScript `tsc --noEmit` 为 0 错误;Go 1.25 中协议包、本次外观/邮件/密码重置相关测试全部通过并完成 gofmt 检查。后端和前端生产镜像构建成功,Vite 8.1.5 转换 13,513 个模块,仅有既有大分块提示。后端全量测试中的 3 个存储/公告原子性用例在未修改的线上 v1.2.5 源码中同样独立失败;前端全量 Bun 套件为 1,358 通过、27 失败、2 error,失败集中在既有全局 `window` 测试污染与未改动模块,均作为上游基线记录。生产浏览器覆盖 `/register` 与 `/forgot-password` 的 1440×900、1280×800、430×932、390×844,四档均 `scrollWidth === clientWidth`、无内置品牌正文、动态 SEO/版权正确;管理后台因浏览器无登录态按权限边界跳回登录页,真实后台亮暗与四皮肤保存仍保留为人工验收项。
- 集成验证:在隔离容器环境完成 schema 6/6 迁移、前后端健康、公开路由、HTTP→HTTPS 和未登录管理员 API 权限边界检查;既有自定义品牌、英文标识、classic 皮肤与 appearance 配置摘要保持不变,新 SEO/版权按当前品牌补全,备案默认关闭。测试没有覆盖或改写运维平台、代理、证书及其他站点资源。
- 潜在影响:首次读取旧 appearance JSON 时公开投影会即时补全新字段,但只有管理员保存后才写回;历史 `FromName = 影策` 现在被视为继承站点名,管理员明确填写其他发件人名称仍保持独立。关键词字段为兼容其他搜索引擎或站内扩展保留,界面不承诺 Google 排名效果。扩展皮肤覆盖共享语义层,因此尚未迁移到语义 token 的少数历史业务专用颜色不会随皮肤变化;后续皮肤应继续通过注册表扩展,不在页面按 ID 增加分支。
- 逐项回滚:源码以基线提交 `f8e87bcc4ce3e6f7eae7a89dc8b9231801116072` 为准,按本批涉及范围逐项恢复并保留后续修改。本批不增加关系型数据库迁移,回滚外观代码时仍应先备份现有 appearance 配置;`project-memory/` 继续忽略且不进入 Git。
## 批次 136:可编辑皮肤主题库与组件令牌统一
- 日期时间:2026-09-03 14:08:28 CST
- 目的:把批次 135 的固定皮肤注册表升级为真正可维护的主题库。默认经典主题继续精确保留项目原始外观并永久只读;其他主题允许新建、复制、改名、编辑、启用与删除,预置配色只作为初始数据,而不是写死的主题分支。
- 领域与安全合同:外观 JSON schema 升级为 v5,新增 `skinThemes`,不增加关系型数据库迁移。主题库最多 16 套;每套包含浅色/深色各 41 项语义颜色,以及按钮、输入、卡片、弹层、菜单、复选框圆角、三档高度、描边、焦点环、图标尺寸、按钮字重、悬停抬升、两档动效和阴影在内的 17 项组件参数。颜色只接受 6/8 位 HEX,数值与相互关系由后端校验;不接受任意 CSS、选择器、URL 或脚本。公开接口只返回当前 `activeSkin`,管理接口才返回完整主题库。经典主题由服务端逐字段与规范值比对,伪造请求也不能修改或删除。
- 后台交互:复用“站点及外观”原有卡片、表单、操作栏和统一草稿/保存模型。主题库卡片同时显示色板、名称、说明、锁定、选中、复制与删除动作;可“从默认新建”或“复制当前”。编辑区支持主题名称/说明、浅色/深色切换、实时控件组合预览、四组语义颜色和组件参数。删除当前主题时草稿切回经典主题;保存前允许继续编辑非法中间 HEX,但前端保存和后端权威校验都会阻止其生效。
- 全站映射:自定义主题同时投影到根节点 CSS Custom Properties 与 Ant Design 全局/组件 token,统一按钮、输入、选择、菜单、开关、勾选框、卡片、弹层、图标、状态色、后台、登录页与工作区。默认主题不写任何覆盖变量,保持原 CSS 和 Ant 配置。应用仍先取得公开外观并应用主题后才动态导入 React,避免自定义主题首屏闪现经典色系。
- 研究依据:采用 Design Tokens Community Group 的分组/类型思想、Style Dictionary 的平台无关层级、Ant Design 的 Seed/Map/Alias 与组件 token,以及浏览器原生 CSS Custom Properties。当前单应用不增加 Style Dictionary 构建依赖,保留未来标准令牌导入导出空间。
- 验证结果:Go 1.25 外观专项测试通过并完成 gofmt 检查。固定 Bun 1.3.13 在独立工作卷中从提交的 `bun.lock` 安装依赖;外观、后台、对象存储与密码重置 5 组 28 项测试、235 个断言全部通过,完整 `tsc --noEmit` 为 0 错误。前后端生产镜像构建成功,Vite 8.1.5 转换 13,514 个模块,仅保留既有大分块提示。候选前端在 127.0.0.1:17301 健康、0 重启,初始 HTML 不含内置品牌或 `/logo.svg`;重建后的候选后端使用独立 SQLite 临时卷完成插件扫描、健康和 schema v5 `activeSkin` 启动烟测。
- 集成验证:隔离环境迁移正常退出,schema 保持 6/6,前后端与持久服务健康;公开 `activeSkin` 仅返回经典主题当前投影、41 项颜色和 17 项组件参数,完整 `skinThemes` 未泄漏。既有自定义品牌、Logo、视频、SEO、备案和 appearance 数据摘要保持不变,公开路由、API、HTTPS 跳转及未登录权限边界均符合预期。
- 打包防护:一次 macOS tar 上下文携带 `._*` AppleDouble 旁车文件,插件扫描将旁车误判为损坏插件包。候选镜像在进入可用发布前被拒绝;清除旁车、在 `.dockerignore` 增加 `._*`/`.DS_Store` 防护并重建后,独立后端启动烟测和插件扫描通过。此记录说明跨平台打包原因,不包含目标服务器信息。
- 浏览器验收:注册页覆盖 1440×900、1280×800、430×932、390×844,四档 `scrollWidth === clientWidth`,无可见内置品牌残留;标题、description、favicon、theme-color、版权和当前经典主题正确。1440 与 430 截图完成视觉检查,媒体、层级、文字、表单和响应式无阻断。管理路由按权限正确跳转到 `/login?next=%2Fadmin%2Fsettings%2Fappearance`;测试会话无管理员登录态,因此真实主题增删改保存与后台亮暗截图继续列入人工验收,不伪造账号或写运营配置。
- 回滚与残余风险:本批不增加关系型数据库迁移;源码回滚应成对恢复 schema v5 外观结构、后端校验、前端类型/编辑器和主题映射,并先备份当前 appearance JSON。`project-memory/` 继续忽略且不进入 Git。
## 批次 137:主题状态色、真实色板与管理员后台菜单圆角收口
- 日期时间:2026-09-03 15:26:03 CST
- 目的:在批次 136 的可编辑主题库上补齐开关、警告/危险操作和同类控件状态,让颜色选择器只由色块触发,让主题卡片展示该主题真实使用的颜色,并确认“菜单圆角”只作用于管理员后台左侧菜单;同时重新设计三套非默认预置主题的配色。默认经典主题继续锁定且不可修改。
- 令牌与兼容:外观 JSON schema 从 v5 升至 v6,不增加关系型数据库迁移。每个明暗模式由 41 项扩展为 50 项颜色令牌,新增开关开启背景/悬停/手柄、关闭背景/悬停/手柄,以及危险悬停、危险按下和危险前景 9 项。内置预置按规范值补齐;历史自定义主题缺失字段时从主色、控件和危险色确定性派生,既有主题无需手工迁移即可读取。CSS Custom Properties、Ant Design 全局状态色、Button 与 Switch 组件 token 使用同一语义来源。
- 交互与视觉:删除主题按钮改为 `primary + danger`,普通、hover、focus、active 均使用主题自己的危险色;系统成功、警告、错误/危险和信息状态统一映射主题状态色。Switch 的开启/关闭背景、悬停和手柄分别可配,选中态同时保留边界与轻微焦点环,不再只靠几乎不可见的灰度差。颜色项外层改为普通容器,只有可见色块上的原生颜色输入会打开拾色器,文字、HEX 输入和留白不会触发。主题卡片从明暗两套 50 项真实角色中按注册表使用频次交错去重,固定单行溢出裁切,空间不足时自然只显示高频前色。
- 预置主题:保留 `classic / 经典黑白` 不变;另外三套改为 `青瓷工作室(雾白青瓷 · 珊瑚点睛)`、`暖柿纸境(米纸暖棕 · 柿橙强调)`、`霓光紫境(冷白雾紫 · 夜幕电光)`,各自拥有独立的亮暗背景、主色、交互色、状态色、开关色和危险色,仍可改名、编辑、复制、删除。
- 管理员菜单圆角:本批按用户澄清只处理管理员后台左侧菜单。既有 Ant `Menu.itemBorderRadius/subMenuItemBorderRadius` 继续读取 `skin.tokens.components.menuRadius`;自定义后台导航 `.admin-shell .app-workspace-nav-link` 从固定 `8px` 改为 `var(--menu-radius)`,主题预览新增“后台菜单”样例并直接使用当前草稿的 `menuRadius`。未改前台、普通用户工作区或其他无关导航圆角。
- 验证结果:修改文件通过定向 Prettier 与 `git diff --check`。固定 Bun 1.3.13、提交的 `bun.lock` 和干净依赖环境运行外观主题专项测试 8 项全部通过、53 个断言无失败,完整 `tsc --noEmit` 为 0 错误;Go 1.25 外观与密码重置专项测试通过。生产后端镜像编译成功,Vite 8.1.5 转换 13,514 个模块并在约 8.69 秒完成,仅有既有大分块提示。隔离候选环境的 `/` 与 readiness 返回 200,schema v6 公开主题为明暗各 50 色、`menuRadius=8`。
- 集成验证:隔离迁移正常退出,schema current/expected 6/6,公开主题可从 schema 5 配置读取并投影为 schema 6;既有 appearance 数据摘要保持不变。首页、注册、登录、找回密码、后台深链、liveness、readiness、公开外观与版本接口均通过,未登录管理员外观 API 返回 401。生产构建产物已确认包含 `.admin-shell .app-workspace-nav-link{border-radius:var(--menu-radius)}` 与“后台菜单”预览。
- 浏览器验收:1440×900、1280×800、430×932、390×844 均无横向溢出、无可见内置品牌或仓库名残留,首屏直接显示当前自定义品牌。测试会话无管理员登录态,因此真实主题增删改保存、危险按钮/开关各状态和后台菜单圆角的登录后截图仍留作人工验收,不伪造账户或运营数据。
- 回滚与残余风险:本批不增加关系型数据库迁移;源码回滚应成对恢复 schema v6 新增颜色字段、前后端兼容补全、Ant/CSS 映射、编辑器和测试。回滚前先备份当前 appearance JSON,避免丢失管理员在 schema v6 下保存的主题状态色。`project-memory/` 继续 Git 忽略且不进入 Git。
+1
View File
@@ -35,6 +35,7 @@
- 资源与策略:将账号配额、任务并发、任务超时、业务频控、渠道中转与熔断视为五个会立即影响运行中业务的策略域,不把 42 个数值项当作一张普通长表单。页面先展示配置来源、待保存数量和关键并发摘要,再按上述五个策略域直接纵向呈现设置区。较窄 PC 保持 1440px 以内阅读宽度和两至三列表单;1600px 以上状态、概览与策略卡随主内容扩展,右侧只保留正常页边距,1800px 以上参数再改为四列。全部数值先在本页暂存,按真实字段差异计算待保存数;点击一次“保存修改”直接校验并提交,不再打开二次确认。自用模式属于全量高上限预设,必须先解释会覆盖草稿且只填入本页;恢复默认属于立即删除管理员配置的写操作,继续二次确认。提供撤销、刷新覆盖确认、浏览器刷新与后台导航保护;读取和保存响应需校验全部 42 个整数、配置来源及与提交一致性,单文件上限不能大于账号文件总容量,失败不得自动重试。
- 登录与注册:必须把“能否创建新账号”和“Linux.do OAuth 登录”视为两个独立保存域,并在状态栏明确说明两者分别读取、分别保存。注册开关切换后立即保存,不再打开确认层;页面内必须持续说明本地注册、未绑定第三方账号和已有账号分别受到什么影响。Linux.do 入口开关在 Client、HTTPS 端点和回调地址满足服务端规则时立即保存,条件不足则恢复原状态并明确提示;凭据、OAuth 地址、Scopes 和字段映射仍在同一草稿中,点击一次“保存修改”直接提交。提供真实待保存状态、撤销、刷新覆盖确认、浏览器刷新和后台导航保护;不在界面或接口响应中展示 Client Secret。凭据、连接地址和高级字段映射使用明确二级分组,高级映射默认折叠但保留原生键盘语义。读取失败提供页面级重试,已有数据刷新失败时保留上次成功状态;保存响应必须校验除密钥明文外的全部公开字段与提交一致,失败不得自动重试。
- 邮件服务:将注册验证码投递、SMTP 服务器、身份验证和发件人身份作为一组配置域。验证码投递开关在主机、端口、发件邮箱及验证凭据满足服务端规则时立即保存;条件不足则恢复原状态并明确缺项。SMTP 文本、密码、连接安全和发件身份继续暂存,点击一次“保存修改”直接提交,不再二次确认。页面先展示投递状态、服务器、连接安全和发件身份概览,再按“验证码投递、SMTP 配置”纵向呈现;不得在后端没有探测或试发接口时提供虚假测试反馈。提供真实待保存状态、撤销、刷新覆盖确认、浏览器刷新与后台导航保护;SMTP 密码不得回显,留空明确表示保留已有值。保存响应必须校验全部公开字段与密钥存在状态,失败不得自动重试,也不得误称配置已通过连接验证。
- 站点及外观:按“品牌识别 → 登录页内容与媒体 → SEO 信息 → 首页收尾与备案 → 皮肤主题”纵向组织,复用设置页状态操作栏和 `SettingsSectionCard`,不另造视觉体系。品牌名必须投影到登录/注册/找回密码、继承型邮件发件人、用户可见导出/诊断和插件说明;内置名称只允许用于默认值与明确的恢复动作。首屏先读取公开外观再渲染应用,禁止自定义配置下闪现旧名称、Logo、海报或色系。皮肤通过 Primitive、Semantic、Component 三层 token 管理,业务页面不得按皮肤 ID 写条件样式;默认 `classic` 不覆盖既有 token 且不可删改,其他主题是可增删改名、复制和启用的数据。每套主题必须成对提供亮暗模式、按钮 hover/active、选中/焦点、开关、表面层级、图标、圆角、尺寸、动效和阴影,并同时映射 CSS Variables 与 Ant Design token。SEO 与版权允许留空后按当前品牌推导,备案展示默认关闭,开启时必须填写备案号并链接 `https://beian.miit.gov.cn/`;关键词字段不能宣称影响 Google 排名。所有字段、主题库与媒体保持单一草稿/保存/撤销/刷新覆盖保护,恢复默认不删除上传资源。
- 存储服务:必须把“新增资源默认写入位置”和“历史资源读取依据”明确区分。存储位置以可键盘选择的规则卡呈现服务器本地、阿里云 OSS、腾讯云 COS 与七牛云 Kodo;目标配置完整时选择后立即保存,缺少 Endpoint、Bucket 或凭据时只展开相应表单并明确提示补全后点击“保存修改”,不得提交无效配置。切换不得暗示会迁移、覆盖或删除已有资源;历史资源仍按自身记录读取,服务端在成功切换云厂商后归档上一厂商凭据。服务器本地与云存储使用不同表单层级;云存储按连接与读取出口、服务端凭据分组。文本和密钥调整点击一次“保存修改”直接提交,不再二次确认;没有后端检测接口时不得提供虚假验证反馈。提供撤销、刷新覆盖确认、浏览器刷新与后台导航保护,不显示 Secret 明文;读取与保存响应均需结构和一致性校验,失败不自动重试。
- 方舟素材库:该入口是 Seedance 可信参考素材的部署级同步策略和 IAM 接入配置,不得呈现为远端素材浏览列表。同步开关在 Region、ProjectName、AccessKey 与 SecretKey 条件满足时立即保存;条件不足则恢复原状态并提示缺项。项目和凭据继续暂存,点击一次“保存修改”直接提交,不再二次确认。页面必须准确说明触发条件及停用影响;Region、ProjectName 或 AccessKey 改变时说明服务端会清除默认素材组缓存并在下一次真实同步时惰性重建,保存本身不连接方舟、创建素材组、上传图片或等待审核。AccessKey 未变化时 SecretKey 留空可保留原密钥,更换 AccessKey 后启用前必须要求新的匹配 SecretKey。提供撤销、刷新覆盖确认、浏览器刷新与后台导航保护,不显示 Secret 明文;读取和保存响应需结构与字段一致性校验,失败不得自动重试。
- 模型响应拦截:必须定位为“用户可见错误文案投影”,不能暗示会修改上游响应、内部错误、失败记录或请求明细。全局开关切换后立即保存当前有效规则;规则内容和顺序继续暂存,点击一次“保存修改”直接提交,不再二次确认。规则语义必须与服务端一致:裁剪首尾空白、忽略英文大小写做包含判断、按列表顺序首条命中后整条替换。规则支持上移、下移、删除和最多 100 条限制;重复匹配文案需警告后续同文案无法命中。提供撤销、刷新覆盖确认、浏览器刷新与后台导航保护;启用但零规则不得描述为有效替换。本地预览只在浏览器内计算,不发送、不保存、不进入审计。读取和保存响应需做结构与规则顺序一致性校验,失败时即时开关恢复原状态且不得自动重试。
+100
View File
@@ -0,0 +1,100 @@
# 站点及外观与皮肤主题设计合同
## 1. 目标与边界
本模块让部署方在不修改源码的前提下管理站点身份、登录页内容、搜索摘要、首页收尾信息与全站皮肤。默认 `classic` 皮肤必须等同项目既有样式;自定义品牌不得在首次渲染、邮件、诊断包、素材插件或后台说明中短暂或持续露出内置品牌。
技术兼容标识不属于品牌文案:仓库名、容器/升级器路径、剪贴板协议、localStorage key、插件 API version、数据库基线校验值和 User-Agent 可以继续使用 `open-ai-canvas` 或 `infinite-canvas`。英文品牌标识只用于新资源路径建议,不能自动改写已有对象存储前缀或历史资源。
## 2. 领域模型
| 分组 | 字段 | 行为 |
| -------- | ------------------------------ | --------------------------------------------------------------------------------- |
| 品牌 | `brandName`、`brandSlug` | 中文/展示名称进入页面、邮件、导出与诊断说明;slug 用于安全的路径建议 |
| Logo | 浅色 Logo、深色 Logo、外框开关 | 两套可独立上传;只有一套时双主题复用;关闭外框时在原占位内等比放大 |
| 登录页 | 主标题、说明、视频、封面 | 登录/注册/找回密码共用;自定义视频无自定义封面时使用中性背景,不回退旧封面 |
| SEO | 标题、描述、关键词 | 标题/描述用于搜索摘要;关键词保留给其他搜索引擎或站内扩展,不宣称影响 Google 排名 |
| 首页收尾 | 版权信息、备案开关、备案号 | 备案号只有在显式开启且非空时显示,并链接工信部备案系统 |
| 皮肤 | `skinId`、`skinThemes` | 选择当前皮肤并维护主题库;每套同时定义亮色、暗色与组件参数 |
配置继续存储在 `system_settings.appearance` JSON 中,schema version 为 6,不增加关系型数据库迁移。旧配置缺失 SEO、版权、备案、主题库、独立开关状态或破坏性操作交互色时,运行时会按原有主色、控件色和危险色向后补齐;只有管理员保存后才写回数据库。管理接口返回完整 `skinThemes`,公开接口只返回当前 `activeSkin`,避免将未启用的运营草稿暴露给前台。
## 3. 皮肤架构
皮肤采用三层令牌和一个受控运行时适配层:
1. Primitive:色值、透明度、圆角数值。
2. Semantic:`background`、`foreground`、`surface`、`workspace-accent`、`danger`、`border` 等用途。
3. Component:按钮、输入、卡片、弹层、菜单与复选框圆角,以及控件高度、描边、焦点环、图标、字重、悬停抬升、动效和阴影。
4. Adapter:将同一份语义令牌同时映射到 CSS Custom Properties 和 Ant Design 全局/组件 token。
皮肤合同位于 `backend/internal/service/appearance_skins.go`,前端映射位于 `web/src/lib/skin-themes.ts`。页面不得按皮肤 ID 写条件样式;业务组件只能消费语义 token。`classic` 在运行时不写覆盖变量,使既有 `globals.css` 与 `app-theme.ts` 保持原样式唯一事实源;服务端会逐字段比对经典主题,任何删除或伪造修改都会被拒绝。其他主题均为可编辑数据,用根节点 CSS 变量覆盖自研组件语义层,并向 Ant Design `ConfigProvider` 提供同一套颜色、交互状态、圆角、尺寸、动效和阴影值。
主题库初始包含:
- 经典黑白:项目原始样式,默认值且永久只读。
- 创作室青橙、暖调柿棕、品牌紫蓝:作为开箱即用的初始数据,管理员可改名、编辑、复制或删除,不是写死的特殊主题。
每套主题包含浅色/深色各 50 项颜色令牌,覆盖页面、表面、文字、边界、普通控件、主操作、选中态、开关开/关轨道与滑块、图标、成功/警告/危险/信息状态、危险操作 hover/active/前景、画布、后台与登录场景;另含 17 项组件参数,覆盖六类圆角、三档控件高度、描边、焦点环、图标尺寸、按钮字重、悬停抬升、两档动效和阴影。主题总数上限为 16,颜色只接受 6/8 位 HEX,数值均有服务端范围与相互关系校验,不接受任意 CSS、选择器、URL、表达式或脚本。
管理员后台左侧导航是自定义菜单,现已显式消费“菜单圆角”参数;编辑器预览同步展示后台菜单样例,确保参数修改可以被直接确认。
主题卡色带不是装饰性样例:它按页面/表面/文字/边界/控件/主操作/状态等实际使用频次列出浅色与深色令牌的全部去重色值,固定宽度内按顺序截断尾部。青瓷工作室、暖柿纸境、霓光紫境三套预置主题分别维护完整的浅深色、开关与状态配色;经典黑白仍是不可编辑的系统基线。
管理员可从经典参数完整复制一套新主题,也可复制任意自定义主题;复制后得到新 ID 和独立深拷贝。创建、重命名、编辑、启用与删除都属于同一页草稿,保存时一次提交;删除当前主题会把草稿切回经典主题。颜色变化不能成为唯一状态信息,主题卡同时使用边界、勾选图标与文字表达选中。
实现依据采用业界通用的 design token 分层方式:Design Tokens Community Group 规范定义分组、类型与别名;Style Dictionary 强调平台无关的层级令牌;Ant Design 提供 Seed/Map/Alias 与组件 token,并建议用 CSS variables 支持动态切换;浏览器原生 Custom Properties 负责级联到自研组件。当前不引入 Style Dictionary 构建依赖,避免在单应用中增加无收益的生成链,但数据模型保留以后导入/导出标准令牌文件的空间。
## 4. 首屏与品牌一致性
`index.html` 保持中性标题和无品牌 Logo。`main.tsx` 必须先请求 `/api/public/appearance`,完成归一化、皮肤变量和 metadata 应用后,才能动态导入 React 应用。请求失败时才使用内置默认;自定义视频没有自定义封面时绝不加载内置海报。该顺序同时避免品牌文字、Logo、封面和色系闪现旧值。
运行时品牌投影包括:
- 登录、注册、找回密码页及邮件标题、正文、默认发件人名称。
- 普通工作区、管理端、素材插件、第三方导入说明。
- 画布批量导出、诊断 ZIP 的文件名和 README。
- 浏览器 title、description、keywords、Open Graph、Twitter Card、theme-color、favicon 与 canonical。
邮件“发件人名称”留空表示继承站点名;历史配置若仍为内置品牌,也按继承处理。管理员明确填写其他名称时保留独立值。
## 5. SEO 与备案合同
SEO 标题建议控制在 70 字符内,描述 200 字符内,关键词 300 字符内。Google 支持 title 与 description,但忽略 `meta keywords`;界面必须如实说明关键词不保证影响 Google 排名。客户端路由切换后 canonical 使用当前 origin 与 path,不包含查询串或 hash。
备案展示默认关闭。开启时必须填写备案号,页脚显示原样备案号并使用 `https://beian.miit.gov.cn/`,新窗口打开且设置 `noopener noreferrer`。不自动补造省份、序号或公安备案;版权和备案独立控制。
参考:
- [Ant Design 定制主题](https://ant.design/docs/react/customize-theme/?theme=dark)
- [Google 标题链接规范](https://developers.google.com/search/docs/appearance/title-link)
- [Google 支持的 meta 标签](https://developers.google.com/search/docs/crawling-indexing/special-tags)
- [工信部互联网信息服务管理规定](https://scca.miit.gov.cn/cms_files/filemanager/doc/201911/07d641dd71f54b519736e8d9e32b1dc7.pdf)
## 6. 后台交互合同
后台入口名称为“站点及外观”,继续复用系统设置页的页面框架、状态操作栏、`SettingsSectionCard`、Ant Form/Input/Switch 与统一保存模型。五个顺序固定为:品牌识别、登录页内容与媒体、SEO 信息、首页收尾与备案、皮肤主题。主题编辑器由主题库、身份编辑、浅/深模式切换、实时控件预览、语义颜色分组和组件参数分组组成;默认主题展示锁定原因,自定义主题显示复制与删除动作。
所有调整先形成页面草稿;只有点击“保存修改”才上传新资源并提交配置。保存响应成为新基线。离开、刷新覆盖和恢复内置品牌需要沿用现有未保存保护;恢复操作不删除已经上传的存储资源。皮肤卡必须可键盘操作,并以 radio/`aria-checked` 语义暴露选中状态。原生取色器只在点击颜色方块本身时打开;点击字段名称、说明或 HEX 输入不会代理触发系统取色器。取色器与 HEX 输入共享同一字段,非法中间值允许留在草稿中便于继续编辑,但前端保存校验和后端权威校验都会阻止其生效。
## 7. 验收清单
- 全仓用户可见 `影策` 只允许出现在内置默认值和“恢复影策默认”动作。
- 自定义站点名同时进入注册邮件、密码重置邮件和继承型发件人名称。
- 自定义品牌首次加载不闪现内置名称、Logo、视频封面或经典皮肤。
- `classic` 不写任何覆盖变量,管理端和伪造请求都不能修改或删除;三套初始扩展主题可以编辑和删除。
- 可从经典或任意当前主题复制出完整独立副本;新建、改名、编辑、启用、删除、撤销和刷新后的状态一致。
- 50×2 项颜色和 17 项控件参数经前后端校验,非法 HEX、越界数值、重复/非法 ID、超过 16 套、缺少当前主题均拒绝保存。
- 自定义主题同时驱动 CSS variables 与 Ant Design token;按钮、输入、选择、菜单、开关、勾选框、卡片、弹层、图标和状态色的同类实例保持一致。
- 开关开启和关闭均有独立轨道、悬停和滑块色;开启态还同时使用边界与外环反馈,不能只靠滑块位移表达。危险删除操作使用危险色的常态、悬停、按下和前景组合,警告提示统一消费主题警告色。
- SEO/版权/备案字段经前后端归一化、长度校验、存储、公开接口和 DOM metadata/页脚完整投影。
- 备案开关关闭时不渲染链接;开启且有号时链接只指向工信部备案系统。
- 亮暗主题、1600×1000 与 1278×900 后台视口无横向溢出,键盘焦点、hover、active 与减少动画偏好可用。
## 8. 主题研究参考
- [Design Tokens Community Group 格式规范](https://www.designtokens.org/tr/2025.10/format/)
- [Style Dictionary:Design tokens](https://styledictionary.com/info/tokens/)
- [Ant Design:定制主题与动态切换](https://ant.design/docs/react/customize-theme/?theme=dark)
- [Ant Design:CSS Variables](https://5x.ant.design/docs/react/css-variables/)
- [MDN:Using CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascading_variables/Using_custom_properties)