DSH 浅绿主题
一套浅绿配色,覆盖 DSH 的 --dsw-* 令牌,并让选中的菜单项与会话行加粗。
配色预览
一、安装
桌面端的 desktop profile 被 Electron 应用独占管理,CLI 装不了,只能走侧栏:
-
左侧栏点 「插件」
-
点 「添加插件」,粘下面任意一种:
| 你手上的是 | 输入框里粘 |
|---|
| 这个文件夹(本地开发) | 文件夹的绝对路径,例如 E:\deepseek的一个工作区\dsh-my-theme |
一个 .tgz 包 | 那个 tgz 的绝对路径 |
| 一个 Git 仓库 | github:catEatRabbit/dsh-light-green-theme |
-
安装 → 「立即启用」
不用重启,HMR 会热挂载。
装好后如果改了 lib/client.js,要重启应用才生效——客户端模块的 HMR
覆盖不到第三方包的新版本。
二、第一次使用
去 设置 → 通用 → 外观:
- 明暗选 浅色(别用「跟随系统」——系统若是深色,生效的是深色那一套值)
- 会多出一个主题方块,可以选它
不过默认配置下不用手动选:插件把那套配色常驻叠在当前主题上,装完就已经是浅绿了。
那个方块的作用是让你能一键切回原生配色。
三、它改了什么
配色对照
浅色一侧是拿界面截图逐点采样出来的,不是目测估的:
| 界面位置 | 颜色 | 覆盖的令牌 |
|---|
| 主区底色 | #f6f8f5 | --dsw-alias-bg-base |
| 侧栏底色 | #e3ece4 | --dsw-specific-sidebar-fill |
| 白卡片 | #ffffff | --dsw-alias-bg-layer-1 |
| 浅绿包裹层 | #e9f4ea | --dsw-alias-bg-layer-2 |
| 浮层 | #ffffff | --dsw-alias-bg-overlay |
| 卡片描边 | #dce7dd / #cde0ce | --dsw-alias-border-l1 / -l2 |
| 品牌绿 | #3c8c4e | --dsw-alias-brand-primary |
| 正文 | #283a2f | --dsw-alias-label-primary |
| 次级文字 | #606c64 | --dsw-alias-label-secondary |
| 悬停 | #d8e8dc | --dsw-alias-interactive-bg-hover |
| 选中 | #c3dcc6 | --dsw-alias-bg-module-platform |
| 设置导航选中 | #c3dcc6 | --dsw-specific-sidebar-nav-item-active |
| 设置导航悬停 | #d8e8dc | --dsw-specific-sidebar-nav-item-hover |
深色一侧按浅色色相(H≈126°)派生,保证明暗两套是同一个配色族。
两处刻意的偏差
- 次级文字压暗了。采样原值是
#7a897f,但它在底色上的对比度只有 3.44,
低于 WCAG AA 的 4.5,正文级文字偏难读。这里改成 #606c64(色相不变),
对比度 5.14。想还原原样,把 PALETTE 里那一行换回 #7a897f。
--dsw-alias-bg-module-platform 影响不止一处。它同时被「外观」的选中方块和
会话的 EnterBehavior 选择器消费,所以那两处也会变浅绿。这是预期效果。
加粗
| 位置 | 效果 |
|---|
| 设置对话框左侧导航的选中项 | 加粗 |
| 侧栏会话列表的选中行 | 加粗 |
--dsw-* 是颜色/材质令牌,表达不了 font-weight,所以这两条是注入 CSS 实现的,
选择器写在 lib/client.js 的 extraCss() 里。改动注意事项见第八节。
四、改配色
打开 lib/client.js,只改 PALETTE。每一项必须是 { light, dark } 一对:
'--dsw-alias-brand-primary': { light: '#3c8c4e', dark: '#3c8c4e' },
只写一个字符串会抛错——这是官方的校验,防止你切到另一套明暗时颜色变得不可读:
theme override "…" is a bare string — pass { light: …, dark: … }
(repeat the value when it is the same in both palettes);
a single value goes illegible when the user switches color scheme
改完跑自检:
node verify.mjs
还能改哪些令牌
官方文档化的 14 个(全是颜色):
--dsw-alias-bg-base、--dsw-alias-bg-layer-1、--dsw-alias-bg-layer-2、
--dsw-alias-bg-overlay、--dsw-alias-border-l1、--dsw-alias-border-l2、
--dsw-alias-brand-primary、--dsw-alias-label-primary、--dsw-alias-label-secondary、
--dsw-alias-state-error-primary、--dsw-alias-state-idle-primary、
--dsw-alias-state-success-primary、--dsw-alias-state-warn-primary、
--dsw-specific-sidebar-fill
未列出但同样有效的还有很多(主题包自己的样式表就在消费它们)。本插件用到的有
--dsw-alias-interactive-bg-hover、--dsw-alias-bg-module-platform、
--dsw-specific-sidebar-nav-item-active / -hover / -accent。
状态色
成功/警告/错误的颜色在原截图里看不出来,所以没有覆盖,沿用 DSH 内置值。
想把它们也统一成绿色系,加进 PALETTE:
'--dsw-alias-state-success-primary': { light: '#2f8f4a', dark: '#4fae66' },
'--dsw-alias-state-warn-primary': { light: '#b8860b', dark: '#d8a63d' },
'--dsw-alias-state-error-primary': { light: '#c0453f', dark: '#e0706a' },
'--dsw-alias-state-idle-primary': { light: '#7a897f', dark: '#9baba1' },
五、开关速查
lib/client.js 顶部的 OPTIONS:
| 开关 | 默认 | 作用 |
|---|
registerLight | true | 在外观里注册一个可选主题方块 |
registerDark | false | 再注册一个深色系主题方块 |
pinPalette | true | 常驻染色,让配色跟着内置明暗偏好一起持久化 |
forceLightEverywhere | false | 深色模式也用浅色那一套值 |
boldSelected | true | 选中项加粗 |
pinPalette 为什么默认开
DSH 只把内置偏好写进设置(THEME_PREFERENCES = ["light","dark","system"])。
所以用 register 注册的主题能选、能立即生效,但选择不会跨重启保留,
重启后回落到内置偏好。
pinPalette 改用 overrideTokens,把这套令牌常驻叠在当前主题上,偏好本身仍是内置值,
于是天然持久化。
| 取值 | 效果 |
|---|
true | 无论选哪个主题都是这套绿,重启后还在 |
false | 只有那个方块是绿的;选别的就回原生配色,且重启后选择丢失 |
六、换背景图(可选,默认关)
const WALLPAPER = {
enabled: true,
url: 'https://example.com/pic.jpg', // 或 'file:///E:/图片/壁纸.jpg'
opacity: 0.35,
blur: '8px',
scrim: 'rgba(0,0,0,.25)', // 压暗图片,保文字可读
extraCss: '',
}
DSH 的令牌 valueType 是 CSS color,装不下图片,所以这一块是自己往
document.head 注入 <style>,把图铺在 body::before 上。
各面板默认不透明,会盖住它——想看见图,得同时把底色令牌改成半透明:
'--dsw-alias-bg-base': { light: 'rgba(246,248,245,.72)', dark: 'rgba(19,24,17,.68)' },
'--dsw-alias-bg-layer-1': { light: 'rgba(255,255,255,.66)', dark: 'rgba(25,31,26,.62)' },
'--dsw-specific-sidebar-fill': { light: 'rgba(227,236,228,.60)', dark: 'rgba(12,18,13,.58)' },
想要精致的壁纸(玻璃拟态、层叠上下文、文字可读性处理)建议直接用现成的:
dsh-dream-skin —— 8 套主题 + 弥散光壁纸
dsh-plugin-wallpaper-engine —— 播本机 Wallpaper Engine 的壁纸,自带 WebGL 引擎
七、卸载与恢复
卸载:侧栏 「插件」→「已安装」 → 找到 dsh-light-green-theme → 卸载。
界面被搞坏了、进不去设置页:启动失败时应用会弹恢复框,选
「禁用第三方插件、备份 profile patch 并重启」。
⚠️ 那个操作会把 dsh.profile.bundles 重置回默认,你手动开过的其他可选组合包
(例如 dsh-experimental-auto-review)也会一起被清掉。所以它只当最后手段用。
八、二次开发
文件结构
dsh-my-theme/ ← 本地文件夹名(包名是 dsh-light-green-theme)
├── package.json 组合包声明(dsh.bundle.patch)+ 浏览器半侧声明(dsh.client)
├── cordis.patch.yml Loader 层:插入一行,name 必须等于包名
├── LICENSE MIT
├── locale/
│ ├── zh.json 显示名:DSH 浅绿主题
│ └── en.json 显示名(英文)
├── lib/
│ ├── index.js 宿主半侧(普通 ESM,空实现)
│ └── client.js 浏览器半侧 —— 配色、开关、加粗 CSS 都在这里
├── tools/
│ └── find-token.mjs 令牌/选择器反查工具
├── verify.mjs 结构自检
├── palette-preview.png 配色预览图
├── README.md 本文件
└── SHARING.md 分享与发布
三条硬性约束
-
cordis.patch.yml 里那一行的 name 必须与 package.json 的 name 一致 ——
浏览器半侧的模块身份取自清单里的包名。
-
必须有 dsh.bundle.patch —— 没有组合包 patch 的包,插件管理页在安装前就拒绝。
-
两个半侧的模块格式不一样:
| 半侧 | 文件 | 格式 |
|---|
| 宿主 | lib/index.js | 普通 ESM(export { apply }) |
| 浏览器 | lib/client.js | window.__ModuleLoader__.load({...}) 包着的惰性 CJS factory |
浏览器侧必须是那个外壳:写成普通 ESM 时加载器等不到 load() 调用,
这一行会静默不生效——不报错、不弹窗,界面纹丝不动。
所以 client.js 外面那层壳不能删,改配色只动里面的 PALETTE。
改完跑 node verify.mjs 验证:它会用桩模拟加载器,检查 load() 是否被调用、
factory 是否导出 apply/inject、每个令牌是否是合法的 { light, dark } 对、
注入的加粗 CSS 是否包含预期选择器。
加粗用的哈希类名会随版本失效
加粗的选择器用的是 DSH 构建产物的 CSS-module 哈希类名:
.wCInkW_navCell.wCInkW_active, /* 设置导航选中项,来自 ui-settings-general */
.wCInkW_navCell[aria-current] /* 同一处的语义兜底,哈希变了还能命中 */
.hIlkoa_sessionRow.hIlkoa_selected /* 会话列表选中行,来自 ui-workspace */
DSH 升级后如果加粗失效——不报错,只是没效果——用自带工具重新定位:
# 必须用 Electron 的 node 模式:普通 node 读不了 app.asar
$env:ELECTRON_RUN_AS_NODE=1
& "E:\DeepSeek Harness\DeepSeek Harness.exe" "<插件目录>\tools\find-token.mjs" --dsw-specific-sidebar-nav-item-active
它会输出定义值和消费它的选择器,照抄进 extraCss() 即可。不带参数跑则列出
名字含 select/active/nav/hover 的令牌,方便先找候选:
& "E:\DeepSeek Harness\DeepSeek Harness.exe" "<插件目录>\tools\find-token.mjs" --list-active
九、分享与发布
见 SHARING.md。