dsh-seasons-theme
Verifieddsh-seasons-theme · v1.0.2 · MIT · Web UI
四季主题:为 DSH Web GUI 增加默认与春、夏、秋、冬四套季节主题,每套均含浅色/深色,并提供侧栏主题切换菜单。
Install
dsh plugin add dsh-seasons-theme Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
四季主题 · dsh-seasons-theme
给 DSH Web GUI 增加 默认 + 春 / 夏 / 秋 / 冬 五套主题,每套都有浅色 / 深色两种模式;侧栏底部(设置按钮上方)新增一个主题切换菜单,四时色卡与明暗开关都在里面。
配色并非另配一套,而是直接沿用原教学系统的四季调色板(web/css/themes.css):
| 季节 | 主题名 | 浅色纸面 | 深色纸面 |
|---|---|---|---|
| 默认 | 暖纸 | #f5f6f3 |
#17212e |
| 春 | 花信 | #f4f7f1 |
#19252e |
| 夏 | 晴海 | #f0f7f7 |
#152531 |
| 秋 | 知秋 | #f8f5ef |
#232832 |
| 冬 | 初雪 | #f2f5f9 |
#1a2435 |
做了什么
- 季节 = 覆盖层:通过 DSH 的主题扩展点
ctx.theme.overrideTokens(),把一套季节 token(浅/深成对)叠在内置主题上。季节选择记在浏览器localStorage;「默认」不注册覆盖层,保持 DSH 原生外观。 - 明暗 = DSH 自带偏好:浅色/深色按钮调用
ctx.theme.setTheme('light' | 'dark'),因此与「设置 → 通用 → 外观」完全同步。偏好为跟随系统且系统此刻正好是所点模式时不会改写偏好,系统切换深浅时菜单状态也会跟着变。 - 切换菜单:触发按钮注册在
sidebar.footer.action(展开时是「主题 + 当前季节」,收起时是 36×36 图标);浮层注册在shell.overlay,从触发按钮处向上展开,点击外部 / Esc 关闭,Tab 有焦点循环。 - 弹层为不透明纸面:主题菜单与其他弹出式菜单统一使用不透明的季节纸面底色,不做毛玻璃、不做背景模糊、没有任何发光描边;文字层级与可点击区域保持宿主原有行为。
- 菜单展开/收起:主题切换菜单展开与收起是一对互逆的纯淡入淡出(约 140–160ms,无位移、无缩放、无过冲甩尾),收起动画播完才卸载。
- 四季插画背景:四季各有原教学系统原版 720×240 插画(
web/assets/themes/*.svg,构建时内联)。按原教学系统的处理方式只放在外壳边缘——页面右下角一幅、侧栏底部一幅(展开时才有),低透明度、顶部渐隐,内容区不加图案、不改变卡片底色;默认主题不铺插画,保持原生外观。手机上侧栏只剩 56px 导轨,侧栏插画自动隐藏,只留页面右下角一幅(更淡);侧栏展开/收起时插画跟着做缩放淡入淡出,和侧栏动画同步。- 说明:DSH 没有开放"页面背景"槽位,插画是以
pointer-events:none的边缘覆盖层画在shell.overlay里的,因此不写宿主 DOM、不遮点击;文字密集处它自然很淡。
- 说明:DSH 没有开放"页面背景"槽位,插画是以
- 太阳 / 月亮:浅色模式在插画的日轮位置叠一枚季节色太阳(圆盘 + 八道光芒 + 柔光);深色模式叠一枚原教学系统同款的弯月(同一套
night-sky-moon月牙路径 + 暖金柔光)。手机端太阳/月亮移到右上角,避免压到输入框。 - 深色星空与流星:季节深色模式下叠加
stars.svg星点底纹 + 16 颗自绘闪烁星;每 8–15 秒随机落下 1–2 颗流星,位置、长度、时长都随机;同一批的两颗像同一场流星雨——飞行方向一致,入射角差 ≤6°。prefers-reduced-motion下流星与闪烁关闭,插画保留。 - 运行中标签的扫光动画:
深度求索中,用时…与上方运行行使用 DSH 的TextShimmer。之前把label-deep-diving/label-deep-diving-shimmer映射成了半透明色,扫光块变成透明→动画看不见;现在两个 token 都是不透明的季节色(深色下底色为中调、扫光为亮调),扫光恢复可见。 - 夜间鼠标光晕(默认关闭):在「设置 → 通用 → 鼠标光晕拖尾」里打开后,季节深色模式下鼠标在操作区移动时跟一层很淡的季节色光晕(直径约 60px)+ 3 个渐小的拖尾点;指针静止约 0.7 秒自动淡出并停止 rAF。开关按浏览器记忆(
localStorage),默认关闭;侧栏、主题菜单内、触屏设备不显示;pointer-events:none且mix-blend-mode:screen,不拦截任何点击/拖拽,prefers-reduced-motion下关闭。 - 切换过渡:季节切换与明暗切换都有 420ms 淡入过渡——支持 View Transitions 的浏览器做整页交叉淡入(新画面盖在旧画面上淡入,不闪白、不打断菜单操作);不支持的浏览器退化为背景/文字/边框/图标描边的 420ms 颜色渐变。
prefers-reduced-motion下直接切换。 - 覆盖范围:110 个 token(
--dsw-alias-*、--dsw-specific-*、菜单底色等),覆盖画布、卡片、浮层、侧栏、菜单、按钮、输入、Markdown 代码块、文件 diff、状态色、滚动条、Toast、Tooltip、引导页等。遮罩、图片工具栏、shiki 语法色、阴影刻意保留原生值。 - 兼容与可验证:所有派生色在构建时算成普通
#rrggbb/rgba(),生成物里没有color-mix(),较老的手机浏览器也能正确上色。build.mjs会在构建时用真实 token 做对比度/亮度断言,写反一处就直接构建失败。
构建时强制保证
node build.mjs 会对四套季节 × 明暗两种模式逐项检查:
- 正文
label-primary在画布、卡片、次级表面、侧栏、气泡、菜单材质、代码块等 13 类内容表面上 ≥ 4.5:1; - 次级文字在主要表面上 ≥ 4.5:1,三级文字在纸面与菜单材质上 ≥ 4.5:1;
- 主按钮文字、Toast 文字、浮层角标文字、链接、状态色文字 ≥ 4.5:1;运行中标签底色 ≥4.5:1,扫光色与底色文字拉开可感知差异;
- 发送键(写死白图标)的填充色与白色 ≥ 3.5:1;
- 深色模式下所有“浅色表面类” token 亮度 ≤ 0.45,浅色模式下的纸面类 token 亮度 ≥ 0.5(防止深浅写反);
- 深色代码块必须比它的标题条更暗,也必须比卡片更暗;深色细描边必须弱于 l2 描边;
- 所有 token 值只允许
#hex/rgba()/var()/linear-gradient()。
安装
从 npm(推荐)
# 在 DSH 会话中调用 plugin_manager
action: install_bundle
target: [email protected]
或命令行:
dsh plugin --profile web add dsh-seasons-theme
从 GitHub
dsh plugin --profile web add github:Sirilean/dsh-seasons-theme
从“发现”页(自定义市场索引)
- 插件页 →「实验性插件 → 更多」启用自定义插件市场;
- 「发现 → 添加索引源」,填:
https://sirilean.github.io/dsh-seasons-theme/market.json - 搜到「四季主题」后点安装。
这个地址需要先在 GitHub 仓库 Settings → Pages 里把
main分支根目录设为 Pages;没开 Pages 时前两种方式照样可用。
本地开发
action: install_bundle
target: D:\工作区\dsh-seasons-theme
或:
dsh plugin --profile web add link:D:/工作区/dsh-seasons-theme
安装后侧栏底部「设置」上方会出现「主题」一行,点开即是四时菜单。已打开的页面通常会在几秒内通过 client HMR 自动加载新 bundle;若未生效(例如没有运行 bundle watcher),刷新页面即可。 卸载/停用后覆盖层、样式与菜单会一起移除,不会留下写死的颜色。
目录
dsh-seasons-theme/
├─ package.json # bundle 清单 + dsh.client(web / immediately / inject)
├─ cordis.patch.yml # 插入 Host 行
├─ index.js # Host 空壳
├─ client.js # 构建产物:调色板数据 + 主题覆盖 + 菜单(自包含,无外部依赖)
├─ build.mjs # 由 src/ 生成 client.js,并做对比度/亮度/兼容性断言
├─ market.json # 自建插件市场索引(format 1,GitHub Pages 托管)
├─ .github/workflows/ # verify(push/PR)+ publish(打 tag 时 npm publish --provenance)
├─ src/
│ ├─ palette.mjs # 原教学系统四季 × 明暗调色板(唯一颜色出处)
│ ├─ tokens.mjs # 调色板 → DSH token 的映射规则(构建时算色)
│ └─ client.template.js # 菜单、插画层、星空/流星与插件逻辑模板
├─ assets/ # 原教学系统四季插画与星点图(构建时内联为 data URI)
├─ tests/smoke.mjs # Node 冒烟测试:注册、菜单、覆盖层、明暗、对比度、插画、卸载
├─ locale/{zh,en}.json # 插件列表里的标题与说明
└─ icon.svg # 四时主题图标
改配色只需要动 src/palette.mjs(或 src/tokens.mjs 里某个 token 的取法),然后:
node build.mjs # 生成 client.js + 校验
node --check client.js
node tests/smoke.mjs # 冒烟测试
开源与发布
- 仓库:https://github.com/Sirilean/dsh-seasons-theme
- npm:https://www.npmjs.com/package/dsh-seasons-theme
- 自建市场索引:https://sirilean.github.io/dsh-seasons-theme/market.json
- 作者:李卓奇 · License:MIT(代码);四季插画为作者自有素材,随本插件一并授权使用,详见
PROVENANCE.md。
发布新版本:
- 修改
package.json的version; - 在
market.json的versions数组里追加一条(精确 SemVer + Unix 秒publishTimestamp); - 提交并打 tag:
git tag vX.Y.Z && git push origin vX.Y.Z; - GitHub Actions 的
publish工作流会用NPM_TOKENsecret 执行npm publish --provenance(prepublishOnly会先跑npm run verify); - 用户在「发现」页刷新(缓存约 10 分钟)即可看到新版本;当前市场不支持原地升级,需要卸载后重装。
也可以本地手动发布:
npm run verify
npm pack --dry-run # 检查清单
npm publish
更新
- 1.0.2:统一主题菜单面板——默认主题(尤其浅色)下不再使用宿主的半透明菜单底色,改为不透明
bg-layer-1,与四季主题下的菜单一致。 - 1.0.1:修复侧栏底部插画在拖动侧栏宽度时不跟随、裁切错位的问题。
- 已安装旧版的人:先在插件页看
dsh-seasons-theme是否出现「可更新 / 更新」并点更新;如果只有「已安装」,就卸载后重新安装:- 插件 → 已安装插件 →
dsh-seasons-theme→ 卸载; - 插件 → 添加插件 → 输入
dsh-seasons-theme(或精确指定[email protected]); - 刷新页面。
- 插件 → 已安装插件 →
- 也可以用
plugin_manager:remove_bundle(targetdsh-seasons-theme)→install_bundle(target[email protected])。 - 季节、明暗、鼠标光晕开关都存在当前浏览器的
localStorage,卸载重装不会丢失;主题菜单里的当前季节会自动恢复。 - 市场索引有约 10 分钟缓存;刚发的版本若暂时看不到,等缓存过期后刷新「发现」页。
兼容性
- 在 DSH 0.2.1-rc.2 上测试通过;插件只依赖 DSH 内置 Client 包,DSH 升级后若包名或扩展点变化,需要跟着更新。
- 只用公开扩展点:
ctx.theme(getTheme/setTheme/overrideTokens/theme/change)、ctx.slots、ctx.locale;没有 import 任何 Harness Client 包,也没有读写别的插件的 DOM。 - 依赖的内置包:
@deepseek-ai/dsh-client-ui-theme(主题服务)、dsh-client-ui-sidebar(sidebar.footer.action)、dsh-client-ui-layout(shell.overlay)。缺少时插件不激活,不会报错刷屏。 - 与内置「外观」设置共存:季节是一层,明暗是内置偏好,两者互不覆盖。
已知限制
- 季节选择存在当前浏览器的
localStorage,不跨浏览器同步(与原教学系统原版一致)。 - 主题 token 是 DSH 的 alias 层;若未来 DSH 新增组件只消费静态色(
--dsw-static-*),那部分不会跟着换季。这一类颜色属于原生语义色,本插件有意不动。 - 少数组件把白字直接写进样式(例如附件失败徽标用
state-error-primary作底 + 固定白字)。深色季节的粉色错误色与白字对比约 2:1;发送键同 token 也被 11px 徽标文字复用(深色约 2.3–2.5:1,原生约 5.2:1)。要在“白图标可用”和“徽标文字可读”之间取舍;如更在意徽标文字,可把button-info-fill深色比例从 55% 调到 65%。 - 视觉验证:本次交付在无浏览器控制的环境下完成,已确认 JS 语法、manifest、安装结果、插槽的实时注册、HMR 实际加载新 bundle、主题服务接受 110 个覆盖 token、构建期对比度/亮度断言与冒烟测试全部通过;像素级观感请刷新页面后目视确认。