dsh-theme-palette 1.13.2 → 1.13.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 CHANGED
@@ -8,6 +8,43 @@
8
8
  > 1.13.2 起逐节标注 —— 此前 27 个版本节看起来都能装,用户按 CHANGELOG 钉版本会撞 404
9
9
  > (2026-10-29 审计 P2-9)。
10
10
 
11
+ ### 1.13.4
12
+ 用户第二次回执:同一张悬停卡「还是深灰底色」。这次**明暗两套截图对比**把 1.13.3 的方向证伪了 ——
13
+ 浅色模式下(画布 `#f8fcf6`)卡片仍是 `#2c2c2e` + 白字,颜色一个像素都没变:
14
+ 它根本不读调色板,所以改多少条 token 都碰不到。
15
+
16
+ 逐文件扫宿主 asar 后定位到根因:**`dsh-web-frontend` 把悬停卡底色写死在卡片元素上** ——
17
+ `._card_38jqx_9{--dsw-hovercard-bg:#2C2C2E;background:var(--dsw-hovercard-bg)}`。
18
+ 这是全站唯一的大写手写 hex:既不读色阶、也不读别名,与主题完全无关(连浅色模式也是深灰)。
19
+
20
+ - **修法**:`buildTokens` 新增专用 token `--dsh-tp-hovercard-bg`(明暗两档都取色阶 **850 的暗面**),
21
+ 并注入第三条样式 `dsh-theme-palette/host-patch.css`:
22
+ `*{--dsw-hovercard-bg:var(--dsh-tp-hovercard-bg,#2c2c2e)!important}`。
23
+ 宿主的声明在卡片元素**自身**,普通声明压不过它,必须 `!important`;只改这一个自定义属性,
24
+ 其它元素即使命中也没有副作用。卡片保持**暗底白字**(对比度不变),但从此带上配色色相。
25
+ 黑白档没有色阶可接,回落到宿主原色(行为不变)。
26
+ - **断言**:`check-audit` 第 28 组 —— 明暗同值 / = 850 暗面 / 补丁样式的形态 / 黑白档不产出。
27
+ - 复核:`npm run check` 8/8;两档报表 exit 0。
28
+
29
+ ### 1.13.3
30
+ 用户实测反馈:**左侧会话行的悬停卡(会话标题 / 时间 / 状态)底色不跟随主题色** —— 卡片背景停在
31
+ `#2c2c2e`、标题近白,而旁边的侧栏与画布都是染过色的。
32
+
33
+ 核实(像素取样 + 宿主构建对账):卡片背景正好是宿主 **原始**色阶 `--dsw-static-neutral-bluish-850`
34
+ (`#2c2c2e`)、标题是原始 `50`(`#f9fafb`);而宿主把这些表面别名声明成
35
+ `var(--dsw-static-neutral-bluish-NN)` 的**引用**,插件过去只覆盖色阶、指望浏览器在 `body` 上完成替换 ——
36
+ 这条链在浮层里没有生效,于是卡片拿到了宿主原色。
37
+
38
+ - **修法**:把宿主里**全部 47 个**「纯粹是色阶引用」的别名(`bg-base` / `bg-layer-1..3` / `tooltip-bg` /
39
+ `label-primary` / `toast-bg` / `switch-thumb` / `specific-tip` / `specific-input-major` …)在覆盖层里
40
+ **直接写成色阶值**,不再依赖任何中间引用。已经由求解器给值的键(`label-secondary` / `label-tertiary` /
41
+ `link` / `brand` / `bubble` / `sidebar-fill` / `markdown-code-block` 等)一律跳过,保持求解结果。
42
+ 能正常替换的地方结果完全一致(同一档),链不生效的地方就是修复。
43
+ - **防回退**:`check-audit` 新增第 27 组 —— 每个别名都必须在覆盖表里、且值等于它声明的色阶档;
44
+ `check-host-contract` 改为从**宿主真实构建**里解出这 47 条映射并与插件对表(宿主改映射会红,不会静默错色)。
45
+ - 覆盖的 token 数从 122 增至 **158**(黑白档 17 → 19),六语 README 同步。
46
+ - 复核:`npm run check` 8/8;两档报表 exit 0;`npm pack` 28 文件。
47
+
11
48
  ### 1.13.2
12
49
  对 2026-10-29 全量审计(**34 条**,报告与反哺回执在仓库根目录的 `AUDIT-2026-10-29.md` /
13
50
  `AUDIT-2026-10-29-FEEDBACK.md`)的修订。审计的核心判断成立:**引擎正确,缺的是"防回归"的工程能力** ——
package/README-es.md CHANGED
@@ -28,7 +28,7 @@ El plugin solo apila tokens de color mediante `ctx.theme.overrideTokens`; no reg
28
28
 
29
29
  - **4 preajustadas + personalizada** — Mono, Arena cálida, Índigo, Musgo (cada una adaptada de forma independiente a claro y oscuro), más una paleta personalizada derivada de tres colores;
30
30
  - la escala se **recalcula** completa: reconstrucción OKLCH → croma por rol → **ajuste al gamut sRGB** → contraste resuelto sobre superficies reales;
