@linxin666/dsh-client-ui-skin-center 0.3.3 → 0.3.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/contracts/semantic-attrs-v1.md +10 -2
- package/lib/client.js +104 -21
- package/lib/client.js.map +1 -1
- package/lib/index.js +22 -19
- package/package.json +1 -1
|
@@ -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 组(
|
|
48
|
+
## part 组(38 行,含各 owner 行)
|
|
49
49
|
|
|
50
50
|
shell 区域(owner: shell):
|
|
51
51
|
|
|
@@ -59,6 +59,7 @@ shell 区域(owner: shell):
|
|
|
59
59
|
| `queue-dock` | 排队条;`[data-queue-dock]` |
|
|
60
60
|
| `turn-tail` | turn 尾行;`[data-turn-tail]` |
|
|
61
61
|
| `resize-handle` | 列宽手柄;`[data-side]` |
|
|
62
|
+
| `new-session` | 侧栏新会话按钮;官方稳定属性落地前由兼容适配器从 `button[class*="newSession"]` 补打,皮肤不得依赖本地化文案 |
|
|
62
63
|
|
|
63
64
|
family / 插件区域:
|
|
64
65
|
|
|
@@ -101,8 +102,14 @@ family / 插件区域:
|
|
|
101
102
|
| `row` | session-id | 会话列表行;面板内行容器(`[data-dsh-part="row"]`) |
|
|
102
103
|
| `copy` | session-id | 每行复制按钮;`button[data-dsh-part="copy"]` |
|
|
103
104
|
| `search` | session-id | 面板搜索输入框;`input[type="search"][data-dsh-part="search"]` |
|
|
105
|
+
| `sprite` | miku-pet | 宠物帧舞台;`[data-dsh-plugin="miku-pet"] [data-dsh-part="sprite"]` |
|
|
106
|
+
| `menu` | miku-pet | 悬停菜单(两级);`[data-dsh-part="menu"]` |
|
|
107
|
+
| `stats` | miku-pet | 左侧属性彩条;`[data-dsh-part="stats"]` |
|
|
108
|
+
| `shop` | miku-pet | 商店居中窗口;`[data-dsh-part="shop"]` |
|
|
109
|
+
| `bubble` | miku-pet | 对话气泡;`[data-dsh-part="bubble"]` |
|
|
110
|
+
| `float` | miku-pet | 互动飘字;`[data-dsh-part="float"]` |
|
|
104
111
|
|
|
105
|
-
## plugin 组(
|
|
112
|
+
## plugin 组(13 个,含停更 aionui-panel)
|
|
106
113
|
|
|
107
114
|
| data-dsh-plugin | owner | 锚定方式 |
|
|
108
115
|
| --- | --- | --- |
|
|
@@ -118,6 +125,7 @@ family / 插件区域:
|
|
|
118
125
|
| `dsh-web-ui-market` | dsh-market | 创意工坊商店一级页(settings.section id `dsh-web-ui-market`),商店卡与目录条目容器 |
|
|
119
126
|
| `skin-center` | skins/skin-center | 一级设置分区 settings.section id `skin-center`(列已安装皮肤,属内置源时显式标记) |
|
|
120
127
|
| `session-id` | dsh-session-id | footer action slot entry id `session-id`;`[data-dsh-plugin="session-id"]`(面板 overlay 根 + 入口触发器) |
|
|
128
|
+
| `miku-pet` | dsh-miku-pet | 宠物浮层根 `[data-dsh-plugin="miku-pet"]`;host 路由前缀 `/miku-pet/*`;设置页 settings.section id `miku-pet-config` |
|
|
121
129
|
|
|
122
130
|
## 已知脆弱点(上游主题缝 PR 诉求)
|
|
123
131
|
|
package/lib/client.js
CHANGED
|
@@ -746,6 +746,11 @@ window.__ModuleLoader__.load({
|
|
|
746
746
|
this.publish();
|
|
747
747
|
this.scope.set("weLibraryDirs", this.dirsValue);
|
|
748
748
|
}
|
|
749
|
+
failedIds = /* @__PURE__ */ new Set();
|
|
750
|
+
isDisplaying = () => {
|
|
751
|
+
const id = this.activeId();
|
|
752
|
+
return this.enabledValue && id !== null && !this.failedIds.has(id);
|
|
753
|
+
};
|
|
749
754
|
activeId = () => {
|
|
750
755
|
const current = this.previewing ?? this.applied;
|
|
751
756
|
return this.mediaLayer !== null && current !== null ? current.id : null;
|
|
@@ -811,6 +816,7 @@ window.__ModuleLoader__.load({
|
|
|
811
816
|
this.scope.set("volume", this.volumeValue);
|
|
812
817
|
}
|
|
813
818
|
applySelection(descriptor) {
|
|
819
|
+
this.failedIds.delete(descriptor.id);
|
|
814
820
|
this.applied = descriptor;
|
|
815
821
|
this.previewing = null;
|
|
816
822
|
this.selectionValue = descriptor.id;
|
|
@@ -842,6 +848,7 @@ window.__ModuleLoader__.load({
|
|
|
842
848
|
if (descriptor !== null) this.probeSceneCapabilitiesIfNeeded(descriptor);
|
|
843
849
|
}
|
|
844
850
|
tryOn(descriptor) {
|
|
851
|
+
this.failedIds.delete(descriptor.id);
|
|
845
852
|
this.previewing = descriptor;
|
|
846
853
|
this.render();
|
|
847
854
|
this.publish();
|
|
@@ -1111,6 +1118,22 @@ window.__ModuleLoader__.load({
|
|
|
1111
1118
|
const nextFallback = frameUrl !== null ? previewUrl : null;
|
|
1112
1119
|
const img = this.buildImage(nextUrl, nextFallback);
|
|
1113
1120
|
if (img && video.parentElement) video.parentElement.replaceChild(img, video);
|
|
1121
|
+
else {
|
|
1122
|
+
const currentId = this.previewing?.id ?? this.applied?.id;
|
|
1123
|
+
if (currentId) {
|
|
1124
|
+
this.failedIds.add(currentId);
|
|
1125
|
+
this.render();
|
|
1126
|
+
this.publish();
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}, { once: true });
|
|
1130
|
+
else video.addEventListener("error", () => {
|
|
1131
|
+
const currentId = this.previewing?.id ?? this.applied?.id;
|
|
1132
|
+
if (currentId) {
|
|
1133
|
+
this.failedIds.add(currentId);
|
|
1134
|
+
this.render();
|
|
1135
|
+
this.publish();
|
|
1136
|
+
}
|
|
1114
1137
|
}, { once: true });
|
|
1115
1138
|
video.play()?.catch(() => {});
|
|
1116
1139
|
return video;
|
|
@@ -1161,9 +1184,18 @@ window.__ModuleLoader__.load({
|
|
|
1161
1184
|
const image = this.doc.createElement("img");
|
|
1162
1185
|
image.src = url;
|
|
1163
1186
|
image.alt = "";
|
|
1164
|
-
|
|
1165
|
-
if (
|
|
1166
|
-
|
|
1187
|
+
image.addEventListener("error", () => {
|
|
1188
|
+
if (fallbackUrl !== null && fallbackUrl !== url && image.src !== fallbackUrl) {
|
|
1189
|
+
image.src = fallbackUrl;
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
const currentId = this.previewing?.id ?? this.applied?.id;
|
|
1193
|
+
if (currentId) {
|
|
1194
|
+
this.failedIds.add(currentId);
|
|
1195
|
+
this.render();
|
|
1196
|
+
this.publish();
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1167
1199
|
styleCover(image, this.fitValue);
|
|
1168
1200
|
return image;
|
|
1169
1201
|
}
|
|
@@ -2130,7 +2162,7 @@ window.__ModuleLoader__.load({
|
|
|
2130
2162
|
* @returns the plugin card.
|
|
2131
2163
|
*/
|
|
2132
2164
|
function SkinCenter({ t, runtime, theme, background, wallpaper, preview, customTheme }) {
|
|
2133
|
-
|
|
2165
|
+
(0, react.useSyncExternalStore)((listener) => theme.subscribe(listener), () => theme.getTheme());
|
|
2134
2166
|
const enabled = (0, react.useSyncExternalStore)(background.subscribe, background.enabled);
|
|
2135
2167
|
const opacity = (0, react.useSyncExternalStore)(background.subscribe, background.opacity);
|
|
2136
2168
|
const blurEmpty = (0, react.useSyncExternalStore)(background.subscribe, background.blurEmpty);
|
|
@@ -2253,7 +2285,7 @@ window.__ModuleLoader__.load({
|
|
|
2253
2285
|
return active;
|
|
2254
2286
|
}));
|
|
2255
2287
|
};
|
|
2256
|
-
const dark =
|
|
2288
|
+
const dark = document.body.hasAttribute("data-ds-dark-theme");
|
|
2257
2289
|
/** One row: try-on control + apply button. Shared by the official card and every skin card. */
|
|
2258
2290
|
const actionButtons = (opts) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2259
2291
|
className: skin_center_module_css_default.actions,
|
|
@@ -3055,20 +3087,30 @@ window.__ModuleLoader__.load({
|
|
|
3055
3087
|
}
|
|
3056
3088
|
return Object.keys(patch).length === 0 ? null : patch;
|
|
3057
3089
|
}
|
|
3090
|
+
/** Deterministic serialization of the user layer for content-based dedup. */
|
|
3091
|
+
function serializeSkinBackgroundUserLayer(user) {
|
|
3092
|
+
const extracted = extractSkinBackgroundUserLayer(user);
|
|
3093
|
+
return extracted === null ? "" : JSON.stringify(extracted);
|
|
3094
|
+
}
|
|
3058
3095
|
/**
|
|
3059
|
-
* Accept a scope publication only when its namespace revision is new
|
|
3060
|
-
*
|
|
3061
|
-
*
|
|
3096
|
+
* Accept a scope publication only when its namespace revision is new AND the
|
|
3097
|
+
* user layer has actually changed. A revision bump with identical user-layer
|
|
3098
|
+
* content is a replay (settings-mirror resync, WS reconnect, or another
|
|
3099
|
+
* plugin writing to the global settings document) and must not overwrite the
|
|
3100
|
+
* authoritative v2 state.
|
|
3062
3101
|
*/
|
|
3063
|
-
function reconcileSkinBackgroundScope(current, snapshot, lastRevision) {
|
|
3064
|
-
|
|
3102
|
+
function reconcileSkinBackgroundScope(current, snapshot, lastRevision, lastUserJson) {
|
|
3103
|
+
const currentUserJson = serializeSkinBackgroundUserLayer(snapshot.user);
|
|
3104
|
+
if (snapshot.revision === void 0 || snapshot.revision === lastRevision || currentUserJson === lastUserJson) return {
|
|
3065
3105
|
accepted: false,
|
|
3066
|
-
revision: lastRevision,
|
|
3106
|
+
revision: snapshot.revision ?? lastRevision,
|
|
3107
|
+
lastUserJson: currentUserJson,
|
|
3067
3108
|
patch: null
|
|
3068
3109
|
};
|
|
3069
3110
|
return {
|
|
3070
3111
|
accepted: true,
|
|
3071
3112
|
revision: snapshot.revision,
|
|
3113
|
+
lastUserJson: currentUserJson,
|
|
3072
3114
|
patch: skinBackgroundUserPatch(current, snapshot.user)
|
|
3073
3115
|
};
|
|
3074
3116
|
}
|
|
@@ -3431,6 +3473,11 @@ window.__ModuleLoader__.load({
|
|
|
3431
3473
|
attrs: [["data-dsh-part", "resize-handle"]],
|
|
3432
3474
|
note: "column resize handle"
|
|
3433
3475
|
},
|
|
3476
|
+
{
|
|
3477
|
+
selector: "button[class*=\"newSession\"]",
|
|
3478
|
+
attrs: [["data-dsh-part", "new-session"]],
|
|
3479
|
+
note: "sidebar new-session action (compat seam shields skins from localized labels)"
|
|
3480
|
+
},
|
|
3434
3481
|
{
|
|
3435
3482
|
selector: "[data-dsh-taskboard-view], [data-dsh-taskboard-board], [data-dsh-taskboard-entry]",
|
|
3436
3483
|
attrs: [["data-dsh-plugin", "task-board"]],
|
|
@@ -3610,10 +3657,31 @@ window.__ModuleLoader__.load({
|
|
|
3610
3657
|
${scoped("[data-dsh-part=\"scrollport\"]")} {
|
|
3611
3658
|
/* The composer is the scrollport's final in-flow child. Reserving physical
|
|
3612
3659
|
padding after it lifts the active dock by one composer height and also
|
|
3613
|
-
shifts the hero above center.
|
|
3614
|
-
clearance without changing either layout's geometry. */
|
|
3660
|
+
shifts the hero above center. */
|
|
3615
3661
|
padding-bottom: 0 !important;
|
|
3616
|
-
|
|
3662
|
+
}
|
|
3663
|
+
/* #978 / #1133: Line-level scroll-margin retains scrollIntoView() clearance
|
|
3664
|
+
above the sticky composer without placing a scrollport-level scroll-padding
|
|
3665
|
+
that breaks browser caret-reveal geometry (which caused micro-scrolling on
|
|
3666
|
+
every keystroke while reading history). */
|
|
3667
|
+
${scoped("[data-conversation-scroll] [data-chat-anchor-key]")},
|
|
3668
|
+
${scoped("[data-conversation-scroll] [data-chat-flow-kind]")},
|
|
3669
|
+
${scoped("[data-conversation-scroll] [data-dsh-part=\"message-row\"]")},
|
|
3670
|
+
${scoped("[data-conversation-scroll] [data-turn-tail]")},
|
|
3671
|
+
${scoped("[data-conversation-scroll] [class*=\"_userRow\"]")},
|
|
3672
|
+
${scoped("[data-conversation-scroll] [class*=\"_compactionRow\"]")},
|
|
3673
|
+
${scoped("[data-conversation-scroll] [class*=\"_contextRow\"]")},
|
|
3674
|
+
${scoped("[data-conversation-scroll] [class*=\"_turnErrorRow\"]")} {
|
|
3675
|
+
scroll-margin-bottom: var(--dsh-composer-height, 100px) !important;
|
|
3676
|
+
}
|
|
3677
|
+
/* #1117: The upstream recommended badge pairs two background-fill tokens
|
|
3678
|
+
as bg + text — in dark mode, skins like Blue Fantasy collapse them to
|
|
3679
|
+
near-identical dark navy values (contrast ~1:1). Override the text
|
|
3680
|
+
color to a readable foreground and tweak the background for contrast. */
|
|
3681
|
+
body[data-ds-dark-theme] ${scoped("[data-question-key] [class*=\"_badge\"]")},
|
|
3682
|
+
body[data-ds-dark-theme] ${scoped("[data-question-scroll] [class*=\"_badge\"]")} {
|
|
3683
|
+
color: var(--dsw-alias-label-primary, #ffffff) !important;
|
|
3684
|
+
background: var(--dsw-alias-interactive-bg-active, color-mix(in srgb, var(--dsw-alias-button-info-fill, #4a5fa8) 50%, transparent)) !important;
|
|
3617
3685
|
}
|
|
3618
3686
|
`;
|
|
3619
3687
|
}
|
|
@@ -4159,9 +4227,11 @@ window.__ModuleLoader__.load({
|
|
|
4159
4227
|
active = payload.ok && typeof payload.active === "string" ? payload.active : null;
|
|
4160
4228
|
}
|
|
4161
4229
|
if (active === null) return;
|
|
4162
|
-
|
|
4230
|
+
let entry = store.find(active);
|
|
4163
4231
|
if (entry === null) {
|
|
4164
|
-
|
|
4232
|
+
const defaultEntry = store.find("blue-fantasy");
|
|
4233
|
+
if (defaultEntry !== null) await controller.switchTo("blue-fantasy", defaultEntry);
|
|
4234
|
+
else await controller.switchTo(null, null);
|
|
4165
4235
|
return;
|
|
4166
4236
|
}
|
|
4167
4237
|
await controller.switchTo(active, entry);
|
|
@@ -4169,6 +4239,18 @@ window.__ModuleLoader__.load({
|
|
|
4169
4239
|
await controller.switchTo(null, null).catch(() => {});
|
|
4170
4240
|
}
|
|
4171
4241
|
})();
|
|
4242
|
+
if (typeof doc.defaultView !== "undefined" && doc.defaultView !== null) {
|
|
4243
|
+
const win = doc.defaultView;
|
|
4244
|
+
const onSkinApplied = (e) => {
|
|
4245
|
+
const detail = e.detail;
|
|
4246
|
+
if (detail && typeof detail.id === "string") refreshCatalog().then(async () => {
|
|
4247
|
+
const entry = store.find(detail.id);
|
|
4248
|
+
if (entry !== null) await controller.switchTo(detail.id, entry);
|
|
4249
|
+
});
|
|
4250
|
+
};
|
|
4251
|
+
win.addEventListener("dsh-skin-applied", onSkinApplied);
|
|
4252
|
+
listeners.add(() => win.removeEventListener("dsh-skin-applied", onSkinApplied));
|
|
4253
|
+
}
|
|
4172
4254
|
return store;
|
|
4173
4255
|
}
|
|
4174
4256
|
//#endregion
|
|
@@ -4552,7 +4634,7 @@ window.__ModuleLoader__.load({
|
|
|
4552
4634
|
/** The building package's version, when the bundle carries it. */
|
|
4553
4635
|
function bakedVersion() {
|
|
4554
4636
|
try {
|
|
4555
|
-
return "0.3.
|
|
4637
|
+
return "0.3.4";
|
|
4556
4638
|
} catch {
|
|
4557
4639
|
return;
|
|
4558
4640
|
}
|
|
@@ -4707,6 +4789,7 @@ window.__ModuleLoader__.load({
|
|
|
4707
4789
|
};
|
|
4708
4790
|
let v2Loaded = false;
|
|
4709
4791
|
let lastScopeRevision = backgroundScope.getSnapshot().revision;
|
|
4792
|
+
let lastUserJson = serializeSkinBackgroundUserLayer(backgroundScope.getSnapshot().user);
|
|
4710
4793
|
const background = new BackgroundController(scopeConfig(), persistBackground);
|
|
4711
4794
|
const reconcileScope = () => {
|
|
4712
4795
|
if (!v2Loaded) return;
|
|
@@ -4714,10 +4797,10 @@ window.__ModuleLoader__.load({
|
|
|
4714
4797
|
const result = reconcileSkinBackgroundScope(background.snapshot(), {
|
|
4715
4798
|
revision: snapshot.revision,
|
|
4716
4799
|
user: snapshot.user
|
|
4717
|
-
}, lastScopeRevision);
|
|
4718
|
-
if (!result.accepted) return;
|
|
4800
|
+
}, lastScopeRevision, lastUserJson);
|
|
4719
4801
|
lastScopeRevision = result.revision;
|
|
4720
|
-
|
|
4802
|
+
lastUserJson = result.lastUserJson;
|
|
4803
|
+
if (!result.accepted || result.patch === null) return;
|
|
4721
4804
|
const current = background.snapshot();
|
|
4722
4805
|
background.init({
|
|
4723
4806
|
...current,
|
|
@@ -4743,7 +4826,7 @@ window.__ModuleLoader__.load({
|
|
|
4743
4826
|
const wallpaper = new WallpaperController(binder.bind({ namespace: SKIN_WALLPAPER_NS }));
|
|
4744
4827
|
ctx.effect(() => () => wallpaper.dispose(), "ui-skin-center: wallpaper dispose");
|
|
4745
4828
|
installBootRestore(wallpaper);
|
|
4746
|
-
const runtime = bootSkinRuntime({ suppressBackgroundMedia: () => wallpaper.enabled() && wallpaper.
|
|
4829
|
+
const runtime = bootSkinRuntime({ suppressBackgroundMedia: () => wallpaper.enabled() && wallpaper.isDisplaying() });
|
|
4747
4830
|
ctx.effect(() => () => runtime.shutdown(), "ui-skin-center: runtime shutdown");
|
|
4748
4831
|
ctx.effect(() => wallpaper.subscribe(() => {
|
|
4749
4832
|
runtime.controller.refresh();
|