@iasiv5/dsh-skins 1.5.12 → 1.5.14

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.
Files changed (2) hide show
  1. package/lib/client.js +194 -257
  2. package/package.json +5 -2
package/lib/client.js CHANGED
@@ -1264,19 +1264,14 @@ ${darkSelector}{${dark.join(";")}}`;
1264
1264
  setDeletingId(null);
1265
1265
  }
1266
1266
  };
1267
- const previewRefsFor = (assetId) => (configClient.dirtyFields?.() ?? []).filter((entry) => entry.value === assetId).map((entry) => `${labelFor(entry.skinId)} · ${entry.key} · ${tr("personalization.library.previewRef")}`);
1267
+ const referenceLabelsFor = (assetId) => configClient.referencesFor(assetId).map((entry) => entry.layer === "preview" ? `${labelFor(entry.skinId)} · ${entry.key} · ${tr("personalization.library.previewRef")}` : `${labelFor(entry.skinId)} · ${entry.key}`);
1268
1268
  const removeAsset = (asset) => {
1269
1269
  if (deletingId !== null || clearing) return;
1270
- const references = state.references[asset.id] ?? [];
1271
- const previewRefs = previewRefsFor(asset.id);
1272
- if (references.length === 0 && previewRefs.length === 0) return deleteAsset(asset);
1273
- const names = [
1274
- ...references.map((entry) => `${labelFor(entry.skinId)} · ${entry.key}`),
1275
- ...previewRefs
1276
- ].join("\n");
1270
+ const references = referenceLabelsFor(asset.id);
1271
+ if (references.length === 0) return deleteAsset(asset);
1277
1272
  requestConfirm(
1278
1273
  `${tr("personalization.library.deleteConfirm")}
1279
- ${names}`,
1274
+ ${references.join("\n")}`,
1280
1275
  () => deleteAsset(asset)
1281
1276
  );
1282
1277
  };
@@ -1284,10 +1279,7 @@ ${names}`,
1284
1279
  if (clearing || deletingId !== null || library.length === 0) return;
1285
1280
  const names = /* @__PURE__ */ new Map();
1286
1281
  for (const asset of library) {
1287
- for (const entry of state.references[asset.id] ?? []) {
1288
- names.set(`${labelFor(entry.skinId)} · ${entry.key}`, true);
1289
- }
1290
- for (const label of previewRefsFor(asset.id)) {
1282
+ for (const label of referenceLabelsFor(asset.id)) {
1291
1283
  names.set(label, true);
1292
1284
  }
1293
1285
  }
@@ -1483,8 +1475,7 @@ ${names}`,
1483
1475
  if (confirmationRef.current !== confirmation) return;
1484
1476
  confirmationRef.current = null;
1485
1477
  setConfirmation(null);
1486
- const current = configClient.getState();
1487
- if (current.status === "synced" && current.mode !== "recovery") {
1478
+ if (configClient.canWrite()) {
1488
1479
  void confirmation.accept();
1489
1480
  }
1490
1481
  };
@@ -1496,7 +1487,7 @@ ${names}`,
1496
1487
  headerRef.current?.focus?.(wideLayout ? { preventScroll: true } : void 0);
1497
1488
  }, []);
1498
1489
  if (schema === null) return null;
1499
- const writesBlocked = state.status !== "synced" || state.mode === "recovery";
1490
+ const writesBlocked = !configClient.canWrite();
1500
1491
  const overrides = configClient.effectiveOverrides(skinId);
1501
1492
  const { values } = mergeValues(skinId, overrides, void 0, profile);
1502
1493
  const hasAnyOverride = Object.keys(overrides).length > 0;
@@ -1547,7 +1538,7 @@ ${names}`,
1547
1538
  jsx("button", {
1548
1539
  type: "button",
1549
1540
  className: "dsh-skins-pz-btn",
1550
- onClick: () => configClient.retry(),
1541
+ onClick: () => configClient.refetch(),
1551
1542
  children: tr("personalization.status.retry")
1552
1543
  })
1553
1544
  ] }));
@@ -1557,22 +1548,26 @@ ${names}`,
1557
1548
  jsx("span", { children: tr("personalization.status.unsupported") })
1558
1549
  ] }));
1559
1550
  }
1560
- if (state.lastFlushCode === "REVISION_CONFLICT") {
1551
+ const notices = state.notices;
1552
+ const conflictNotice = notices.find((notice) => notice.kind === "conflict");
1553
+ const errorNotice = notices.find((notice) => notice.kind === "error");
1554
+ if (conflictNotice !== void 0) {
1561
1555
  statusCluster.push(jsx("div", { key: "save-conflict", className: "dsh-skins-pz-status dsh-skins-pz-warn", children: [
1562
1556
  jsx("span", { children: tr("personalization.saveConflict") })
1563
1557
  ] }));
1564
- } else if (state.lastFlushError) {
1558
+ } else if (errorNotice !== void 0) {
1565
1559
  statusCluster.push(jsx("div", { key: "save-error", className: "dsh-skins-pz-status dsh-skins-pz-warn", children: [
1566
1560
  jsx("span", { children: tr("personalization.saveFailed") }),
1567
- jsx("div", { className: "dsh-skins-pz-muted", children: state.lastFlushError })
1561
+ jsx("div", { className: "dsh-skins-pz-muted", children: errorNotice.message })
1568
1562
  ] }));
1569
1563
  }
1570
- if (Array.isArray(state.revertedFields) && state.revertedFields.length > 0) {
1564
+ const revertedNotice = notices.find((notice) => notice.kind === "reverted");
1565
+ if (revertedNotice !== void 0 && revertedNotice.fields.length > 0) {
1571
1566
  statusCluster.push(jsx("div", { key: "reverted", className: "dsh-skins-pz-status", children: [
1572
1567
  jsx("div", { children: tr("personalization.fieldReverted") }),
1573
1568
  jsx("div", {
1574
1569
  className: "dsh-skins-pz-muted",
1575
- children: state.revertedFields.map((entry) => `${labelFor(entry.skinId)} · ${entry.key}`).join("、")
1570
+ children: revertedNotice.fields.map((entry) => `${labelFor(entry.skinId)} · ${entry.key}`).join("、")
1576
1571
  })
1577
1572
  ] }));
1578
1573
  }
@@ -2213,13 +2208,20 @@ ${names}`,
2213
2208
  let fetchGeneration = 0;
2214
2209
  let disposed = false;
2215
2210
  let writeChain = Promise.resolve();
2216
- let lastFlushCode = null;
2217
- let lastFlushError = null;
2218
- let revertedFields = [];
2211
+ let notices = [];
2219
2212
  let channel = null;