31
- - se cubren todos los tokens de color del host (122 tokens en paletas con tinte, 17 en mono; 1080 combinaciones de ajuste escaneadas): texto, secundario, terciario, notas, enlaces, barras laterales, tarjetas, burbuja del usuario, botón primario, barras de desplazamiento, interruptores, títulos/negritas de Markdown, bloques de código;
31
+ - se cubren todos los tokens de color del host (158 tokens en paletas con tinte, 19 en mono; 1080 combinaciones de ajuste escaneadas): texto, secundario, terciario, notas, enlaces, barras laterales, tarjetas, burbuja del usuario, botón primario, barras de desplazamiento, interruptores, títulos/negritas de Markdown, bloques de código;
32
32
  - ajustable: intensidad del texto (3), profundidad de la barra lateral (3), énfasis de Markdown, barras de desplazamiento, color de interruptores;
33
33
  - **paleta personalizada** (elige superficie / texto / acento — el motor mantiene sus garantías de contraste), **exportación/importación de configuración** con un código `dshs1.`, **modo de alto contraste** y **4 idiomas de interfaz**;
34
34
  - **autorreparable**: si el host descarta la capa de override, la paleta se vuelve a aplicar; tras fallos repetidos la autorreparación se pausa y la página de ajustes ofrece un botón para reactivarla;
package/README-hi.md CHANGED
@@ -28,7 +28,7 @@ DeepSeek Harness (वेब और डेस्कटॉप) के लिए
28
28
 
29
29
  - **4 प्रीसेट + कस्टम** — मोनो, वार्म सैंड, इंडिगो, मॉस (हर एक लाइट और डार्क दोनों के लिए अलग से अनुकूलित), साथ ही तीन रंगों से निकली कस्टम पैलेट;
30
30
  - पूरी रैंप **दोबारा गणना** होती है, बदली नहीं जाती: OKLCH पुनर्निर्माण → भूमिका-आधारित क्रोमा → **sRGB गैमट क्लैंप** → वास्तविक सतहों पर कंट्रास्ट हल;
31
- - होस्ट के सभी रंग टोकन शामिल (रंगीन पैलेट में 122 टोकन, मोनो में 17; 1080 सेटिंग संयोजन पूरी तरह स्कैन किए गए): मुख्य टेक्स्ट, द्वितीयक, तृतीयक, कैप्शन, लिंक, साइडबार, कार्ड, उपयोगकर्ता बबल, प्राइमरी बटन, स्क्रॉलबार, स्विच, Markdown शीर्षक/बोल्ड, कोड ब्लॉक;
31
+ - होस्ट के सभी रंग टोकन शामिल (रंगीन पैलेट में 158 टोकन, मोनो में 19; 1080 सेटिंग संयोजन पूरी तरह स्कैन किए गए): मुख्य टेक्स्ट, द्वितीयक, तृतीयक, कैप्शन, लिंक, साइडबार, कार्ड, उपयोगकर्ता बबल, प्राइमरी बटन, स्क्रॉलबार, स्विच, Markdown शीर्षक/बोल्ड, कोड ब्लॉक;
32
32
  - समायोज्य: टेक्स्ट की तीव्रता (3), साइडबार की गहराई (3), Markdown ज़ोर, स्क्रॉलबार, स्विच का रंग;
33
33
  - **कस्टम पैलेट** (सतह / टेक्स्ट / एक्सेंट चुनें — इंजन अपने कंट्रास्ट वादे बनाए रखता है), `dshs1.` कोड से **कॉन्फ़िगरेशन निर्यात/आयात**, **हाई-कॉन्ट्रास्ट** मोड, और **4 UI भाषाएँ**;
34
34
  - **स्व-उपचार**: यदि होस्ट ओवरराइड परत हटा दे, पैलेट फिर से लगा दी जाती है; बार-बार विफलता पर स्व-उपचार रुक जाता है और सेटिंग्स पेज पर इसे दोबारा चालू करने का बटन मिलता है;
package/README-ja.md CHANGED
@@ -28,7 +28,7 @@ package.json の `engines` は `^22.19.0 || >=24.0.0` —— 上の表と同じ
28
28
 
29
29
  - **4 プリセット + カスタム** —— モノクロ / ウォームサンド / インディゴ / モスグリーンがライトとダークをそれぞれ独立に適応し、さらに 3 色から派生するカスタム配色;
30
30
  - 色階は置き換えではなく**全体を再計算**:OKLCH 再構築 → 役割ごとの彩度 → **sRGB ガマット・クランプ** → 実際の面でコントラストを解く;
31
- - ホストの全色トークンを網羅(着色パレットで 122、モノクロで 17。1080 通りの設定を全走査):本文、二次、三次、注記、リンク、サイドバー、カード、ユーザー吹き出し、プライマリボタン、スクロールバー、スイッチ、Markdown 見出し/太字、コードブロック;
31
+ - ホストの全色トークンを網羅(着色パレットで 158、モノクロで 19。1080 通りの設定を全走査):本文、二次、三次、注記、リンク、サイドバー、カード、ユーザー吹き出し、プライマリボタン、スクロールバー、スイッチ、Markdown 見出し/太字、コードブロック;
32
32
  - 調整可:テキストの着色 3 段、サイドバー 3 段、Markdown 強調、スクロールバー、スイッチの配色;
33
33
  - **カスタム配色**(背景 / テキスト / アクセントの 3 色。極端に明るい・暗いアクセントは正規化されます)、**設定のエクスポート/インポート**(`dshs1.` ショートコードに 3 色を含む)、**ハイコントラスト**、UI 4 言語;
