dsh-background-by-model 0.7.3 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +180 -171
- package/CHANGELOG.zh.md +181 -170
- package/LICENSE +21 -21
- package/README.md +297 -300
- package/README.zh.md +297 -300
- package/cordis.patch.yml +8 -8
- package/lib/client.js +62 -11
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.zh.md
CHANGED
|
@@ -1,170 +1,181 @@
|
|
|
1
|
-
# 更新日志
|
|
2
|
-
|
|
3
|
-
> 这里保留完整的历史记录;最近两个版本(v0.7.
|
|
4
|
-
|
|
5
|
-
## v0.7.
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- **门禁** —— `check:transition
|
|
15
|
-
|
|
16
|
-
## v0.7.
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
- **门禁** —— `check:
|
|
35
|
-
|
|
36
|
-
## v0.7.
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
-
|
|
74
|
-
- **
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
- **`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
-
|
|
112
|
-
- **`
|
|
113
|
-
-
|
|
114
|
-
|
|
115
|
-
## v0.4.
|
|
116
|
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
-
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
## v0.3.
|
|
149
|
-
|
|
150
|
-
-
|
|
151
|
-
-
|
|
152
|
-
-
|
|
153
|
-
|
|
154
|
-
## v0.3.
|
|
155
|
-
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
> 这里保留完整的历史记录;最近两个版本(v0.7.4 / v0.7.3)同时列在 [README.zh.md](./README.zh.md#近期优化) 里。
|
|
4
|
+
|
|
5
|
+
## v0.7.4
|
|
6
|
+
|
|
7
|
+
- **弹窗里的控件现在和壁纸走同一个时钟,而不是等它切完再跳(这一条是修复)** —— 换主题色那一下,设置弹窗里的控件(「节日特殊背景」的开关填充、「平移推入」「标准」这些胶囊按钮)会**整整一套切换时长**停在上一套颜色上,直到背景切完才瞬间换成新的:一次 3 秒的换图看起来就是"界面先不管它、末尾来一下硬切"。这是从一个真实会话里量出来的(探针每 100ms 读一次 `getComputedStyle`):`body` 上的 `--dsw-alias-brand-primary` 确实在插值,930ms 起跑、3000ms 走完,中间点 `rgb(199,131,30)` 与 `ease` 曲线在 53% 时间点的值吻合;而同一个探针读到的**胶囊按钮实际底色**在整个 3 秒里每一次采样都是 `rgb(53,152,177)` —— 与旧值逐位相同,而不是混合值 —— 直到 4063ms(body 的动画刚结束)之后才用约 150ms 跳到 `rgb(230,126,0)`。
|
|
8
|
+
- **卡住的是中间层,不是"继承拿不到动画值"** —— 这是先被排除掉的猜想。WPT 有一条 [custom-property-animation-inherited-used-by-standard-property](https://github.com/web-platform-tests/wpt/blob/master/css/css-properties-values-api/animation/custom-property-animation-inherited-used-by-standard-property.html) 明确要求"祖先上动画的自定义属性必须体现在子元素使用它的标准属性上",隔离实验也证实了:只继承、自己没有过渡的消费者**逐帧跟随**声明它的那个元素。真正的成因是插件自己把**整张 token 表**挂到了三个元素上,而其中两个(设置弹窗与轨迹页根节点)**只重新声明**三个 layer token,其余全是继承来的。给一个只继承的 token 挂过渡,该元素的过渡目标就是**武装那一刻它看到的值** —— 祖先正在插值,那个值还是旧的 —— 于是它自己变成一条被阻尼的过渡,整棵子树跟着这份滞后的副本走。同一组隔离实验里的对比:声明方跑 1200ms 过渡时,只继承且**没有**自己过渡的消费者逐帧跟随;只继承但**挂了**同样过渡的中间层到 t=1500ms 才走到 113/255。
|
|
9
|
+
- **修法:过渡表按作用域给,每个元素只拿自己声明的 token** —— `paletteFadeCss` 的输入从 `selectors: string[]` 变成 `scopes: { selector, tokens }[]`:`body` 拿全表(其余一切都从它继承),弹窗与轨迹页根节点只拿它们重新声明的那三个 layer token。这不是"少挂几条"的优化,而是这个形状存在的全部理由 —— 一个作用域拿到自己没有声明的名字,就是把上面那条滞后复制到整棵子树上。产出的 CSS 从 `body,.dlg,[data-conversation-composer-overlay]{transition:…全表…}` 变成 `body{…全表…}` 加两条只列 layer token 的规则。
|
|
10
|
+
- **门禁** —— `check:transition` 新增两条:**「a scope is never given a token it only inherits」**(弹窗那份列表里绝不允许出现 `--dsw-alias-label-primary` 这种它只继承的名字),以及「自己什么都没声明的 scope 不发规则」。原来那条「每个注册 token 都在过渡表里」照旧保留(`body` 仍然是全表),所以这次修复不可能悄悄退化成"所有作用域都拿全表"。
|
|
11
|
+
- **顺带记录一个不构成原因的现象**:探针还显示那张 fade 表在武装后的一帧左右,就被后续一次非调色板 apply 重写成了不带 `transition` 的版本(`applyPaletteFade` 的 `animate=false` 分支),而**已经起跑的过渡不会因为声明被撤掉而中断**(同一次测量里,body 的过渡在表里已经没有 `transition` 的情况下照旧跑满 3000ms)。所以它不是这次卡顿的成因;但它意味着"过渡还没开始"的元素什么都拿不到 —— 留给下一次动这块代码的人。
|
|
12
|
+
- **还有三块在硬切,而且正是那些用插件自己的颜色画的面(这一条是修复)** —— 后续反馈("还有几个元素的背景色是直接换的",界面透明度拉到最大)不是上一条那个 bug,随它一起来的截图直接指出了是哪几块:把中间那帧的每个像素分别与首帧、末帧比对(已到终色 / 仍在首色)之后,**设置弹窗自己那块底板** —— 表现为左侧栏、标题行和卡片四周的留白 —— 已经在终色上,而它里面的每一个 `.dab-card` 还在首色上。卡片在渐变、它背后的底板不渐变,说明这走的是另一条上色路径:底板不是用注册过的 alias token 画的,而是用 `--dsh-any-bg-settings-surface` —— 一个插件自有、内联写在 `<html>` 上、已经折进设置透明度的变量;而**未注册**的自定义属性根本不能插值,既没有 token 可注册,也没有 token 可过渡。同一形状还有两处:文件预览面板(`--dsh-any-bg-rightbar`,由 `RIGHTBAR_STYLE_RULE` 那三个选择器读取)和 Cordis 面板(`--dsh-any-op-menu-cordis`,在它上面重新声明 `--dsw-specific-menu`)。
|
|
13
|
+
- **修法:作用域可以点一个标准属性,且上色规则与淡入共用同一个选择器** —— `PaletteFadeScope` 新增 `properties?: string[]`,与 token 一起排进同一条 `transition`,并且**故意不**按注册名过滤(属性名不是宿主需要发布的东西)。`fadeScopes()` 里设置弹窗底板与文件预览面板各带一条 `background-color`,Cordis 面板带 `--dsw-specific-menu` —— 它是同一类问题的第三种,但因为它重新声明的那个 token 本来就是我们自己的,所以点 token 就能到它。两条上色规则与各自的淡入作用域现在各读同一个共享常量(`RIGHTBAR_SEL`、`CORDIS_PANEL_SEL`),上色的那一半和淡入的那一半不可能再走岔。在 Chromium 里拿**真实产出的 CSS** 量过、按截图里那几个颜色跑一次 3000ms `ease`:旧 CSS 下底板、右侧面板、Cordis 面板在第一次采样时就已经是**终色**并且再没动过,而卡片从 `rgba(217,233,237)` 爬到 `rgba(255,255,255)`、胶囊从 `rgb(87,167,188)` 爬到 `rgb(236,151,67)`;新 CSS 下五者**每一次采样都处在同一进度** —— t=1500ms 时 80.2%,恰好是 `ease(0.5)`:底板 `rgba(239,234,221)`、右侧面板 `rgba(181,178,168)`,各自在自身的起止区间上与卡片逐位吻合。`0` ms 时长同样会把这几个属性一起解除武装,所以拖动滑杆时底板依旧贴着指针走。
|
|
14
|
+
- **门禁** —— `check:transition` 补上了淡入形状的另一半:只带标准属性的作用域照样发规则、该属性与 token 用同一套时长与缓动、属性绝不会被当成颜色去注册、一个未注册的 token 名不再连累同一作用域里的属性、`0` ms 同样解除它。`check:repaint` 补上了配对本身:三块插件自绘的表面必须既由自有变量上色、又有一个点着同一个共享常量的淡入作用域 —— 以后再添第四块而忘了淡入,会是一条失败的门禁,而不是一张没人拍的截图。
|
|
15
|
+
|
|
16
|
+
## v0.7.3
|
|
17
|
+
|
|
18
|
+
- **切换效果本身成了一个设置:四种效果、一种缓动、一个时长,都在「配置」页上** —— 这个插件做的每一次换图(切模型、轮换一步、手动「下一张」、节日接管、换成另一条规则生效)此前都走同一个写死的交叉淡入,而它的时长读的是一个没有任何控件能碰到的字段。效果和缓动是全局的,因为规则没有「过渡」这个概念:**淡入淡出**(opacity)、**直接切换**、**缩放淡入**、**平移推入**(transform,只作用在进来的那一层上 —— 壁纸层从来没用过这个属性,所以两种新效果一个字节的额外传输都不花)。「直接切换」和 `0` 毫秒是同一个硬切,而不是其中一个被读成「没设置」;`0` 是一个被保留的真实取值,不会被默认值顶掉;系统的「减少动态效果」是**否决**,而不是把动画缩短。判定是纯函数(`src/client/transition.ts`),正因如此 `check:transition` 才能钉住那些不会抛错的失败:起始状态与结束状态相同的效果(看上去什么都没做)、会把进来的那一层留在缩放状态上的效果(此后每一张壁纸都会被裁掉一块),以及 `fade` 不再逐字节等于早先版本写下的那个字符串。
|
|
19
|
+
- **卡片上带一个预览色块,而它不是装饰** —— 壁纸淡入它自己是什么都看不见的,所以「在已经在屏的那张图上重放效果」会什么都不显示:这是这个功能唯一可能「明明在工作却看起来坏了」的方式。色块按此刻一次真实切换会用的时长重放选中的效果,点效果或点缓动都会立刻重放一次。
|
|
20
|
+
- **时长只有一个,「跟随每条规则」删掉了** —— 那张卡的默认值是「跟随每条规则」,而它指向一个界面根本设不了的值:`rotate.fadeMs` 从 0.7.0 起就在格式里,却从来没有控件能到达它,所以那个选项是在一个真设置和一个幻影设置之间做选择。现在滑块本身就是那个设置,它让位的字段也一起删了。对唯一可能带上它的那种配置来说,这并不是一次无声的丢失:那个字段只可能被手工编辑,所以当一份早于这个设置的配置第一次被读取时,`legacyFadeMs` 会把找到的第一个「有意为之」的值折进全局时长 —— 等于出厂值 320 ms 的一律忽略(普通配置就保持普通默认值),而显式的 `durationMs` 永远胜过它旁边的旧字段。`rules[].rotate.fadeMs` 同样豁免漂移警告,理由相同:它是在被迁移,不是在漂移。
|
|
21
|
+
- **界面配色现在和壁纸走同一个时钟** —— 换一个主题色本质是一次 `body{--dsw-alias-…}` 的重写,它在一帧之内改掉每一个表面,而背后的图还在淡入淡出:这就是动画前面接了一下硬切。这个渐变是**注册**问题而不是声明问题 —— 未注册的自定义属性无法插值 —— 所以 `src/client/palette-fade.ts` 会发出把别名令牌变成 `<color>` 的 `@property` 规则,外加一条 `transition`,作用于「自身的声明会随调色板变化」的那些元素:`body`,以及两个**重新声明**层令牌而不是继承它们的表面(设置弹窗与轨迹页根节点)。插件**内联**绘制的两处(三栏列,以及对话/轨迹卡片)根本不读这些令牌,所以它们把同一个时长直接挂在 `background-color` 上。时长、缓动与两项否决都来自壁纸用的**同一个** `transitionPlan`,所以「直接切换」、`0` 毫秒和「减少动态效果」不可能对图是一个意思、对界面又是另一个意思。它**只在调色板确实变了**的时候武装:其它每一次 apply 都在重写同一段令牌(拖滑块改的是 alpha),那些写入不带过渡、内联写 `none`,因为那里挂一条活着的过渡会让表面跟不上指针。宿主没有公布的令牌是**刻意不注册**的 —— 注册需要 `initial-value`,而一个没有别的东西去设置它的已注册属性,会解析到那个初始值、而不是插件自己样式表依赖的 `var(…, fallback)` 链,注册它就等于用一个人为的颜色替换掉回退值。
|
|
22
|
+
- **浅↔深互切是立即切换,而壁纸照旧做动画(这一条是修复)** —— 在两套调色板之间插值会让整个界面走过中间调,而那里的墨色**两个方向都是错的**(深色文字走进一半的深色调色板,而且用的是**上一套**方案的墨色),所以浅↔深互切恰恰是渐变会让事情变糟的那一种情况。现在渐变只在**配色深浅不变**时武装(浅→浅、深→深);浅↔深立即切换,也就是渐变出现之前的行为。这条规则刻意不碰壁纸:一张图淡入另一张图没有「深浅」可以搞错,所以它照旧听切换效果的。`paletteFadeAllowed` 就是这条规则的全部,纯函数、由 `check:transition` 钉住;`check:repaint` 则要求调用点把问题的**两半**都问全(调色板变了**且**深浅没变),因为调用点正是后来某次编辑会悄悄丢掉其中一半的地方 —— 而插件内联绘制的那些表面拿到的是同一个答案,所以不可能出现「令牌不渐变、内联面板却在渐变」的半吊子状态。
|
|
23
|
+
- **墨色现在是同步写入的,而那是一个真实存在、且只有一个写入者的 bug(这一条是修复)** —— 把一条规则换成深色主题色时,面板的文字可能留在**上一套**(浅色)调色板上,而所有表面都已经跟到新的那套:深色面板上的深色墨色,读不出来,只有重新加载才能清掉,日志里什么都不会说。这是从报告里的截图**量出来**的,不是猜的:面板是插件自己的深色 `bg-layer-2` —— `hsl(229,59%,27%)` = `rgb(28,43,109)`,在配置的 87% 面板透明度下合成为采样到的 `rgb(23,36,91)` —— 而标签墨色是画在它上面的**浅色**分支令牌:`rgba(0,0,0,0.85)` 压在那块藏青上恰好就是 `rgb(3,6,14)`,也就是从字形核心采样到的值;`rgba(0,0,0,0.7)` 恰好是提示行采样到的 `rgb(7,10,27)`。两个精确吻合,一块面板:表面和墨色来自两套不同的调色板。这种不对称是结构性的 —— 其它每个表面都有第二个同步的写入者(弹窗的层令牌来自 `applySettingsOverrides`,三栏的背景来自 view cards),所以只有令牌样式表可能变旧,而这唯一的写入者只能从一个包在 `catch {}` 里的 `requestAnimationFrame` 回调到达:不在渲染的窗口会吞掉那一帧,而 id 仍然武装着,把此后每一次更新都堵在它后面;写入内部出错则什么都不说。重新加载是唯一的解药,而报告里说的正是这件事。现在调色板一旦移动,就在**与它必须保持一致的表面同一个任务里**同步写入;帧路径留给它本来要做的事(合并一次滑块拖动,那时调色板本来就是对的),积压超过一秒的帧会被丢掉而不是永久阻塞,写入者也会把失败记进日志而不是吞掉。
|
|
24
|
+
- **配置格式升到 5、导出格式升到 6,旧宿主依旧吃不掉配置** —— schema 4 的 sanitizer 会**按自己认识的键重建**配置,所以一个仍在运行的旧宿主进程会在刷新后的第一次写入时丢掉效果、缓动和时长,悄无声息,宿主日志里也什么都没有。因此公布的 `schema` 前进,客户端那句 `>=` 比较会把这样的宿主放进它本来就有的「扣住写入」分支,`warnUnknownConfigKeys` 也出于同样的理由往深一层比较固定形状的 `transition` 块。主题文件升到格式 6;5 及更早仍可导入。这个格式从未发布过,所以 `5` 仍然是它写下时的含义 —— `SCHEMA_VERSION` 防的是「新客户端配旧宿主进程」,而从来没有任何宿主用旧形状报出过 5。
|
|
25
|
+
- **门禁** —— `check:transition`(`scripts/transition-check.ts`)加入 `pnpm test`,现在是**六道**:它逐字节钉住交叉淡入的字符串、「直接切换」与 `0` 时长的硬切语义、「减少动态效果」的否决、每种效果的落点状态、配色渐变的 CSS 形状(包括 `0` 毫秒只发注册、不发过渡规则),以及浅↔深那张真值表。`check:repaint` 新增了这个 bug 由之构成的三行:调色板移动时写入必须是同步的、不许吞掉自己的失败、并且必须在令牌与内联两个调用点都把渐变问题的两半问全。`check:node` 覆盖出厂默认值、往返、恶意取值、被保留的 `0` 时长、`transition` 漂移检查、公布 schema 为 5,以及那次旧值折算(手工调过的 1200、有意的 `0`、平平无奇的 320、显式的全局值胜出)。`check:ui` 覆盖新文案和两个新类(`.dab-tr-preview`、`.dab-tr-preview-in`),并把效果/缓动胶囊的标签登记进 `TABLE_KEYS` —— 它们是通过 `Record<TransitionEffect, …>` 这类表到达的,而这正是「编译器已经保证存在的标签」的既定登记机制。
|
|
26
|
+
|
|
27
|
+
## v0.7.2
|
|
28
|
+
|
|
29
|
+
- **胶片条自己就是控件:拖拽排顺序,双击换画面** —— 顺序以前只能靠下面那排 ↑ / ↓ 和一个「设为第一张」按钮改,而五个缩略图本来就把顺序摆在那里,那对箭头是同一件事的第二种、更差的说法。现在抓住任意一张拖到新位置:落点画成一根 2px 竖条,画在目标格子**内部**,因为一块占位的竖条会把指针正在测量的那些格子推走。而「哪张在屏上」是胶片条的**另一个**手势 —— 双击它。它不改顺序,也**不写任何配置**:在屏哪张是运行时状态而不是设置,所以它不会被保存,下次启动照旧从规则的第一张开始。在非生效规则的格子上双击会说明原因(复用现成的那句「只有正在生效的规则能换画面上的图」),而不是留下一个看起来坏了的双击;两个手势都写在格子的悬停提示里。
|
|
30
|
+
- **顺序和在屏的是哪张,从此互不干涉(这一条是修复)** —— 旧的两个动作(`moveRuleImage`、`setCurrentImage`)都以「把图片下标挪到刚被移动的那张图上」结尾,于是整理列表会把壁纸一起换掉:轮换关着的时候下标是粘住的,而这正是最容易撞见它的状态(「我调整顺序时,即便关了轮换,当前背景也可能会变,拖拽或点按钮调整顺序都有可能发生」)。新的 `moveRuleImageTo(id, slot, to)` 取代了它们两个:摘出之前先记下**正在画的那个槽位**,插回去之后把下标放回它身上。重排不是换主题 —— 三个按钮连同它们背后两个不再被调用的动作一起删掉了,`check:repaint` 的清单同步。
|
|
31
|
+
- **在屏那张不再有边框,只留圆点** —— `.is-sel` 已经给「正在编辑的那张」画了圈,再给「正在显示的那张」画一个,就成了一排几乎一样的缩略图里同时有两个「选中」,而这是胶片条唯一不能留给人猜的问题。现在在屏 = 右上角那个圆点,仅此而已。
|
|
32
|
+
- **一次上传的多张图,每一张都会各自取色** —— 主题色属于**图片**,所以一次带多张的上传有好几个调色板要填,而取色是**按下标**寻址的:`addRuleImages` 先把整批追加完,然后只对 `rule.images[rule.images.length - 1]` 取色。这对它长大时面对的单张上传是对的,对批量则静默地错 —— 最后一张之前的那些图没有自己的颜色、留在系统主题上,而界面上什么都不会说。现在按**这一批自己刚追加的那些槽位**寻址,所以「哪些图会被取色」不再取决于它们落在规则的哪个位置,也不取决于卡片当时选中了哪一张。
|
|
33
|
+
- **卡片文案精简,「编辑位置」换了位置** —— 「规则列表」标题和它下面那句优先级说明、以及自动取色旁边那句解释都删了(面板标题已经介绍了规则,第一张卡上的 `兜底` 徽章说明了优先级;开关和它自己的标签留着)。标签去掉多余的名词:`当前第 1 / 5` → `第 1 / 5`,`添加图片` / `替换这张` / `移除图片` → `添加` / `替换` / `移除`,英文同步。`编辑位置` 从「图片动作」那一行移到**布局模式那一行的末尾**:它打开的东西编辑的是图片如何填满这块区域,正是那一行五个模式在说的事;它留在末尾而不是插在两个模式之间,因为那五个是互斥的,它不是第六个。它仍然只在**适应**下出现 —— 拖拽构图就是适应在做的事。
|
|
34
|
+
- **门禁** —— `check:repaint` 新增一节钉住批量取色:批量形式必须遍历它拿到的每一个槽位、上传必须记录自己这批的槽位并给它们全部取色、按下标寻址的 `maybeAutoExtract(id, rule.images[…])` 不许回来;`moveRuleImageTo` 进入「每个写入路径都必须先采样 winner、再以 `repaintIfMoved` 收尾」的清单,两个被删掉的动作则从中移出。`check:ui` 覆盖新文案与新类(`.dab-strip-bar`,以及 `is-dragging` 状态),并且要求不再有调用者的那三个字典键在同一个提交里离开两份字典。
|
|
35
|
+
|
|
36
|
+
## v0.7.1
|
|
37
|
+
|
|
38
|
+
- **主题色下放到图片** —— 一条规则是一组图片的轮换,而这些图往往是为不同心情收的,不该共用一个强调色。每张图现在带自己的 `color: [h, s, l] | null`,整个调色区——色轮、数值输入、灵感色板、「从本图提取」、吸管、「跟随系统主题」——作用于**胶片条里选中的那张图**。控件上方多了一行写明目标(「作用于选中的图片:2 / 3」),胶片条标出哪些图已经各自有颜色(悬停显示色值),因为一个会悄悄换目标的区块,正是「我改了颜色却没反应」的开端。没有新控件、也没有布局改动:胶片条本来就是选图的入口,也本来就是逐图取景的入口。
|
|
39
|
+
- **规则自己的 `color` 只剩一个含义:一张图都没有时它画什么** —— 它刻意**不是**该规则图片的默认值。没有自己颜色的图**跟随系统主题**,而不是去继承规则色;正是这一点才让「绿的、红的、跟随系统主题」这样一组轮换可以表达——若改成继承,清空某张图的颜色只会把它交还给规则色,「跟随系统主题」按钮看起来就成了失效的按钮(而且一条既有颜色又有图片的规则将无处抵达系统主题)。所以清空某张图的颜色只影响那一张;规则自己的颜色留着,等「只剩它能画」的那个状态。面板的两个分支遵循同一条规则:有图可指就编辑图,`images: []` 就编辑规则。
|
|
40
|
+
- **升级不丢主题色,而区分只靠一个键** —— 这个版本之前写下的图片条目**根本没有** `color` 键,这就是 `normalizeImage` 的全部判据:缺键 = 「这张图从来没有自己的颜色」,于是规则色被抬升到它身上(只做一次,且在共享 sanitizer 里做,两半边行为一致,文件也会在第一次写入时自愈);显式 `null` = 「主动清空过」,任何时候都不会被重新继承覆盖。这也是为什么每次写入都会带上这个键、哪怕是 null——把「没有颜色」写成缺键,等于每次加载都把规则色继承回来。因此这份字段出现之前的配置升级后观感完全一致,0.7 之前那对单图字段(`slot` / `bgState`)也走同一次抬升(只是那一条是构造出来的,不是读出来的)。
|
|
41
|
+
- **轮换每一步都重发界面调色板,否则这个功能一出生就带着那个 bug** —— 换图原本只重画壁纸,于是「逐图主题色」只存在于配置和面板里,界面配色要等**别的**事情顺手重跑一次 apply 才跟上:拖动调色盘,或者切换模型。这正是这个插件已经踩过一次的现象,一字不差(「更新的不太及时,只有我动调色盘或者切模型的时候才出现」)。所以调色板的施加被收成一个函数(`applyPalette`),模型切换和轮换的每一步都走它——定时器 tick 与手动「下一张」共用那个负责画一步的 `paintImage` 出口。只要 `paintImage` 或 `applyActive` 不再经过它、或者它不再读取「当前生效的颜色」(`activeColor`:正在显示的那张图的颜色,否则规则色),`pnpm check:repaint` 就会报错。
|
|
42
|
+
- **节日配色同样逐图** —— 节日的固定配色同时写在节日条目**和它的图片**上,`normalizeHolidayRule` 每次读取都用定义强制覆盖两处(任一处手改都会被替换回来)。所以「节日多图轮换、每张带自己的配色」已经只差 `HOLIDAYS`、它的素材,以及 node 半边的「槽位 → 素材」映射,而不需要在渲染层再开一条代码路径。
|
|
43
|
+
- **配置格式升到 4,旧宿主依旧吃不掉配置** —— `images[].color` 对 schema 3 的 `normalizeImage` 是未知字段,而它会**按自己认识的键重建**每个图片条目:颜色会一直在内存里活到下一次重新加载,然后悄无声息地消失,宿主日志里也什么都不会说。`SCHEMA_VERSION = 4` 在每次 `read` 时公布,客户端用 `>=` 比较,报出更低版本的宿主会进入扣住写入的分支:日志提示一次,面板里说明(「重启 DSH」)。主题文件升到格式 5;4 及更早仍可导入,它们从来没有的颜色由上面那次抬升补上。
|
|
44
|
+
- **没有图片的规则只剩一个上传入口** —— 上方那块大预览**本身就是按钮**了(真正的 `<button>`,可聚焦、可键盘触发;点它上传,也可以把文件拖上去),而胶片条在一张图都没有时**完全不渲染**:它里面除了一块「添加图片」再没有别的东西,而胶片条是一组图片的列表,一张图都没有的状态下它没有存在的理由。拖放处理跟着一起上移而不是消失——把胶片条藏起来,不该把每条规则诞生时都要用的拖放也一起拿走。其它都没动:带文字的 **添加图片** / **从网址** 按钮还在原位,空状态那几句话一字未改;有图片时预览依旧刻意保持惰性(拖到胶片条是新增,「替换这张」仍是显式的带文字按钮——正是这一点让预览不会吞掉用户无意的点击)。
|
|
45
|
+
- **门禁** —— `check:node` 通过真实 RPC 处理器把逐图主题色这套形状端到端跑了一遍:抬升的两个方向(缺键继承规则色、显式 `null` 不继承)、颜色经过文件往返后各自独立且保持顺序、节日两处颜色都被强制、公布的 schema 升到 4,以及 `null` 落盘时是**键**而不是被省略。`check:repaint` 多了一节「轮换步骤必须重发调色板」,而新写入路径 `setImageColor` 也进入它要求「先采样 winner、再以 `repaintIfMoved` 收尾」的清单。`check:ui` 覆盖那三条新文案与两个新类(`.dab-strip-dot`、`.dab-rule-thumb-add`),跟其它每一条一样。
|
|
46
|
+
|
|
47
|
+
## v0.7.0
|
|
48
|
+
|
|
49
|
+
- **每条规则多图轮换 —— 默认关闭** —— 规则现在持有一组有序图片(`images: [{ slot, bgState }]`),可以按自己的节奏循环:10 秒 / 30 秒 / 1 分钟 / 5 分钟 / 30 分钟 / 1 小时,或 5 秒 – 24 小时之间的任意秒数;顺序可选**按顺序**或**随机**。默认是关的:轮换真的要花流量、内存和电,一个偷偷让壁纸动起来的默认值,等于替用户做了决定。
|
|
50
|
+
- **第二种触发完全不需要定时器** —— 「切换模型时也换一张」:每次切换模型落到这条规则上就前进一张。对一条「每次都想看到不一样」的规则来说,这就是全部功能:不排期、不唤醒,只在用户做事的时候换图。
|
|
51
|
+
- **随机绝不会抽到当前正在显示的那张** —— 挑选在**除当前这张之外**的所有下标上等概率进行,因为一次「图没变」的 tick 与一次「压根没触发」的 tick 完全无法区分 —— 而这正是这个功能唯一可能悄无声息失败的方式。`pnpm check:rotation` 对 2、3、7 张图的列表把整个随机取值范围**穷举**了一遍(不是抽一次样本),同时钉住顺序巡回的环绕、越界与小数下标,以及「只有一张图或间隔非有限值时报出的绝不是『正在轮换』」。
|
|
52
|
+
- **全插件只有一个定时器,始终对准生效规则,按签名重排** —— 每条规则一个定时器会让根本没在画的规则白白唤醒,而屏幕上同时只可能有一条规则的图。它只在**排期真正依赖的那些输入**组成的签名变化时重排:规则 id、开关、间隔、顺序、图片数量、标签页可见性。所以拖动滑块导致每秒重跑几十次 apply 也不会把停留计时反复清零(若按「每次 apply 就重排」的写法,把透明度滑块拖上 30 秒就意味着这 30 秒里轮换永远不会前进)。标签页隐藏时轮换跟着画面一起停下,回到前台时按全新间隔重新计时,而不是对着没人看的标签页画三次。
|
|
53
|
+
- **换的只有画面,规则本身不动** —— 主题色、布局模式、背景透明度与模糊度都留在规则上,过渡用的就是切换模型时那套双层交叉淡入。规则还能要求比切换更慢的淡入,或者 `fadeMs: 0` 直接硬切 —— 而 0 是一个真实取值,不会被当成「没设置」。
|
|
54
|
+
- **取景移到图片上,这才是它该在的地方** —— 构图属于某一张图:两张宽高比不同的壁纸共享规则的模式、颜色、透明度与模糊度,但为第一张算出来的那套适应取景,用在第二张上就是错的。每张图各自带一份 `bgState`,背景编辑器编辑的是胶片条里选中的那一张。
|
|
55
|
+
- **单图缩略图变成胶片条** —— 可一次加多张(**多选文件**、**拖放**,或**一行一个网址**批量粘贴,逐个下载以免 N 个请求互相穿插、连进度都没法显示)、点选要编辑的那张、排序、设为**第一张**(不轮换时规则画的就是它)、**原地替换这张**(替换会保住它在轮换里的位置,所以它与「添加」分开命名)、或删除。
|
|
56
|
+
- **规则可以一张图都没有,而这是一个必须成立的状态** —— 这个功能的第一版拒绝删除最后一张,转而「清空它的字节」,结果留下的正是条目本身:胶片条第 1 位一块永远删不掉的空白图,于是下一次上传只能排到第 2 位,规则继续什么都不画,预览也一直停在空帧。现在删除最后一张就是把列表清空。新建的规则也从空列表开始(第一张图到达时才分配槽位);手改导致「每一项都不可用」的列表同样落到这个状态,而不是被硬塞回一个坏槽位。只有「哪里都没提到可用图片」的规则(既没有列表、也没有旧式槽位)才会被 sanitizer 丢掉。
|
|
57
|
+
- **一张图都没有的规则,靠主题色继续生效** —— 空列表不等于「这条规则失效」,而第一版把它当成了失效:「可用」只看有没有图,于是一条图片删光、主题色还在的规则**不再参与匹配**,它那份主题色连同色轮、灵感色板、「跟随系统主题」全成了摆设(报告里的现象就是「主题色无效」),而它原本匹配的模型还会被悄悄交给**下一条**规则 —— 把兜底规则的图删光,屏幕上出现的就是另一个模型的壁纸。现在判定标准是**有图,或者有自己的主题色**(`ruleCanPaint`):这样的规则照旧匹配、照旧当兜底,只是不铺壁纸、只给界面配色;两者都没有(比如刚新增的空规则)才会被跳过。面板上的提示也按三种真实状态分开说:没有图但有主题色、既没有图也没有主题色、有图但选中的那张还没取到内容 —— 之前这三种情况共用一句「这条规则还没有图片」,其中两种是假话;「从本图提取」旁边那句「优先从本图取色」也不再出现在无图可取的时候。
|
|
58
|
+
- **凡是可能改变「谁赢」的编辑,现在都立刻生效;只有不可能改变的才允许跳过重画** —— `color`、`enabled`、`match` 都参与「哪条规则赢」的判定,但每条写入路径各自问的是一个很窄的问题(「这条规则是不是正在画的那条?」),于是只有对**已经**在生效的那条规则的编辑会重画。而「本来没在生效」的编辑恰恰就是**制造**赢家的那些:一条空规则的第一张图(正是它让这条规则变得可画 —— 见 `ruleCanPaint`),以及落在它身上的第一个颜色或自动提取出的颜色。这些改动确实进了配置、也进了面板自己的读数,但背后的界面还停在原来的规则上;报告里的说法是「更新的不太及时,只有我动调色盘或者切模型的时候才出现」—— 拖色轮或切模型才终于重跑了一次解析。现在每条路径都会在改动**之前**取一次赢家、改动之后再做比较(`repaintIfMoved`,判定本身是 `src/client/repaint.ts` 里的纯函数 `shouldRepaint`),这同时修好了一个会变旧的记录:当被编辑的规则**就是**赢家时,即使页面从没把它记成生效规则,也会重画。`pnpm check:repaint` 把这条判定的真值表走了一遍 —— 赢家移动的两个方向、以及那些必须保持廉价的情形 —— 并且只要入口文件里那九条写入路径(外加上传之后才到达的自动提取)中的任何一条不再询问它,就会失败。把它钉下来的实机验证让一条一次性规则走了完整序列(新建空规则 → 移到最上 → 上传一张图 → 之后什么都不碰):用旧判断时画面一直不动,直到有别的东西去动它;用现在这版,约 280 毫秒内画面就跟着换了,而且那张图自动提取出的颜色一起到位。
|
|
59
|
+
- **清空之后再上传** —— 你加进去的那张就是你正在看的那张(卡片会把编辑焦点移到新加入的第一张,胶片条、大预览与位置读数一起跟上),而不是把面板留在之前选中的东西上。
|
|
60
|
+
- **只加载用得到的图** —— 启动时只灌每条规则的**第一张**(与多图出现之前每条规则灌一张完全一致),外加今天生效的节日图与当前模型正在画的那张。其余的在展开卡片时、或轮换即将用到它时再取。若在启动时灌满每条规则的每张图,「五条规则各四张」就意味着首帧之前先把二十张全尺寸 data URL 从本插件自己的 RPC 通道推一遍;同理,store 报出的槽位列表也不再被灌进内存 —— 没有任何规则引用的孤儿槽位,本来就没有卡片可以显示它。
|
|
61
|
+
- **旧宿主进程再也不可能吃掉一份配置 —— 判定改成版本比较,格式版本因此升到 3** —— 浏览器半边与 node 半边是分开加载的,所以「更新包之后只刷新一次页面」会把**新的**客户端 bundle 与仍在运行**上一个** node 半边的宿主进程配在一起。那个旧 sanitizer 完全不认识 `images`,于是会在下一次拖动滑块时悄无声息地丢掉每一条规则。因此 node 半边会公布自己写入的配置格式(每次 `read` 都带 `schema`),而发现答案是旧版的客户端会**扣住所有配置写入**(唯一入口:`src/client/rpc.ts` 的 `canWriteConfig`)、在控制台警告一次,并在面板里说明「重启 DSH」。悄悄不保存的修改,比明说要等重启的修改更糟;而悄悄删掉规则的修改,比两者都糟。0.7.0 开发期间这道闸门真的漏过一次:当时版本号是 2,正在运行的 0.7 node 半边虽然也报 `schema: 2`,却是**空规则修复之前**的构建,于是「把规则删空」的写入照旧放行,宿主把这几条规则从磁盘上抹掉了。所以这个版本号现在表示的是「**空图片列表合法**」(`SCHEMA_VERSION = 3`),而不只是「规则里有 `images` 字段」:任何报出更低版本的宿主一律进入扣住写入的状态。
|
|
62
|
+
- **老配置照常读,老导出照常导入** —— `normalizeRule` 同时接受两种形状:规则里那对单图字段(`slot` / `bgState`)在读取时被提升成 `images: [{ slot, bgState }]`,同一条规则里重复的槽位被去掉,不可用的槽位被去掉。主题导出升到**格式版本 4**,导出与还原的是每条规则的**全部**图片而不只是第一张;版本 3 的文件仍可导入。
|
|
63
|
+
- **各图槽位互不干扰,删除规则只回收它自己那份** —— 一条三张图的规则占三个 `modelbg-<slot>` 文件;`nextSlot` 扫描配置里的**每一个**槽位(用户规则**与**节日条目都算),所以新加的一张图绝不会撞上已有的槽位;删除规则时,只有当某个槽位不再被任何地方引用时才回收。
|
|
64
|
+
- **node 半边连嵌套字段的漂移也一并报告,迁移直接写新形状** —— `warnUnknownConfigKeys` 现在会往深一层比较 `rules[].rotate` 与 `rules[].images[]` —— 一个只有客户端 bundle 知道的字段正是在那里无声消失的;同时 `slot` / `bgState` 这两个旧字段名被明确豁免,因为 sanitizer 是**故意**要提升它们的。0.3 之前配置的迁移也直接写出图片列表,而不是把一个旧形状留在磁盘上等第一次写入。
|
|
65
|
+
|
|
66
|
+
## v0.6.0
|
|
67
|
+
|
|
68
|
+
- **节日特殊背景 —— 只有一个开关,不是一整块设置** —— 中秋与国庆当天,壁纸自动换成那个节日自己的图片、并配上该节日固定的主题色,第二天早上自动换回。功能默认就是开的,而它在界面上**只有一行**:**「配置」页**上一个开关。刻意不做每个节日的卡片、缩略图和选图入口 —— 那些面板短暂存在过,但它们让这个功能看起来像是等着用户去配置的东西,而它恰恰不是。
|
|
69
|
+
- **这个开关是「下车口」,只有显式 `false` 才算关** —— 功能存在之前写下的配置、或者从没动过开关的配置,都照常工作。
|
|
70
|
+
- **没图可画的节日会回落到规则,而不是把背景刷空** —— 覆盖需要同时满足三件事:开关、今天在窗口内、槽位里确实有字节。最后一条是关键:开了开关却没有图的节日,仍然让模型规则说了算。
|
|
71
|
+
- **中秋按农历、国庆按公历,两者都按 Asia/Shanghai 判定** —— 中秋是农历八月十五,在公历上逐年移动(2024-09-17、2025-10-06、2026-09-25、2027-09-15……);国庆是固定的 10 月 1–7 日。农历换算直接用浏览器自带的 ICU,**零依赖**。时区是**钉死的,不取机器本地时区**:农历日期在北京时间午夜翻页,用 UTC 时钟读「今天」会让地球上大多数人过错日子 —— 北京 23:59 / 00:01 的跨日行为有测试钉住。
|
|
72
|
+
- **闰八月不会把中秋拖后一个月** —— ICU 用后缀 `bis` 标记闰月,所以判等必须写死 `month === '8'`,这样中秋才永远落在**正**八月。已对 1900–2100 年间所有闰八月年份做过校验(1900、1957、1976、1995、2052、2071、2090):2052 年插件在 **2052-09-07** 生效,而不是那年落在十月的 `8bis` 十五。
|
|
73
|
+
- **中秋与国庆重叠时中秋优先** —— 两者确实会撞(2025-10-06 就是同一天)。一个精确的单日,比七天窗口里的某一天更值得采信。
|
|
74
|
+
- **壁纸内置在包里,压到原图的十二分之一:8.37 MB → 729 KB** —— 原生分辨率、WebP q80(中秋节 1856 KB → 228 KB,国庆节 6716 KB → 500 KB)。npm 包从 **401 KB 涨到 1.12 MB**;图片本身已是压缩格式,gzip 再压不动,这就是这个功能的全部代价 —— 也正是不能直接塞原图的原因(原图会让安装包重 21 倍,而且每次启动都要把 6.7 MB 的 base64 从插件自己的 RPC 通道推一遍)。
|
|
75
|
+
- **壁纸属于包,任何入口都换不掉** —— 节日槽位是只读的:node 半边直接送出内置资源,从不为此查询数据目录,写入、删除和抓取这些槽位一律被拒。丢进去的文件不会被任何一次读取采用 —— 这正是让这个彩蛋保持为彩蛋、而不是一项设置的原因。
|
|
76
|
+
- **没启用的节日不花任何代价 —— 没在过节的那天也不花** —— 既然覆盖默认开着又不显示,启动时就只取**今天真能生效**的那一个节日,别的日子那 729 KB 一个字节都不读;如果午夜正好跨进某个节日,由跨日轮询去补取(启动时没理由取它)。node 半边同样是按需才去找内置文件,而不是跟着插件一起加载。
|
|
77
|
+
- **节日主题色是常量,不是从图里读出来的** —— 中秋用 `#384A77`,国庆用 `#FFF6EB`:以十六进制写在节日定义里(就在槽位和壁纸旁边),由共享 schema 转成规则形状的 `[h, s, l]`,并在每次读取时强制覆盖 —— 所以手改 `theme-config.json` 里的 `color`,加载时也会被定义值换掉。原来那个「解码一张全尺寸节日照片,只为重新算出一个永远相同的色相」的取色流程,以及配套的「这张图试过了吗」记账,全部删除;配色现在是一项不花启动代价的设计决定。
|
|
78
|
+
- **导出的主题文件只带规则** —— 节日壁纸不在 `dsh-background-by-model-theme.json` 里。它们随包发布,导出意味着给每个文件多加约 970 KB base64,只为了搬运每份安装本来就有、而槽位还拒绝接收的字节。
|
|
79
|
+
- **三道零依赖校验,守住那些「静默出错」的地方** —— `pnpm check:holiday`(`scripts/holiday-check.ts`)钉住两个节日窗口、北京时间的跨日边界、闰八月的行为,以及 `pickHoliday` 允许节日接管背景之前必须通过的四道闸门;`pnpm check:ui`(`scripts/ui-strings-check.ts`)会在某个 `t('…')` 键只存在于一本字典、某个 `dab-…` 类在样式表里没有规则、或某条字典条目已经没人引用时直接失败。第三道 `pnpm check:node`(`scripts/node-half-check.mjs`)把**构建产物**里的 node 半边通过它真实的 RPC 处理器跑一遍,`DSH_HOME` 指向临时目录 —— 因此它覆盖了持久化层却从不碰真实的 `~/.dsh`:节日配置块穿过共享 sanitizer、内置壁纸从空槽位送出、节日槽位拒绝写入 / 删除 / 抓取而丢进去的文件被忽略、普通规则槽位照常写入和删除,以及手改过的配置无法把节日指向别的规则的图片。三道都用裸 `node` 跑(≥ 22.6 自己剥类型),不需要依赖、不需要转译器、也不需要浏览器,`pnpm test` 现在会一并执行。判定本身 —— `pickHoliday` —— 正是为了能测才从插件的 apply 闭包里抽到 `src/holiday.ts` 的。
|
|
80
|
+
- **`check:ui` 当场清掉了从早期版本遗留至今的十个死键** —— `close`、`ruleMatchLabel`、`ruleFraming`、`ruleFramingLocked`、`colorHint`、`swatchTitle`、`hexCaption`、`extractColor`、`extractNoWp`,以及本次刚加进去的 `holidayPreview`。
|
|
81
|
+
|
|
82
|
+
## v0.5.5
|
|
83
|
+
|
|
84
|
+
- **颜色预览块现在把色值打在自己身上,不再像第四个输入框** — 这块实时预览色块位于 H/S/L(R/G/B)数字字段同一列的底部,宽度相同、边框同样 1px,填的是当前颜色却一个字都没有。颜色一浅就露馅 —— 报告里的例子是 `#BADEE8`,L 82%:三个可编辑字段下面一个空白边框矩形,读起来就是第四个空字段,而它并没有任何可输入的内容。现在把 `#RRGGBB` 用等宽字体居中打在颜色本身上,字色按 **Rec.709 亮度**选取(壁纸取色用的就是同一个亮度公式),浅色配深字、深色配浅字,值不会消失在自己的底色里。`scale(1.02)` 的 hover 也一并去掉:它给这个字段并不存在的交互做了广告,那正是它看起来能点的主要原因。
|
|
85
|
+
- **HSL/RGB 切换器上方那行色值文本删掉了** — 预览块已经把同一个值打在颜色上,再显示一遍只会多出一个需要解释的东西。
|
|
86
|
+
- **清空颜色的按钮改成按动作命名,而不是按它落到什么状态** — 它写的是**「系统主题」**,做的却是清掉这条规则的自定义颜色,于是读起来像是旁边那个控件的标签,而不像一个控件本身。现在叫**「跟随系统主题」**,并带上宿主自己的外观字形(太阳,从 `IconLightOutline16` 迁移而来)。这和 0.5.3 修掉的是同一个「文案写状态、动作做另一件事」的毛病,只是在这个状态的两侧各修一次:当时无颜色状态的按钮改成了**「自定义颜色」**;现在这一对命名的是两个去向,而不是两个状态。
|
|
87
|
+
|
|
88
|
+
## v0.5.4
|
|
89
|
+
|
|
90
|
+
- **填充上的文字改读宿主的「色块墨色」,不再用 `brand-text`** — 跟随系统主题时,布局模式的选中胶囊、「+ 新增规则」按钮和设置页的品牌方块,底色取自宿主自己的 `--dsw-alias-brand-primary`,而它**不是品牌色、是对比墨色**:宿主浅色档近黑(`#0f1115`),深色档近白(`#f9fafb`)。它们的文字读的是 `--dsw-alias-brand-text`,而宿主在两档里都把它定义成与底色**完全相同**的值、自己的 CSS 从不使用。于是在深色系统上就成了有底色却没有文字的方块 —— 白底主按钮、白底选中胶囊、白底图标块(实测正好 `#f9fafb`),只有插件自己持有一套调色板时才看得见。四处现在统一读 `--dsw-alias-label-primary-inverted`,也就是宿主自己画在品牌/对比色块上的墨色:浅色档 `#fff`,深色档 `#353638`。
|
|
91
|
+
- **开关打开态的圆点是同一个毛病的小号版本** — 硬编码 `#fff` 画在 `--dsw-alias-brand-primary` 轨道上,而深色档那条轨道本身就是白的。
|
|
92
|
+
- **插件自建的深色调色板是同一问题的镜像** — 那一档的品牌填充故意保持 50% 以上亮度,而**宿主自己的主按钮**用来写标签的 `--dsw-alias-label-primary-foreground`(画在 `--dsw-alias-button-primary-fill` 上)被写死成白色。现在它随填充亮度翻转(与 `brand-text` 共用一条判定),浅色分支也补上了 `label-primary-inverted`,让插件的调色板自己成对,而不是继承宿主当前恰好所处的档位。
|
|
93
|
+
|
|
94
|
+
## v0.5.3
|
|
95
|
+
|
|
96
|
+
- **一次只用一个调色板:清空主题色不再留下上一次的皮肤** — 设置弹窗里那三段重定向(`--dsw-alias-bg-layer-*` → 插件私有变量)**没有宿主回退**,轨迹页与三栏的内联背景同理,而它们只在 teardown 时才清理。于是把主题色切回「系统主题」后会留下「深色界面 + 浅色弹窗、白底白字」。现在这些表面由一个调色板来源统一驱动:有主题色时用规则自己的令牌,没有时**读取宿主自己的令牌**再套上你的透明度,切换时一并交还;无回退的重定向用 `html[data-dab-themed]` 门控,只有变量确实写了才生效。
|
|
97
|
+
- **无主题色也保住壁纸与「界面」页的滑块** — 以前清空主题色会撤掉整套令牌,宿主的实心 `--dsw-alias-bg-base` 就把壁纸整块盖住,主背景 / 左侧栏 / 卡片 / 输入框 / 设置面板 / 轨迹页 / 右侧栏的透明度与模糊也全部失效。现在表面是宿主的颜色乘你的透明度,壁纸继续从背后透出来。
|
|
98
|
+
- **跟随系统主题会把宿主的深色标记交还回去** — 插件持有主题色时会强改 `body[data-ds-dark-theme]`(浅色皮肤直接删掉),而宿主只在**主题快照变化时**才重写它、并不监听这个属性。被删掉的标记因此会一直生效:切回系统主题时读到的是宿主的浅色调色板,界面要等你碰一下滑块才变深。现在切换时按宿主自己解析出的方案同步交还标记(`ctx.theme` 的 `active.colorScheme`,取不到则回退 `html[data-ds-theme-source]` + `prefers-color-scheme`),并且每秒的守护定时器在无主题色状态下也会重读一次宿主调色板;「交还」这一侧不再走 60ms 防抖,避免读到插件自己那套即将下线的皮肤。
|
|
99
|
+
- **无颜色状态下的按钮不再做相反的事** — 那个按钮的文案是「系统主题」,动作却是塞一个硬编码的深蓝 `#1D3463`(同一条文案在有颜色时表示「清空 → 跟随系统主题」)。现在它叫 **「自定义颜色」**,并且先跑一次「从本图提取」,取不到鲜明颜色才退回种子色。
|
|
100
|
+
- **令牌指纹只在样式表写入成功后记账** — 写入抛错时不再把指纹提前记下,避免界面卡在旧调色板上直到另一个 key 变化。
|
|
101
|
+
- **`package.json` 描述里的乱码破折号修正**(它直接显示在 npm 页面上)。
|
|
102
|
+
|
|
103
|
+
## v0.5.0
|
|
104
|
+
|
|
105
|
+
- **宿主自检整块删掉了。** 连同它的一切:设置页的 **「宿主自检」** 选项卡、约定表(`src/host-contracts.ts`)、浏览器探测(`src/client/judge.ts`)、安装目录扫描(`src/host-scan.ts`)、`hostCheck` RPC、`pnpm scan` 脚本以及它的测试。插件只留下它真正做的事:规则、壁纸、界面透明度与模糊。
|
|
106
|
+
- **`0.5.1` 与 `0.5.2` 的内容与 `0.5.0` 完全相同。** 这两个号是发布端的噪音:第一次 `npm publish` 返回的是 HTTP 202,版本要几分钟后才出现在 registry 上,被误当成失败又发了两遍。三个版本都在线上、代码逐字节一致(12 个文件),当时 `latest` 指向 `0.5.2`。装哪个都行;想按标签点名就固定 `0.5.2`。
|
|
107
|
+
|
|
108
|
+
## v0.4.5
|
|
109
|
+
|
|
110
|
+
- **`optionalWhen` 终于按它名字的意思工作了** — 这个字段的文档写着「只有当这块界面在屏幕上时才检查」,但探测实现的是**反过来的**:锚点**不在** DOM 里时反而报 *未观察*,锚点**在**时才会去报失效。于是三条停靠约定里的两条、以及两条对话视图约定,全都在检查错误的状态 —— 这就是健康的停靠栏会报出「停靠空位 失效 / no element matches `[data-dockkit-empty]`」的原因。现在这个辅助函数把锚点当作**正向断言**来读,并且把所有锚点改名成它们真正的含义(`dockHasTab`、`dockHasNoTab`、`chatHasMessages`、`paneFloated` …),这样「用缺席来命名」的锚点再也不可能悄悄把检查反过来。四个测试把由此得到的状态表两个方向都钉住了。
|
|
111
|
+
- **关于消息列的约定不再对着「还没有任何消息」的会话开火** — `[data-chat-flow]` 只在会话**有消息**时才渲染,所以它不在,恰恰是全新会话(宿主的 `data-content-phase="hero"` 首屏)和轨迹页的正常状态。原来的锚点是「对话滚动区存在」,而这三个状态下它都存在,于是检查在首屏和**轨迹页**都报了「属性改名」—— 也就是面板上你看到的第二个失效。现在锚点改用 `[data-chat-turn]`,宿主给每条消息行打的标记,这是唯一「恰好只在消息列该存在时存在」的东西。实测:首屏 → 消息列 0 / 消息行 0;发一条消息后 → 1 / 4;轨迹页 → 0 / 0。
|
|
112
|
+
- **`visible` —— 「存在」和「在屏幕上」不是同一个问题** — 标记了 `visible: true` 的选择器检查现在要求元素真的在屏幕上,于是宿主用 `visibility:hidden` 停放在一边的元素,无法满足一条关于「用户正在看的界面」的约定。停靠空位**故意不标记**:宿主在开合 tab 时一直把它渲染着并隐藏,去问它可不可见,就是在问一个宿主两个方向都在用的状态。
|
|
113
|
+
- **再写死一条锚点规则** — 锚点必须命名「这个属性**预期出现**的状态」,绝不能是恰好同时出现的邻居。这个功能里四次「误报失效」全都是同一个错误:界面明明挂着、宿主行为也对,只是**没有任何东西**能让那个属性落上去。
|
|
114
|
+
|
|
115
|
+
## v0.4.4
|
|
116
|
+
|
|
117
|
+
- **停靠相关的约定不再拿「样式表问题」去问 JS 属性** — `dockkit.content` 与 `dockkit.float` 原本是 `rule` 检查(「宿主样式表里有没有提到这个字面量」)。但这两个属性都是宿主从 **JavaScript** 打上去的:`data-dockkit-content` 只在**有 tab** 的停靠页宿主上,`data-dockkit-float` 只在用户真的把面板浮动起来时;宿主从来没为它们写过任何 CSS 规则。所以那个问题无论宿主健不健康都只会回答「没有」。现在两条都改成**存在性**检查,分别用宿主自己的 tab 标记(`data-dockkit-tab`)和浮动态做守卫,于是「没开 tab 的停靠」会报成 *未观察*,而不是「属性改名」。`dockkit.empty`(宿主在「有 tab」时用来替换空位的那个座位)同样改成存在性检查。已在真实宿主上验证:没开 tab 时 `data-dockkit-tab`/`data-dockkit-content` 都不存在;点一下停靠栏的 `+`,两者同时出现(tab 0→1、content 0→1、empty 1→0),此时检查会给出结论而不是跳过。
|
|
118
|
+
- **锚点不再依赖组合符** — 「有 tab」的锚点最初写成 `[data-dockkit-strip-tabs] > *`,这种写法 DOM 替身回答不了,也让夹具和浏览器悄悄产生分歧。现在改成一个普通属性选择器。
|
|
119
|
+
|
|
120
|
+
## v0.4.3
|
|
121
|
+
|
|
122
|
+
- **「宿主自检」不再虚报故障** — 它第一次在健康的 0.1.7 上实跑,28 条约定报了 **9 条失效**(7 个令牌「不再声明」、2 个属性「消失」)。**全部是探测读错了地方,宿主一条都没坏**:设计令牌发布在 `body{--dsw-…}` 上,探测却去问 `getComputedStyle(document.documentElement)`;而 `data-plugin` —— 宿主自己的 CSS 模块在**每一个** `<style>` 上都写它 —— 被我当成了「这是插件自己的样式表」,于是检查跳过了整个宿主主题,再把令牌报成改名。两处都已修正,并且各配了会让它复发的测试:令牌读取的宿主元素成了 `ProbeEnv` 的显式成员;识别自己的样式表改用一个只由本插件写入的标记(`data-dab-side`),且用 `getAttribute` 而不是 `dataset` —— `dataset` 只暴露驼峰键,按带连字符的名字去索引它,在夹具里能通过、在浏览器里静默返回空。
|
|
123
|
+
- **`rule` 检查现在会说明自己查的是哪一侧** — 一条令牌约定其实断言了两件不同的事:宿主是否仍**声明**这个名字,以及它是否仍**解析出值**。前者只能从宿主的规则回答,后者只能从实时级联回答;而唯一一条「另一半是本插件自己样式表」的(`.dab-card`)现在显式标为 `side: 'own'`,不再和宿主规则混为一谈。所有被重新发出的令牌都同时带上这两项检查,于是「改名」会被报成改名,而不是「值为空」。
|
|
124
|
+
- **可读但没提到目标的宿主样式表算失效,不算盲区** — 旧逻辑只问「有没有任意一张表可读」,于是一张能读、却什么也没提到的宿主表会让所有令牌检查都通过。现在可读性按侧分别跟踪。
|
|
125
|
+
|
|
126
|
+
## v0.4.2
|
|
127
|
+
|
|
128
|
+
- **新增「宿主自检」页 —— 插件现在能说清哪里坏了,而不只是坏掉** — 一个给别人界面做样式的插件,依赖的全是自己不拥有的东西:宿主的会话与模型服务、挂毛玻璃的那些元素、以及被重新发出的设计令牌。这些在 dsh 版本之间随时可能改名,而 0.1.7 那三次故障**全都是静默的** —— 什么都没抛错,界面只是不再跟随设置。现在 设置 → **宿主自检** 会逐条对当前构建做检查(实时 DOM、宿主自己的样式表、Cordis 服务),并给出:是否成立、失效时界面上是什么样子、依赖的字面量、本该由哪个宿主文件定义、以及本插件哪个文件在读取它。**复制诊断报告** 会把两侧结果合并成一份 markdown,直接贴进 issue。仅仅是「当前不在屏幕上」的情况(设置弹窗打开时的对话页、还没开过文件时的右侧栏)会报成 *未观察*,绝不算故障。
|
|
129
|
+
- **同一张表还能离线查,不需要浏览器** — `pnpm scan`(`scripts/host-contract-scan.mjs`)直接扫已安装的 dsh 包,某个约定目标一消失就以非零码退出;所以 `npm i -g @deepseek-ai/dsh@latest` 之后、还没打开界面之前,就能先红一次。它同时打印找到的宿主版本以及是否满足本插件的下限。
|
|
130
|
+
- **一张约定表,三处消费** — `src/host-contracts.ts` 把每个接触点只声明一次,浏览器探测、离线扫描与测试都读它,所以新加的选择器不可能被「本该发现它变化」的检查漏掉。`pnpm test` 覆盖这张表、探测逻辑(对着一个按宿主 DOM 形状写的夹具)、界面样式表与版本下限。
|
|
131
|
+
- **约定断裂不再只留在日志里没人看** — 启动 2.5 秒后,只要有约定失效,浏览器控制台会逐条打印:字面量、本插件读取它的文件、本应由哪个宿主文件定义。
|
|
132
|
+
|
|
133
|
+
## v0.4.1
|
|
134
|
+
|
|
135
|
+
- **右侧面板不再糊出一块常驻磨砂板** — dsh 0.1.7 不再自己绘制文件预览面板:容器变成了滑动/全屏视口,整场会话都以全宽挂载,折叠只是把 dock 用 `transform` + `visibility` 滑出去(从不 `display:none`)。于是这个容器上的背景加 backdrop-filter 在面板折叠时照样盖住右半屏——就是那块磨砂板。现在卡片只画宿主真正在画的元素(dock 的 tab host:`[data-dockkit-content]`、`[data-dockkit-empty]`),跟着宿主自己的开合与滑动过渡走;旧的容器选择器留在 `:has()` 守卫后面以兼容老宿主,backdrop-filter 只在 `[data-sidebar-right-open]` 时生效,折叠态绝不走滤镜。
|
|
136
|
+
- **切换模型重新能切背景** — 0.1.7 的 `sessions.list` 快照不再发布 `current`,插件无法得知当前在屏的是哪个会话:拿不到会话 id → 没有 `modelSelection` 投影 → 模型文本为空 → 所有模型都退到规则 1。现在会话 id 先取宿主自己的 `uiSession.current.key`,老字段 `list.current` 与带 `retainedBy.mainView` 的行作为兜底,三跳都是可选的(`uiSession` 挂载晚也能解析)。换模型仍是即时的:它走的是该会话 `modelSelection` 投影的订阅,而不是轮询。
|
|
137
|
+
- **菜单分组标题不再是白道** — 0.1.7 把菜单面拆成了两个 token:共享的 `MenuSurface` 材质画新的 `--dsw-menu-surface-fill`,其他浮层画 `--dsw-specific-menu`,而宿主把后者别名到前者。插件只重新发射了后者,于是模型选择菜单的面板还是宿主玻璃,吸顶的分组标题却变成了插件近乎不透明的调色板色。现在两个 token 由同一个表达式生成、读同一个插件变量,卡片滑块让它们一起变化,别名也不会再被打断。
|
|
138
|
+
- **卡片滑块的标签改名** — 它同时管菜单与卡片,中文标签从「对话框中选项面板」改为「卡片与菜单面板」,英文从 `Cards & panels` 改为 `Cards & menus`。
|
|
139
|
+
- **声明宿主抬到 `0.1.7-rc.2`** — 所有 `@deepseek-ai/dsh-*` peer 与 `engines.dsh` 现在都要求 0.1.7-rc.2 及以后。宿主的兼容性校验会用自身运行时版本比对(带 `includePrerelease`),因此更旧的宿主会按名字报出插件不兼容,而不是静默运行。代码里的版本兜底逻辑未改动。
|
|
140
|
+
|
|
141
|
+
## v0.4.0
|
|
142
|
+
|
|
143
|
+
- **取色改用「显示器看到的亮度」** — 亮暗带此前按 HSV 明度(max 通道)取平均,它把每个饱和像素都算成亮:纯蓝 `v = 1.0`,而 Rec.709 luma 只有 `0.072`。于是深色但饱和的壁纸被判进亮色带,在暗画面上配出一套浅色界面。现在改为平均 Rec.709 luma——与壁纸判定的同一套度量。
|
|
144
|
+
- **选图即上色** — 选图或换图后自动为规则取主题色(全局开关,默认开)。它**只补空**:你手动选过的颜色(或刻意清空的)绝不会被覆盖;由于解码是异步的,回来时会再确认一次,期间你手选的色优先。
|
|
145
|
+
- **匹配试跑卡取代「当前生效」卡片** — 原状态卡回答的是「现在生效什么」,且会在切换之间留旧值;试跑卡把同一个问题提前一步回答。输入任意模型名(未输入时自动跟随检测到的模型),即时显示会命中哪条规则,或提示走兜底。状态卡里那几句它表达不了的诊断——比如读到的只是**宿主默认**而非本会话模型、会话服务还没就绪——作为提示保留在卡片里,所以坏掉的链路依旧不会伪装成一次正常读取。
|
|
146
|
+
- **配置** — 新增的持久化字段只有一个(`autoExtract`),落在共享 schema 一处,两半边的净化行为因此完全一致。
|
|
147
|
+
|
|
148
|
+
## v0.3.3
|
|
149
|
+
|
|
150
|
+
- **配置结构只声明一份,两半边共用** — node 半边(落盘前净化)与浏览器半边(UI 自己读同一份文件)此前各写一遍结构:键表在两侧合计 6 处、默认值两套,于是只在一边声明的字段会被另一边的净化静默丢掉——滑块当次有效、`writeConfig` 写下的配置里没有它、刷新即回默认。0.3.2 的 `blurs.rightbar` / `rightbarOpacity` 正是这么丢的。现在类型、键表、默认值与纯净化函数都收在 `src/schema.ts` 一处、两半边共同 import,两侧跑的是**同一份**净化代码,界面与磁盘的取值不可能再不一致。
|
|
151
|
+
- **未知字段会被点名** — node 半边净化写入时,对任何「共用结构里未声明」的字段打一次警告(`ignoring unknown config field "blurs.produced" (declared in one half only?)`),这类不同步会出现在宿主日志里,而不是安静地吞掉一个设置项。0.3 之前的旧顶层字段除外(迁移会消费它们)。
|
|
152
|
+
- **行为不变** — 默认值、夹取范围、迁移结果与落盘文件与此前逐字节一致,本次只消除重复声明。
|
|
153
|
+
|
|
154
|
+
## v0.3.2
|
|
155
|
+
|
|
156
|
+
- **「文件预览侧栏」卡片** — 点开文件后从右侧滑出的那一栏现在有自己的透明度与模糊度滑块。它此前的唯一表面就是 `--dsw-alias-bg-base`,也就是「主背景」滑块改写的那个令牌,所以它一直是主背景的第二份拷贝、无法单独调节。新卡片的透明度**默认跟随「主背景」**(首次拖动后才由自己接管),因此升级后外观零变化;模糊则叠加在主背景模糊之上。面板关闭时只是滑出屏幕,这张卡片不会带来任何副作用。
|
|
157
|
+
- **宿主侧配置保留新字段** — `theme-config.json` 新增 `rightbarOpacity` 与 `blurs.rightbar`;缺字段(旧配置)一律按「跟随主背景」处理,导入旧配置文件同样如此。
|
|
158
|
+
|
|
159
|
+
## v0.3.1
|
|
160
|
+
|
|
161
|
+
- **文档与截图更新** — 截图换成当前的三选项卡界面:同一份配置在 DeepSeek 与 Kimi 下的两种外观,外加单条规则的编辑器。旧的七张图(还带着已删除的「色彩」选项卡与旧「背景」页)已删除,图片体积从 3.6 MB 降到 220 KB。
|
|
162
|
+
- **npm 包内附截图** — `example_img/` 现在包含在发布包里,npm 页面上的 README 不再有裂图。
|
|
163
|
+
- **素材致谢** — 示例壁纸素材来源于 bilibili [ZipZipPipe](https://space.bilibili.com/4168597)。
|
|
164
|
+
|
|
165
|
+
## v0.3.0
|
|
166
|
+
|
|
167
|
+
- **模型规则取代单张全局壁纸** — 背景改由有序规则列表驱动,每条规则用匹配串比对当前会话的模型名来选中(先命中者胜,规则 1 兜底);匹配串会同时比对 provider、模型 id 与显示名三者。
|
|
168
|
+
- **外观从全局下放到每条规则** — 壁纸、主题色、布局模式、取景、背景透明度与背景模糊都成为规则自身的属性,不同模型可以有完全不同的外观。
|
|
169
|
+
- **设置选项卡重构** — 现在是 **「界面」**(全局)、**「模型背景」**(规则列表)与 **「配置」**(导入/导出);**「色彩」** 选项卡随全局主题色一并删除,原 **「背景」** 选项卡改造成 **「模型背景」**。
|
|
170
|
+
- **实时状态提示** — 「模型背景」页会显示当前模型及其命中的规则(例如「当前模型 deepseek-flash → 命中 · 规则 1」),检测不到时给出提示。
|
|
171
|
+
- **导出格式 v3** — `dsh-background-by-model-theme.json` 现在包含全部规则配置**以及**每条规则的图片(base64 内联)。
|
|
172
|
+
- **破坏性移除** — 视频背景、生成式背景(网格渐变 / Shader / 几何图案)与全局主题色均已移除。
|
|
173
|
+
- **旧配置自动迁移** — 0.3.0 之前的配置会变成匹配串留空的规则 1 并继承旧外观,旧版遗留的视频文件会被清理。
|
|
174
|
+
- **切换更顺,并带淡入淡出** — 壁纸改用 object URL 绘制,同一张图只解码一次,不再每次切换重新解码;规则切换现在是 320 ms 交叉淡入(新图在旧图上方淡入,底层始终保持不透明,中途不会发亮)。同时移除了拖动滑块时的低清壁纸降级:它会在每次壁纸变化时对整张大图额外解码并缩放,而且它换上的低清图下一帧就被重新覆盖、实际并未生效。
|
|
175
|
+
- **修复“切换模型没反应”** — 三处叠加:① 旧实现读取的 `ctx.modelDirectories` 在插件上下文里不可见(它注册在 ui-model-selection 自己的作用域),于是悄悄退回了宿主全局默认模型;② 本插件的客户端 bundle **早于** `api-session-controller` 加载,`ctx.get('sessions')` 在 `apply()` 时通常还不存在,旧代码在这一步直接放弃、永不重试(这是“完全没反应”的直接原因);③ 状态行拿一个全局默认值冒充了本会话模型。现在改读**本会话自己的持久化模型选择**(`ctx.sessions.binding(id).session.projections.faceOf('modelSelection')`,即模型选择器读的同一份值),以 400 ms 间隔等待 `sessions` 服务出现(最多 2 分钟),带 1.5 秒兜底轮询与会话切换重绑定;只拿到宿主默认值时标注 **宿主默认**,并且状态行会指出是哪一环失败(未挂载 / 无当前会话 / 无投影投影为空)。
|
|
176
|
+
|
|
177
|
+
## v0.2.4
|
|
178
|
+
|
|
179
|
+
- **修复 dsh 0.1.5 持久化失效** — 主题/背景图的 RPC 通道改为在插件自身 `webServer` 作用域内直接注册为 prefix 路由(保留 Host/Origin 鉴权围墙),不再经由 `connection.rpc.handle`(其 effect 绑定到 connection 服务上下文,导致部分 0.1.5 宿主挂载失败)。此前请求落到 SPA 兜底并返回 405、从未写入磁盘的设置,现可正常持久化(0.1.2 与 0.1.5 均已验证)。
|
|
180
|
+
- **声明宿主版本兼容** — 新增 `engines.dsh: ">=0.1.2-rc.1"`,声明插件所支持的 DeepSeek Harness 宿主版本范围。
|
|
181
|
+
- **修复深色徽章令牌(issue #9)** — 深色预设下 `*-tertiary` 徽章表面(轨迹工具/上下文徽章、连接胶囊、计划 chip)与背景色过于接近,浅色标签文字不可读;现已对齐原生深色 800/900 阶令牌,亮色文字落在正确深色徽章上。
|