@linxin666/dsh-client-ui-skin-center 0.3.19 → 0.3.21

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.
@@ -45,7 +45,7 @@
45
45
  | `data-dsh-wallpaper-active` | html + body(body/html 级,另行管理) | WE 壁纸挂载期间置 `true`,卸载 / 禁用清除;供皮肤 CSS 与壁纸中和规则锚定(#734) |
46
46
  | `data-dsh-wallpaper-surface` | 官方 shell 全视口背景元素 + 侧栏工作区淡化条(元素级) | `WallpaperController.markWallpaperSurfaces()` 在 WE 壁纸挂载期间打标(全视口 bg-base 背景 + `data-slot="sidebar.workspaces"` 内渐变淡化条),命中 `html[data-dsh-wallpaper-active] [data-dsh-wallpaper-surface]` 中和;卸载清除,不含哈希类依赖(#734) |
47
47
 
48
- ## part 组(71 行,含各 owner 行)
48
+ ## part 组(79 行,含各 owner 行)
49
49
 
50
50
  shell 区域(owner: shell):
51
51
 
@@ -113,13 +113,15 @@ family / 插件区域:
113
113
  | `bubble` | miku-pet | 对话气泡;`[data-dsh-part="bubble"]` |
114
114
  | `float` | miku-pet | 互动飘字;`[data-dsh-part="float"]` |
115
115
  | `header` | usage | 使用统计分区头部(当前提供方 + 刷新钮);`[data-dsh-plugin="usage"] [data-dsh-part="header"]` |
116
- | `tabs` / `tab` | usage | 用量/个人套餐页签;`[role="tablist"]` / `[role="tab"]` |
116
+ | `tabs` / `tab` | usage | 用量/个人套餐/Token 银行页签;`[role="tablist"]` / `[role="tab"]` |
117
117
  | `today-card` | usage | 今日用量统计卡;`[data-dsh-part="today-card"]` |
118
118
  | `provider-list` / `provider-row` | usage | 今日分 provider 用量列表 / 余额行;卡片内行容器 |
119
119
  | `balance-card` | usage | 各 provider 余额卡;`[data-dsh-part="balance-card"]` |
120
120
  | `trend-card` / `usage-chart` | usage | 近 30 天卡 / 其中的提供方-模型条形图;`[data-dsh-part="trend-card"]` 内 `[data-dsh-part="usage-chart"]` |
121
121
  | `settings-row` | usage | 插件设置行;`[data-dsh-part="settings-row"]` |
122
122
  | `plan-card` / `plan-window` | usage | 套餐卡 / 套餐窗口行(个人套餐页签);`[data-dsh-part="plan-card"]` 内窗口行 |
123
+ | `bank-card` | usage | Token 银行卡(鲸元券,无官方用量时为空状态);`[data-dsh-part="bank-card"]` |
124
+ | `voucher-preview` | usage | 票面 canvas 容器;bank-card 内 `[data-dsh-part="voucher-preview"]` |
123
125
  | `panel` | model-capabilities | 提供方卡片能力扩展区根;`[data-dsh-plugin="model-capabilities"][data-dsh-part="panel"]` |
124
126
  | `toggle` | model-capabilities | 扩展区折叠头按钮;panel 内 `button[data-dsh-part="toggle"]` |
125
127
  | `model-row` / `model-toggle` | model-capabilities | 逐模型能力行与其展开按钮;panel 内 `li[data-dsh-part="model-row"]` 及其中 `button[data-dsh-part="model-toggle"]` |
@@ -128,8 +130,13 @@ family / 插件区域:
128
130
  | `save` / `reset` / `disable` / `enable` / `reload` | model-capabilities | 扩展区动作按钮(保存 / 重置 / 禁用此提供方 / 启用 / 重新读取);panel 内裸值按钮 |
129
131
  | `disabled-state` | model-capabilities | 已禁用提供方的卡片提示区(含启用按钮);panel 内 `[data-dsh-part="disabled-state"]` |
130
132
  | `disabled-footer` / `disabled-row` | model-capabilities | Models 页底部存档区与其行;`settings.models.footer` 槽内 `section[data-dsh-part="disabled-footer"]` 与其中 `li[data-dsh-part="disabled-row"]` |
133
+ | `lever` | liangshen | 首页输入框内的梁神模式拨杆根(模型选择器左侧);`[data-dsh-plugin="liangshen"][data-dsh-part="lever"]`,状态由 `data-state`(`on` / `off` / `locked` / `missing`)锚定 |
134
+ | `lever-track` | liangshen | 拨杆底座槽(臂的转动轨道);lever 内 `[data-dsh-part="lever-track"]` |
135
+ | `lever-arm` | liangshen | 拨杆臂(拉杆 + 球头,随状态转动);lever 内 `[data-dsh-part="lever-arm"]` |
136
+ | `lever-burst` | liangshen | 拨下命中后的中奖特效浮层(闪光 / 冲击环 / 火花 / 横幅);`[data-dsh-part="lever-burst"]`,`prefers-reduced-motion` 下退化为淡出 |
137
+ | `lever-banner` | liangshen | 特效中的梁神横幅(模式名 + 文言文/二进制/摩斯三行);burst 内 `[data-dsh-part="lever-banner"]` |
131
138
 
132
- ## plugin 组(14 个)
139
+ ## plugin 组(15 个)
133
140
 
134
141
  | data-dsh-plugin | owner | 锚定方式 |
135
142
  | --- | --- | --- |
@@ -147,6 +154,7 @@ family / 插件区域:
147
154
  | `usage` | dsh-usage | 一级设置分区 settings.section id `dsh-usage`(创意工坊下方);`[data-dsh-plugin="usage"]` |
148
155
  | `model-capabilities` | dsh-model-capabilities | Models 页 `settings.models.provider-card` keyed 槽 key `llm-pi-ai`(提供方卡片扩展区)+ `settings.models.footer` 槽 entry id `ui-model-capabilities`(存档区);`[data-dsh-plugin="model-capabilities"]` |
149
156
  | `preset-center` | dsh-preset-center | 创意工坊卡片的「预设」标签页面板(`dsh-workshop.panel` keyed 槽 key `preset`);`[data-dsh-plugin="preset-center"]` |
157
+ | `liangshen` | dsh-liangshen | 首页输入框内的梁神模式拨杆;`[data-dsh-plugin="liangshen"][data-dsh-part="lever"]`,slot entry id `liangshen-lever` |
150
158
 
151
159
  ## 已知脆弱点(上游主题缝 PR 诉求)
152
160
 
package/lib/client.js CHANGED
@@ -401,6 +401,16 @@ window.__ModuleLoader__.load({
401
401
  ].join(", ");
402
402
  const sourceSets = /* @__PURE__ */ new WeakMap();
403
403
  const contentObservers = /* @__PURE__ */ new WeakMap();
404
+ const contentFrames = /* @__PURE__ */ new WeakMap();
405
+ /** Write a marker attribute only when the desired state is not applied yet. */
406
+ function applyMarker(el, attr, active) {
407
+ if (el === null) return;
408
+ if (active) {
409
+ if (el.getAttribute(attr) !== "true") el.setAttribute(attr, "true");
410
+ return;
411
+ }
412
+ if (el.hasAttribute(attr)) el.removeAttribute(attr);
413
+ }
404
414
  /**
405
415
  * Report one source's backdrop-art presence. The marker stays on while any
406
416
  * source is active, so the skin and wallpaper controllers never clobber each
@@ -418,16 +428,13 @@ window.__ModuleLoader__.load({
418
428
  }
419
429
  /** Reflect the source set onto html/body and ensure the neutralizer on use. */
420
430
  function syncMarker(doc, sources) {
421
- if (sources.size > 0) {
422
- doc.body?.setAttribute(BACKDROP_ACTIVE_ATTR, "true");
423
- doc.documentElement?.setAttribute(BACKDROP_ACTIVE_ATTR, "true");
431
+ const active = sources.size > 0;
432
+ applyMarker(doc.body, BACKDROP_ACTIVE_ATTR, active);
433
+ applyMarker(doc.documentElement, BACKDROP_ACTIVE_ATTR, active);
434
+ if (active) {
424
435
  ensureSceneNeutralizer(doc);
425
436
  startContentObserver(doc);
426
- } else {
427
- doc.body?.removeAttribute(BACKDROP_ACTIVE_ATTR);
428
- doc.documentElement?.removeAttribute(BACKDROP_ACTIVE_ATTR);
429
- stopContentObserver(doc);
430
- }
437
+ } else stopContentObserver(doc);
431
438
  }
432
439
  /**
433
440
  * Track whether the active conversation scrollport has message rows for the
@@ -436,13 +443,27 @@ window.__ModuleLoader__.load({
436
443
  * those stale rows and flash the composer frost over the new empty topic.
437
444
  */
438
445
  function updateConversationContent(doc) {
439
- if (doc.body !== null && doc.body.querySelector(ACTIVE_CONVERSATION_CONTENT_SELECTOR) !== null) {
440
- doc.body?.setAttribute(CONVERSATION_CONTENT_ATTR, "true");
441
- doc.documentElement?.setAttribute(CONVERSATION_CONTENT_ATTR, "true");
442
- } else {
443
- doc.body?.removeAttribute(CONVERSATION_CONTENT_ATTR);
444
- doc.documentElement?.removeAttribute(CONVERSATION_CONTENT_ATTR);
446
+ const has = doc.body !== null && doc.body.querySelector(ACTIVE_CONVERSATION_CONTENT_SELECTOR) !== null;
447
+ applyMarker(doc.body, CONVERSATION_CONTENT_ATTR, has);
448
+ applyMarker(doc.documentElement, CONVERSATION_CONTENT_ATTR, has);
449
+ }
450
+ /**
451
+ * Coalesce the mutation bursts of a streaming conversation into one content
452
+ * check per frame; a check scheduled for a document that stopped observing is
453
+ * dropped so a late frame can never re-add the marker after teardown.
454
+ */
455
+ function scheduleConversationContent(doc) {
456
+ if (contentFrames.has(doc)) return;
457
+ const win = doc.defaultView;
458
+ if (win === null || typeof win.requestAnimationFrame !== "function") {
459
+ updateConversationContent(doc);
460
+ return;
445
461
  }
462
+ contentFrames.set(doc, win.requestAnimationFrame(() => {
463
+ contentFrames.delete(doc);
464
+ if (!contentObservers.has(doc)) return;
465
+ updateConversationContent(doc);
466
+ }));
446
467
  }
447
468
  /** Observe the conversation tree while a backdrop is visible. */
448
469
  function startContentObserver(doc) {
@@ -450,22 +471,28 @@ window.__ModuleLoader__.load({
450
471
  updateConversationContent(doc);
451
472
  const win = doc.defaultView;
452
473
  if (win === null || typeof win.MutationObserver !== "function") return;
453
- const observer = new win.MutationObserver(() => updateConversationContent(doc));
474
+ const observer = new win.MutationObserver(() => scheduleConversationContent(doc));
454
475
  observer.observe(doc.body ?? doc.documentElement, {
455
476
  childList: true,
456
477
  subtree: true
457
478
  });
458
479
  contentObservers.set(doc, observer);
459
480
  }
460
- /** Stop the content observer and drop the content marker. */
481
+ /** Stop the content observer, cancel pending work and drop the marker. */
461
482
  function stopContentObserver(doc) {
483
+ const frame = contentFrames.get(doc);
484
+ if (frame !== void 0) {
485
+ const win = doc.defaultView;
486
+ if (win !== null && typeof win.cancelAnimationFrame === "function") win.cancelAnimationFrame(frame);
487
+ contentFrames.delete(doc);
488
+ }
462
489
  const observer = contentObservers.get(doc);
463
490
  if (observer !== void 0) {
464
491
  observer.disconnect();
465
492
  contentObservers.delete(doc);
466
493
  }
467
- doc.body?.removeAttribute(CONVERSATION_CONTENT_ATTR);
468
- doc.documentElement?.removeAttribute(CONVERSATION_CONTENT_ATTR);
494
+ applyMarker(doc.body, CONVERSATION_CONTENT_ATTR, false);
495
+ applyMarker(doc.documentElement, CONVERSATION_CONTENT_ATTR, false);
469
496
  }
470
497
  /**
471
498
  * Install the shared composer-seat neutralizer, keyed by head presence so a
@@ -4056,9 +4083,12 @@ window.__ModuleLoader__.load({
4056
4083
  /* #1117: The upstream recommended badge pairs two background-fill tokens
4057
4084
  as bg + text — in dark mode, skins like Blue Fantasy collapse them to
4058
4085
  near-identical dark navy values (contrast ~1:1). Override the text
4059
- color to a readable foreground and tweak the background for contrast. */
4060
- body[data-ds-dark-theme] ${scoped("[data-question-key] [class*=\"_badge\"]")},
4061
- body[data-ds-dark-theme] ${scoped("[data-question-scroll] [class*=\"_badge\"]")} {
4086
+ color to a readable foreground and tweak the background for contrast.
4087
+ The dark-theme attribute lives on <body>, so it belongs inside the
4088
+ scoped selector: prefixing the already-scoped list produced
4089
+ "body ... html ...", a descendant chain that can never match (#1490). */
4090
+ ${scoped("body[data-ds-dark-theme] [data-question-key] [class*=\"_badge\"]")},
4091
+ ${scoped("body[data-ds-dark-theme] [data-question-scroll] [class*=\"_badge\"]")} {
4062
4092
  color: var(--dsw-alias-label-primary, #ffffff) !important;
4063
4093
  background: var(--dsw-alias-interactive-bg-active, color-mix(in srgb, var(--dsw-alias-button-info-fill, #4a5fa8) 50%, transparent)) !important;
4064
4094
  }
@@ -4076,35 +4106,62 @@ window.__ModuleLoader__.load({
4076
4106
  try {
4077
4107
  win?.scrollTo?.(0, 0);
4078
4108
  } catch {}
4109
+ const composerSelector = COMPOSER_SEAT_SELECTORS.join(", ");
4079
4110
  let resizeObserver = null;
4080
4111
  let mutationObserver = null;
4081
4112
  let observedComposer = null;
4113
+ let appliedHeight = "";
4114
+ let scheduledFrame = null;
4115
+ let disposed = false;
4116
+ const resolveComposer = () => {
4117
+ if (observedComposer !== null && observedComposer.isConnected) return observedComposer;
4118
+ return doc.body === null ? null : doc.body.querySelector(composerSelector);
4119
+ };
4082
4120
  const syncHeight = () => {
4083
4121
  if (doc.body === null) return;
4084
- const composer = doc.body.querySelector(COMPOSER_SEAT_SELECTORS.join(", "));
4085
- if (composer !== null) {
4086
- if (observedComposer !== composer) {
4087
- if (observedComposer !== null && resizeObserver !== null) resizeObserver.unobserve(observedComposer);
4088
- observedComposer = composer;
4089
- if (resizeObserver !== null) resizeObserver.observe(composer);
4090
- }
4091
- const rect = composer.getBoundingClientRect();
4092
- if (rect.height > 0) doc.documentElement?.style.setProperty("--dsh-composer-height", `${Math.ceil(rect.height)}px`);
4122
+ const composer = resolveComposer();
4123
+ if (composer === null) return;
4124
+ if (observedComposer !== composer) {
4125
+ if (observedComposer !== null && resizeObserver !== null) resizeObserver.unobserve(observedComposer);
4126
+ observedComposer = composer;
4127
+ if (resizeObserver !== null) resizeObserver.observe(composer);
4093
4128
  }
4129
+ const rect = composer.getBoundingClientRect();
4130
+ if (rect.height <= 0) return;
4131
+ const root = doc.documentElement;
4132
+ const next = `${Math.ceil(rect.height)}px`;
4133
+ if (next === appliedHeight || root === null) return;
4134
+ appliedHeight = next;
4135
+ root.style.setProperty("--dsh-composer-height", next);
4136
+ };
4137
+ const scheduleSync = () => {
4138
+ if (scheduledFrame !== null || disposed) return;
4139
+ if (win === null || typeof win.requestAnimationFrame !== "function") {
4140
+ syncHeight();
4141
+ return;
4142
+ }
4143
+ scheduledFrame = win.requestAnimationFrame(() => {
4144
+ scheduledFrame = null;
4145
+ if (disposed) return;
4146
+ syncHeight();
4147
+ });
4094
4148
  };
4095
4149
  if (win !== null && typeof win.ResizeObserver === "function") resizeObserver = new win.ResizeObserver(() => syncHeight());
4096
4150
  if (win !== null && typeof win.MutationObserver === "function" && doc.body !== null) {
4097
- mutationObserver = new win.MutationObserver(() => syncHeight());
4151
+ mutationObserver = new win.MutationObserver(() => scheduleSync());
4098
4152
  mutationObserver.observe(doc.body, {
4099
4153
  childList: true,
4100
4154
  subtree: true
4101
4155
  });
4102
4156
  }
4103
4157
  syncHeight();
4104
- let disposed = false;
4105
4158
  return () => {
4106
4159
  if (disposed) return;
4107
4160
  disposed = true;
4161
+ if (scheduledFrame !== null) {
4162
+ if (win !== null && typeof win.cancelAnimationFrame === "function") win.cancelAnimationFrame(scheduledFrame);
4163
+ scheduledFrame = null;
4164
+ }
4108
4165
  if (resizeObserver !== null) {
4109
4166
  resizeObserver.disconnect();
4110
4167
  resizeObserver = null;
@@ -4114,6 +4171,7 @@ window.__ModuleLoader__.load({
4114
4171
  mutationObserver = null;
4115
4172
  }
4116
4173
  observedComposer = null;
4174
+ appliedHeight = "";
4117
4175
  doc.documentElement?.style.removeProperty("--dsh-composer-height");
4118
4176
  style.remove();
4119
4177
  };
@@ -4322,22 +4380,28 @@ window.__ModuleLoader__.load({
4322
4380
  function setBackgroundLayer(activation, nodes) {
4323
4381
  const style = doc.body.style;
4324
4382
  const previousBackgroundColor = style.getPropertyValue("background-color");
4383
+ const previousBackgroundImage = style.getPropertyValue("background-image");
4325
4384
  const restore = () => {
4326
4385
  if (currentActivation !== activation) return;
4327
4386
  clearLayer(layers.background);
4328
4387
  setSceneBackdropActive(doc, "skin", false);
4329
4388
  if (previousBackgroundColor === "") style.removeProperty("background-color");
4330
4389
  else style.setProperty("background-color", previousBackgroundColor);
4390
+ if (previousBackgroundImage === "") style.removeProperty("background-image");
4391
+ else style.setProperty("background-image", previousBackgroundImage);
4331
4392
  };
4332
4393
  clearLayer(layers.background);
4333
4394
  if (nodes.length > 0) {
4334
4395
  for (const node of nodes) layers.background.appendChild(node);
4335
4396
  style.setProperty("background-color", "transparent");
4397
+ style.setProperty("background-image", "none");
4336
4398
  setSceneBackdropActive(doc, "skin", true);
4337
4399
  } else {
4338
4400
  setSceneBackdropActive(doc, "skin", false);
4339
4401
  if (previousBackgroundColor === "") style.removeProperty("background-color");
4340
4402
  else style.setProperty("background-color", previousBackgroundColor);
4403
+ if (previousBackgroundImage === "") style.removeProperty("background-image");
4404
+ else style.setProperty("background-image", previousBackgroundImage);
4341
4405
  }
4342
4406
  ledger.record(activation, "background:layer", restore);
4343
4407
  }
@@ -5011,7 +5075,7 @@ window.__ModuleLoader__.load({
5011
5075
  /** The building package's version, when the bundle carries it. */
5012
5076
  function bakedVersion() {
5013
5077
  try {
5014
- return "0.3.19";
5078
+ return "0.3.21";
5015
5079
  } catch {
5016
5080
  return;
5017
5081
  }