dsh-folia 4.4.0 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +202 -54
- package/lib/features.js +260 -0
- package/package.json +5 -3
package/lib/client.js
CHANGED
|
@@ -666,6 +666,85 @@ window.__ModuleLoader__.load({
|
|
|
666
666
|
"裁切失败": "Cropping failed",
|
|
667
667
|
"读不出图片尺寸": "Could not read the image dimensions",
|
|
668
668
|
|
|
669
|
+
|
|
670
|
+
// ── 开机动画 / 桌宠(本轮新增界面)──────────────────────────────────────
|
|
671
|
+
// 这两组文案只有几十条,并进 panel 域最省;将来若继续长,再按 fonts/glass 的做法拆域。
|
|
672
|
+
"已下载:{name}": "Downloaded: {name}",
|
|
673
|
+
"已选中「{name}」,下次启动生效": "Selected \"{name}\" — takes effect on next start",
|
|
674
|
+
"已删除:{name}": "Removed: {name}",
|
|
675
|
+
"开机动画已开启": "Boot animation enabled",
|
|
676
|
+
"开机动画已关闭": "Boot animation disabled",
|
|
677
|
+
"已保存": "Saved",
|
|
678
|
+
"操作失败:{code}({detail})": "Action failed: {code} ({detail})",
|
|
679
|
+
"操作失败:{code}": "Action failed: {code}",
|
|
680
|
+
"请求失败:{msg}": "Request failed: {msg}",
|
|
681
|
+
"网络错误": "network error",
|
|
682
|
+
"🎬 开机动画": "🎬 Boot animation",
|
|
683
|
+
"启用(下次启动播放)": "Enable (plays at next start)",
|
|
684
|
+
"当前:{name}": "Current: {name}",
|
|
685
|
+
"未选择": "None selected",
|
|
686
|
+
"候选清单读不到:{msg}": "Cannot read the candidate list: {msg}",
|
|
687
|
+
"进入方式": "Enter mode",
|
|
688
|
+
"播完再进(默认)": "Play to the end (default)",
|
|
689
|
+
"界面就绪就进": "Enter once the UI is ready",
|
|
690
|
+
"点一下才进": "Enter on click",
|
|
691
|
+
"淡出时长": "Fade out",
|
|
692
|
+
"0.4 秒": "0.4s",
|
|
693
|
+
"0.6 秒": "0.6s",
|
|
694
|
+
"0.9 秒": "0.9s",
|
|
695
|
+
"1.2 秒": "1.2s",
|
|
696
|
+
"1.6 秒": "1.6s",
|
|
697
|
+
"带声音": "With sound",
|
|
698
|
+
"最短显示": "Minimum on screen",
|
|
699
|
+
"不限制": "No minimum",
|
|
700
|
+
"2 秒": "2s",
|
|
701
|
+
"最长停留": "Maximum on screen",
|
|
702
|
+
"10 秒": "10s",
|
|
703
|
+
"20 秒(默认)": "20s (default)",
|
|
704
|
+
"30 秒": "30s",
|
|
705
|
+
"60 秒": "60s",
|
|
706
|
+
"已下载 {done} / {total}": "Downloaded {done} / {total}",
|
|
707
|
+
"下载中… {s}s": "Downloading… {s}s",
|
|
708
|
+
"下载": "Download",
|
|
709
|
+
"使用中": "In use",
|
|
710
|
+
"没有可用的开机动画": "No boot animations available",
|
|
711
|
+
"读取失败:{msg}": "Load failed: {msg}",
|
|
712
|
+
"已安装并启用:{name}": "Installed and enabled: {name}",
|
|
713
|
+
"已卸载:{name}": "Uninstalled: {name}",
|
|
714
|
+
"已导入并启用:{name}": "Imported and enabled: {name}",
|
|
715
|
+
"正在读取桌宠…": "Loading pets…",
|
|
716
|
+
"🐾 桌宠": "🐾 Desktop pet",
|
|
717
|
+
"显示桌宠": "Show pet",
|
|
718
|
+
"把桌宠挪回右下角": "Move the pet back to the bottom-right corner",
|
|
719
|
+
"位置已复位(下一次出现回到右下角)": "Position reset — it returns to the bottom-right next time",
|
|
720
|
+
"复位位置": "Reset position",
|
|
721
|
+
"大小": "Size",
|
|
722
|
+
"卸载": "Uninstall",
|
|
723
|
+
"{cols} 列 · {size}": "{cols} cols · {size}",
|
|
724
|
+
"还没有安装任何桌宠 —— 从下面的站点清单里挑一只。": "No pets installed yet — pick one from the site list below.",
|
|
725
|
+
"本机可导入": "Importable from this machine",
|
|
726
|
+
"来自其它宠物插件 · {size}": "From another pet plugin · {size}",
|
|
727
|
+
"站点桌宠": "Pets on the site",
|
|
728
|
+
"安装": "Install",
|
|
729
|
+
"安装中…": "Installing…",
|
|
730
|
+
"导入": "Import",
|
|
731
|
+
"试演动作": "Try an action",
|
|
732
|
+
"闲置": "Idle",
|
|
733
|
+
"向右走": "Walk right",
|
|
734
|
+
"向左走": "Walk left",
|
|
735
|
+
"挥手": "Wave",
|
|
736
|
+
"跳一下": "Jump",
|
|
737
|
+
"失败": "Fail",
|
|
738
|
+
"发呆": "Wait",
|
|
739
|
+
"干活": "Work",
|
|
740
|
+
"完成": "Done",
|
|
741
|
+
"再大一点": "Bigger",
|
|
742
|
+
"再小一点": "Smaller",
|
|
743
|
+
"回右下角": "Back to corner",
|
|
744
|
+
"不显示它": "Hide it",
|
|
745
|
+
"站点上还没有桌宠。": "No pets on the site yet.",
|
|
746
|
+
"站点不可达": "Site unreachable",
|
|
747
|
+
"预览尺寸": "Preview-size",
|
|
669
748
|
};
|
|
670
749
|
|
|
671
750
|
// ── 内联模块:src/i18n-copy-picker.js —— 英文词表域:壁纸选择器与快捷面板(picker-* · quick-panel · sidebar-right · theme-follow)(构建期注入;勿手改本段)──
|
|
@@ -17022,18 +17101,18 @@ window.__ModuleLoader__.load({
|
|
|
17022
17101
|
const resp = await apiPostJson("/boot/" + kind, payload || {}, { parse: "always" });
|
|
17023
17102
|
const r = (resp && resp.data) || null;
|
|
17024
17103
|
if (resp && resp.ok && r && r.ok) {
|
|
17025
|
-
if (kind === "download") setNote({ ok: true, text: weT("已下载:"
|
|
17026
|
-
if (kind === "select") setNote({ ok: true, text: weT("已选中「"
|
|
17027
|
-
if (kind === "remove") setNote({ ok: true, text: weT("已删除:"
|
|
17104
|
+
if (kind === "download") setNote({ ok: true, text: weT("已下载:{name}", { name: label }) });
|
|
17105
|
+
if (kind === "select") setNote({ ok: true, text: weT("已选中「{name}」,下次启动生效", { name: label }) });
|
|
17106
|
+
if (kind === "remove") setNote({ ok: true, text: weT("已删除:{name}", { name: label }) });
|
|
17028
17107
|
if (kind === "toggle") setNote({ ok: true, text: payload.enabled ? weT("开机动画已开启") : weT("开机动画已关闭") });
|
|
17029
17108
|
if (kind === "settings") setNote({ ok: true, text: weT("已保存") });
|
|
17030
17109
|
await load(true);
|
|
17031
17110
|
} else {
|
|
17032
17111
|
const code = (r && r.error) || "failed";
|
|
17033
|
-
setNote({ ok: false, text:
|
|
17112
|
+
setNote({ ok: false, text: r && r.detail ? weT("操作失败:{code}({detail})", { code, detail: String(r.detail) }) : weT("操作失败:{code}", { code }) });
|
|
17034
17113
|
}
|
|
17035
17114
|
} catch (e) {
|
|
17036
|
-
setNote({ ok: false, text: weT("请求失败:"
|
|
17115
|
+
setNote({ ok: false, text: weT("请求失败:{msg}", { msg: (e && e.message) ? e.message : weT("网络错误") }) });
|
|
17037
17116
|
} finally {
|
|
17038
17117
|
setBusy("");
|
|
17039
17118
|
}
|
|
@@ -17047,7 +17126,7 @@ window.__ModuleLoader__.load({
|
|
|
17047
17126
|
const children = [];
|
|
17048
17127
|
|
|
17049
17128
|
children.push(React.createElement("div", { className: "we-picker__section-head", key: "head" },
|
|
17050
|
-
React.createElement("span", { className: "we-picker__section-label" }, weT("🎬 开机动画")
|
|
17129
|
+
React.createElement("span", { className: "we-picker__section-label" }, weT("🎬 开机动画")),
|
|
17051
17130
|
React.createElement("button", {
|
|
17052
17131
|
type: "button", className: "we-picker__btn", style: { marginLeft: "auto" },
|
|
17053
17132
|
disabled: Boolean(busy), onClick: () => load(true),
|
|
@@ -17066,7 +17145,7 @@ window.__ModuleLoader__.load({
|
|
|
17066
17145
|
weT("启用(下次启动播放)"),
|
|
17067
17146
|
),
|
|
17068
17147
|
React.createElement("span", { className: "we-picker__hint" },
|
|
17069
|
-
activeId ? weT("当前:"
|
|
17148
|
+
activeId ? weT("当前:{name}", { name: (clips.find((c) => c.id === activeId) || {}).title || activeId }) : weT("未选择")),
|
|
17070
17149
|
));
|
|
17071
17150
|
|
|
17072
17151
|
children.push(React.createElement("div", { key: "hint", className: "we-picker__hint", style: { margin: "2px 0 6px", opacity: 0.75 } },
|
|
@@ -17074,7 +17153,7 @@ window.__ModuleLoader__.load({
|
|
|
17074
17153
|
|
|
17075
17154
|
if (state && state.error && !clips.length) {
|
|
17076
17155
|
children.push(React.createElement("div", { key: "err", className: "we-picker__hint", style: { color: "#ff9a9a" } },
|
|
17077
|
-
weT("候选清单读不到:"
|
|
17156
|
+
weT("候选清单读不到:{msg}", { msg: String(state.error) })));
|
|
17078
17157
|
}
|
|
17079
17158
|
|
|
17080
17159
|
if (note) {
|
|
@@ -17107,7 +17186,7 @@ window.__ModuleLoader__.load({
|
|
|
17107
17186
|
React.createElement("option", { value: "click" }, weT("点一下才进")),
|
|
17108
17187
|
),
|
|
17109
17188
|
),
|
|
17110
|
-
opt(weT("淡出时长"), "fadeMs", [[400, "0.4 秒"], [600, "0.6 秒"], [900, "0.9 秒"], [1200, "1.2 秒"], [1600, "1.6 秒"]]),
|
|
17189
|
+
opt(weT("淡出时长"), "fadeMs", [[400, weT("0.4 秒")], [600, weT("0.6 秒")], [900, weT("0.9 秒")], [1200, weT("1.2 秒")], [1600, weT("1.6 秒")]]),
|
|
17111
17190
|
// 声音:默认关(带声音的自动播放会被浏览器策略拦)。打开后若仍被拦,
|
|
17112
17191
|
// 脚本会自动退回静音播放 —— 画面优先,不会黑屏。
|
|
17113
17192
|
React.createElement("label", { style: { display: "flex", gap: "6px", alignItems: "center", fontSize: "12px" } },
|
|
@@ -17119,13 +17198,13 @@ window.__ModuleLoader__.load({
|
|
|
17119
17198
|
}),
|
|
17120
17199
|
weT("带声音"),
|
|
17121
17200
|
),
|
|
17122
|
-
opt(weT("最短显示"), "minShowMs", [[0, "不限制"], [600, "0.6 秒"], [1200, "1.2 秒"], [2000, "2 秒"]]),
|
|
17123
|
-
opt(weT("最长停留"), "maxHoldMs", [[10000, "10 秒"], [20000, "20 秒(默认)"], [30000, "30 秒"], [60000, "60 秒"]]),
|
|
17201
|
+
opt(weT("最短显示"), "minShowMs", [[0, weT("不限制")], [600, weT("0.6 秒")], [1200, weT("1.2 秒")], [2000, weT("2 秒")]]),
|
|
17202
|
+
opt(weT("最长停留"), "maxHoldMs", [[10000, weT("10 秒")], [20000, weT("20 秒(默认)")], [30000, weT("30 秒")], [60000, weT("60 秒")]]),
|
|
17124
17203
|
));
|
|
17125
17204
|
}
|
|
17126
17205
|
|
|
17127
17206
|
children.push(React.createElement("div", { key: "count", className: "we-picker__hint", style: { margin: "2px 0 4px" } },
|
|
17128
|
-
weT("已下载
|
|
17207
|
+
weT("已下载 {done} / {total}", { done: installedCount, total: clips.length })));
|
|
17129
17208
|
|
|
17130
17209
|
if (clips.length) {
|
|
17131
17210
|
children.push(React.createElement("div", { key: "grid", style: BOOT_STYLE.grid },
|
|
@@ -17141,7 +17220,7 @@ window.__ModuleLoader__.load({
|
|
|
17141
17220
|
}, label);
|
|
17142
17221
|
const actions = [];
|
|
17143
17222
|
if (!c.installed) {
|
|
17144
|
-
actions.push(btn(isBusy ?
|
|
17223
|
+
actions.push(btn(isBusy ? weT("下载中… {s}s", { s: tick }) : weT("下载"), () => act("download", { id: c.id }, c.title), false, true));
|
|
17145
17224
|
} else if (!isActive) {
|
|
17146
17225
|
actions.push(btn(weT("使用"), () => act("select", { id: c.id }, c.title), false, true));
|
|
17147
17226
|
actions.push(btn(weT("删除"), () => act("remove", { id: c.id }, c.title), isBusy, false));
|
|
@@ -17227,9 +17306,9 @@ window.__ModuleLoader__.load({
|
|
|
17227
17306
|
if (imDoc && imDoc.ok) setImportable(imDoc.pets || []);
|
|
17228
17307
|
} catch { /* 无外部目录是正常情况 */ }
|
|
17229
17308
|
}
|
|
17230
|
-
else setNote({ ok: false, text: weT("读取失败:"
|
|
17309
|
+
else setNote({ ok: false, text: weT("读取失败:{msg}", { msg: (resp && resp.error) || "unknown" }) });
|
|
17231
17310
|
} catch (e) {
|
|
17232
|
-
setNote({ ok: false, text: weT("请求失败:"
|
|
17311
|
+
setNote({ ok: false, text: weT("请求失败:{msg}", { msg: (e && e.message) || weT("网络错误") }) });
|
|
17233
17312
|
}
|
|
17234
17313
|
}, []);
|
|
17235
17314
|
|
|
@@ -17242,17 +17321,17 @@ window.__ModuleLoader__.load({
|
|
|
17242
17321
|
const resp = await apiPostJson("/pets/" + kind, payload || {}, { parse: "always" });
|
|
17243
17322
|
const r = (resp && resp.data) || null;
|
|
17244
17323
|
if (resp && resp.ok && r && r.ok) {
|
|
17245
|
-
if (kind === "install") setNote({ ok: true, text: weT("已安装并启用:"
|
|
17246
|
-
if (kind === "remove") setNote({ ok: true, text: weT("已卸载:"
|
|
17247
|
-
if (kind === "import") setNote({ ok: true, text: weT("已导入并启用:"
|
|
17324
|
+
if (kind === "install") setNote({ ok: true, text: weT("已安装并启用:{name}", { name: label || "" }) });
|
|
17325
|
+
if (kind === "remove") setNote({ ok: true, text: weT("已卸载:{name}", { name: label || "" }) });
|
|
17326
|
+
if (kind === "import") setNote({ ok: true, text: weT("已导入并启用:{name}", { name: label || "" }) });
|
|
17248
17327
|
if (kind === "config") setNote({ ok: true, text: weT("已保存") });
|
|
17249
17328
|
await load(true);
|
|
17250
17329
|
} else {
|
|
17251
17330
|
const code = (r && r.error) || "failed";
|
|
17252
|
-
setNote({ ok: false, text: weT("操作失败:"
|
|
17331
|
+
setNote({ ok: false, text: weT("操作失败:{code}", { code }) });
|
|
17253
17332
|
}
|
|
17254
17333
|
} catch (e) {
|
|
17255
|
-
setNote({ ok: false, text: weT("请求失败:"
|
|
17334
|
+
setNote({ ok: false, text: weT("请求失败:{msg}", { msg: (e && e.message) || weT("网络错误") }) });
|
|
17256
17335
|
} finally {
|
|
17257
17336
|
setBusy("");
|
|
17258
17337
|
}
|
|
@@ -17272,7 +17351,7 @@ window.__ModuleLoader__.load({
|
|
|
17272
17351
|
|
|
17273
17352
|
children.push(React.createElement("div", { className: "we-picker__section-head", key: "head" },
|
|
17274
17353
|
React.createElement("span", { className: "we-picker__section-label" },
|
|
17275
|
-
weT("🐾 桌宠")
|
|
17354
|
+
weT("🐾 桌宠")),
|
|
17276
17355
|
React.createElement("button", {
|
|
17277
17356
|
type: "button", className: "we-picker__btn", style: { marginLeft: "auto" },
|
|
17278
17357
|
disabled: Boolean(busy), onClick: () => load(true),
|
|
@@ -17372,7 +17451,7 @@ window.__ModuleLoader__.load({
|
|
|
17372
17451
|
}),
|
|
17373
17452
|
React.createElement("div", { style: PET_STYLE.title }, p.name),
|
|
17374
17453
|
React.createElement("div", { style: PET_STYLE.meta },
|
|
17375
|
-
|
|
17454
|
+
weT("{cols} 列 · {size}", { cols: p.columns || 8, size: p.cell ? p.cell.width + "×" + p.cell.height : "" })),
|
|
17376
17455
|
React.createElement("div", { style: PET_STYLE.row }, actions),
|
|
17377
17456
|
);
|
|
17378
17457
|
})
|
|
@@ -17383,7 +17462,7 @@ window.__ModuleLoader__.load({
|
|
|
17383
17462
|
if (importable.length) {
|
|
17384
17463
|
children.push(React.createElement("div", { key: "impHead", className: "we-picker__section-head", style: { marginTop: "14px" } },
|
|
17385
17464
|
React.createElement("span", { className: "we-picker__section-label" },
|
|
17386
|
-
weT("本机可导入")
|
|
17465
|
+
weT("本机可导入")),
|
|
17387
17466
|
));
|
|
17388
17467
|
children.push(React.createElement("div", { key: "imp", style: PET_STYLE.grid },
|
|
17389
17468
|
importable.map((it) => {
|
|
@@ -17391,7 +17470,7 @@ window.__ModuleLoader__.load({
|
|
|
17391
17470
|
return React.createElement("div", { key: "imp:" + it.id, style: PET_STYLE.card },
|
|
17392
17471
|
React.createElement("div", { style: PET_STYLE.title }, it.name || it.id),
|
|
17393
17472
|
React.createElement("div", { style: PET_STYLE.meta },
|
|
17394
|
-
weT("来自其它宠物插件 · "
|
|
17473
|
+
weT("来自其它宠物插件 · {size}", { size: petFmtBytes(it.bytes) })),
|
|
17395
17474
|
React.createElement("div", { style: PET_STYLE.row },
|
|
17396
17475
|
btn(isBusy ? weT("导入中…") : weT("导入"), () => act("import", { id: it.id }, it.name || it.id), Boolean(busy))),
|
|
17397
17476
|
);
|
|
@@ -17403,7 +17482,7 @@ window.__ModuleLoader__.load({
|
|
|
17403
17482
|
const available = site.filter((s) => !installedIds.has(s.id));
|
|
17404
17483
|
children.push(React.createElement("div", { key: "siteHead", className: "we-picker__section-head", style: { marginTop: "14px" } },
|
|
17405
17484
|
React.createElement("span", { className: "we-picker__section-label" },
|
|
17406
|
-
weT("站点桌宠")
|
|
17485
|
+
weT("站点桌宠")),
|
|
17407
17486
|
state.siteError
|
|
17408
17487
|
? React.createElement("span", { className: "we-picker__hint", style: { marginLeft: "auto" } }, weT("站点不可达"))
|
|
17409
17488
|
: null,
|
|
@@ -17883,9 +17962,11 @@ window.__ModuleLoader__.load({
|
|
|
17883
17962
|
"background:rgba(28,32,40,0.96)", "border:1px solid rgba(255,255,255,0.16)",
|
|
17884
17963
|
"box-shadow:0 10px 30px rgba(0,0,0,0.45)", "backdrop-filter:blur(8px)",
|
|
17885
17964
|
].join(";");
|
|
17886
|
-
|
|
17965
|
+
// 九条轨道的中文名是**界面文案**(右键菜单里给用户点的)⇒ 必须走 weT;
|
|
17966
|
+
// 上面 PET_ACTIVITY_TEXTS 那几条是拿去匹配页面文字的,翻不动,登记在 i18n 的 VALUE_ALLOW。
|
|
17967
|
+
const titles = [weT("闲置"), weT("向右走"), weT("向左走"), weT("挥手"), weT("跳一下"), weT("失败"), weT("发呆"), weT("干活"), weT("完成")];
|
|
17887
17968
|
const head = document.createElement("div");
|
|
17888
|
-
head.textContent = "试演动作";
|
|
17969
|
+
head.textContent = weT("试演动作");
|
|
17889
17970
|
head.style.cssText = "padding:4px 10px 6px;opacity:0.55;font-size:11px";
|
|
17890
17971
|
menu.appendChild(head);
|
|
17891
17972
|
titles.forEach((name, r) => {
|
|
@@ -17900,15 +17981,15 @@ window.__ModuleLoader__.load({
|
|
|
17900
17981
|
const hr = document.createElement("div");
|
|
17901
17982
|
hr.style.cssText = "height:1px;margin:6px 0;background:rgba(255,255,255,0.14)";
|
|
17902
17983
|
menu.appendChild(hr);
|
|
17903
|
-
menu.appendChild(buildMenuItem("再大一点", () => { applyScale(scale + 0.2); closeMenu(); }));
|
|
17904
|
-
menu.appendChild(buildMenuItem("再小一点", () => { applyScale(Math.max(0.5, scale - 0.2)); closeMenu(); }));
|
|
17905
|
-
menu.appendChild(buildMenuItem("回右下角", () => {
|
|
17984
|
+
menu.appendChild(buildMenuItem(weT("再大一点"), () => { applyScale(scale + 0.2); closeMenu(); }));
|
|
17985
|
+
menu.appendChild(buildMenuItem(weT("再小一点"), () => { applyScale(Math.max(0.5, scale - 0.2)); closeMenu(); }));
|
|
17986
|
+
menu.appendChild(buildMenuItem(weT("回右下角"), () => {
|
|
17906
17987
|
try { localStorage.removeItem("wePetPos"); } catch { /* ignore */ }
|
|
17907
17988
|
layerEl.style.left = ""; layerEl.style.top = "";
|
|
17908
17989
|
layerEl.style.right = "24px"; layerEl.style.bottom = "16px";
|
|
17909
17990
|
closeMenu();
|
|
17910
17991
|
}));
|
|
17911
|
-
menu.appendChild(buildMenuItem("不显示它", () => {
|
|
17992
|
+
menu.appendChild(buildMenuItem(weT("不显示它"), () => {
|
|
17912
17993
|
// 只隐藏本地这一层;真正的开关在面板里(下一次轮询会被尊重)。
|
|
17913
17994
|
if (layerEl) layerEl.style.display = "none";
|
|
17914
17995
|
closeMenu();
|
|
@@ -18065,6 +18146,76 @@ window.__ModuleLoader__.load({
|
|
|
18065
18146
|
|
|
18066
18147
|
// 仅供单测驱动(构建期内联时会剥掉 export,不影响产物)。
|
|
18067
18148
|
|
|
18149
|
+
// ── 内联模块:src/features.js —— 客户端功能注册表:页签条 / 整区面板 / 常驻挂载层。装配点(quick-panel、client.js)只查表,不写功能名(构建期注入;勿手改本段)──
|
|
18150
|
+
/**
|
|
18151
|
+
* features.js(客户端)— **功能注册表**:页签声明、面板工厂、挂载钩子。
|
|
18152
|
+
*
|
|
18153
|
+
* 为什么需要它:加一个功能过去要改五处共享文件(client.js 挂载 / quick-panel 的 QP_TABS 与
|
|
18154
|
+
* 渲染点 / settings-schema / build-client 的内联表 / lib/index.js 的路由注册)。前两处是纯
|
|
18155
|
+
* "接线",写错了症状是「页签在、点开空白」或「渲染层根本没挂」。把这些收成一份声明后:
|
|
18156
|
+
*
|
|
18157
|
+
* · 页签条 = WE_FEATURE_TABS(顺序就是用户看到的顺序)
|
|
18158
|
+
* · 整区面板 = WE_FEATURE_PANELS(哪些页签整区交给功能自己的面板)
|
|
18159
|
+
* · 常驻层 = WE_FEATURE_MOUNTS(随插件生命周期挂载/卸载的浮动层,例如桌宠)
|
|
18160
|
+
*
|
|
18161
|
+
* 谁也别再往 quick-panel 里写 `qpTab === "xxx"` —— 那是把功能名焊死进装配点。
|
|
18162
|
+
* 判据:test/verify-features.mjs 会检查 quick-panel 里不再出现具体功能分支。
|
|
18163
|
+
*
|
|
18164
|
+
* ⚠️ 内联顺序:本文件必须排在**它引用的所有符号之后**(panel-tabs-boot / panel-tabs-pets /
|
|
18165
|
+
* pet-layer),且排在 quick-panel.js 与 client.js **之前** —— 那两处在模块顶层读本表。
|
|
18166
|
+
*/
|
|
18167
|
+
|
|
18168
|
+
/** 页签条(顺序 = 界面顺序)。label 用 getter:语言切换后能立刻生效。 */
|
|
18169
|
+
const WE_FEATURE_TABS = [
|
|
18170
|
+
// 开机动画与壁纸并列:它们回答的是同一个问题"开机/桌面看到什么",不是壁纸的子功能。
|
|
18171
|
+
{ id: "boot", get label() { return weT("开机动画"); } },
|
|
18172
|
+
{ id: "wallpaper", get label() { return weT("壁纸"); } },
|
|
18173
|
+
{ id: "appearance", get label() { return weT("外观"); } },
|
|
18174
|
+
{ id: "playback", get label() { return weT("播放"); } },
|
|
18175
|
+
// 桌宠是"桌面上多出来的一只东西",与壁纸/开机动画并列。
|
|
18176
|
+
{ id: "pets", get label() { return weT("桌宠"); } },
|
|
18177
|
+
];
|
|
18178
|
+
|
|
18179
|
+
/**
|
|
18180
|
+
* 整区面板:这个页签的内容**整个**由功能自己的组件渲染(而不是 quick-panel 内的通用列表)。
|
|
18181
|
+
* 没登记的页签走 quick-panel 自己的通用布局(壁纸列表 / 外观节 / 播放节)。
|
|
18182
|
+
*/
|
|
18183
|
+
const WE_FEATURE_PANELS = {
|
|
18184
|
+
boot: BootTabPanel,
|
|
18185
|
+
pets: PetsTabPanel,
|
|
18186
|
+
};
|
|
18187
|
+
|
|
18188
|
+
/**
|
|
18189
|
+
* 常驻层:插件挂载时启动、卸载时归还。每个都必须返回 cleanup(或 undefined)。
|
|
18190
|
+
* 它们自己决定"要不要显示"(例如桌宠要读配置才知道是否启用),装配点不参与判断。
|
|
18191
|
+
*/
|
|
18192
|
+
const WE_FEATURE_MOUNTS = [
|
|
18193
|
+
{ id: "pets", mount: mountPetLayer },
|
|
18194
|
+
];
|
|
18195
|
+
|
|
18196
|
+
/** 页签 → 功能归属(宿主清单 lib/features.js 的客户端镜像,供守卫对账)。 */
|
|
18197
|
+
const WE_FEATURE_TAB_IDS = WE_FEATURE_TABS.map((t) => t.id);
|
|
18198
|
+
|
|
18199
|
+
/**
|
|
18200
|
+
* 页签底部那枚「去设置里改」的引导条。
|
|
18201
|
+
*
|
|
18202
|
+
* 为什么要收进注册表:它原本是 quick-panel 里的一条 `qpTab === "boot"` 分支 —— 属于
|
|
18203
|
+
* 「功能名焊死进装配点」。功能自己声明自己的引导语,装配点只查表。
|
|
18204
|
+
* 没声明的页签走 quick-panel 的通用文案(壁纸 / 外观 / 播放那三档是泛型布局,留在原地)。
|
|
18205
|
+
*/
|
|
18206
|
+
const WE_FEATURE_FOOTERS = {
|
|
18207
|
+
boot: {
|
|
18208
|
+
get label() { return weT("打开设置 ›"); },
|
|
18209
|
+
target: "",
|
|
18210
|
+
get title() { return weT("开机动画的全部参数都在侧栏「壁纸引擎」设置里"); },
|
|
18211
|
+
},
|
|
18212
|
+
pets: {
|
|
18213
|
+
get label() { return weT("打开设置 ›"); },
|
|
18214
|
+
target: "",
|
|
18215
|
+
get title() { return weT("桌宠的开关 / 大小 / 声音都在「桌宠」页签里调整"); },
|
|
18216
|
+
},
|
|
18217
|
+
};
|
|
18218
|
+
|
|
18068
18219
|
// ── 内联模块:src/quick-panel.js —— 快捷播放面板(官方侧栏 tab 与低版本抽屉共用同一份内容):当前壁纸 + 轮播 + 列表快切 + 声音 + 设置入口。列表虚拟滚动(spacer + 可视窗口)(构建期注入;勿手改本段)──
|
|
18069
18220
|
/**
|
|
18070
18221
|
* quick-panel.js — 快捷播放面板(侧边栏的**唯一**内容):当前壁纸 + 轮播 + 三档页签
|
|
@@ -18234,15 +18385,9 @@ window.__ModuleLoader__.load({
|
|
|
18234
18385
|
// 位置在「轮播」之下:当前壁纸与轮播在三档页签下都显示(调外观 / 播放参数时想换一张
|
|
18235
18386
|
// 对照很常见)。与设置页的页签表(PICKER_TABS)是两件事 —— 这里只镜像用户点名要的
|
|
18236
18387
|
// 两页,外加壁纸页。
|
|
18237
|
-
|
|
18238
|
-
|
|
18239
|
-
|
|
18240
|
-
{ id: "wallpaper", get label() { return weT("壁纸"); } },
|
|
18241
|
-
{ id: "appearance", get label() { return weT("外观"); } },
|
|
18242
|
-
{ id: "playback", get label() { return weT("播放"); } },
|
|
18243
|
-
// 桌宠是"桌面上多出来的一只东西",与壁纸/开机动画并列,不是它们的子功能。
|
|
18244
|
-
{ id: "pets", get label() { return weT("桌宠"); } },
|
|
18245
|
-
];
|
|
18388
|
+
// 页签条从**功能注册表**取(src/features.js):这里不再出现具体功能名。
|
|
18389
|
+
// 加功能只该动注册表,不该动装配点 —— 否则又变成"每加一个功能改五处"。
|
|
18390
|
+
const QP_TABS = WE_FEATURE_TABS;
|
|
18246
18391
|
// 页签记忆(同 picker-tab / qp-view 口径:仅 UI 状态,localStorage,不进 config.json)。
|
|
18247
18392
|
const QP_TAB_KEY = "dsh-folia:qp-tab";
|
|
18248
18393
|
/** 读页签偏好;缺失 / 非法回落「壁纸」。 */
|
|
@@ -18418,7 +18563,7 @@ window.__ModuleLoader__.load({
|
|
|
18418
18563
|
? React.createElement("span", {
|
|
18419
18564
|
className: "we-qp__card-badge",
|
|
18420
18565
|
style: { right: "auto", left: "6px", background: "rgba(255,196,120,0.9)", color: "#3a2600" },
|
|
18421
|
-
title: weT("这张图只有 "
|
|
18566
|
+
title: weT("这张图只有 {size},当壁纸会糊 —— 建议在站点上传原图", { size: w.width + "×" + w.height }),
|
|
18422
18567
|
}, weT("预览尺寸"))
|
|
18423
18568
|
: null,
|
|
18424
18569
|
w.id === sel.id && React.createElement("span", { className: "we-qp__card-badge" }, weT("当前")),
|
|
@@ -18916,12 +19061,11 @@ window.__ModuleLoader__.load({
|
|
|
18916
19061
|
// 设置页同名页签 —— 玻璃详细调节仍只在侧栏(本页,折叠块),设置页那边留玻璃预设、
|
|
18917
19062
|
// 全量配置与**字体节**(三次修订后字体节两档都画);播放页的出图来源 /
|
|
18918
19063
|
// 实时帧仍住设置页。
|
|
18919
|
-
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
18923
|
-
|
|
18924
|
-
}
|
|
19064
|
+
// 引导条:整区面板类页签的文案由**功能注册表**给(WE_FEATURE_FOOTERS),装配点只查表;
|
|
19065
|
+
// 外观 / 播放 / 壁纸是泛型布局,文案留在原地。
|
|
19066
|
+
const featFooter = WE_FEATURE_FOOTERS[qpTab] || null;
|
|
19067
|
+
const foot = featFooter
|
|
19068
|
+
? featFooter
|
|
18925
19069
|
: qpTab === "appearance"
|
|
18926
19070
|
? {
|
|
18927
19071
|
label: weT("更多外观设置 ›"),
|
|
@@ -18954,10 +19098,10 @@ window.__ModuleLoader__.load({
|
|
|
18954
19098
|
React.createElement("div", { className: tabBodyClass, ref: qpPaneRef },
|
|
18955
19099
|
qpTab === "wallpaper" && userPropsPanelOpen() && propsAvailable
|
|
18956
19100
|
&& React.createElement("div", { className: "we-qp__propsview we-qp__propsview--drill" }, renderUserPropsPanel()),
|
|
18957
|
-
//
|
|
18958
|
-
|
|
18959
|
-
qpTab
|
|
18960
|
-
!(qpTab === "wallpaper" && userPropsPanelOpen() && propsAvailable) && qpTab
|
|
19101
|
+
// 整区面板:由注册表声明哪些页签整块交给功能自己的组件(开机动画 / 桌宠)。
|
|
19102
|
+
// 装配点只查表,不写功能名 —— 判据见 test/verify-features.mjs。
|
|
19103
|
+
Boolean(WE_FEATURE_PANELS[qpTab]) && React.createElement(WE_FEATURE_PANELS[qpTab], null),
|
|
19104
|
+
!(qpTab === "wallpaper" && userPropsPanelOpen() && propsAvailable) && !WE_FEATURE_PANELS[qpTab] && (qpTab === "appearance"
|
|
18961
19105
|
? qpRenderAppearancePane(sel, {
|
|
18962
19106
|
fontOpen, onToggleFontSection: toggleFontSection,
|
|
18963
19107
|
uiColorOpen, onToggleUiColorSection: toggleUiColorSection,
|
|
@@ -32289,9 +32433,13 @@ window.__ModuleLoader__.load({
|
|
|
32289
32433
|
if (ctx.effect && typeof document !== "undefined") {
|
|
32290
32434
|
ctx.effect(() => installSkinInterop() || undefined);
|
|
32291
32435
|
}
|
|
32292
|
-
// 3c.
|
|
32293
|
-
|
|
32294
|
-
|
|
32436
|
+
// 3c. 常驻层:由**功能注册表**声明(src/features.js 的 WE_FEATURE_MOUNTS)。
|
|
32437
|
+
// 装配点不再点名具体功能 —— 每个 mount 自己决定要不要显示(例如桌宠先读配置)。
|
|
32438
|
+
if (typeof WE_FEATURE_MOUNTS !== "undefined") {
|
|
32439
|
+
for (const feat of WE_FEATURE_MOUNTS) {
|
|
32440
|
+
if (!ctx.effect || typeof document === "undefined") break;
|
|
32441
|
+
ctx.effect(() => feat.mount() || undefined);
|
|
32442
|
+
}
|
|
32295
32443
|
}
|
|
32296
32444
|
|
|
32297
32445
|
// 3. Chat-interface rope dock: the draggable pull-cord + glass repo side
|
package/lib/features.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/features.js — **功能清单**(单一真源)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要这张表:这个插件已经长到 19 个宿主路由文件 + 70 个客户端文件 + 24k 行,
|
|
5
|
+
* 而"某个功能到底由哪些文件负责"过去只存在于人脑里。后果是真实的:
|
|
6
|
+
* · 加一个功能要同时改 client.js / quick-panel.js / settings-schema.js / build-client.mjs
|
|
7
|
+
* / lib/index.js 五处接线,漏一处就"功能看着在、点开是空的";
|
|
8
|
+
* · 有的功能(如站点缩略图)横跨 host + client,谁都能往里塞逻辑,边界逐渐糊掉。
|
|
9
|
+
*
|
|
10
|
+
* 这张表把"归属"写成数据,并由 test/verify-features.mjs 机器校验:
|
|
11
|
+
* ① 表里每个文件都必须真实存在;
|
|
12
|
+
* ② `lib/routes/*.js` 里的**每一个文件都必须被且仅被一个功能认领**(不许有孤儿路由);
|
|
13
|
+
* ③ 每个 `tab` 必须真的出现在客户端 QP_TABS 里(不许有幽灵页签);
|
|
14
|
+
* ④ 用到的站点分类必须在这里登记(站点是数据源,分类就是功能的入口)。
|
|
15
|
+
*
|
|
16
|
+
* 这张表**不改变运行行为**(运行时仍按各文件自己的注册方式装配),它的价值是:
|
|
17
|
+
* 让"模块化"变成可失败的判据,而不是口头承诺。下次要加功能,先在这里登记,再动手。
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {object} Feature
|
|
22
|
+
* @property {string} id 功能 id(与 tab / 站点分类对齐)
|
|
23
|
+
* @property {string} name 中文名(界面与文档用)
|
|
24
|
+
* @property {string} role 这一层负责什么(一句话)
|
|
25
|
+
* @property {string[]} host 宿主侧文件(相对仓库根)
|
|
26
|
+
* @property {string[]} client 浏览器侧文件(相对仓库根)
|
|
27
|
+
* @property {string[]} [tab] 客户端页签 id(没有页签的写 null)
|
|
28
|
+
* @property {string[]} [site] 使用的站点分类 slug(站点数据源入口)
|
|
29
|
+
* @property {string[]} [settings] 拥有的设置键前缀(可空)
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/** @type {Feature[]} */
|
|
33
|
+
export const FEATURES = [
|
|
34
|
+
{
|
|
35
|
+
id: 'wallpaper',
|
|
36
|
+
name: '壁纸',
|
|
37
|
+
role: '本机/上传/站点三源合并成壁纸库;着色、图层、播放与轮换由客户端接管',
|
|
38
|
+
host: [
|
|
39
|
+
'lib/routes/inventory.js',
|
|
40
|
+
'lib/routes/media-bytes.js',
|
|
41
|
+
'lib/routes/media-derived.js',
|
|
42
|
+
'lib/routes/scene-frame.js',
|
|
43
|
+
'lib/routes/scene-media.js',
|
|
44
|
+
'lib/routes/scene-serve.js',
|
|
45
|
+
'lib/routes/live-frame.js',
|
|
46
|
+
'lib/routes/occlusion.js',
|
|
47
|
+
'lib/routes/props.js',
|
|
48
|
+
'lib/routes/we-assets.js',
|
|
49
|
+
'lib/routes/upload.js',
|
|
50
|
+
'lib/inventory.js',
|
|
51
|
+
'lib/wallpaper-scan.js',
|
|
52
|
+
'lib/upload-store.js',
|
|
53
|
+
'lib/scene-manifest.js',
|
|
54
|
+
'lib/faststart.js',
|
|
55
|
+
'lib/mp4-vfs.js',
|
|
56
|
+
'lib/media/frame-store.js',
|
|
57
|
+
'lib/media/transcode.js',
|
|
58
|
+
'lib/media/video-preview.js',
|
|
59
|
+
'lib/media/image-preview.js',
|
|
60
|
+
'lib/media/scene-probe.js',
|
|
61
|
+
'lib/media/mp4-probe.js',
|
|
62
|
+
'lib/media/media-dirs.js',
|
|
63
|
+
],
|
|
64
|
+
client: [
|
|
65
|
+
'src/quick-panel.js',
|
|
66
|
+
'src/picker-modal.js',
|
|
67
|
+
'src/picker-model.js',
|
|
68
|
+
'src/picker-props-panel.js',
|
|
69
|
+
'src/panel-tabs-wallpaper.js',
|
|
70
|
+
'src/video-layer.js',
|
|
71
|
+
'src/layer-core.js',
|
|
72
|
+
'src/live-layer.js',
|
|
73
|
+
'src/live-layer-watch.js',
|
|
74
|
+
'src/live-layer-gate.js',
|
|
75
|
+
'src/live-layer-pointer.js',
|
|
76
|
+
'src/live-layer-underlay.js',
|
|
77
|
+
'src/live-layer-diag.js',
|
|
78
|
+
'src/media-prep.js',
|
|
79
|
+
'src/client-media-frame.js',
|
|
80
|
+
'src/client-rotation.js',
|
|
81
|
+
'src/client-audio-playback.js',
|
|
82
|
+
'src/occlusion.js',
|
|
83
|
+
],
|
|
84
|
+
tab: ['wallpaper'],
|
|
85
|
+
site: ['wallpaper'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'site',
|
|
89
|
+
name: '站点数据源',
|
|
90
|
+
role: '把站点当唯一数据源:清单拉取、分类过滤、缩略图代理、模块索引',
|
|
91
|
+
host: [
|
|
92
|
+
'lib/routes/site-thumb.js',
|
|
93
|
+
'lib/routes/modules.js',
|
|
94
|
+
],
|
|
95
|
+
client: [],
|
|
96
|
+
tab: [],
|
|
97
|
+
site: ['wallpaper', 'boot-animation', 'desktop-pet', 'assistant-skin'],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'boot',
|
|
101
|
+
name: '开机动画',
|
|
102
|
+
role: '站点候选 → 并行下载 → 本地目录 → 启动注入播放(脚本在宿主侧注入,不依赖应用挂载)',
|
|
103
|
+
host: [
|
|
104
|
+
'lib/routes/boot.js',
|
|
105
|
+
'lib/boot/index.js',
|
|
106
|
+
],
|
|
107
|
+
client: ['src/panel-tabs-boot.js'],
|
|
108
|
+
tab: ['boot'],
|
|
109
|
+
site: ['boot-animation'],
|
|
110
|
+
settings: ['boot'],
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 'pets',
|
|
114
|
+
name: '桌宠',
|
|
115
|
+
role: '自渲染:站点/本机宠物 → 安装解包 → canvas 逐帧绘 sprite2d + 动作状态机 + 语音',
|
|
116
|
+
host: ['lib/routes/pets.js'],
|
|
117
|
+
client: ['src/panel-tabs-pets.js', 'src/pet-layer.js'],
|
|
118
|
+
tab: ['pets'],
|
|
119
|
+
site: ['desktop-pet'],
|
|
120
|
+
settings: ['pet'],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 'appearance',
|
|
124
|
+
name: '外观',
|
|
125
|
+
role: '玻璃、主题、字体、预设、页签样式 —— 纯客户端表现层',
|
|
126
|
+
host: [
|
|
127
|
+
'lib/routes/settings.js',
|
|
128
|
+
'lib/routes/presets.js',
|
|
129
|
+
'lib/settings-schema.js',
|
|
130
|
+
'lib/components/fonts/routes/fontsets.js',
|
|
131
|
+
'lib/components/fonts/routes/system-fonts.js',
|
|
132
|
+
],
|
|
133
|
+
client: [
|
|
134
|
+
'src/panel-tabs-appearance.js',
|
|
135
|
+
'src/glass.js',
|
|
136
|
+
'src/glass-panel.js',
|
|
137
|
+
'src/glass-surfaces.js',
|
|
138
|
+
'src/glass-extra.js',
|
|
139
|
+
'src/theme-follow.js',
|
|
140
|
+
'src/system-fonts.js',
|
|
141
|
+
'src/fontset-store.js',
|
|
142
|
+
'src/preset-store.js',
|
|
143
|
+
'src/styles-base.js',
|
|
144
|
+
'src/styles-chrome.js',
|
|
145
|
+
'src/styles-ext.js',
|
|
146
|
+
'src/styles-panel.js',
|
|
147
|
+
'src/styles-quick.js',
|
|
148
|
+
'src/styles-settings.js',
|
|
149
|
+
'src/styles-shell.js',
|
|
150
|
+
'src/styles-sidebar.js',
|
|
151
|
+
'src/about-assets.js',
|
|
152
|
+
'src/nav-icon.js',
|
|
153
|
+
],
|
|
154
|
+
tab: ['appearance'],
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: 'playback',
|
|
158
|
+
name: '播放',
|
|
159
|
+
role: '音量、静音、轮换节奏与播放控制(壁纸的播放面,独立页签)',
|
|
160
|
+
host: [],
|
|
161
|
+
client: [
|
|
162
|
+
'src/panel-tabs-advanced.js',
|
|
163
|
+
'src/effects.js',
|
|
164
|
+
'src/adapter.js',
|
|
165
|
+
],
|
|
166
|
+
tab: ['playback'],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: 'components',
|
|
170
|
+
name: '可选组件行',
|
|
171
|
+
role: '上游形态保留的 7 个组件行(fx/parallax/fonts/mascot-avatar/media-bridge/pet-link/about-notice),各自独立装载',
|
|
172
|
+
host: [
|
|
173
|
+
'lib/components/fx/index.js',
|
|
174
|
+
'lib/components/parallax/index.js',
|
|
175
|
+
'lib/components/fonts/index.js',
|
|
176
|
+
'lib/components/mascot-avatar/index.js',
|
|
177
|
+
'lib/components/media-bridge/index.js',
|
|
178
|
+
'lib/components/pet-link/index.js',
|
|
179
|
+
'lib/components/about-notice/index.js',
|
|
180
|
+
],
|
|
181
|
+
client: [],
|
|
182
|
+
tab: [],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'system',
|
|
186
|
+
name: '系统',
|
|
187
|
+
role: '诊断、缓存目录、设置存储、客户端装配骨架(不属于任何单个功能)',
|
|
188
|
+
host: [
|
|
189
|
+
'lib/routes/diag.js',
|
|
190
|
+
'lib/routes/cache-dir.js',
|
|
191
|
+
'lib/index.js',
|
|
192
|
+
'lib/kernel/host-kernel.js',
|
|
193
|
+
'lib/kernel/host-session.js',
|
|
194
|
+
'lib/kernel/config.js',
|
|
195
|
+
'lib/kernel/data-dir.js',
|
|
196
|
+
'lib/diag-trace.js',
|
|
197
|
+
'lib/cache-dir.js',
|
|
198
|
+
'lib/serve.js',
|
|
199
|
+
'lib/http-body.js',
|
|
200
|
+
'lib/http-lifecycle.js',
|
|
201
|
+
'lib/json-response.js',
|
|
202
|
+
'lib/pkg-read.js',
|
|
203
|
+
'lib/log.js',
|
|
204
|
+
'lib/notice.js',
|
|
205
|
+
'lib/host-boot.js',
|
|
206
|
+
'lib/subpackage-boot.js',
|
|
207
|
+
'lib/startup-sweep.js',
|
|
208
|
+
'lib/fs-paths.js',
|
|
209
|
+
'lib/upload-dir.js',
|
|
210
|
+
'lib/steam-discovery.js',
|
|
211
|
+
'lib/shim-seed.js',
|
|
212
|
+
'lib/we-props.js',
|
|
213
|
+
'lib/we-focus-guard.js',
|
|
214
|
+
'lib/media-origin.js',
|
|
215
|
+
'lib/types/index.d.ts',
|
|
216
|
+
'lib/types/client.d.ts',
|
|
217
|
+
],
|
|
218
|
+
client: [
|
|
219
|
+
'src/client.js',
|
|
220
|
+
'src/api-client.js',
|
|
221
|
+
'src/persistence.js',
|
|
222
|
+
'src/extension-registry.js',
|
|
223
|
+
'src/i18n.js',
|
|
224
|
+
'src/i18n-copy.js',
|
|
225
|
+
'src/i18n-copy-core.js',
|
|
226
|
+
'src/i18n-copy-ext.js',
|
|
227
|
+
'src/i18n-copy-font.js',
|
|
228
|
+
'src/i18n-copy-glass.js',
|
|
229
|
+
'src/i18n-copy-live.js',
|
|
230
|
+
'src/i18n-copy-panel.js',
|
|
231
|
+
'src/i18n-copy-pet-link.js',
|
|
232
|
+
'src/i18n-copy-picker.js',
|
|
233
|
+
'src/we-base.js',
|
|
234
|
+
'src/we-cond.js',
|
|
235
|
+
'src/module-reset.js',
|
|
236
|
+
'src/focus-handback.js',
|
|
237
|
+
'src/sidebar-right.js',
|
|
238
|
+
'src/section-head.js',
|
|
239
|
+
'src/avatar-import.js',
|
|
240
|
+
'src/avatar-layer.js',
|
|
241
|
+
'src/ext-avatar.js',
|
|
242
|
+
'src/panel-tabs.js',
|
|
243
|
+
'src/panel-tabs-effects.js',
|
|
244
|
+
'src/panel-tabs-mascot.js',
|
|
245
|
+
],
|
|
246
|
+
tab: [],
|
|
247
|
+
},
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
/** 页签 id → 功能 id(供校验与文档使用)。 */
|
|
251
|
+
export const TAB_OWNERS = FEATURES.reduce((acc, f) => {
|
|
252
|
+
for (const t of f.tab || []) acc[t] = f.id;
|
|
253
|
+
return acc;
|
|
254
|
+
}, {});
|
|
255
|
+
|
|
256
|
+
/** 站点分类 slug → 功能 id。 */
|
|
257
|
+
export const SITE_OWNERS = FEATURES.reduce((acc, f) => {
|
|
258
|
+
for (const s of f.site || []) acc[s] = f.id;
|
|
259
|
+
return acc;
|
|
260
|
+
}, {});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-folia",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "Folia 壁纸引擎:把本机 Wallpaper Engine 壁纸搬进 DSH 界面(场景实时渲染 / 视频 / 网页),内置液态玻璃与 Folia 吉祥物,并可从自建站点拉取壁纸。单包形态(组件已合并)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -155,7 +155,8 @@
|
|
|
155
155
|
"README.md",
|
|
156
156
|
"README.en.md",
|
|
157
157
|
"README.beginner.md",
|
|
158
|
-
"lib/components/"
|
|
158
|
+
"lib/components/",
|
|
159
|
+
"lib/features.js"
|
|
159
160
|
],
|
|
160
161
|
"dsh": {
|
|
161
162
|
"bundle": {
|
|
@@ -193,7 +194,8 @@
|
|
|
193
194
|
"test:boot": "node test/boot-http.mjs",
|
|
194
195
|
"test:pets": "node test/pets-http.mjs",
|
|
195
196
|
"test:pets-layer": "node test/pets-layer.mjs",
|
|
196
|
-
"
|
|
197
|
+
"test:features": "node test/verify-features.mjs",
|
|
198
|
+
"gate": "node scripts/build-client.mjs \u0026\u0026 node test/run-guards.mjs smoke \u0026\u0026 node test/verify-features.mjs \u0026\u0026 node test/boot-http.mjs \u0026\u0026 node test/pets-http.mjs \u0026\u0026 node test/pets-layer.mjs"
|
|
197
199
|
},
|
|
198
200
|
"peerDependencies": {
|
|
199
201
|
"@deepseek-ai/cordis": "^4.0.4",
|