2220
2213
  function setFlushFailure(code, message) {
2221
- lastFlushCode = code;
2222
- lastFlushError = message;
2214
+ notices = notices.filter((notice) => notice.kind === "reverted");
2215
+ if (code === "REVISION_CONFLICT") notices.push({ kind: "conflict" });
2216
+ else if (message) notices.push({ kind: "error", message });
2217
+ }
2218
+ function noteReverted(entry) {
2219
+ const current = notices.find((notice) => notice.kind === "reverted");
2220
+ if (current !== void 0 && current.fields.some((field) => field.skinId === entry.skinId && field.key === entry.key)) return;
2221
+ notices = [
2222
+ ...notices.filter((notice) => notice.kind !== "reverted"),
2223
+ { kind: "reverted", fields: [...current?.fields ?? [], entry] }
2224
+ ];
2223
2225
  }
2224
2226
  function emit() {
2225
2227
  for (const listener of [...listeners]) {
@@ -2239,9 +2241,7 @@ ${names}`,
2239
2241
  references: snapshot.references ?? {},
2240
2242
  recovery: snapshot.recovery,
2241
2243
  quota: snapshot.quota,
2242
- lastFlushCode,
2243
- lastFlushError,
2244
- revertedFields: revertedFields.map((entry) => ({ ...entry })),
2244
+ notices: structuredClone(notices),
2245
2245
  dirtyCount: previews.size
2246
2246
  };
2247
2247
  }
@@ -2305,8 +2305,10 @@ ${names}`,
2305
2305
  }
2306
2306
  const FLUSH_DEBOUNCE_MS = 400;
2307
2307
  let flushTimer = null;
2308
- function gateWrites() {
2309
- if (status === "synced") return null;
2308
+ function writeGate() {
2309
+ if (status === "synced") {
2310
+ return snapshot.mode === "recovery" ? "recovery" : null;
2311
+ }
2310
2312
  if (status === "loading") return "loading";
2311
2313
  if (status === "unsupported-readonly") return "unsupported";
2312
2314
  return "offline";
@@ -2333,7 +2335,7 @@ ${names}`,
2333
2335
  writeChain = writeChain.then(async () => {
2334
2336
  try {
2335
2337
  if (disposed) return { flushed: 0, blocked: "disposed" };
2336
- const blocked = gateWrites();
2338
+ const blocked = writeGate();
2337
2339
  if (blocked !== null) return { flushed: 0, blocked };
2338
2340
  const attemptedRevision = snapshot.revision;
2339
2341
  for (let attempt = 0; attempt < 2; attempt += 1) {
@@ -2410,10 +2412,7 @@ ${names}`,
2410
2412
  if (previews.has(composite)) {
2411
2413
  previews.delete(composite);
2412
2414
  excised = true;
2413
- const alreadyNoted = revertedFields.some(
2414
- (entry) => entry.skinId === issue.skinId && entry.key === issue.key
2415
- );
2416
- if (!alreadyNoted) revertedFields.push({ skinId: issue.skinId, key: issue.key });
2415
+ noteReverted({ skinId: issue.skinId, key: issue.key });
2417
2416
  }
2418
2417
  }
2419
2418
  }
@@ -2430,7 +2429,7 @@ ${names}`,
2430
2429
  if (previews.get(composite) === value) previews.delete(composite);
2431
2430
  }
2432
2431
  setFlushFailure(null, null);
2433
- revertedFields = [];
2432
+ notices = [];
2434
2433
  await refetch();
2435
2434
  announce();
2436
2435
  return { flushed: count };
@@ -2488,10 +2487,6 @@ ${names}`,
2488
2487
  }
2489
2488
  return merged;
2490
2489
  }