34
34
  - **自己修復**:ホストがオーバーライド層を破棄すると自動で再適用。連続失敗すると自動再適用を停止し、設定ページに「再有効化」の入口を出します;
package/README-pt.md CHANGED
@@ -28,7 +28,7 @@ O plugin apenas empilha tokens de cor via `ctx.theme.overrideTokens`; não regis
28
28
 
29
29
  - **4 predefinidas + personalizada** — Mono, Areia quente, Índigo, Musgo (cada uma adaptada de forma independente ao claro e ao escuro), mais uma paleta personalizada derivada de três cores;
30
30
  - a escala é **recalculada** por completo: reconstrução OKLCH → croma por papel → **limite de gamut sRGB** → contraste resolvido sobre superfícies reais;
31
- - todos os tokens de cor do host são cobertos (122 tokens nas paletas com tinta, 17 na mono; 1080 combinações de ajuste escaneadas): texto, secundário, terciário, legendas, links, barras laterais, cartões, balão do usuário, botão primário, barras de rolagem, interruptores, títulos/negrito de Markdown, blocos de código;
31
+ - todos os tokens de cor do host são cobertos (158 tokens nas paletas com tinta, 19 na mono; 1080 combinações de ajuste escaneadas): texto, secundário, terciário, legendas, links, barras laterais, cartões, balão do usuário, botão primário, barras de rolagem, interruptores, títulos/negrito de Markdown, blocos de código;
32
32
  - ajustável: intensidade do texto (3), profundidade da barra lateral (3), ênfase de Markdown, barras de rolagem, cor dos interruptores;
33
33
  - **paleta personalizada** (escolha superfície / texto / acento — o motor mantém as garantias de contraste), **exportação/importação de configuração** por um código `dshs1.`, **modo de alto contraste** e **4 idiomas de interface**;
34
34
  - **autorrecuperação**: se o host descartar a camada de override, a paleta é reaplicada; após falhas repetidas a autorrecuperação pausa e a página de ajustes oferece um botão para reativá-la;
package/README-zh.md CHANGED
@@ -28,7 +28,7 @@ package.json 的 `engines` 字段写的是 `^22.19.0 || >=24.0.0`——与上表
28
28
 
29
29
  - **4 套预设 + 自定义** —— 黑白 / 暖砂 / 靛蓝 / 苔绿各自独立适配明暗两侧,另加由三色派生的自定义配色;
30
30
  - 色阶**整体重算**而不是替换:OKLCH 重建 → 角色化色度 → **sRGB 色域钳位** → 在真实承载面上求解对比度;
31
- - 覆盖宿主全部颜色 token(自定义/染色档 122 个、黑白档 17 个;1080 组设置全扫描):正文、次级、三级、注释、链接、侧栏、卡片、主人气泡、主按钮、滚动条、开关、Markdown 标题/加粗、代码块;
31
+ - 覆盖宿主全部颜色 token(自定义/染色档 158 个、黑白档 19 个;1080 组设置全扫描):正文、次级、三级、注释、链接、侧栏、卡片、主人气泡、主按钮、滚动条、开关、Markdown 标题/加粗、代码块;
32
32
  - 可调:文字着色三档、侧栏三档、Markdown 强调、滚动条、开关配色;
33
33
  - **自定义配色**(给 底色/文字/强调 三色,文字色相也参与派生;过亮/过暗的强调色会归一化)、**配置导入导出**(`dshs1.` 短码含三色)、**高对比**档、4 种界面语言;
34
34
  - **自愈**:宿主丢弃 override 层时自动重放;自动重放连续失败后会停用,并在设置页给出「重新启用」入口;
package/README.md CHANGED
@@ -28,7 +28,7 @@ The plugin only stacks colour tokens through `ctx.theme.overrideTokens`; it does
28
28
 
29
29
  - **4 presets + custom** — Mono, Warm sand, Indigo, Moss (each adapting to light *and* dark independently), plus a custom palette derived from three colours;
30
30
  - the whole ramp is **recomputed**, not swapped: OKLCH rebuild → role-based chroma → **sRGB gamut clamp** → contrast solved on real surfaces;
31
- - every host colour token is covered (122 tokens for tinted palettes, 17 for mono; 1080 setting combinations fully scanned): body, secondary, tertiary, captions, links, sidebars, cards, user bubble, primary button, scrollbars, switches, Markdown headings/bold, code blocks;
31
+ - every host colour token is covered (158 tokens for tinted palettes, 19 for mono; 1080 setting combinations fully scanned): body, secondary, tertiary, captions, links, sidebars, cards, user bubble, primary button, scrollbars, switches, Markdown headings/bold, code blocks;
32
32
  - adjustable: text tint (3), sidebar depth (3), Markdown emphasis, scrollbars, switch colour;
33
33
  - **custom palette** (pick surface / text / accent — the engine keeps its contrast guarantees), **config export/import** via a `dshs1.` code, **high-contrast** mode, and 4 UI languages;
34
34
  - **self-healing**: if the host drops the override layer, the palette is re-applied; after repeated failures auto-restore pauses and the settings page offers a re-enable button;
