dsh-theme-palette 1.5.3 → 1.6.0
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 +29 -0
- package/README-es.md +2 -0
- package/README-hi.md +2 -0
- package/README-pt.md +2 -0
- package/README-zh.md +3 -1
- package/README.md +3 -1
- package/client.js +85 -90
- package/docs/DESIGN.md +14 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -13,6 +13,35 @@
|
|
|
13
13
|
复核宿主源码发现它带 `includePrerelease`,结论相反。现在这条判断固化进脚本,不再靠手算
|
|
14
14
|
- 该改动只影响本地发版工具,**不进 npm 包**(`files` 不含 `tools/`),故不升版本号
|
|
15
15
|
|
|
16
|
+
### 1.6.0
|
|
17
|
+
视觉与可访问性整改(依据 2026-10-22 第三方 UI 视觉验收审计,60/100):
|
|
18
|
+
|
|
19
|
+
- **A2 配置块重做**:改用 `.dsh-tp-field` 容器(与普通行同节奏),导出/导入各占一行,
|
|
20
|
+
反馈文案就地显示(复制→复制按钮旁,导入→导入按钮旁),导出框加 `text-overflow:ellipsis`
|
|
21
|
+
- **A3 复制不再谎报**:`await navigator.clipboard.writeText()`,失败或无 API 时显示
|
|
22
|
+
「复制失败,请手选后 Ctrl+C」,不再无条件报成功
|
|
23
|
+
- **A4 布局从视口断点改容器驱动**:卡片 `repeat(auto-fit,minmax(196px,1fr))`、色块 `minmax(86px,1fr)`、
|
|
24
|
+
行与分段控件 `flex-wrap`;日语长标签改短(右栏「サイドバー / キャンバス」、滚动条「無彩 / 追従 / 強調」)。
|
|
25
|
+
实测 4 语 × 内容宽 564/336/216:**越界元素 0**(改前日语 216px 溢出 61px)
|
|
26
|
+
- **A5 语言属性**:`<section lang>` 跟随手选语言,`auto` 时回落宿主 `documentElement.lang`
|
|
27
|
+
- **A6 分段控件有名字**:`role="radiogroup"` + `aria-labelledby` 指向行标题,选项改
|
|
28
|
+
`role="radio" aria-checked`(8 组 22 个按钮)
|
|
29
|
+
- **A7 反馈可播报**:复制/导入/自愈状态挂 `role="status" aria-live="polite"`,错误用 `alert`;
|
|
30
|
+
导入框补 `aria-label`
|
|
31
|
+
- **A8 自定义面板层级**:面板底改 `bg-layer-1`(按钮不再与面板同底 1.00:1)、说明文字提到
|
|
32
|
+
`label-secondary` 12px;色值从只读 `<code>` 改为**可输入 hex**(回车/失焦生效,非法值忽略)
|
|
33
|
+
- **A9 缩略图跟随侧栏档位**:`cardColors()` 接收 `sidebarMode`,不再写死默认档
|
|
34
|
+
- **A11** 黑白配色下「滚动条」「开关」置灰禁用(点了也不会有变化)
|
|
35
|
+
- **A12** 卡片与分段按钮 `:focus-visible{outline-offset:2px}`,焦点环不再与选中边框贴死
|
|
36
|
+
- **A13** 加 `prefers-reduced-motion` 降级
|
|
37
|
+
- **A14** `docs/DESIGN.md` 补「当前标定值」表(旧推演内容保留,注明以 `client.js` 为准)
|
|
38
|
+
- **A15** 删掉 4 语共 36 条从未渲染的文案键与未被调用的 `swatches()`
|
|
39
|
+
- **A10 证据链**:README 首图换成当前版本(5 张卡)的**静态渲染**,按真机内容宽 564 px 出图
|
|
40
|
+
(浅色 / 深色 / 自定义面板三张,`--scale 2` 即 1240 px 宽),并在五语 README 里注明「静态渲染」;
|
|
41
|
+
`screenshots.json` 同步为这三张
|
|
42
|
+
- 工具:`tools/preview-settings.mjs` 新增 `--width`(默认按真机 564px 内容宽)与 `--adv`(默认折叠),
|
|
43
|
+
token 跟随 `--palette`;新增 `tools/measure-preview.mjs`(量越界/行高/关键计算色,非 0 越界退出 1)
|
|
44
|
+
|
|
16
45
|
### 1.5.3
|
|
17
46
|
修:选中「自定义」后滚动条不跟随取色。
|
|
18
47
|
|
package/README-es.md
CHANGED
|
@@ -6,6 +6,8 @@ Paleta de tema para DeepSeek Harness (web y escritorio): **4 paletas × claro/os
|
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
9
|
+
*Render estático con el ancho real del panel (564 px de contenido).*
|
|
10
|
+
|
|
9
11
|
## Compatibility
|
|
10
12
|
|
|
11
13
|
| Superficie | Estado |
|
package/README-hi.md
CHANGED
package/README-pt.md
CHANGED
|
@@ -6,6 +6,8 @@ Paleta de tema para o DeepSeek Harness (web e desktop): **4 paletas × claro/esc
|
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
9
|
+
*Render estático na largura real do painel (564 px de conteúdo).*
|
|
10
|
+
|
|
9
11
|
## Compatibility
|
|
10
12
|
|
|
11
13
|
| Superfície | Estado |
|
package/README-zh.md
CHANGED
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Theme palette for DeepSeek Harness (web & desktop): **4 palettes × light/dark**, two independent axes.
|
|
6
6
|
|
|
7
|
-