2491
- function retry() {
2492
- if (status !== "offline-failed" && status !== "synced") return refetch();
2493
- return refetch();
2494
- }
2495
2490
  async function assetFingerprint(bytes) {
2496
2491
  if (typeof crypto?.subtle?.digest !== "function") return null;
2497
2492
  const digest = await crypto.subtle.digest("SHA-256", bytes);
@@ -2525,7 +2520,7 @@ ${names}`,
2525
2520
  return { error: `HTTP ${response.status}` };
2526
2521
  }
2527
2522
  async function uploadImage(file, displayName) {
2528
- const blocked = gateWrites();
2523
+ const blocked = writeGate();
2529
2524
  if (blocked !== null) return { error: blocked };
2530
2525
  const bytes = file instanceof Uint8Array ? file : new Uint8Array(await file.arrayBuffer());
2531
2526
  let networkError;
@@ -2574,7 +2569,7 @@ ${names}`,
2574
2569
  function runGalleryOp(operations, goalAchieved) {
2575
2570
  writeChain = writeChain.then(async () => {
2576
2571
  if (disposed) return { error: "disposed" };
2577
- const blocked = gateWrites();
2572
+ const blocked = writeGate();
2578
2573
  if (blocked !== null) return { error: blocked };
2579
2574
  for (let attempt = 0; attempt < 2; attempt += 1) {
2580
2575
  let response;
@@ -2623,7 +2618,7 @@ ${names}`,
2623
2618
  return writeChain;
2624
2619
  }
2625
2620
  async function deleteImage(id) {
2626
- const blocked = gateWrites();
2621
+ const blocked = writeGate();
2627
2622
  if (blocked !== null) return { error: blocked };
2628
2623
  return runGalleryOp(
2629
2624
  [{ op: "deleteAsset", assetId: id }],
@@ -2633,7 +2628,7 @@ ${names}`,
2633
2628
  function clearLibrary() {
2634
2629
  return runGalleryOp([{ op: "clearLibrary" }], () => snapshot.library.length === 0);
2635
2630
  }
2636
- function dirtyFields() {
2631
+ function valuedPreviews() {
2637
2632
  const fields = [];
2638
2633
  for (const [composite, value] of previews) {
2639
2634
  if (value === null) continue;
@@ -2642,6 +2637,11 @@ ${names}`,
2642
2637
  }
2643
2638
  return fields;
2644
2639
  }
2640
+ function referencesFor(assetId) {
2641
+ const persisted = (snapshot.references?.[assetId] ?? []).map((entry) => ({ skinId: entry.skinId, key: entry.key, layer: "persisted" }));
2642
+ const preview2 = valuedPreviews().filter((entry) => entry.value === assetId).map((entry) => ({ skinId: entry.skinId, key: entry.key, layer: "preview" }));
2643
+ return [...persisted, ...preview2];
2644
+ }
2645
2645
  async function confirmRecovery() {
2646
2646
  const response = await request("/recovery", { method: "POST" });
2647
2647
  if (!response.ok) {
@@ -2658,7 +2658,6 @@ ${names}`,
2658
2658
  const api = {
2659
2659
  boot: refetch,
2660
2660
  refetch,
2661
- retry,
2662
2661
  flushNow,
2663
2662
  preview,
2664
2663
  previewReset,
@@ -2666,11 +2665,11 @@ ${names}`,
2666
2665
  uploadImage,
2667
2666
  deleteImage,
2668
2667
  clearLibrary,
2669
- dirtyFields,
2668
+ referencesFor,
2670
2669
  confirmRecovery,
2671
2670
  assetUrl,
2672
2671
  getState: publicState,
2673
- writeBlocked: gateWrites,
2672
+ canWrite: () => writeGate() === null,
2674
2673
  onStateChange(listener) {
2675
2674
  listeners.add(listener);
2676
2675
  return () => listeners.delete(listener);
@@ -2873,6 +2872,41 @@ ${names}`,
2873
2872
  };
2874
2873
  }
2875
2874
 
2875
+ // src/client/skins/decoration.js
2876
+ var BUBBLE_HOOKS = {
2877
+ chat: { exact: "Sixlwa_bubble", container: "userStack" },
2878
+ goal: { exact: "oRe1gG_bubble", container: "_stack" },
2879
+ bubbleLocal: "_bubble"
2880
+ };
2881
+ var unionSelector = (hook) => `:is([class*="${hook.exact}"], [class*="${hook.container}"] > [class*="${BUBBLE_HOOKS.bubbleLocal}"])`;
2882
+ function decorationCss(scope, palette) {
2883
+ const chat = unionSelector(BUBBLE_HOOKS.chat);
2884
+ const goal = unionSelector(BUBBLE_HOOKS.goal);
2885
+ return [
2886
+ `${scope} ${chat}{border:1px solid rgba(${palette.light}, 0.38);box-shadow:0 1px 4px rgba(${palette.light}, 0.10)}`,
2887
+ `${scope}[data-ds-dark-theme] ${chat}{border-color:rgba(${palette.dark}, 0.38);box-shadow:0 1px 6px rgba(${palette.dark}, 0.10)}`,
2888
+ `${scope} ${goal}{border:1px solid rgba(${palette.light}, 0.38);box-shadow:0 1px 4px rgba(${palette.light}, 0.10)}`,
2889
+ `${scope}[data-ds-dark-theme] ${goal}{border-color:rgba(${palette.dark}, 0.38);box-shadow:0 1px 6px rgba(${palette.dark}, 0.10)}`
2890
+ ].join("\n");
2891
+ }
2892
+ function rootClear(scope) {
2893
+ return `${scope} [id="root"]{background:0 0}`;
2894
+ }
2895
+ function badgeCss(scope, className, colors, metrics) {
2896
+ return [
2897
+ `${scope} ${className}{display:inline-flex;align-items:center;background:${colors.light.bg};border-radius:4px;padding:0 5px;font-size:10px;line-height:${metrics.lineHeight};font-weight:${metrics.fontWeight};letter-spacing:.08em;color:${colors.light.fg}}`,
2898
+ `${scope}[data-ds-dark-theme] ${className}{background:${colors.dark.bg};color:${colors.dark.fg}}`
2899
+ ].join("\n");
2900
+ }
2901
+ function streamingCss(scope, palette) {
2902
+ const KEYFRAMES = "dsh-skins-stream-pulse";
2903
+ return [
2904
+ `${scope} [data-streaming]{border-radius:4px;box-shadow:inset 3px 0 0 var(--dsw-alias-brand-primary)}`,
2905
+ `@keyframes ${KEYFRAMES}{from{box-shadow:inset 3px 0 0 var(--dsw-alias-brand-primary)}to{box-shadow:inset 3px 0 0 rgba(${palette.decay}, 0.20)}}`,
2906
+ `@media (prefers-reduced-motion: no-preference){${scope} [data-streaming]{animation:${KEYFRAMES} 1.6s ease-in-out infinite alternate}}`
2907
+ ].join("\n");
2908
+ }
2909
+
2876
2910
  // src/client/skins/meirenzhi/index.js
2877
2911
  var SCOPE = "body[data-dsh-meirenzhi-skin]";
2878
2912
  var TINTS = {
@@ -2881,21 +2915,23 @@ ${names}`,
2881
2915
  };
2882
2916
  var MARK_URL = "data:image/webp;base64,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";
2883
2917
  var CSS2 = [
2884
- // 反色徽章(official HARNESS 反色语言,tgcf badge 同构):亮=玄夜底雾白字,
2885
- // 暗=雾白底玄夜字。#12121A/#FAF9F6 与面板底色族同源。
2886
- `${SCOPE} .dsh-mrz-badge{display:inline-flex;align-items:center;background:#12121A;border-radius:4px;padding:0 5px;font-size:10px;line-height:16px;font-weight:600;letter-spacing:.08em;color:#FAF9F6}`,
2887
- `body[data-dsh-meirenzhi-skin][data-ds-dark-theme] .dsh-mrz-badge{background:#FAF9F6;color:#12121A}`,
2888
- // 用户气泡描边 + 轻投影(openbmc 同款泡泡边框:框出用户输入区)。挂接用
2889
- // :is() 并集(精确哈希 ∪ 结构化,见 docs/adr/0006):哈希漂移与 DOM 结构
2890
- // 变化两种单点故障各有一支兜底,钩子前提由 verify-upstream-hooks 守卫在
2891
- // check 时钉住。失效仅影响描边装饰,token 填充不受影响。
2892
- `${SCOPE} :is([class*="Sixlwa_bubble"], [class*="userStack"] > [class*="_bubble"]){border:1px solid rgba(184, 67, 63, 0.38);box-shadow:0 1px 4px rgba(184, 67, 63, 0.10)}`,
2893
- `body[data-dsh-meirenzhi-skin][data-ds-dark-theme] :is([class*="Sixlwa_bubble"], [class*="userStack"] > [class*="_bubble"]){border-color:rgba(229, 138, 128, 0.38);box-shadow:0 1px 6px rgba(229, 138, 128, 0.10)}`,
2894
- // 目标面板气泡(goal stack > bubble,与用户气泡同族描边)。ADR-0006 v1.0.4
2895
- // amendment:主人目测 goal 无描边观感不佳,裁决扩入;同款并集策略,守卫
2896
- // 清单已登记 goal 精确哈希与 _stack 结构前提。
2897
- `${SCOPE} :is([class*="oRe1gG_bubble"], [class*="_stack"] > [class*="_bubble"]){border:1px solid rgba(184, 67, 63, 0.38);box-shadow:0 1px 4px rgba(184, 67, 63, 0.10)}`,
2898
- `body[data-dsh-meirenzhi-skin][data-ds-dark-theme] :is([class*="oRe1gG_bubble"], [class*="_stack"] > [class*="_bubble"]){border-color:rgba(229, 138, 128, 0.38);box-shadow:0 1px 6px rgba(229, 138, 128, 0.10)}`,
2918
+ // 反色徽章(official HARNESS 反色语言,tgcf badge 同构):规则唯一来源在
2919
+ // ../decoration.js(ADR-0016);#12121A/#FAF9F6 与面板底色族同源。
2920
+ badgeCss(
2921
+ SCOPE,
2922
+ ".dsh-mrz-badge",
2923
+ { light: { bg: "#12121A", fg: "#FAF9F6" }, dark: { bg: "#FAF9F6", fg: "#12121A" } },
2924
+ { lineHeight: "16px", fontWeight: 600 }
2925
+ ),
2926
+ // 用户+目标气泡描边(ADR-0006 并集挂接谱系,goal v1.0.4 扩入):规则唯一
2927
+ // 来源在 ../decoration.js(ADR-0016),本皮肤只持描边色。
2928
+ decorationCss(SCOPE, { light: "184, 67, 63", dark: "229, 138, 128" }),
2929
+ // 防御性根容器清底(ADR-0016 Q12):上游 #root 现无背景,今日 no-op。
2930
+ rootClear(SCOPE),
2931
+ // 流式呼吸光条(ADR-0016 视觉窗口,本皮新增):品牌令牌骨架 + 鎏金衰减
2932
+ // rgba(217, 180, 92, 0.20)(Q10 主人裁定例外,与萤火虫同源色)——规则
2933
+ // 唯一来源在 ../decoration.js streamingCss。
2934
+ streamingCss(SCOPE, { decay: "217, 180, 92" }),
2899
2935
  // Ambient motion: a slow glow-breath riding the runtime's wallpaper ::before
2900
2936
  // layer + two drifting fireflies on the #root pseudo budget (same shape and
2901
2937
  // cost as the tgcf butterflies); prefers-reduced-motion kills all of it.
@@ -3139,159 +3175,55 @@ ${names}`,
3139
3175
  };
3140
3176
  const SPEC = { anchor: 55, riding: RIDING };
3141
3177
  const CSS3 = `
3142
- /* ---------- ③ 配色 · 亮色 ---------- */
3178
+ /* ---------- ③ 配色:常量族已迁声明表 constantTokens(ADR-0016 C1),
3179
+ 此处只留随动族 ridingDecl 插值行(ADR-0004 锚点字节不变式的载体) ---------- */
3143
3180
  body[data-dsh-openbmc-skin] {
3144
- /* 品牌主色(按钮/高亮/选中/链接) */
3145
- --dsw-alias-brand-primary: #0083b0;
3146
- --dsw-alias-brand-primary-invert: #ffffff;
3147
- --dsw-alias-brand-text: #007197;
3148
-
3149
- /* 表面/背景(低不透明度 → 背景画透光;overlay 浮层保持较实) */
3150
3181
  ${ridingDecl(SPEC, "--dsw-alias-bg-base", "light")}
3151
- --dsw-alias-bg-overlay: rgba(250, 252, 253, 0.82);
3152
3182
  ${ridingDecl(SPEC, "--dsw-alias-bg-module-platform", "light")}
3153
3183
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-1", "light")}
3154
3184
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-2", "light")}
3155
3185
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-3", "light")}
3156
-
3157
- /* 侧栏列 + 顶栏标题行(冰白透纱,与背景画同调) */
3158
3186
  ${ridingDecl(SPEC, "--dsw-specific-sidebar-fill", "light")}
3159
- --dsw-specific-sidebar-nav-item-hover: rgba(231, 241, 248, 0.90);
3160
- --dsw-specific-sidebar-nav-item-active: rgba(220, 235, 245, 0.90);
3161
- --dsw-specific-sidebar-nav-item-active-accent: #9cc8e0;
3162
-
3163
- /* 输入/菜单/选择器/提示 同系冰蓝。(菜单面三件套经 frost-family.js 家族段统一接管) */
3164
3187
  ${ridingDecl(SPEC, "--dsw-specific-input-major", "light")}
3165
3188
  ${ridingDecl(SPEC, "--dsw-specific-login-input", "light")}
3166
- --dsw-specific-selector: rgba(227, 239, 247, 0.85);
3167
- --dsw-specific-tip: rgba(240, 246, 250, 0.90);
3168
-
3169
- /* 文字层级 */
3170
- --dsw-alias-label-primary: #16262e;
3171
- --dsw-alias-label-secondary: #3f5a66;
3172
- --dsw-alias-label-dimmed: #6b838e;
3173
-
3174
- /* 交互态(品牌蓝) */
3175
- --dsw-alias-interactive-bg-hover: rgba(0, 138, 191, 0.08);
3176
- --dsw-alias-interactive-bg-active: rgba(0, 138, 191, 0.14);
3177
- --dsw-alias-interactive-bg-hover-accent: rgba(140, 206, 63, 0.14); /* 绿点缀 */
3178
3189
  }
3179
3190
 
3180
- /* ---------- ③ 配色 · 暗色(跟随系统明暗) ---------- */
3181
3191
  body[data-dsh-openbmc-skin][data-ds-dark-theme] {
3182
- --dsw-alias-brand-primary: #3ec1e8;
3183
- --dsw-alias-brand-primary-invert: #06222e;
3184
- --dsw-alias-brand-text: #5ec8e8;
3185
-
3186
3192
  ${ridingDecl(SPEC, "--dsw-alias-bg-base", "dark")}
3187
- --dsw-alias-bg-overlay: rgba(10, 22, 32, 0.88);
3188
3193
  ${ridingDecl(SPEC, "--dsw-alias-bg-module-platform", "dark")}
3189
3194
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-1", "dark")}
3190
3195
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-2", "dark")}
3191
3196
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-3", "dark")}
3192
-
3193
- /* 侧栏列 + 顶栏标题行:深冰蓝海军(与画面同色相,拒绝纯黑) */
3194
3197
  ${ridingDecl(SPEC, "--dsw-specific-sidebar-fill", "dark")}
3195
- --dsw-specific-sidebar-nav-item-hover: rgba(18, 41, 58, 0.90);
3196
- --dsw-specific-sidebar-nav-item-active: rgba(20, 47, 68, 0.90);
3197
- --dsw-specific-sidebar-nav-item-active-accent: #29526f;
3198
-
3199
- /* 输入/菜单/选择器/提示 同系深冰蓝(菜单面三件套经 frost-family.js 家族段统一接管) */
3200
3198
  ${ridingDecl(SPEC, "--dsw-specific-input-major", "dark")}
3201
3199
  ${ridingDecl(SPEC, "--dsw-specific-login-input", "dark")}
3202
- --dsw-specific-selector: rgba(16, 40, 64, 0.85);
3203
- --dsw-specific-tip: rgba(12, 30, 44, 0.92);
3204
-
3205
- /* 用户气泡:深冰蓝(替换此前的中性暗块) */
3206
- --dsw-specific-bubble: rgba(20, 41, 60, 0.90);
3207
- --dsw-specific-bubble-highlight: rgba(29, 61, 85, 0.90);
3208
-
3209
- --dsw-alias-label-primary: #dde9ee;
3210
- --dsw-alias-label-secondary: #9fb4bd;
3211
- --dsw-alias-label-dimmed: #69818c;
3212
-
3213
- --dsw-alias-interactive-bg-hover: rgba(62, 193, 232, 0.10);
3214
- --dsw-alias-interactive-bg-active: rgba(62, 193, 232, 0.16);
3215
- --dsw-alias-interactive-bg-hover-accent: rgba(165, 212, 64, 0.16);
3216
- }
3217
-
3218
- /* ---------- ④ 字体:系统 UI + 等宽代码 ---------- */
3219
- body[data-dsh-openbmc-skin] {
3220
- --dsw-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
3221
- "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
3222
- --ds-font-family-code: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code",
3223
- Menlo, Consolas, monospace;
3224
3200
  }
3225
3201
 
3226
- /* ---------- ④b 品牌徽章:官方 ▐HARNESS▌ 同构反色片(HTML/CSS 绘制) ----------
3227
- * 壳里不存在 --dsw-alias-label-primary-inverted 令牌(那是官方 BrandWordmark
3228
- * 的内部实现细节),内联 var() 取不到值会让字色整体失效——改为皮肤自带
3229
- * 规则 + 明暗两套显式颜色(与 tgcf 的 NO TABOOS 徽章同一模式)。
3230
- * 圆角 4px:官方 SVG rect 虽是 rx=2,但实测对比需在 14px 高度上取 4px
3231
- * 才有官方观感的弧度(tgcf 徽章同值)。 */
3232
- body[data-dsh-openbmc-skin] .dsh-openbmc-badge {
3233
- display: inline-flex; align-items: center;
3234
- background: #14202B; color: #F7FAFC;
3235
- border-radius: 4px; padding: 0 5px;
3236
- font-size: 10px; line-height: 14px; font-weight: 650; letter-spacing: .08em;
3237
- }
3238
- body[data-dsh-openbmc-skin][data-ds-dark-theme] .dsh-openbmc-badge {
3239
- background: #F7FAFC; color: #14202B;
3240
- }
3202
+ /* ---------- ④b 品牌徽章:官方 ▐HARNESS▌ 同构反色片 ----------
3203
+ * 规则唯一来源在 ../decoration.js badgeCss(ADR-0016;裁决史见其头注),
3204
+ * 本皮自持色值与 metrics(14px/650,Q7 参数化保留现值)。 */
3205
+ ${badgeCss(
3206
+ "body[data-dsh-openbmc-skin]",
3207
+ ".dsh-openbmc-badge",
3208
+ { light: { bg: "#14202B", fg: "#F7FAFC" }, dark: { bg: "#F7FAFC", fg: "#14202B" } },
3209
+ { lineHeight: "14px", fontWeight: 650 }
3210
+ )}
3241
3211
 
3242
- /* ---------- ⑥ 会话气泡装饰:品牌描边 + 流式呼吸光条 ---------- */
3243
- /* 用户气泡填充换品牌蓝 tint(token 层,随版本稳定) */
3244
- body[data-dsh-openbmc-skin] {
3245
- --dsw-specific-bubble: rgba(0, 138, 191, 0.10);
3246
- --dsw-specific-bubble-highlight: rgba(0, 138, 191, 0.18);
3247
- }
3248
- body[data-dsh-openbmc-skin][data-ds-dark-theme] {
3249
- /* 暗色气泡填充由 ③ 暗色块的深冰蓝接管(rgba(20,41,60,.90)),此处不再重定义 */
3250
- }
3251
- /* 用户气泡描边 + 轻投影(框出用户输入区)。挂接用 :is() 并集(精确哈希 ∪
3252
- * 结构化,见 docs/adr/0006):哈希漂移与 DOM 结构变化两种单点故障各有一支
3253
- * 兜底,钩子前提由 verify-upstream-hooks 守卫在 check 时钉住。失效仅影响
3254
- * 描边装饰,token 填充仍然生效;结构分支不命中 goal 面板气泡(其容器
3255
- * _stack 不含 userStack 子串,ADR-0006 实测),goal 维持不描边。 */
3256
- body[data-dsh-openbmc-skin] :is([class*="Sixlwa_bubble"], [class*="userStack"] > [class*="_bubble"]) {
3257
- border: 1px solid rgba(0, 131, 176, 0.38);
3258
- box-shadow: 0 1px 4px rgba(0, 131, 176, 0.10);
3259
- }
3260
- body[data-dsh-openbmc-skin][data-ds-dark-theme] :is([class*="Sixlwa_bubble"], [class*="userStack"] > [class*="_bubble"]) {
3261
- border-color: rgba(62, 193, 232, 0.38);
3262
- box-shadow: 0 1px 6px rgba(62, 193, 232, 0.10);
3263
- }
3264
- /* 目标面板气泡(goal stack > bubble,与用户气泡同族描边)。ADR-0006
3265
- * v1.0.4 amendment:主人目测 goal 无描边观感不佳,裁决扩入;同款并集
3266
- * 策略,守卫清单已登记 goal 精确哈希与 _stack 结构前提。 */
3267
- body[data-dsh-openbmc-skin] :is([class*="oRe1gG_bubble"], [class*="_stack"] > [class*="_bubble"]) {
3268
- border: 1px solid rgba(0, 131, 176, 0.38);
3269
- box-shadow: 0 1px 4px rgba(0, 131, 176, 0.10);
3270
- }
3271
- body[data-dsh-openbmc-skin][data-ds-dark-theme] :is([class*="oRe1gG_bubble"], [class*="_stack"] > [class*="_bubble"]) {
3272
- border-color: rgba(62, 193, 232, 0.38);
3273
- box-shadow: 0 1px 6px rgba(62, 193, 232, 0.10);
3274
- }
3275
- /* 助手消息流式输出中:左侧品牌色呼吸光条(box-shadow 不产生布局位移) */
3276
- body[data-dsh-openbmc-skin] [data-streaming] {
3277
- border-radius: 4px;
3278
- box-shadow: inset 3px 0 0 0 var(--dsw-alias-brand-primary);
3279
- }
3280
- @keyframes obmc-stream-pulse {
3281
- from { box-shadow: inset 3px 0 0 0 var(--dsw-alias-brand-primary); }
3282
- to { box-shadow: inset 3px 0 0 0 rgba(62, 193, 232, 0.20); }
3283
- }
3284
- @media (prefers-reduced-motion: no-preference) {
3285
- body[data-dsh-openbmc-skin] [data-streaming] {
3286
- animation: obmc-stream-pulse 1.6s ease-in-out infinite alternate;
3287
- }
3288
- }
3289
- /* ---------- ⑦ 根容器清底 + 滚动条同系(防御 + 细节,鲸吟同款) ---------- */
3290
- body[data-dsh-openbmc-skin] [id="root"] { background: 0 0; }
3291
- body[data-dsh-openbmc-skin] {
3292
- --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
3293
- --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
3294
- }
3212
+ /* ---------- ⑥ 会话气泡装饰:品牌描边 + 流式呼吸光条 ----------
3213
+ * 用户气泡填充(明色品牌蓝 tint / 暗色深冰蓝)已随常量族迁声明表
3214
+ * (ADR-0016 C1:--dsw-specific-bubble(-highlight))。 */
3215
+ /* 用户+目标气泡描边(ADR-0006 并集挂接谱系,goal v1.0.4 扩入;结构分支
3216
+ * 不命中 goal 面板气泡、goal 经自己的 _stack 并集描边——全谱系说明见
3217
+ * ../decoration.js 头注):规则唯一来源在 decoration.js(ADR-0016),
3218
+ * 本皮肤只持描边色。 */
3219
+ ${decorationCss("body[data-dsh-openbmc-skin]", { light: "0, 131, 176", dark: "62, 193, 232" })}
3220
+ /* 助手消息流式输出中:左侧品牌色呼吸光条——规则唯一来源在
3221
+ * ../decoration.js streamingCss(ADR-0016 视觉窗口;keyframes 家族化改名
3222
+ * obmc-stream-pulse → dsh-skins-stream-pulse,像素不变)。 */
3223
+ ${streamingCss("body[data-dsh-openbmc-skin]", { decay: "62, 193, 232" })}
3224
+ /* ---------- ⑦ 根容器清底(防御,鲸吟同款家族化 ADR-0016;滚动条同系
3225
+ * token 已随常量族迁声明表) ---------- */
3226
+ ${rootClear("body[data-dsh-openbmc-skin]")}
3295
3227
  /* 注意:不要用类名选择器定位侧栏元素 —— 插件样式经 CSS modules 哈希,
3296
3228
  * 类名不可预测;一律通过 token 或 data-* 属性作用。 */
3297
3229
 
@@ -3310,7 +3242,40 @@ ${names}`,
3310
3242
  favicon: { href: FAVICON_DATA_URL, mime: FAVICON_MIME },
3311
3243
  anchor: 55,
3312
3244
  riding: RIDING,
3313
- constantTokens: null,
3245
+ // 常量族(ADR-0016 C1:原 CSS 模板手写行逐字迁入,明暗同键;等式钉在
3246
+ // tests/translucency-contract.test.mjs「openbmc C1」)。品牌色取自 logo
3247
+ // 渐变(蓝 #00b0da→#008abf、绿 #a5d440→#8cce3f):亮用深一档蓝保证白底
3248
+ // 对比度,暗提亮为青;交互 hover-accent 为绿点缀;暗气泡=深冰蓝海军
3249
+ // (与画面同色相,拒绝纯黑);滚动条同系引用壳令牌。
3250
+ constantTokens: {
3251
+ "--dsw-alias-brand-primary": { light: "#0083b0", dark: "#3ec1e8" },
3252
+ "--dsw-alias-brand-primary-invert": { light: "#ffffff", dark: "#06222e" },
3253
+ "--dsw-alias-brand-text": { light: "#007197", dark: "#5ec8e8" },
3254
+ "--dsw-alias-bg-overlay": { light: "rgba(250, 252, 253, 0.82)", dark: "rgba(10, 22, 32, 0.88)" },
3255
+ "--dsw-specific-sidebar-nav-item-hover": { light: "rgba(231, 241, 248, 0.90)", dark: "rgba(18, 41, 58, 0.90)" },
3256
+ "--dsw-specific-sidebar-nav-item-active": { light: "rgba(220, 235, 245, 0.90)", dark: "rgba(20, 47, 68, 0.90)" },
3257
+ "--dsw-specific-sidebar-nav-item-active-accent": { light: "#9cc8e0", dark: "#29526f" },
3258
+ "--dsw-specific-selector": { light: "rgba(227, 239, 247, 0.85)", dark: "rgba(16, 40, 64, 0.85)" },
3259
+ "--dsw-specific-tip": { light: "rgba(240, 246, 250, 0.90)", dark: "rgba(12, 30, 44, 0.92)" },
3260
+ "--dsw-alias-label-primary": { light: "#16262e", dark: "#dde9ee" },
3261
+ "--dsw-alias-label-secondary": { light: "#3f5a66", dark: "#9fb4bd" },
3262
+ "--dsw-alias-label-dimmed": { light: "#6b838e", dark: "#69818c" },
3263
+ "--dsw-alias-interactive-bg-hover": { light: "rgba(0, 138, 191, 0.08)", dark: "rgba(62, 193, 232, 0.10)" },
3264
+ "--dsw-alias-interactive-bg-active": { light: "rgba(0, 138, 191, 0.14)", dark: "rgba(62, 193, 232, 0.16)" },
3265
+ "--dsw-alias-interactive-bg-hover-accent": { light: "rgba(140, 206, 63, 0.14)", dark: "rgba(165, 212, 64, 0.16)" },
3266
+ "--dsw-specific-bubble": { light: "rgba(0, 138, 191, 0.10)", dark: "rgba(20, 41, 60, 0.90)" },
3267
+ "--dsw-specific-bubble-highlight": { light: "rgba(0, 138, 191, 0.18)", dark: "rgba(29, 61, 85, 0.90)" },
3268
+ "--dsw-font-family": {
3269
+ light: '-apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif',
3270
+ dark: '-apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif'
3271
+ },
3272
+ "--ds-font-family-code": {
3273
+ light: '"JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace',
3274
+ dark: '"JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace'
3275
+ },
3276
+ "--dsh-scrollbar-thumb": { light: "var(--dsw-alias-scrollbar-bg-l2)", dark: "var(--dsw-alias-scrollbar-bg-l2)" },
3277
+ "--dsh-scrollbar-thumb-hover": { light: "var(--dsw-alias-scrollbar-hover-l2)", dark: "var(--dsw-alias-scrollbar-hover-l2)" }
3278
+ },
3314
3279
  scrim: {
3315
3280
  kind: "baked-gradient",
3316
3281
  stops: {
@@ -3397,85 +3362,34 @@ ${names}`,
3397
3362
  };
3398
3363
  const SPEC = { anchor: 55, riding: RIDING };
3399
3364
  const css = `
3365
+ /* 配色常量族已迁声明表 constantTokens(ADR-0016 C1);此处只留随动族
3366
+ * ridingDecl 插值行(ADR-0004 锚点字节不变式的载体)。 */
3400
3367
  body[data-dsh-uefi-harness] {
3401
- --dsw-alias-brand-primary: #6553d8;
3402
- --dsw-alias-brand-primary-invert: #ffffff;
3403
- --dsw-alias-brand-text: #5846c2;
3404
3368
  ${ridingDecl(SPEC, "--dsw-alias-bg-base", "light")}
3405
- --dsw-alias-bg-overlay: rgba(252, 251, 255, 0.82);
3406
3369
  ${ridingDecl(SPEC, "--dsw-alias-bg-module-platform", "light")}
3407
3370
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-1", "light")}
3408
3371
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-2", "light")}
3409
3372
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-3", "light")}
3410
3373
  ${ridingDecl(SPEC, "--dsw-specific-sidebar-fill", "light")}
3411
- --dsw-specific-sidebar-nav-item-hover: rgba(101, 83, 216, 0.09);
3412
- --dsw-specific-sidebar-nav-item-active: rgba(101, 83, 216, 0.15);
3413
- --dsw-specific-sidebar-nav-item-active-accent: #8b7cff;
3414
3374
  ${ridingDecl(SPEC, "--dsw-specific-input-major", "light")}
3415
- --dsw-specific-selector: rgba(232, 228, 255, 0.78);
3416
- --dsw-specific-tip: rgba(244, 242, 255, 0.88);
3417
- --dsw-alias-label-primary: #211c36;
3418
- --dsw-alias-label-secondary: #554d74;
3419
- --dsw-alias-label-dimmed: #81799e;
3420
- --dsw-alias-interactive-bg-hover: rgba(101, 83, 216, 0.09);
3421
- --dsw-alias-interactive-bg-active: rgba(101, 83, 216, 0.15);
3422
- --dsw-specific-bubble: rgba(101, 83, 216, 0.11);
3423
- --dsw-specific-bubble-highlight: rgba(101, 83, 216, 0.18);
3424
- --dsw-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif;
3425
3375
  }
3426
3376
  body[data-dsh-uefi-harness][data-ds-dark-theme] {
3427
- --dsw-alias-brand-primary: #a99cff;
3428
- --dsw-alias-brand-primary-invert: #1b143a;
3429
- --dsw-alias-brand-text: #b7acff;
3430
3377
  ${ridingDecl(SPEC, "--dsw-alias-bg-base", "dark")}
3431
- --dsw-alias-bg-overlay: rgba(27, 21, 54, 0.88);
3432
3378
  ${ridingDecl(SPEC, "--dsw-alias-bg-module-platform", "dark")}
3433
3379
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-1", "dark")}
3434
3380
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-2", "dark")}
3435
3381
  ${ridingDecl(SPEC, "--dsw-alias-bg-layer-3", "dark")}
3436
3382
  ${ridingDecl(SPEC, "--dsw-specific-sidebar-fill", "dark")}
3437
- --dsw-specific-sidebar-nav-item-hover: rgba(169, 156, 255, 0.10);
3438
- --dsw-specific-sidebar-nav-item-active: rgba(169, 156, 255, 0.17);
3439
- --dsw-specific-sidebar-nav-item-active-accent: #6657a8;
3440
3383
  ${ridingDecl(SPEC, "--dsw-specific-input-major", "dark")}
3441
- --dsw-specific-selector: rgba(51, 40, 96, 0.78);
3442
- --dsw-specific-tip: rgba(34, 27, 65, 0.90);
3443
- --dsw-alias-label-primary: #f0edff;
3444
- --dsw-alias-label-secondary: #b9b1d6;
3445
- --dsw-alias-label-dimmed: #827a9f;
3446
- --dsw-alias-interactive-bg-hover: rgba(169, 156, 255, 0.11);
3447
- --dsw-alias-interactive-bg-active: rgba(169, 156, 255, 0.18);
3448
- --dsw-specific-bubble: rgba(60, 48, 108, 0.90);
3449
- --dsw-specific-bubble-highlight: rgba(78, 63, 138, 0.92);
3450
- }
3451
- body[data-dsh-uefi-harness] [id="root"] { background: transparent; }
3452
- body[data-dsh-uefi-harness] [data-streaming] {
3453
- border-radius: 4px;
3454
- box-shadow: inset 3px 0 0 var(--dsw-alias-brand-primary);
3455
- }
3456
- /* 用户气泡描边 + 轻投影(openbmc 同款泡泡边框:框出用户输入区)。挂接用
3457
- * :is() 并集(精确哈希 ∪ 结构化,见 docs/adr/0006):哈希漂移与 DOM 结构
3458
- * 变化两种单点故障各有一支兜底,钩子前提由 verify-upstream-hooks 守卫在
3459
- * check 时钉住。失效仅影响描边装饰,token 填充仍然生效。 */
3460
- body[data-dsh-uefi-harness] :is([class*="Sixlwa_bubble"], [class*="userStack"] > [class*="_bubble"]) {
3461
- border: 1px solid rgba(101, 83, 216, 0.38);
3462
- box-shadow: 0 1px 4px rgba(101, 83, 216, 0.10);
3463
- }
3464
- body[data-dsh-uefi-harness][data-ds-dark-theme] :is([class*="Sixlwa_bubble"], [class*="userStack"] > [class*="_bubble"]) {
3465
- border-color: rgba(169, 156, 255, 0.38);
3466
- box-shadow: 0 1px 6px rgba(169, 156, 255, 0.10);
3467
- }
3468
- /* 目标面板气泡(goal stack > bubble,与用户气泡同族描边)。ADR-0006
3469
- * v1.0.4 amendment:主人目测 goal 无描边观感不佳,裁决扩入;同款并集
3470
- * 策略,守卫清单已登记 goal 精确哈希与 _stack 结构前提。 */
3471
- body[data-dsh-uefi-harness] :is([class*="oRe1gG_bubble"], [class*="_stack"] > [class*="_bubble"]) {
3472
- border: 1px solid rgba(101, 83, 216, 0.38);
3473
- box-shadow: 0 1px 4px rgba(101, 83, 216, 0.10);
3474
- }
3475
- body[data-dsh-uefi-harness][data-ds-dark-theme] :is([class*="oRe1gG_bubble"], [class*="_stack"] > [class*="_bubble"]) {
3476
- border-color: rgba(169, 156, 255, 0.38);
3477
- box-shadow: 0 1px 6px rgba(169, 156, 255, 0.10);
3478
3384
  }
3385
+ ${rootClear("body[data-dsh-uefi-harness]")}
3386
+ /* 流式呼吸光条(ADR-0016 视觉窗口:静态版升级呼吸,衰减色 = 暗色品牌主色
3387
+ * @0.20,Q16):规则唯一来源在 ../decoration.js streamingCss。 */
3388
+ ${streamingCss("body[data-dsh-uefi-harness]", { decay: "169, 156, 255" })}
3389
+ /* 用户+目标气泡描边(ADR-0006 并集挂接谱系,goal v1.0.4 扩入——全谱系说明
3390
+ * 见 ../decoration.js 头注):规则唯一来源在 decoration.js(ADR-0016),
3391
+ * 本皮肤只持描边色。 */
3392
+ ${decorationCss("body[data-dsh-uefi-harness]", { light: "101, 83, 216", dark: "169, 156, 255" })}
3479
3393
 
3480
3394
  ${frostFamilyCss("body[data-dsh-uefi-harness]", TINTS2)}
3481
3395
 
@@ -3490,7 +3404,30 @@ body[data-dsh-uefi-harness][data-ds-dark-theme] :is([class*="oRe1gG_bubble"], [c
3490
3404
  favicon: { href: favicon, mime: "image/svg+xml" },
3491
3405
  anchor: 55,
3492
3406
  riding: RIDING,
3493
- constantTokens: null,
3407
+ // 常量族(ADR-0016 C1:原 css 模板手写行逐字迁入;等式钉在
3408
+ // tests/translucency-contract.test.mjs「uefi C1」)。
3409
+ constantTokens: {
3410
+ "--dsw-alias-brand-primary": { light: "#6553d8", dark: "#a99cff" },
3411
+ "--dsw-alias-brand-primary-invert": { light: "#ffffff", dark: "#1b143a" },
3412
+ "--dsw-alias-brand-text": { light: "#5846c2", dark: "#b7acff" },
3413
+ "--dsw-alias-bg-overlay": { light: "rgba(252, 251, 255, 0.82)", dark: "rgba(27, 21, 54, 0.88)" },
3414
+ "--dsw-specific-sidebar-nav-item-hover": { light: "rgba(101, 83, 216, 0.09)", dark: "rgba(169, 156, 255, 0.10)" },
3415
+ "--dsw-specific-sidebar-nav-item-active": { light: "rgba(101, 83, 216, 0.15)", dark: "rgba(169, 156, 255, 0.17)" },
3416
+ "--dsw-specific-sidebar-nav-item-active-accent": { light: "#8b7cff", dark: "#6657a8" },
3417
+ "--dsw-specific-selector": { light: "rgba(232, 228, 255, 0.78)", dark: "rgba(51, 40, 96, 0.78)" },
3418
+ "--dsw-specific-tip": { light: "rgba(244, 242, 255, 0.88)", dark: "rgba(34, 27, 65, 0.90)" },
3419
+ "--dsw-alias-label-primary": { light: "#211c36", dark: "#f0edff" },
3420
+ "--dsw-alias-label-secondary": { light: "#554d74", dark: "#b9b1d6" },
3421
+ "--dsw-alias-label-dimmed": { light: "#81799e", dark: "#827a9f" },
3422
+ "--dsw-alias-interactive-bg-hover": { light: "rgba(101, 83, 216, 0.09)", dark: "rgba(169, 156, 255, 0.11)" },
3423
+ "--dsw-alias-interactive-bg-active": { light: "rgba(101, 83, 216, 0.15)", dark: "rgba(169, 156, 255, 0.18)" },
3424
+ "--dsw-specific-bubble": { light: "rgba(101, 83, 216, 0.11)", dark: "rgba(60, 48, 108, 0.90)" },
3425
+ "--dsw-specific-bubble-highlight": { light: "rgba(101, 83, 216, 0.18)", dark: "rgba(78, 63, 138, 0.92)" },
3426
+ "--dsw-font-family": {
3427
+ light: '-apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif',
3428
+ dark: '-apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif'
3429
+ }
3430
+ },
3494
3431
  scrim: {
3495
3432
  kind: "baked-gradient",
3496
3433
  stops: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iasiv5/dsh-skins",
3
3
  "description": "DSH Web 皮肤插件:多套品牌皮肤侧栏热切换。",
4
- "version": "1.5.12",
4
+ "version": "1.5.14",
5
5
  "homepage": "https://github.com/iasiv5/dsh-skins#readme",
6
6
  "repository": {
7
7
  "type": "git",
@@ -66,6 +66,8 @@
66
66
  "devDependencies": {
67
67
  "@deepseek-ai/cordis": "^4.0.4",
68
68
  "esbuild": "^0.28.2",
69
+ "eslint": "^10.13.0",
70
+ "globals": "^17.13.0",
69
71
  "playwright-core": "1.62.1",
70
72
  "semver": "^7.8.5"
71
73
  },
@@ -77,6 +79,7 @@
77
79
  "verify:readme": "node scripts/verify-readme-pairing.mjs",
78
80
  "verify:bundle": "node scripts/verify-bundle-guard.mjs",
79
81
  "verify:hooks": "node scripts/verify-upstream-hooks.mjs",
80
- "check": "pnpm run check:lockfile && pnpm run build && node --check lib/client.js && node --check lib/index.js && pnpm run test && pnpm run verify:readme && pnpm run verify:bundle && pnpm run verify:hooks"
82
+ "check": "pnpm run check:lockfile && pnpm run build && node --check lib/client.js && node --check lib/index.js && pnpm run lint && pnpm run test && pnpm run verify:readme && pnpm run verify:bundle && pnpm run verify:hooks && git diff --exit-code -- lib/index.js lib/client.js",
83
+ "lint": "eslint ."
81
84
  }
82
85
  }