Binary file
Binary file
@@ -1,6 +1,6 @@
1
1
  {
2
- "generatedAt": "2026-10-29T08:38:25.942Z",
3
- "pluginVersion": "1.13.2",
2
+ "generatedAt": "2026-10-29T11:56:54.301Z",
3
+ "pluginVersion": "1.13.4",
4
4
  "chrome": "Chrome/156.0.8078.49",
5
5
  "width": 620,
6
6
  "scale": 1,
@@ -14,13 +14,13 @@
14
14
  "--adv",
15
15
  "0"
16
16
  ],
17
- "htmlSha256": "41c23ed56875a8ba0fe08d8a94a927a60bde92a9c9a5d8f49d434f81180322a3",
17
+ "htmlSha256": "54916add6cedff817044eaf0eee2297265f8ff5b2fb336d3e201dad504bf2b35",
18
18
  "cssWidth": 620,
19
19
  "cssHeight": 888,
20
20
  "width": 620,
21
21
  "height": 888,
22
- "bytes": 47493,
23
- "sha256": "ec6a7fb41bd433e853d1ae856a2729aefd5c579295603642f1b78fa7148d9dfd"
22
+ "bytes": 47498,
23
+ "sha256": "d5fc7fe7a3a5012fc0e3947038e6faf69e3df23b5897d346fc3381da655b0fa0"
24
24
  },
25
25
  {
26
26
  "file": "assets/screenshot-settings-dark.png",
@@ -31,13 +31,13 @@
31
31
  "--adv",
32
32
  "0"
33
33
  ],
34
- "htmlSha256": "4a3b259c2acad16f9e2ef0fff8d19b734fd93f3304ddd448b1422e18741e0d56",
34
+ "htmlSha256": "0348f7373871e7d430cf07615cfcd481476bc62478c0a57ba7918e6611b6dd98",
35
35
  "cssWidth": 620,
36
36
  "cssHeight": 888,
37
37
  "width": 620,
38
38
  "height": 888,
39
39
  "bytes": 47810,
40
- "sha256": "8385f5668da31a5f39dceba34420545bd8afccc895e3bd16e0744c417a083e5d"
40
+ "sha256": "ba07e44099f33978f5f7d62563b96e999f240aed4971e0657a145aa5188a452b"
41
41
  },
42
42
  {
43
43
  "file": "assets/screenshot-settings-custom.png",
@@ -50,13 +50,13 @@
50
50
  "--out",
51
51
  "customadv"
52
52
  ],
53
- "htmlSha256": "3b3643539b513b916816b110ed7ff6eddf00ed903fba77c37c75202fd195dd0b",
53
+ "htmlSha256": "5929bc3227c1c53bd6264bb9f3be23557b481a77271e204e77676ac526edc530",
54
54
  "cssWidth": 620,
55
55
  "cssHeight": 1753,
56
56
  "width": 620,
57
57
  "height": 1753,
58
- "bytes": 116563,
59
- "sha256": "4e59831c236d3c3660cd40c652872c1ae521410b99cce720246171302d3cf329"
58
+ "bytes": 116566,
59
+ "sha256": "b7853a193d0be58f3284c363f379cc66fa9f490b83a49fd5abd6780cc70fa728"
60
60
  },
61
61
  {
62
62
  "file": "assets/screenshot-settings-hc.png",
@@ -69,13 +69,13 @@
69
69
  "--out",
70
70
  "hcadv"
71
71
  ],
72
- "htmlSha256": "b855508855018b1e8c21a4502673dbca3266e68227cf2ee8b790f2a59706da23",
72
+ "htmlSha256": "5b68173af9cf81d3586c1ed4a206475427a7f266174420da1df22f1f1d84277d",
73
73
  "cssWidth": 620,
74
74
  "cssHeight": 1463,
75
75
  "width": 620,
76
76
  "height": 1463,
77
- "bytes": 94783,
78
- "sha256": "d58e614eac2f08265421e1579f0f6699e370560e4d81c75b51680bc4dfc4dfd7"
77
+ "bytes": 94792,
78
+ "sha256": "e021a907dd32378591b0e5198027bd4ba2d19da112ccf3e4bf6fbb1929796c0e"
79
79
  }
80
80
  ]
81
81
  }
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.13.2'
30
+ const PLUGIN_VERSION = '1.13.4'
31
31
  const STORE_KEY = 'dsh-theme-palette.v1'
32
32
  const OVERRIDE_SOURCE = 'dsh-theme-palette'
33
33
 