|
|
8
|
+
|
|
9
|
+
*Static render of the settings page at the real panel width (564 px content).*
|
|
8
10
|
|
|
9
11
|
## Compatibility
|
|
10
12
|
|
package/client.js
CHANGED
|
@@ -27,7 +27,7 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
const React = require('react')
|
|
28
28
|
const h = React.createElement
|
|
29
29
|
|
|
30
|
-
const PLUGIN_VERSION = '1.
|
|
30
|
+
const PLUGIN_VERSION = '1.6.0'
|
|
31
31
|
const STORE_KEY = 'dsh-theme-palette.v1'
|
|
32
32
|
const OVERRIDE_SOURCE = 'dsh-theme-palette'
|
|
33
33
|
|
|
@@ -807,16 +807,10 @@ window.__ModuleLoader__.load({
|
|
|
807
807
|
return pairs
|
|
808
808
|
}
|
|
809
809
|
|
|
810
|
-
|
|
811
|
-
function swatches(scheme, textMode) {
|
|
812
|
-
if (!scheme.tinted) return ['#ffffff', '#e5e5e5', '#0f1115']
|
|
813
|
-
const r = rampsFor(scheme, textMode || DEFAULT_TEXT)
|
|
814
|
-
return [r.bluish['00'], r.bluish['100'], r.deepseek['500']]
|
|
815
|
-
}
|
|
816
|
-
|
|
810
|
+
|
|
817
811
|
|
|
818
812
|
/** 卡片缩略图用的一小组颜色(画布/侧栏/文字/强调),按当前强度档取。 */
|
|
819
|
-
function cardColors(scheme, textMode) {
|
|
813
|
+
function cardColors(scheme, textMode, sidebarMode) {
|
|
820
814
|
const r = rampsFor(scheme, textMode || DEFAULT_TEXT)
|
|
821
815
|
if (!r) {
|
|
822
816
|
return {
|
|
@@ -824,7 +818,7 @@ window.__ModuleLoader__.load({
|
|
|
824
818
|
dark: { canvas: '#151517', side: '#1b1b1c', text: '#f9fafb', accent: '#7aaaff' },
|
|
825
819
|
}
|
|
826
820
|
}
|
|
827
|
-
const side = sidebarTokens(r, DEFAULT_SIDEBAR, scheme.tinted)
|
|
821
|
+
const side = sidebarTokens(r, sidebarMode || DEFAULT_SIDEBAR, scheme.tinted)
|
|
828
822
|
return {
|
|
829
823
|
light: {
|
|
830
824
|
canvas: r.bluish['00'],
|
|
@@ -868,10 +862,10 @@ window.__ModuleLoader__.load({
|
|
|
868
862
|
.dsh-tp-head h2{margin:0;font-size:18px;font-weight:600;letter-spacing:.2px}
|
|
869
863
|
.dsh-tp-badge{margin-left:auto;font:11px/1.7 ui-monospace,Consolas,monospace;color:var(--dsw-alias-label-tertiary);border:.5px solid var(--dsw-alias-border-l4);border-radius:999px;padding:0 8px}
|
|
870
864
|
.dsh-tp-sub{margin:-6px 0 0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
|
|
871
|
-
.dsh-tp-grid{display:grid;grid-template-columns:repeat(
|
|
872
|
-
|
|
873
|
-
.dsh-tp-card{position:relative;display:flex;flex-direction:column;gap:8px;text-align:left;font:inherit;cursor:pointer;padding:9px;border-radius:14px;border:.5px solid var(--dsw-alias-border-l4);background:transparent;transition:background .12s ease,border-color .12s ease}
|
|
865
|
+
.dsh-tp-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(196px,1fr));gap:10px}
|
|
866
|
+
.dsh-tp-card{position:relative;display:flex;flex-direction:column;gap:8px;text-align:left;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;padding:9px;border-radius:14px;border:.5px solid var(--dsw-alias-border-l4);background:transparent;transition:background .12s ease,border-color .12s ease}
|
|
874
867
|
.dsh-tp-card:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
868
|
+
.dsh-tp-card:focus-visible{outline-offset:2px}
|
|
875
869
|
.dsh-tp-card.is-on{background:var(--dshtp-card-picked,var(--dsw-alias-bg-module-platform));border-color:var(--t-accent-l)}
|
|
876
870
|
body[data-ds-dark-theme] .dsh-tp-card.is-on{border-color:var(--t-accent-d)}
|
|
877
871
|
.dsh-tp-thumb{display:flex;height:56px;border-radius:9px;overflow:hidden;border:.5px solid rgba(128,128,128,.28)}
|
|
@@ -885,20 +879,21 @@ body[data-ds-dark-theme] .dsh-tp-thumb-main b{background:var(--t-text-d)}
|
|
|
885
879
|
.dsh-tp-thumb-main b:nth-of-type(3){width:44%;background:var(--t-accent-l);opacity:.9}
|
|
886
880
|
body[data-ds-dark-theme] .dsh-tp-thumb-main b:nth-of-type(3){background:var(--t-accent-d)}
|
|
887
881
|
.dsh-tp-card-meta{display:flex;align-items:baseline;gap:6px;flex-wrap:wrap}
|
|
888
|
-
.dsh-tp-card-name{font-size:
|
|
889
|
-
.dsh-tp-card-desc{font-size:
|
|
882
|
+
.dsh-tp-card-name{font-size:14px;font-weight:500}
|
|
883
|
+
.dsh-tp-card-desc{font-size:12px;color:var(--dsw-alias-label-tertiary)}
|
|
890
884
|
.dsh-tp-check{position:absolute;top:7px;right:7px;width:16px;height:16px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;line-height:1;background:var(--t-accent-l);color:var(--t-canvas-l);opacity:0;transition:opacity .12s ease}
|
|
891
885
|
body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--t-canvas-d)}
|
|
892
886
|
.dsh-tp-card.is-on .dsh-tp-check{opacity:1}
|
|
893
|
-
.dsh-tp-row{display:flex;align-items:center;gap:12px;padding:11px 0;border-top:.5px solid var(--dsw-alias-border-l2)}
|
|
887
|
+
.dsh-tp-row{display:flex;align-items:center;gap:12px;padding:11px 0;border-top:.5px solid var(--dsw-alias-border-l2);flex-wrap:wrap}
|
|
894
888
|
.dsh-tp-row-label{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
|
|
895
889
|
.dsh-tp-row-label b{font-size:13.5px;font-weight:500}
|
|
896
890
|
.dsh-tp-row-label span{font-size:11.5px;color:var(--dsw-alias-label-tertiary);line-height:16px}
|
|
897
|
-
.dsh-tp-seg{display:inline-flex;gap:2px;padding:2px;border-radius:10px;background:var(--dsw-alias-interactive-bg-hover);flex:none}
|
|
891
|
+
.dsh-tp-seg{display:inline-flex;flex-wrap:wrap;gap:2px;padding:2px;border-radius:10px;background:var(--dsw-alias-interactive-bg-hover);flex:none;max-width:100%}
|
|
898
892
|
.dsh-tp-seg button{font:inherit;font-size:12.5px;line-height:20px;cursor:pointer;border:0;border-radius:8px;padding:5px 12px;background:transparent;color:var(--dsw-alias-label-secondary);white-space:nowrap;transition:background .12s,color .12s}
|
|
899
893
|
.dsh-tp-seg button:hover{color:var(--dsw-alias-label-primary)}
|
|
900
894
|
.dsh-tp-seg button.is-on{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);box-shadow:0 1px 2px rgba(0,0,0,.10)}
|
|
901
|
-
|
|
895
|
+
.dsh-tp-seg button:focus-visible{outline-offset:2px}
|
|
896
|
+
.dsh-tp-seg button[disabled]{opacity:.45;cursor:default}
|
|
902
897
|
.dsh-tp-more{display:inline-flex;align-items:center;gap:6px;font:inherit;font-size:12.5px;color:var(--dsw-alias-label-tertiary);background:0 0;border:0;padding:6px 0 2px;cursor:pointer;align-self:flex-start;transition:color .12s}
|
|
903
898
|
.dsh-tp-more:hover{color:var(--dsw-alias-label-primary)}
|
|
904
899
|
.dsh-tp-adv{display:flex;flex-direction:column}
|
|
@@ -906,21 +901,27 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
906
901
|
.dsh-tp-input::placeholder{color:var(--dsw-alias-label-tertiary)}
|
|
907
902
|
.dsh-tp-mini{font:inherit;font-size:12.5px;line-height:20px;padding:5px 12px;border-radius:8px;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);cursor:pointer}
|
|
908
903
|
.dsh-tp-mini:hover{background:var(--dsw-alias-bg-layer-1)}
|
|
909
|
-
.dsh-tp-custom{display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:14px;border:.5px solid var(--dsw-alias-border-
|
|
904
|
+
.dsh-tp-custom{display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:14px;border:.5px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-1)}
|
|
910
905
|
.dsh-tp-custom-head{display:flex;align-items:center;justify-content:space-between;gap:8px}
|
|
911
906
|
.dsh-tp-custom-head b{font-size:13.5px;font-weight:500}
|
|
912
|
-
.dsh-tp-swatches{display:grid;grid-template-columns:repeat(
|
|
913
|
-
@media (max-width:520px){.dsh-tp-swatches{grid-template-columns:1fr}}
|
|
907
|
+
.dsh-tp-swatches{display:grid;grid-template-columns:repeat(auto-fit,minmax(86px,1fr));gap:10px}
|
|
914
908
|
.dsh-tp-swatch{display:flex;flex-direction:column;gap:6px;cursor:pointer}
|
|
915
909
|
.dsh-tp-color{width:100%;height:44px;padding:0;border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;background:transparent;cursor:pointer}
|
|
916
910
|
.dsh-tp-color::-webkit-color-swatch-wrapper{padding:3px}
|
|
917
911
|
.dsh-tp-color::-webkit-color-swatch{border:none;border-radius:8px}
|
|
918
912
|
.dsh-tp-swatch-name{font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
919
913
|
.dsh-tp-hex{font:11.5px/1 ui-monospace,Consolas,monospace;color:var(--dsw-alias-label-tertiary)}
|
|
920
|
-
.dsh-tp-
|
|
914
|
+
.dsh-tp-hexinput{width:100%;box-sizing:border-box;font:11.5px/16px ui-monospace,Consolas,monospace;padding:3px 6px;border-radius:6px;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary)}
|
|
915
|
+
.dsh-tp-hexinput:focus-visible{outline-offset:1px}
|
|
916
|
+
.dsh-tp-custom-hint{margin:0;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}
|
|
921
917
|
.dsh-tp-note{font-size:11.5px;color:var(--dsw-alias-label-tertiary)}
|
|
922
918
|
.dsh-tp-status{margin:0;font-size:11.5px;line-height:18px;color:var(--dsw-alias-label-tertiary)}
|
|
923
919
|
.dsh-tp-status.is-bad{color:var(--dsw-alias-state-error-primary)}
|
|
920
|
+
.dsh-tp-field{display:flex;flex-direction:column;gap:8px;padding:11px 0;border-top:.5px solid var(--dsw-alias-border-l2)}
|
|
921
|
+
.dsh-tp-field-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
|
|
922
|
+
.dsh-tp-field-title{font-size:13.5px;font-weight:500}
|
|
923
|
+
.dsh-tp-input{text-overflow:ellipsis}
|
|
924
|
+
@media (prefers-reduced-motion:reduce){.dsh-tp-card,.dsh-tp-seg button,.dsh-tp-more,.dsh-tp-check,.dsh-tp-mini{transition:none}}
|
|
924
925
|
`
|
|
925
926
|
|
|
926
927
|
function installRightbarStyle() {
|
|
@@ -1172,14 +1173,10 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1172
1173
|
nav: '主题色',
|
|
1173
1174
|
hint: '配色与明暗模式独立;切换后立即生效并保存在 localStorage。',
|
|
1174
1175
|
md: 'Markdown 强调',
|
|
1175
|
-
mdHint: '标题与加粗用「正文色混强调色」,比正文更有色;关掉则与正文同色。',
|
|
1176
1176
|
control: '开关 / 勾选',
|
|
1177
|
-
controlHint: '宿主的开关、复选框、单选都压在近黑/近白上;开启后改用强调色。',
|
|
1178
1177
|
scroll: '滚动条',
|
|
1179
|
-
scrollHint: '默认中性灰;「跟随」上配色色相,「强调」用强调色。明暗关系不变。',
|
|
1180
1178
|
scrollHintMono: '当前是黑白配色,没有色相可跟随,滚动条保持中性灰。',
|
|
1181
1179
|
rightbar: '右侧栏底色',
|
|
1182
|
-
rightbarHint: '右栏本来没有自己的背景,露的是会话区画布色。',
|
|
1183
1180
|
advanced: '更多选项',
|
|
1184
1181
|
textSub: '正文与强调的着色程度',
|
|
1185
1182
|
sidebarSub: '相对会话区的层次',
|
|
@@ -1188,16 +1185,11 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1188
1185
|
scrollSub: '滚动条与滑轨的色相',
|
|
1189
1186
|
controlSub: '开关与复选框是否跟强调色',
|
|
1190
1187
|
langSub: '自动跟随宿主界面语言',
|
|
1191
|
-
surface: '面板表面',
|
|
1192
|
-
surfaceHint: '决定侧栏与右栏相对会话区是「浮起」还是「凹陷」。',
|
|
1193
|
-
ok: '✓ 配色已生效',
|
|
1194
1188
|
bad: '⚠ 部分 token 未生效(宿主可能改名),请查看控制台',
|
|
1195
1189
|
healed: '配色层被宿主丢过一次,已自动恢复 ',
|
|
1196
1190
|
healedSuffix: ' 次',
|
|
1197
1191
|
text: '强度',
|
|
1198
|
-
textHint: '让正文/次级文字带配色色味;三档都满足 AA。',
|
|
1199
1192
|
sidebar: '左侧栏底色',
|
|
1200
|
-
sidebarHint: '让侧栏比会话区更浅(或更深),做出区块层次。',
|
|
1201
1193
|
lang: '语言',
|
|
1202
1194
|
hc: '高对比',
|
|
1203
1195
|
custom: '自定义配色',
|
|
@@ -1208,6 +1200,7 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1208
1200
|
copy: '复制',
|
|
1209
1201
|
applyImport: '导入',
|
|
1210
1202
|
copied: '已复制',
|
|
1203
|
+
copyFail: '复制失败,请手选后 Ctrl+C',
|
|
1211
1204
|
importOk: '已导入',
|
|
1212
1205
|
importBad: '短码无效,已忽略',
|
|
1213
1206
|
hcSub: '把文字下限抬到 AAA(正文 ≥15、次文 ≥9、三级 ≥7)',
|
|
@@ -1216,14 +1209,10 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1216
1209
|
nav: '主題色',
|
|
1217
1210
|
hint: '配色與明暗模式獨立;切換後立即生效並存在 localStorage。',
|
|
1218
1211
|
md: 'Markdown 強調',
|
|
1219
|
-
mdHint: '標題與粗體用「本文色混強調色」,比本文更有色;關掉則與本文同色。',
|
|
1220
1212
|
control: '開關 / 勾選',
|
|
1221
|
-
controlHint: '宿主開關、核取方塊、單選都用近黑/近白;開啟後改用強調色。',
|
|
1222
1213
|
scroll: '捲軸',
|
|
1223
|
-
scrollHint: '預設中性灰;「跟隨」上配色色相,「強調」用強調色。明暗關係不變。',
|
|
1224
1214
|
scrollHintMono: '目前是黑白配色,沒有色相可跟隨,捲軸保持中性灰。',
|
|
1225
1215
|
rightbar: '右側欄底色',
|
|
1226
|
-
rightbarHint: '右欄本來沒有自己的背景,露的是會話區畫布色。',
|
|
1227
1216
|
advanced: '更多選項',
|
|
1228
1217
|
textSub: '本文與強調的著色程度',
|
|
1229
1218
|
sidebarSub: '相對會話區的層次',
|
|
@@ -1232,16 +1221,11 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1232
1221
|
scrollSub: '捲軸與軌道的色相',
|
|
1233
1222
|
controlSub: '開關與核取方塊是否跟強調色',
|
|
1234
1223
|
langSub: '自動跟隨宿主介面語言',
|
|
1235
|
-
surface: '面板表面',
|
|
1236
|
-
surfaceHint: '決定側欄與右欄相對會話區是「浮起」還是「凹陷」。',
|
|
1237
|
-
ok: '✓ 配色已生效',
|
|
1238
1224
|
bad: '⚠ 部分 token 未生效(宿主可能改名),請看主控台',
|
|
1239
1225
|
healed: '配色層被宿主丟棄過一次,已自動恢復 ',
|
|
1240
1226
|
healedSuffix: ' 次',
|
|
1241
1227
|
text: '強度',
|
|
1242
|
-
textHint: '讓本文/次級文字帶配色色味;三檔都符合 AA。',
|
|
1243
1228
|
sidebar: '左側欄底色',
|
|
1244
|
-
sidebarHint: '讓側欄比會話區更淺(或更深),做出區塊層次。',
|
|
1245
1229
|
lang: '語言',
|
|
1246
1230
|
hc: '高對比',
|
|
1247
1231
|
custom: '自訂配色',
|
|
@@ -1252,6 +1236,7 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1252
1236
|
copy: '複製',
|
|
1253
1237
|
applyImport: '匯入',
|
|
1254
1238
|
copied: '已複製',
|
|
1239
|
+
copyFail: '複製失敗,請手選後 Ctrl+C',
|
|
1255
1240
|
importOk: '已匯入',
|
|
1256
1241
|
importBad: '短碼無效,已忽略',
|
|
1257
1242
|
hcSub: '把文字下限抬到 AAA(正文 ≥15、次文 ≥9、三級 ≥7)',
|
|
@@ -1260,14 +1245,10 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1260
1245
|
nav: 'Color theme',
|
|
1261
1246
|
hint: 'Independent of light/dark mode. Applies immediately and is saved to localStorage.',
|
|
1262
1247
|
md: 'Markdown emphasis',
|
|
1263
|
-
mdHint: 'Headings and bold mix the accent into body colour; off keeps them identical to body text.',
|
|
1264
1248
|
control: 'Switches / checks',
|
|
1265
|
-
controlHint: 'Switches, checkboxes and radios use near-black/white in the host. Turn this on to use the accent colour.',
|
|
1266
1249
|
scroll: 'Scrollbars',
|
|
1267
|
-
scrollHint: 'Neutral grey by default. Tint follows the palette hue; Accent uses the accent colour. Lightness is unchanged.',
|
|
1268
1250
|
scrollHintMono: 'Monochrome has no hue to follow; scrollbars stay neutral.',
|
|
1269
1251
|
rightbar: 'Right panel surface',
|
|
1270
|
-
rightbarHint: 'The right panel has no fill of its own; it shows the canvas.',
|
|
1271
1252
|
advanced: 'More options',
|
|
1272
1253
|
textSub: 'How strongly text follows the palette',
|
|
1273
1254
|
sidebarSub: 'Layer relative to the conversation',
|
|
@@ -1276,16 +1257,11 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1276
1257
|
scrollSub: 'Hue of the scrollbar',
|
|
1277
1258
|
controlSub: 'Switches and checkboxes',
|
|
1278
1259
|
langSub: 'Follow the host interface language',
|
|
1279
|
-
surface: 'Panel surfaces',
|
|
1280
|
-
surfaceHint: 'Whether the sidebars sit above or below the conversation area.',
|
|
1281
|
-
ok: '✓ Palette applied',
|
|
1282
1260
|
bad: '⚠ Some tokens did not apply (host may have renamed them); check the console',
|
|
1283
1261
|
healed: 'Palette layer was dropped by the host; restored ',
|
|
1284
1262
|
healedSuffix: 'x',
|
|
1285
1263
|
text: 'Strength',
|
|
1286
|
-
textHint: 'Tints body and secondary text toward the palette; all three levels meet AA.',
|
|
1287
1264
|
sidebar: 'Sidebar surface',
|
|
1288
|
-
sidebarHint: 'Makes the sidebar lighter (or deeper) than the conversation area.',
|
|
1289
1265
|
lang: 'Language',
|
|
1290
1266
|
hc: 'High contrast',
|
|
1291
1267
|
custom: 'Custom palette',
|
|
@@ -1296,6 +1272,7 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1296
1272
|
copy: 'Copy',
|
|
1297
1273
|
applyImport: 'Import',
|
|
1298
1274
|
copied: 'Copied',
|
|
1275
|
+
copyFail: 'Copy failed — select the code and press Ctrl+C',
|
|
1299
1276
|
importOk: 'Imported',
|
|
1300
1277
|
importBad: 'Invalid code, ignored',
|
|
1301
1278
|
hcSub: 'Raises text floors to AAA (body ≥15, secondary ≥9, tertiary ≥7)',
|
|
@@ -1304,14 +1281,10 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1304
1281
|
nav: 'カラーテーマ',
|
|
1305
1282
|
hint: 'ライト/ダークとは独立です。変更は即時反映され、localStorage に保存されます。',
|
|
1306
1283
|
md: 'Markdown の強調',
|
|
1307
|
-
mdHint: '見出しと太字にアクセント色を混ぜます。オフにすると本文と同じ色になります。',
|
|
1308
1284
|
control: 'スイッチ / チェック',
|
|
1309
|
-
controlHint: 'ホストのスイッチ・チェックボックスはほぼ白黒です。オンにするとアクセント色になります。',
|
|
1310
1285
|
scroll: 'スクロールバー',
|
|
1311
|
-
scrollHint: '既定はニュートラルグレー。「追従」でテーマの色相、「アクセント」でアクセント色になります。',
|
|
1312
1286
|
scrollHintMono: 'モノクロには色相がないため、スクロールバーはグレーのままです。',
|
|
1313
1287
|
rightbar: '右パネルの背景',
|
|
1314
|
-
rightbarHint: '右パネルは独自の背景を持たず、キャンバス色が見えています。',
|
|
1315
1288
|
advanced: 'その他のオプション',
|
|
1316
1289
|
textSub: '本文と強調の色づき具合',
|
|
1317
1290
|
sidebarSub: '会話エリアとの段差',
|
|
@@ -1320,16 +1293,11 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1320
1293
|
scrollSub: 'スクロールバーの色相',
|
|
1321
1294
|
controlSub: 'スイッチとチェックの色',
|
|
1322
1295
|
langSub: 'ホストの表示言語に合わせます',
|
|
1323
|
-
surface: 'パネル表面',
|
|
1324
|
-
surfaceHint: 'サイドバーが会話エリアより浮くか沈むかを決めます。',
|
|
1325
|
-
ok: '✓ 配色を適用しました',
|
|
1326
1296
|
bad: '⚠ 一部の token が適用されていません(ホスト側で改名された可能性)。コンソールを確認してください',
|
|
1327
1297
|
healed: '配色レイヤーがホストに破棄されたため、自動で復元しました(',
|
|
1328
1298
|
healedSuffix: ' 回)',
|
|
1329
1299
|
text: '強さ',
|
|
1330
|
-
textHint: '本文と副次テキストをテーマ色に寄せます。3 段階とも AA を満たします。',
|
|
1331
1300
|
sidebar: '左サイドバーの背景',
|
|
1332
|
-
sidebarHint: 'サイドバーを会話エリアより明るく(または暗く)して段差を作ります。',
|
|
1333
1301
|
lang: '言語',
|
|
1334
1302
|
hc: 'ハイコントラスト',
|
|
1335
1303
|
custom: 'カスタム配色',
|
|
@@ -1340,6 +1308,7 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1340
1308
|
copy: 'コピー',
|
|
1341
1309
|
applyImport: '読み込み',
|
|
1342
1310
|
copied: 'コピーしました',
|
|
1311
|
+
copyFail: 'コピーできません。選択して Ctrl+C してください',
|
|
1343
1312
|
importOk: '読み込みました',
|
|
1344
1313
|
importBad: '無効なコードです',
|
|
1345
1314
|
hcSub: '本文の下限を AAA に引き上げます(本文 ≥15、副次 ≥9、三次 ≥7)',
|
|
@@ -1392,8 +1361,8 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1392
1361
|
desc: { mono: '色なし · 既定', warm: 'クリーム + ブラウン', indigo: 'クールホワイト + ブルー', moss: 'グレーグリーン', custom: '3 色から派生' },
|
|
1393
1362
|
text: { neutral: '控えめ', tinted: '標準', deep: '強め' },
|
|
1394
1363
|
sidebar: { light: '明るく', match: '同じ', deep: '暗く' },
|
|
1395
|
-
rightbar: { sidebar: '
|
|
1396
|
-
scroll: { neutral: '
|
|
1364
|
+
rightbar: { sidebar: 'サイドバー', canvas: 'キャンバス' },
|
|
1365
|
+
scroll: { neutral: '無彩', tinted: '追従', accent: '強調' },
|
|
1397
1366
|
control: { accent: 'アクセント', mono: 'モノクロ' },
|
|
1398
1367
|
md: { on: '色づけ', off: '本文と同じ' },
|
|
1399
1368
|
lang: { auto: '自動' },
|
|
@@ -1415,32 +1384,42 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1415
1384
|
const health = React.useSyncExternalStore(props.subscribeHealth, props.getHealth)
|
|
1416
1385
|
const [importText, setImportText] = React.useState('')
|
|
1417
1386
|
const [importState, setImportState] = React.useState(null)
|
|
1387
|
+
const [copyState, setCopyState] = React.useState(null)
|
|
1418
1388
|
const [advanced, setAdvanced] = React.useState(false)
|
|
1419
1389
|
const locale = React.useSyncExternalStore(props.subscribeLocale, props.getLocale)
|
|
1420
1390
|
const langPref = React.useSyncExternalStore(props.subscribeLocale, props.getLangPref)
|
|
1391
|
+
const langAttr = langPref !== 'auto'
|
|
1392
|
+
? langPref
|
|
1393
|
+
: ((typeof document !== 'undefined' && document.documentElement && document.documentElement.lang) || 'zh-CN')
|
|
1421
1394
|
const txt = TEXT[locale] || TEXT['zh-CN']
|
|
1422
1395
|
const lb = LABELS[locale] || LABELS['zh-CN']
|
|
1423
1396
|
|
|
1424
|
-
|
|
1397
|
+
// A6:读屏需要知道"这是哪个设置的选项组";单选用 radio 语义更准
|
|
1398
|
+
const seg = (modes, value, onPick, labels, labelId, disabled) => h(
|
|
1425
1399
|
'div',
|
|
1426
|
-
{ className: 'dsh-tp-seg', role: '
|
|
1400
|
+
{ className: 'dsh-tp-seg', role: 'radiogroup', 'aria-labelledby': labelId, 'aria-disabled': disabled ? 'true' : undefined },
|
|
1427
1401
|
modes.map((mode) => h(
|
|
1428
1402
|
'button',
|
|
1429
1403
|
{
|
|
1430
1404
|
key: mode.id,
|
|
1431
1405
|
type: 'button',
|
|
1406
|
+
role: 'radio',
|
|
1432
1407
|
className: mode.id === value ? 'is-on' : undefined,
|
|
1433
|
-
'aria-
|
|
1434
|
-
|
|
1408
|
+
'aria-checked': mode.id === value,
|
|
1409
|
+
'aria-disabled': disabled ? 'true' : undefined,
|
|
1410
|
+
disabled: disabled === true,
|
|
1411
|
+
onClick: () => { if (!disabled) onPick(mode.id) },
|
|
1435
1412
|
},
|
|
1436
1413
|
(labels && labels[mode.id]) || mode.label,
|
|
1437
1414
|
)),
|
|
1438
1415
|
)
|
|
1439
1416
|
|
|
1440
|
-
const
|
|
1417
|
+
const rowId = (key) => 'dsh-tp-row-' + key
|
|
1418
|
+
const row = (key, titleText, subText, control) => h(
|
|
1441
1419
|
'div',
|
|
1442
1420
|
{ className: 'dsh-tp-row' },
|
|
1443
|
-
h('div', { className: 'dsh-tp-row-label'
|
|
1421
|
+
h('div', { className: 'dsh-tp-row-label', id: rowId(key) + '-desc' },
|
|
1422
|
+
h('b', { id: rowId(key) }, titleText), h('span', null, subText)),
|
|
1444
1423
|
control,
|
|
1445
1424
|
)
|
|
1446
1425
|
|
|
@@ -1468,13 +1447,21 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1468
1447
|
'aria-label': (lb.custom && lb.custom[field]) || field,
|
|
1469
1448
|
}),
|
|
1470
1449
|
h('span', { className: 'dsh-tp-swatch-name' }, (lb.custom && lb.custom[field]) || field),
|
|
1471
|
-
h('
|
|
1450
|
+
h('input', {
|
|
1451
|
+
key: customColors[field],
|
|
1452
|
+
className: 'dsh-tp-hexinput',
|
|
1453
|
+
defaultValue: customColors[field],
|
|
1454
|
+
spellCheck: false,
|
|
1455
|
+
'aria-label': ((lb.custom && lb.custom[field]) || field) + ' HEX',
|
|
1456
|
+
onBlur: (e) => props.setCustomColor(field, e.target.value.trim()),
|
|
1457
|
+
onKeyDown: (e) => { if (e.key === 'Enter') props.setCustomColor(field, e.target.value.trim()) },
|
|
1458
|
+
})))),
|
|
1472
1459
|
h('p', { className: 'dsh-tp-custom-hint' }, txt.customHint),
|
|
1473
1460
|
)
|
|
1474
1461
|
|
|
1475
1462
|
const card = (scheme) => {
|
|
1476
1463
|
const picked = scheme.id === current
|
|
1477
|
-
const c = cardColors(scheme, textMode)
|
|
1464
|
+
const c = cardColors(scheme, textMode, sidebarMode)
|
|
1478
1465
|
return h(
|
|
1479
1466
|
'button',
|
|
1480
1467
|
{
|
|
@@ -1502,16 +1489,16 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1502
1489
|
|
|
1503
1490
|
return h(
|
|
1504
1491
|
'section',
|
|
1505
|
-
{ className: 'dsh-tp' },
|
|
1492
|
+
{ className: 'dsh-tp', lang: langAttr },
|
|
1506
1493
|
h('div', { className: 'dsh-tp-head' },
|
|
1507
1494
|
h('h2', null, txt.nav),
|
|
1508
1495
|
h('span', { className: 'dsh-tp-badge' }, 'v' + PLUGIN_VERSION)),
|
|
1509
1496
|
h('p', { className: 'dsh-tp-sub' }, txt.hint),
|
|
1510
1497
|
h('div', { className: 'dsh-tp-grid' }, SCHEMES.map(card)),
|
|
1511
1498
|
customPanel,
|
|
1512
|
-
row(txt.text, txt.textSub, seg(TEXT_MODES, textMode, props.setTextMode, lb.text)),
|
|
1513
|
-
row(txt.sidebar, txt.sidebarSub, seg(SIDEBAR_MODES, sidebarMode, props.setSidebarMode, lb.sidebar)),
|
|
1514
|
-
row(txt.rightbar, txt.rightbarSub, seg(RIGHTBAR_MODES, rightbarMode, props.setRightbarMode, lb.rightbar)),
|
|
1499
|
+
row('text', txt.text, txt.textSub, seg(TEXT_MODES, textMode, props.setTextMode, lb.text, rowId('text'))),
|
|
1500
|
+
row('sidebar', txt.sidebar, txt.sidebarSub, seg(SIDEBAR_MODES, sidebarMode, props.setSidebarMode, lb.sidebar, rowId('sidebar'))),
|
|
1501
|
+
row('rightbar', txt.rightbar, txt.rightbarSub, seg(RIGHTBAR_MODES, rightbarMode, props.setRightbarMode, lb.rightbar, rowId('rightbar'))),
|
|
1515
1502
|
health && !health.ok && h('p', { className: 'dsh-tp-status is-bad' }, txt.bad),
|
|
1516
1503
|
health && health.ok && health.reapplies > 0 && h(
|
|
1517
1504
|
'p',
|
|
@@ -1527,35 +1514,43 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1527
1514
|
advanced && h(
|
|
1528
1515
|
'div',
|
|
1529
1516
|
{ className: 'dsh-tp-adv' },
|
|
1530
|
-
row(txt.lang, txt.langSub, seg(LANG_OPTIONS, langPref, props.setLangPref, lb.lang)),
|
|
1517
|
+
row('lang', txt.lang, txt.langSub, seg(LANG_OPTIONS, langPref, props.setLangPref, lb.lang, rowId('lang'))),
|
|
1531
1518
|
h(
|
|
1532
1519
|
'div',
|
|
1533
|
-
{
|
|
1534
|
-
h('div', {
|
|
1535
|
-
h('div', {
|
|
1520
|
+
{ className: 'dsh-tp-field' },
|
|
1521
|
+
h('div', { className: 'dsh-tp-field-title', id: rowId('config') }, txt.config),
|
|
1522
|
+
h('div', { className: 'dsh-tp-field-row' },
|
|
1536
1523
|
h('input', {
|
|
1537
1524
|
className: 'dsh-tp-input',
|
|
1538
1525
|
readOnly: true,
|
|
1539
1526
|
value: props.getConfigCode(),
|
|
1527
|
+
title: props.getConfigCode(),
|
|
1540
1528
|
onFocus: (e) => { try { e.target.select() } catch (err) { /* 忽略 */ } },
|
|
1541
|
-
'aria-label': txt.config,
|
|
1529
|
+
'aria-label': txt.config + ' — ' + txt.copy,
|
|
1542
1530
|
}),
|
|
1543
1531
|
h('button', {
|
|
1544
1532
|
type: 'button',
|
|
1545
1533
|
className: 'dsh-tp-mini',
|
|
1546
|
-
onClick: () => {
|
|
1534
|
+
onClick: async () => {
|
|
1547
1535
|
const code = props.getConfigCode()
|
|
1548
1536
|
try {
|
|
1549
|
-
if (navigator.clipboard
|
|
1550
|
-
|
|
1551
|
-
|
|
1537
|
+
if (!navigator.clipboard || typeof navigator.clipboard.writeText !== 'function') throw new Error('no clipboard api')
|
|
1538
|
+
await navigator.clipboard.writeText(code)
|
|
1539
|
+
setCopyState('copied')
|
|
1540
|
+
} catch (err) {
|
|
1541
|
+
// 剪贴板可能被拒(无安全上下文/权限);不能谎报成功
|
|
1542
|
+
setCopyState('fail')
|
|
1543
|
+
}
|
|
1552
1544
|
},
|
|
1553
|
-
}, txt.copy)
|
|
1554
|
-
|
|
1545
|
+
}, txt.copy),
|
|
1546
|
+
copyState && h('span', { className: 'dsh-tp-note', role: 'status', 'aria-live': 'polite' },
|
|
1547
|
+
copyState === 'copied' ? txt.copied : txt.copyFail)),
|
|
1548
|
+
h('div', { className: 'dsh-tp-field-row' },
|
|
1555
1549
|
h('input', {
|
|
1556
1550
|
className: 'dsh-tp-input',
|
|
1557
1551
|
placeholder: 'dshs1.…',
|
|
1558
1552
|
value: importText,
|
|
1553
|
+
'aria-label': txt.applyImport,
|
|
1559
1554
|
onChange: (e) => { setImportText(e.target.value); setImportState(null) },
|
|
1560
1555
|
}),
|
|
1561
1556
|
h('button', {
|
|
@@ -1563,14 +1558,14 @@ body[data-ds-dark-theme] .dsh-tp-check{background:var(--t-accent-d);color:var(--
|
|
|
1563
1558
|
className: 'dsh-tp-mini',
|
|
1564
1559
|
onClick: () => setImportState(props.applyConfigCode(importText) ? 'ok' : 'bad'),
|
|
1565
1560
|
}, txt.applyImport),
|
|
1566
|
-
importState && h('span', { className: 'dsh-tp-note' },
|
|
1567
|
-
importState === 'ok' ? txt.importOk :
|
|
1568
|
-
h('p', {
|
|
1561
|
+
importState && h('span', { className: 'dsh-tp-note', role: importState === 'bad' ? 'alert' : 'status', 'aria-live': 'polite' },
|
|
1562
|
+
importState === 'ok' ? txt.importOk : txt.importBad)),
|
|
1563
|
+
h('p', { className: 'dsh-tp-custom-hint' }, txt.configHint),
|
|
1569
1564
|
),
|
|
1570
|
-
row(txt.md, txt.mdSub, seg(MD_MODES, mdMode, props.setMdMode, lb.md)),
|
|
1571
|
-
row(txt.hc, txt.hcSub, seg(HC_MODES, hcMode, props.setHcMode, lb.hc)),
|
|
1572
|
-
row(txt.scroll, current === 'mono' ? txt.scrollHintMono : txt.scrollSub, seg(SCROLL_MODES, scrollMode, props.setScrollMode, lb.scroll)),
|
|
1573
|
-
row(txt.control, txt.controlSub, seg(CONTROL_MODES, controlMode, props.setControlMode, lb.control)),
|
|
1565
|
+
row('md', txt.md, txt.mdSub, seg(MD_MODES, mdMode, props.setMdMode, lb.md, rowId('md'))),
|
|
1566
|
+
row('hc', txt.hc, txt.hcSub, seg(HC_MODES, hcMode, props.setHcMode, lb.hc, rowId('hc'))),
|
|
1567
|
+
row('scroll', txt.scroll, current === 'mono' ? txt.scrollHintMono : txt.scrollSub, seg(SCROLL_MODES, scrollMode, props.setScrollMode, lb.scroll, rowId('scroll'), current === 'mono')),
|
|
1568
|
+
row('control', txt.control, txt.controlSub, seg(CONTROL_MODES, controlMode, props.setControlMode, lb.control, rowId('control'), current === 'mono')),
|
|
1574
1569
|
),
|
|
1575
1570
|
)
|
|
1576
1571
|
}
|
package/docs/DESIGN.md
CHANGED
|
@@ -42,6 +42,20 @@
|
|
|
42
42
|
旧写法把 `-0.020×0.6` 夹成 `-0.004`,深色导轨与画布只剩 ΔE 0.49 —— 边界直接消失,
|
|
43
43
|
而同一档在浅色侧是 2.10。现在两侧都是 1.9–2.1,同一个档位在明暗两模式下强度一致。
|
|
44
44
|
|
|
45
|
+
## 当前标定值(真源:`client.js`)
|
|
46
|
+
|
|
47
|
+
> 下面各节的推演过程保留原样(它们是当时的推理轨迹),但**具体数值以本表为准**。
|
|
48
|
+
> 2026-10-22 视觉审计发现旧表格仍写着 1.8 / 2.6 与「中性 / 跟随 / 浓一些」,与实现已不一致。
|
|
49
|
+
|
|
50
|
+
| 档位(UI 文案) | id | textScale | paperScale | textLift |
|
|
51
|
+
|---|---|---|---|---|
|
|
52
|
+
| 静 | `neutral` | 1 | 1 | 0 |
|
|
53
|
+
| **标准(默认)** | `tinted` | 3.0 | 2.4 | +0.055 |
|
|
54
|
+
| 浓 | `deep` | 4.6 | 3.6 | +0.085 |
|
|
55
|
+
|
|
56
|
+
高对比档(`HC_MODES`,默认关)把文字下限整体抬到正文 ≥15 / 次文 ≥9 / 三级 ≥7 / 链接 ≥7,
|
|
57
|
+
并把求解器位移上限从 0.13 放宽到 0.30(低档位下 4.6 → 7 需要 ΔL≈0.2,原上限够不着)。
|
|
58
|
+
|
|
45
59
|
## 文字着色
|
|
46
60
|
|
|
47
61
|
正文原来只给 0.004 的色度(近中性),视觉上就是「黑字 / 白字」。现在有第三行「文字着色」,
|