@@ -1492,6 +1492,68 @@ window.__ModuleLoader__.load({
1492
1492
  // (低于自己声明的 0.006),而上面的注释还宣称"整条色阶单调"。
1493
1493
  const RAMP_ORDER = ['00', '50', '60', '75', '100', '150', '200', '300', '400', '500', '600', '700', '750', '800', '850', '875', '900', '950', '1000']
1494
1494
 
1495
+ /**
1496
+ * 宿主里所有「只是 `var(--dsw-static-neutral-bluish-NN)` 引用」的别名 → 色阶档位。
1497
+ *
1498
+ * 为什么要在插件侧再落一遍(2026-10-29,用户实测:左侧会话行的悬停卡不跟随主题色):
1499
+ * 插件过去只覆盖色阶,指望浏览器在 `body` 上把这些引用替换掉。实测那张卡拿到的仍是
1500
+ * **宿主原始色阶**(背景 #2c2c2e = 宿主 850,标题近白 = 宿主 50),说明这条链在浮层里不生效。
1501
+ * 这里把 47 个别名**直接写成色阶值**,不再依赖中间引用 —— 链正常时结果完全一致(同一档),
1502
+ * 链不生效时就是修复。表由宿主构建逐条导出,`tools/check-host-contract.mjs` 会核对映射没漂。
1503
+ *
1504
+ * 只补**插件没有专门求解过**的键:label-secondary / tertiary / link / brand / bubble /
1505
+ * markdown-code-block / sidebar-fill 等由求解器给值,循环里遇到已存在的一律跳过。
1506
+ */
1507
+ const SURFACE_ALIAS_STEPS = {
1508
+ '--dsw-alias-bg-base': { light: '00', dark: '950' },
1509
+ '--dsw-alias-bg-document-preview': { light: '100', dark: '950' },
1510
+ '--dsw-alias-bg-layer-1': { light: '00', dark: '875' },
1511
+ '--dsw-alias-bg-layer-2': { light: '00', dark: '850' },
1512
+ '--dsw-alias-bg-layer-3': { light: '00', dark: '800' },
1513
+ '--dsw-alias-bg-module-platform': { light: '60', dark: '800' },
1514
+ '--dsw-alias-bg-overlay': { light: '150', dark: '700' },
1515
+ '--dsw-alias-brand-primary': { light: '1000', dark: '50' },
1516
+ '--dsw-alias-brand-primary-invert': { light: '1000', dark: '50' },
1517
+ '--dsw-alias-brand-text': { light: '1000', dark: '50' },
1518
+ '--dsw-alias-button-contrast-fill': { light: '700', dark: '50' },
1519
+ '--dsw-alias-button-elevated-fill': { light: '00', dark: '750' },
1520
+ '--dsw-alias-button-floating-fill': { light: '00', dark: '850' },
1521
+ '--dsw-alias-button-floating-hover': { light: '75', dark: '800' },
1522
+ '--dsw-alias-button-ghost-active-border': { light: '500', dark: '600' },
1523
+ '--dsw-alias-button-ghost-active-fill': { light: '100', dark: '750' },
1524
+ '--dsw-alias-button-ghost-active-hover': { light: '150', dark: '700' },
1525
+ '--dsw-alias-button-primary-dimmed': { light: '100', dark: '750' },
1526
+ '--dsw-alias-button-primary-hover': { light: '750', dark: '100' },
1527
+ '--dsw-alias-interactive-bg-hover-solid': { light: '75', dark: '800' },
1528
+ '--dsw-alias-label-caption': { light: '400', dark: '600' },
1529
+ '--dsw-alias-label-dimmed': { light: '200', dark: '750' },
1530
+ '--dsw-alias-label-document-preview': { light: '700', dark: '300' },
1531
+ '--dsw-alias-label-primary': { light: '1000', dark: '50' },
1532
+ '--dsw-alias-label-primary-dimmed': { light: '950', dark: '100' },
1533
+ '--dsw-alias-label-primary-foreground': { light: '00', dark: '1000' },
1534
+ '--dsw-alias-label-primary-inverted': { light: '00', dark: '800' },
1535
+ '--dsw-alias-label-secondary': { light: '700', dark: '300' },
1536
+ '--dsw-alias-label-tertiary': { light: '600', dark: '400' },
1537
+ '--dsw-alias-markdown-citation': { light: '100', dark: '800' },
1538
+ '--dsw-alias-markdown-code-block': { light: '50', dark: '900' },
1539
+ '--dsw-alias-markdown-code-block-banner': { light: '50', dark: '850' },
1540
+ '--dsw-alias-markdown-code-segment-selected': { light: '00', dark: '800' },
1541
+ '--dsw-alias-markdown-code-segment-unselected': { light: '75', dark: '900' },
1542
+ '--dsw-alias-markdown-placeholder': { light: '60', dark: '850' },
1543
+ '--dsw-alias-markdown-tag': { light: '75', dark: '850' },
1544
+ '--dsw-alias-switch-thumb': { light: '00', dark: '400' },
1545
+ '--dsw-alias-toast-bg': { light: '800', dark: '750' },
1546
+ '--dsw-alias-toast-label': { light: '00', dark: '00' },
1547
+ '--dsw-alias-tooltip-bg': { light: '850', dark: '750' },
1548
+ '--dsw-specific-input-major': { light: '00', dark: '850' },
1549
+ '--dsw-specific-login-input': { light: '50', dark: '900' },
1550
+ '--dsw-specific-selector': { light: '60', dark: '800' },
1551
+ '--dsw-specific-sidebar-fill': { light: '50', dark: '900' },
1552
+ '--dsw-specific-sidebar-nav-item-active': { light: '100', dark: '750' },
1553
+ '--dsw-specific-sidebar-nav-item-hover': { light: '75', dark: '850' },
1554
+ '--dsw-specific-tip': { light: '60', dark: '800' },
1555
+ }
1556
+
1495
1557
  /**
1496
1558
  * 把色阶压回「序号越大越深」。**没有返回值**(审计 2026-10-29 P3-6):
1497
1559
  * 原来返回一个 `changed` 布尔,但唯一调用点丢弃它 —— 看起来像是打算用来触发重解或提示,
@@ -1860,6 +1922,26 @@ window.__ModuleLoader__.load({
1860
1922
  // 色阶排序归一化(审计 3.2):放在最后 —— 前面的求解与参考墨色对齐都可能把某一档
1861
1923
  // 推出反序,收尾统一压一次,保证「序号越大越深」在整条色阶上成立。
1862
1924
  if (params.tinted) enforceRampOrder(pairs)
1925
+ // 表面别名**显式落地**(2026-10-29 用户实测:左侧会话行的悬停卡没跟随主题色)。
1926
+ //
1927
+ // 宿主在 `body` / `body[data-ds-dark-theme]` 上把这一批别名写成
1928
+ // `var(--dsw-static-neutral-bluish-NN)` 的**引用**;插件过去只覆盖色阶,指望浏览器
1929
+ // 在 body 上完成 var 替换。实测那张悬停卡拿到的仍是宿主原始色阶值(#2c2c2e =
1930
+ // 宿主 850),说明这条链在某些浮层里不生效。这里把别名**直接写成色阶值**,
1931
+ // 不再依赖任何中间引用 —— 对能正常替换的地方结果完全一致(同一档),对不生效的地方是修复。
1932
+ // 已由求解器给值的键(label-secondary / link / brand / bubble / sidebar-fill …)一律保留,不覆盖。
1933
+ for (const [name, steps] of Object.entries(SURFACE_ALIAS_STEPS)) {
1934
+ if (pairs[name]) continue
1935
+ const light = pairs['--dsw-static-neutral-bluish-' + steps.light]
1936
+ const dark = pairs['--dsw-static-neutral-bluish-' + steps.dark]
1937
+ if (light && dark) pairs[name] = { light: light.light, dark: dark.dark }
1938
+ }
1939
+ // 宿主悬停卡的专用底色(配合 HOST_PATCH_CSS):宿主把卡片底色写死成 #2C2C2E,
1940
+ // 这里给一个**两档都取暗面**的 token —— 卡片始终是暗底白字(对比度不变),但带上配色色相。
1941
+ if (pairs['--dsw-static-neutral-bluish-850']) {
1942
+ const hoverBg = pairs['--dsw-static-neutral-bluish-850'].dark
1943
+ pairs['--dsh-tp-hovercard-bg'] = { light: hoverBg, dark: hoverBg }
1944
+ }
1863
1945
  // 覆盖层标记(自愈判据用):宿主撤销这一层时它会一起消失。
1864
1946
  pairs[LAYER_MARK] = { light: '1', dark: '1' }
1865
1947
  return pairs
@@ -1920,7 +2002,25 @@ return pairs
1920
2002
  '[class*="_markdown_"] :not(pre) > code{background:var(--dshtp-code-inline,inherit)}',
1921
2003
  ].join('')
1922
2004
 
1923
- /* ================= 设置页样式(head 里第二条 CSS) ================= */
2005
+ /* ================= 宿主补丁样式(head 里第三条 CSS) =================
2006
+ *
2007
+ * 为什么需要它(2026-10-29 用户实测,第二轮回执):
2008
+ * 宿主的「悬停卡」(hover card,会话行悬停时弹出的小卡)把底色**写死在卡片元素上**:
2009
+ * dsh-web-frontend 的 `._card_38jqx_9{--dsw-hovercard-bg:#2C2C2E;background:var(--dsw-hovercard-bg)}`。
2010
+ * 这是一个**手写字面量**(全站唯一的大写 hex),既不读色阶也不读别名 ——
2011
+ * 所以浅色模式下它也是深灰、明暗两套主题下颜色一模一样。改多少条 token 都碰不到它。
2012
+ *
2013
+ * 修法:给一个**专用 token**(`--dsh-tp-hovercard-bg`,见 buildTokens:两档都取色阶 850 的暗色值),
2014
+ * 再用 `*` + `!important` 把它接到宿主的 `--dsw-hovercard-bg` 上 —— 宿主的声明在卡片元素自身,
2015
+ * 普通声明压不过它,必须 important。白字保持不变(暗底白字,对比度不受影响),
2016
+ * 卡片从此带上配色的色相,而不是一块中性的深灰。
2017
+ */
2018
+ const HOST_PATCH_STYLE_ID = 'dsh-theme-palette/host-patch.css'
2019
+ const HOST_PATCH_CSS = `
2020
+ /* 宿主悬停卡:--dsw-hovercard-bg 是宿主写死的 #2C2C2E;这里接回配色的暗面(见 buildTokens 的 --dsh-tp-hovercard-bg) */
2021
+ *{--dsw-hovercard-bg:var(--dsh-tp-hovercard-bg,#2c2c2e)!important}
2022
+ `
2023
+ /* ================= 设置页样式(head 里第四条 CSS) ================= */
1924
2024
  const SETTINGS_STYLE_ID = 'dsh-theme-palette/settings.css'
1925
2025
  const SETTINGS_CSS = `
1926
2026
  .dsh-tp{display:flex;flex-direction:column;gap:14px;width:100%;color:var(--dsw-alias-label-primary);box-sizing:border-box}
@@ -2051,8 +2151,7 @@ body[data-ds-dark-theme] .dsh-tp{color-scheme:dark}
2051
2151
  }
2052
2152
  }
2053
2153
 
2054
- function installSettingsStyle() {
2055
- try {
2154
+ function installSettingsStyle() { try {
2056
2155
  if (typeof document === 'undefined' || !document.head) return () => {}
2057
2156
  let tag = document.querySelector('style[data-plugin-css="' + SETTINGS_STYLE_ID + '"]')
2058
2157
  if (!tag) {
@@ -2070,6 +2169,25 @@ body[data-ds-dark-theme] .dsh-tp{color-scheme:dark}
2070
2169
  }
2071
2170
  }
2072
2171
 
2172
+ /** 宿主补丁(悬停卡写死的底色)——与另外两条样式同构:覆盖写 + 卸载移除。 */
2173
+ function installHostPatchStyle() {
2174
+ try {
2175
+ if (typeof document === 'undefined' || !document.head) return () => {}
2176
+ let tag = document.querySelector('style[data-plugin-css="' + HOST_PATCH_STYLE_ID + '"]')
2177
+ if (!tag) {
2178
+ tag = document.createElement('style')
2179
+ tag.dataset.plugin = 'dsh-theme-palette'
2180
+ tag.dataset.pluginCss = HOST_PATCH_STYLE_ID
2181
+ document.head.appendChild(tag)
2182
+ }
2183
+ tag.textContent = HOST_PATCH_CSS
2184
+ return () => { if (tag.parentNode) tag.remove() }
2185
+ } catch (err) {
2186
+ console.warn('[dsh-theme-palette] 宿主补丁样式注入失败:', err)
2187
+ return () => {}
2188
+ }
2189
+ }
2190
+
2073
2191
  /* ================= 运行时自检 ================= */
2074
2192
  /**
2075
2193
  * 宿主若改了 token 名,插件会**静默失效**(overrideTokens 照收,样式不生效)。
@@ -2379,7 +2497,7 @@ body[data-ds-dark-theme] .dsh-tp{color-scheme:dark}
2379
2497
  derive: '由主色派生',
2380
2498
  deriveHint: '用当前强调色的色相与色度推导底色与文字(明暗跟随当前模式)',
2381
2499
  deriveNote: '「由主色派生」以强调色为唯一输入,自动算出底色与文字 —— 会覆盖你手动设置的底色与文字;派生之后仍可逐项手改。',
2382
- notice: '1.13.2:无障碍与文案修正——面板的 lang 跟随实际界面语言、「色觉缺陷」提示改称 OKLab ΔE、对比度矩阵的承载面名跟随语言;配色数值不变。',
2500
+ notice: '1.13.4:悬停卡底色不再被宿主写死成中性深灰 —— 接到配色的暗面,白字与对比度不变。',
2383
2501
  dismiss: '知道了',
2384
2502
  explainClamp: '强调色已归一化:{from} → {to}(保证按钮与勾选可读)',
2385
2503
  explainLink: '链接已为可读性压暗:{ratio}:1(目标 {target}:1)',
@@ -2452,7 +2570,7 @@ body[data-ds-dark-theme] .dsh-tp{color-scheme:dark}
2452
2570
  derive: '由主色派生',
2453
2571
  deriveHint: '用目前強調色的色相與彩度推導底色與文字(明暗跟隨目前模式)',
2454
2572
  deriveNote: '「由主色派生」以強調色為唯一輸入,自動算出底色與文字 —— 會覆蓋你手動設置的底色與文字;派生之後仍可逐項手改。',
2455
- notice: '1.13.2:無障礙與文案修正——面板的 lang 跟隨實際介面語言、「色覺缺陷」提示改稱 OKLab ΔE、對比度矩陣的承載面名跟隨語言;配色數值不變。',
2573
+ notice: '1.13.4:懸停卡底色不再被宿主寫死成中性深灰 —— 接到配色的暗面,白字與對比度不變。',
2456
2574
  dismiss: '知道了',
2457
2575
  explainClamp: '強調色已正規化:{from} → {to}(確保按鈕與勾選可讀)',
2458
2576
  explainLink: '連結已為可讀性壓暗:{ratio}:1(目標 {target}:1)',
@@ -2525,7 +2643,7 @@ body[data-ds-dark-theme] .dsh-tp{color-scheme:dark}
2525
2643
  derive: 'Derive from accent',
2526
2644
  deriveHint: 'Derive background and text from the current accent hue and chroma (follows the current light/dark mode)',
2527
2645
  deriveNote: '"Derive from accent" takes the accent as its only input and computes background and text from it — this overwrites the background and text you set by hand; you can still edit each of them afterwards.',
2528
- notice: '1.13.2: accessibility and wording fixes — the panel lang now matches the rendered UI language, the colour-vision note says OKLab ΔE, and contrast-matrix surface names follow the UI language. Palette values are unchanged.',
2646
+ notice: '1.13.4: the hover card background is no longer the hardcoded neutral dark from the host — it now follows the palette dark surface, keeping white text and contrast.',
2529
2647
  dismiss: 'Got it',
2530
2648
  explainClamp: 'Accent normalised: {from} → {to} (keeps buttons and checks readable)',
2531
2649
  explainLink: 'Link darkened for readability: {ratio}:1 (target {target}:1)',
@@ -2598,7 +2716,7 @@ body[data-ds-dark-theme] .dsh-tp{color-scheme:dark}
2598
2716
  derive: 'メイン色から生成',
2599
2717
  deriveHint: '現在のアクセント色の色相と彩度から背景色と文字色を生成します(明暗は現在のモードに従います)',
2600
2718
  deriveNote: '「メイン色から生成」はアクセント色だけを入力として背景色と文字色を自動計算します。手動で設定した背景色と文字色は上書きされます(生成後に個別に変更できます)。',
2601
- notice: '1.13.2:アクセシビリティと文言の修正 — パネルの lang を実際の表示言語に合わせ、「OKLab ΔE」表記に訂正、コントラスト表の面名も表示言語に追従。配色の数値は変わりません。',
2719
+ notice: '1.13.4:ホバーカードの背景がホスト固定の中立ダークから配色の暗面に切り替わりました(白文字とコントラストはそのまま)。',
2602
2720
  dismiss: '了解',
2603
2721
  explainClamp: 'アクセント色を正規化しました:{from} → {to}(ボタンとチェックの可読性のため)',
2604
2722
  explainLink: 'リンクを可読性のため暗くしました:{ratio}:1(目標 {target}:1)',
@@ -3249,7 +3367,7 @@ body[data-ds-dark-theme] .dsh-tp{color-scheme:dark}
3249
3367
  // 必须能在测试里读到"实现里的那个数"。此前测试拿 floors() 的返回值当期望值 ——
3250
3368
  // 常量一改、期望值跟着改,那道门就是空转的(变异实测:CONTRAST_FLOOR 4.5→1.0 全绿)。
3251
3369
  if (DEV_OPT_IN && typeof window !== 'undefined' && typeof window.__DSH_THEME_PALETTE_DEV__ === 'function') {
3252
- window.__DSH_THEME_PALETTE_DEV__({ buildTokens, SCHEMES, SIDEBAR_MODES, TEXT_MODES, SCROLL_MODES, CONTROL_MODES, MD_MODES, HC_MODES, contrast, toOklch, fromOklch, flatten, luminance, withAlpha, mixHex, harmonize, deltaE, simulateCvd, rampsFor, floors, floorsDark, apcaContrast, raiseToLc, solveForeground, pickLocale, hostLocale, encodeConfig, decodeConfig, customScheme, deriveCustomFromAccent, readCustom, writeCustom, CONTRAST_SURFACES, CONTRAST_ROLES, buildContrastReport, devContrastReport, CONTRAST_TARGETS, CONTRAST_EXEMPT, CONTRAST_FLOOR, CONTRAST_SOLVER_MARGIN, MIN_MAIN, MIN_SECONDARY, MIN_TERTIARY, MIN_LINK, MIN_LINK_DARK, MIN_SECONDARY_DARK, MIN_TERTIARY_DARK, FLOORS_HC, FLOORS_HC_DARK, RAMP_MIN_GAP, RAMP_ORDER, hexToRgb, LAYER_MARK, settingsCss: SETTINGS_CSS, markdownCss: MARKDOWN_CSS, cardColors })
3370
+ window.__DSH_THEME_PALETTE_DEV__({ buildTokens, SCHEMES, SIDEBAR_MODES, TEXT_MODES, SCROLL_MODES, CONTROL_MODES, MD_MODES, HC_MODES, contrast, toOklch, fromOklch, flatten, luminance, withAlpha, mixHex, harmonize, deltaE, simulateCvd, rampsFor, floors, floorsDark, apcaContrast, raiseToLc, solveForeground, pickLocale, hostLocale, encodeConfig, decodeConfig, customScheme, deriveCustomFromAccent, readCustom, writeCustom, CONTRAST_SURFACES, CONTRAST_ROLES, buildContrastReport, devContrastReport, CONTRAST_TARGETS, CONTRAST_EXEMPT, CONTRAST_FLOOR, CONTRAST_SOLVER_MARGIN, MIN_MAIN, MIN_SECONDARY, MIN_TERTIARY, MIN_LINK, MIN_LINK_DARK, MIN_SECONDARY_DARK, MIN_TERTIARY_DARK, FLOORS_HC, FLOORS_HC_DARK, RAMP_MIN_GAP, RAMP_ORDER, SURFACE_ALIAS_STEPS, hexToRgb, LAYER_MARK, hostPatchCss: HOST_PATCH_CSS, settingsCss: SETTINGS_CSS, markdownCss: MARKDOWN_CSS, cardColors })
3253
3371
  }
3254
3372
 
3255
3373
  return {
@@ -3865,10 +3983,12 @@ body[data-ds-dark-theme] .dsh-tp{color-scheme:dark}
3865
3983
  applyAll('boot')
3866
3984
  const removeStyle = installMarkdownStyle()
3867
3985
  const removeSettings = installSettingsStyle()
3986
+ const removeHostPatch = installHostPatchStyle()
3868
3987
  return () => {
3869
3988
  disposeLayer()
3870
3989
  removeStyle()
3871
3990
  removeSettings()
3991
+ removeHostPatch()
3872
3992
  try {
3873
3993
  document.removeEventListener('visibilitychange', healOnVisible)
3874
3994
  window.removeEventListener('focus', healOnFocus)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-theme-palette",
3
- "version": "1.13.2",
3
+ "version": "1.13.4",
4
4
  "description": "DSH 主题配色:4 套配色 × 明暗两模式,OKLCH 色域安全重建 + 真实承载面对比度求解,可调强度与面板表面。",
5
5
  "type": "module",
6
6
  "main": "index.js",