dsh-any-background 0.2.10 → 0.3.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/README.md +32 -19
- package/README.zh.md +33 -19
- package/lib/client.js +534 -43
- package/lib/client.js.map +1 -1
- package/lib/index.js +67 -5
- package/package.json +18 -10
package/lib/client.js
CHANGED
|
@@ -52,8 +52,11 @@ window.__ModuleLoader__.load({
|
|
|
52
52
|
uiSop: "设置界面透明度",
|
|
53
53
|
uiChatRegion: "对话文本框",
|
|
54
54
|
uiTrajectory: "轨迹页",
|
|
55
|
-
uiPanelRegion: "
|
|
55
|
+
uiPanelRegion: "bettersidebar",
|
|
56
|
+
uiPanelNative: "右方侧边栏",
|
|
57
|
+
guideDesc: "管理主题色、壁纸与界面透明度",
|
|
56
58
|
uiProduced: "产出物/高亮内容",
|
|
59
|
+
uiHeader: "顶栏选项",
|
|
57
60
|
fontPageTitle: "字体与描边",
|
|
58
61
|
fontTitle: "自定义字体",
|
|
59
62
|
fontHint: "支持 ttf/otf/woff/woff2 字体文件(上限 100MB),将应用到整个界面的文字;代码块的等宽字体保持不变。中文字体通常有几十 MB,首次上传与刷新加载需要片刻",
|
|
@@ -241,8 +244,11 @@ window.__ModuleLoader__.load({
|
|
|
241
244
|
uiSop: "Settings interface opacity",
|
|
242
245
|
uiChatRegion: "Conversation text frame",
|
|
243
246
|
uiTrajectory: "Trajectory view",
|
|
244
|
-
uiPanelRegion: "
|
|
247
|
+
uiPanelRegion: "bettersidebar",
|
|
248
|
+
uiPanelNative: "Right sidebar",
|
|
249
|
+
guideDesc: "Theme color, wallpaper and interface opacity in the right sidebar",
|
|
245
250
|
uiProduced: "Produced / highlights",
|
|
251
|
+
uiHeader: "Header popovers",
|
|
246
252
|
fontPageTitle: "Font & outline",
|
|
247
253
|
fontTitle: "Custom font",
|
|
248
254
|
fontHint: "Accepts ttf/otf/woff/woff2 files (up to 100MB) and applies them to the whole interface; code blocks keep their monospace stack. CJK fonts routinely span tens of MB, so the first upload and each reload take a moment",
|
|
@@ -421,7 +427,8 @@ window.__ModuleLoader__.load({
|
|
|
421
427
|
trajectory: 30,
|
|
422
428
|
input: 30,
|
|
423
429
|
panel: 30,
|
|
424
|
-
produced: 30
|
|
430
|
+
produced: 30,
|
|
431
|
+
header: 30
|
|
425
432
|
},
|
|
426
433
|
strokes: {
|
|
427
434
|
bg: {
|
|
@@ -468,6 +475,11 @@ window.__ModuleLoader__.load({
|
|
|
468
475
|
width: 0,
|
|
469
476
|
color: "auto",
|
|
470
477
|
customColor: "#808080"
|
|
478
|
+
},
|
|
479
|
+
header: {
|
|
480
|
+
width: 0,
|
|
481
|
+
color: "auto",
|
|
482
|
+
customColor: "#808080"
|
|
471
483
|
}
|
|
472
484
|
},
|
|
473
485
|
settingsOpacity: .5,
|
|
@@ -498,6 +510,7 @@ window.__ModuleLoader__.load({
|
|
|
498
510
|
trajectoryOpacity: .5,
|
|
499
511
|
panelOpacity: .5,
|
|
500
512
|
producedOpacity: .5,
|
|
513
|
+
headerOpacity: .5,
|
|
501
514
|
profiles: [],
|
|
502
515
|
rotation: {
|
|
503
516
|
enabled: false,
|
|
@@ -637,7 +650,8 @@ window.__ModuleLoader__.load({
|
|
|
637
650
|
"trajectory",
|
|
638
651
|
"input",
|
|
639
652
|
"panel",
|
|
640
|
-
"produced"
|
|
653
|
+
"produced",
|
|
654
|
+
"header"
|
|
641
655
|
]) {
|
|
642
656
|
const v = b[k];
|
|
643
657
|
out[k] = typeof v === "number" ? Math.min(60, Math.max(0, v)) : DEFAULT_CONFIG.blurs[k];
|
|
@@ -653,7 +667,8 @@ window.__ModuleLoader__.load({
|
|
|
653
667
|
"trajectory",
|
|
654
668
|
"input",
|
|
655
669
|
"panel",
|
|
656
|
-
"produced"
|
|
670
|
+
"produced",
|
|
671
|
+
"header"
|
|
657
672
|
];
|
|
658
673
|
const STROKE_COLOR_KEYS = [
|
|
659
674
|
"auto",
|
|
@@ -702,6 +717,9 @@ window.__ModuleLoader__.load({
|
|
|
702
717
|
function rProducedOpacity() {
|
|
703
718
|
return clamp01(cfg.producedOpacity, DEFAULT_CONFIG.producedOpacity);
|
|
704
719
|
}
|
|
720
|
+
function rHeaderOpacity() {
|
|
721
|
+
return clamp01(cfg.headerOpacity, DEFAULT_CONFIG.headerOpacity);
|
|
722
|
+
}
|
|
705
723
|
function rBgState() {
|
|
706
724
|
return cfg.bgState;
|
|
707
725
|
}
|
|
@@ -765,7 +783,8 @@ window.__ModuleLoader__.load({
|
|
|
765
783
|
chatTextOpacity: rChatTextOpacity(),
|
|
766
784
|
trajectoryOpacity: rTrajectoryOpacity(),
|
|
767
785
|
panelOpacity: rPanelOpacity(),
|
|
768
|
-
producedOpacity: rProducedOpacity()
|
|
786
|
+
producedOpacity: rProducedOpacity(),
|
|
787
|
+
headerOpacity: rHeaderOpacity()
|
|
769
788
|
};
|
|
770
789
|
}
|
|
771
790
|
/** Apply an appearance snapshot onto cfg (meta fields untouched). */
|
|
@@ -787,6 +806,7 @@ window.__ModuleLoader__.load({
|
|
|
787
806
|
cfg.trajectoryOpacity = clamp01(ap.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity);
|
|
788
807
|
cfg.panelOpacity = clamp01(ap.panelOpacity, DEFAULT_CONFIG.panelOpacity);
|
|
789
808
|
cfg.producedOpacity = clamp01(ap.producedOpacity, DEFAULT_CONFIG.producedOpacity);
|
|
809
|
+
cfg.headerOpacity = clamp01(ap.headerOpacity, DEFAULT_CONFIG.headerOpacity);
|
|
790
810
|
}
|
|
791
811
|
const num = (n, def) => typeof n === "number" ? n : def;
|
|
792
812
|
const cl = (n, lo, hi, def) => typeof n === "number" ? Math.min(hi, Math.max(lo, n)) : def;
|
|
@@ -820,7 +840,8 @@ window.__ModuleLoader__.load({
|
|
|
820
840
|
chatTextOpacity: clamp01(ac.chatTextOpacity, DEFAULT_CONFIG.chatTextOpacity),
|
|
821
841
|
trajectoryOpacity: clamp01(ac.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity),
|
|
822
842
|
panelOpacity: clamp01(ac.panelOpacity, DEFAULT_CONFIG.panelOpacity),
|
|
823
|
-
producedOpacity: clamp01(ac.producedOpacity, DEFAULT_CONFIG.producedOpacity)
|
|
843
|
+
producedOpacity: clamp01(ac.producedOpacity, DEFAULT_CONFIG.producedOpacity),
|
|
844
|
+
headerOpacity: clamp01(ac.headerOpacity, DEFAULT_CONFIG.headerOpacity)
|
|
824
845
|
}
|
|
825
846
|
});
|
|
826
847
|
}
|
|
@@ -885,7 +906,8 @@ window.__ModuleLoader__.load({
|
|
|
885
906
|
"trajectory",
|
|
886
907
|
"input",
|
|
887
908
|
"panel",
|
|
888
|
-
"produced"
|
|
909
|
+
"produced",
|
|
910
|
+
"header"
|
|
889
911
|
]) blurs[k] = num(bl[k], DEFAULT_CONFIG.blurs[k]);
|
|
890
912
|
const bgType = [
|
|
891
913
|
"video",
|
|
@@ -928,6 +950,7 @@ window.__ModuleLoader__.load({
|
|
|
928
950
|
trajectoryOpacity: clamp01(c.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity),
|
|
929
951
|
panelOpacity: clamp01(c.panelOpacity, DEFAULT_CONFIG.panelOpacity),
|
|
930
952
|
producedOpacity: clamp01(c.producedOpacity, DEFAULT_CONFIG.producedOpacity),
|
|
953
|
+
headerOpacity: clamp01(c.headerOpacity, DEFAULT_CONFIG.headerOpacity),
|
|
931
954
|
profiles: adoptProfiles(c.profiles),
|
|
932
955
|
rotation: adoptRotation(c.rotation),
|
|
933
956
|
schedule: adoptSchedule(c.schedule),
|
|
@@ -971,6 +994,95 @@ window.__ModuleLoader__.load({
|
|
|
971
994
|
};
|
|
972
995
|
}
|
|
973
996
|
//#endregion
|
|
997
|
+
//#region src/client/host.ts
|
|
998
|
+
/**
|
|
999
|
+
* Host release detection + feature classification.
|
|
1000
|
+
*
|
|
1001
|
+
* WHY THIS EXISTS
|
|
1002
|
+
* The client context exposes no host version: there is no `hostVersion` /
|
|
1003
|
+
* `dshVersion` field on `ctx`, and `window.__DSH_BOOT__.version` is the
|
|
1004
|
+
* module-table format tag (`'client'`), not a release. Capability probing alone
|
|
1005
|
+
* is also not sufficient, because the obvious probes do not separate the
|
|
1006
|
+
* generations — `ctx.sidebarRightTabs` and the native `[data-sidebar-right-panel]`
|
|
1007
|
+
* marker both exist on 0.1.5-rc.2 already, so using either as a "0.1.6+" test
|
|
1008
|
+
* mis-classifies 0.1.5 as newer.
|
|
1009
|
+
*
|
|
1010
|
+
* So the release is resolved on the Node half (where the launcher's on-disk
|
|
1011
|
+
* layout is visible) and handed to this half through the `read` RPC payload.
|
|
1012
|
+
* This module stores that verdict and turns it into the feature flags the rest
|
|
1013
|
+
* of the plugin gates on. When the release cannot be determined the flags fall
|
|
1014
|
+
* back to capability probing, never to a guess.
|
|
1015
|
+
*
|
|
1016
|
+
* @module
|
|
1017
|
+
*/
|
|
1018
|
+
let current = {
|
|
1019
|
+
version: null,
|
|
1020
|
+
generation: "unknown"
|
|
1021
|
+
};
|
|
1022
|
+
/** False until the server verdict lands; feature gates must not treat "not
|
|
1023
|
+
* asked yet" as "old host". */
|
|
1024
|
+
let resolved = false;
|
|
1025
|
+
const subs$1 = /* @__PURE__ */ new Set();
|
|
1026
|
+
/** Adopt the verdict delivered by the server's `read` payload. */
|
|
1027
|
+
function adoptHostInfo(raw) {
|
|
1028
|
+
if (raw === null || typeof raw !== "object") return;
|
|
1029
|
+
const h = raw;
|
|
1030
|
+
const version = typeof h.version === "string" && h.version.trim() !== "" ? h.version.trim() : null;
|
|
1031
|
+
const generation = h.generation === "0.1.5" || h.generation === "0.1.6" || h.generation === "0.1.7" ? h.generation : "unknown";
|
|
1032
|
+
const changed = !resolved || current.version !== version || current.generation !== generation;
|
|
1033
|
+
current = {
|
|
1034
|
+
version,
|
|
1035
|
+
generation
|
|
1036
|
+
};
|
|
1037
|
+
resolved = true;
|
|
1038
|
+
if (changed) subs$1.forEach((cb) => cb());
|
|
1039
|
+
}
|
|
1040
|
+
/** Subscribe to a verdict landing (or changing). */
|
|
1041
|
+
function subscribeHostInfo(cb) {
|
|
1042
|
+
subs$1.add(cb);
|
|
1043
|
+
return () => {
|
|
1044
|
+
subs$1.delete(cb);
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
/** Ordered generation rank, for "at least this generation" tests. `unknown`
|
|
1048
|
+
* has no rank and must be handled by the caller's fallback. */
|
|
1049
|
+
const RANK = {
|
|
1050
|
+
"0.1.5": 5,
|
|
1051
|
+
"0.1.6": 6,
|
|
1052
|
+
"0.1.7": 7
|
|
1053
|
+
};
|
|
1054
|
+
/**
|
|
1055
|
+
* Whether the host is at least `gen`. An unknown generation answers `false`:
|
|
1056
|
+
* callers treat that as "do not assume the newer behaviour" and use whatever
|
|
1057
|
+
* capability probe they own, which is the safe direction for every gate here.
|
|
1058
|
+
*/
|
|
1059
|
+
function hostAtLeast(gen) {
|
|
1060
|
+
const rank = RANK[current.generation];
|
|
1061
|
+
return rank !== void 0 && rank >= RANK[gen];
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Whether this host's own right Sidebar already carries the appearance page,
|
|
1065
|
+
* which makes the plugin's dsh-better-sidebar page a duplicate entry on the same
|
|
1066
|
+
* guide surface.
|
|
1067
|
+
*
|
|
1068
|
+
* `true` — 0.1.6 or newer: the better-sidebar page stands down.
|
|
1069
|
+
* `false` — 0.1.5 or an undetermined-but-answered generation: keep it.
|
|
1070
|
+
* `null` — the verdict has not landed yet (the probe is a Node round-trip).
|
|
1071
|
+
*
|
|
1072
|
+
* Callers must treat `null` as "not yet known": register nothing eagerly on a
|
|
1073
|
+
* `true`, and arm a withdrawal for a later `true` rather than blocking on it.
|
|
1074
|
+
*
|
|
1075
|
+
* NOTE: 0.1.5-rc.2 ALSO ships the native right Sidebar (verified: the
|
|
1076
|
+
* `ui-sidebar-right` entry is in that release's `dsh-web-app/cordis.patch.yml`),
|
|
1077
|
+
* so this gate deliberately keys off the release rather than off the presence of
|
|
1078
|
+
* the native sidebar service — the two are not the same fact.
|
|
1079
|
+
*/
|
|
1080
|
+
function suppressesBetterSidebar() {
|
|
1081
|
+
if (!resolved) return null;
|
|
1082
|
+
if (current.generation === "unknown") return false;
|
|
1083
|
+
return hostAtLeast("0.1.6");
|
|
1084
|
+
}
|
|
1085
|
+
//#endregion
|
|
974
1086
|
//#region src/client/rpc.ts
|
|
975
1087
|
const RPC_CHANNEL = "/dsh-any-background";
|
|
976
1088
|
/** Same-origin serve URL of the persisted video (enough for <video src>/fetch). */
|
|
@@ -1035,6 +1147,7 @@ window.__ModuleLoader__.load({
|
|
|
1035
1147
|
const data = await rpcCall("read", {});
|
|
1036
1148
|
if (data && typeof data === "object") {
|
|
1037
1149
|
const d = data;
|
|
1150
|
+
adoptHostInfo(d.host);
|
|
1038
1151
|
if (d.config) adoptConfig(d.config);
|
|
1039
1152
|
if (typeof d.wallpaperUrl === "string") setWpImageUrl(d.wallpaperUrl);
|
|
1040
1153
|
else if (d.wallpaperUrl === null) setWpImageUrl(null);
|
|
@@ -2711,6 +2824,7 @@ window.__ModuleLoader__.load({
|
|
|
2711
2824
|
lastBgKey = bgKey;
|
|
2712
2825
|
applyPartOpacities(ops);
|
|
2713
2826
|
}
|
|
2827
|
+
applyExemptDefaults();
|
|
2714
2828
|
} catch {}
|
|
2715
2829
|
}
|
|
2716
2830
|
const SETTINGS_PANEL_SEL = "[role=\"dialog\"][aria-modal=\"true\"][aria-labelledby]";
|
|
@@ -2729,17 +2843,98 @@ window.__ModuleLoader__.load({
|
|
|
2729
2843
|
if (px > 0) document.documentElement.style.setProperty("--dsh-any-part-blur-global", `blur(${px}px)`);
|
|
2730
2844
|
else document.documentElement.style.removeProperty("--dsh-any-part-blur-global");
|
|
2731
2845
|
}
|
|
2732
|
-
const PANEL_TOKEN_RULE = "[data-dsh-bottom-panel],[data-sidebar-right-panel]{--dsw-alias-bg-base:var(--dsh-any-panel-bg-base);--dsw-alias-bg-layer-1:var(--dsh-any-panel-layer-1);--dsw-alias-bg-layer-2:var(--dsh-any-panel-layer-2);--dsw-alias-bg-layer-3:var(--dsh-any-panel-layer-3)
|
|
2733
|
-
const
|
|
2734
|
-
const
|
|
2846
|
+
const PANEL_TOKEN_RULE = "[data-dsh-bottom-panel],[data-sidebar-right-panel]{--dsw-alias-bg-base:var(--dsh-any-panel-bg-base);--dsw-alias-bg-layer-1:var(--dsh-any-panel-layer-1);--dsw-alias-bg-layer-2:var(--dsh-any-panel-layer-2);--dsw-alias-bg-layer-3:var(--dsh-any-panel-layer-3)}";
|
|
2847
|
+
const NO_DOCKKIT = ":not(:has([data-dockkit-host],[data-dockkit-empty]))";
|
|
2848
|
+
const PANEL_BLUR_RULE = `[data-sidebar-right-panel] [data-dockkit-host="dock"],[data-sidebar-right-panel] [data-dockkit-empty]{-webkit-backdrop-filter:var(--dsh-any-blur-panel,none);backdrop-filter:var(--dsh-any-blur-panel,none)}[data-sidebar-right-panel]${NO_DOCKKIT}{-webkit-backdrop-filter:var(--dsh-any-blur-panel,none);backdrop-filter:var(--dsh-any-blur-panel,none)}[data-dsh-bottom-panel]{-webkit-backdrop-filter:var(--dsh-any-blur-panel,none);backdrop-filter:var(--dsh-any-blur-panel,none)}`;
|
|
2849
|
+
const PANEL_PROMOTION_RULE = `[data-sidebar-right-panel]${NO_DOCKKIT}{position:fixed!important;z-index:26!important}[data-sidebar-right-panel="fullscreen"]${NO_DOCKKIT}{z-index:40!important}`;
|
|
2850
|
+
const HEADER_POPOVER_RULE = "[data-dsh-any-header-popover][role],ul[class*=\"_menu\"],div[role=\"dialog\"][class*=\"_panel\"]:not([aria-modal=\"true\"]),[role=\"menu\"][class*=\"_denseList\"]:not([class*=\"_portal\"]),[role=\"tree\"][class*=\"_menu\"]{-webkit-backdrop-filter:var(--dsh-any-blur-header,none);backdrop-filter:var(--dsh-any-blur-header,none)}";
|
|
2851
|
+
const EXEMPT_DEFAULT_RULE = "[role=\"dialog\"][aria-modal=\"true\"]:not([aria-labelledby]){backdrop-filter:none;-webkit-backdrop-filter:none}[role=\"menu\"]:has([class*=\"_danger\"]){backdrop-filter:none;-webkit-backdrop-filter:none;-webkit-text-stroke-width:0}";
|
|
2852
|
+
/** Selector the dynamic header token rule targets — kept in sync with the
|
|
2853
|
+
* static HEADER_POPOVER_RULE selector list (specificity equal or higher than
|
|
2854
|
+
* the card group's `[role="menu"]:not(...)` so it wins). */
|
|
2855
|
+
const HEADER_TOKEN_SELECTOR = "[data-dsh-any-header-popover][role],ul[class*=\"_menu\"],div[role=\"dialog\"][class*=\"_panel\"]:not([aria-modal=\"true\"]),[role=\"menu\"][class*=\"_denseList\"]:not([class*=\"_portal\"]),[role=\"tree\"][class*=\"_menu\"]";
|
|
2856
|
+
/** Header-popover surfaces: retint the menu token and (re)write the blur.
|
|
2857
|
+
* Mirrors applyProduced: the static rule above never changes, so a drag only
|
|
2858
|
+
* rewrites the blur variable and this one dynamic rule. */
|
|
2859
|
+
function applyHeaderPopovers() {
|
|
2860
|
+
const root = document.documentElement;
|
|
2861
|
+
const px = rBlurs().header;
|
|
2862
|
+
if (px > 0) root.style.setProperty("--dsh-any-blur-header", `blur(${px}px)`);
|
|
2863
|
+
else root.style.removeProperty("--dsh-any-blur-header");
|
|
2864
|
+
let opacity = rHeaderOpacity();
|
|
2865
|
+
if (opacity < 0) opacity = 0;
|
|
2866
|
+
if (opacity > 1) opacity = 1;
|
|
2867
|
+
const menu = (paletteTokens() ?? readHostOpacityTokens())?.["--dsw-specific-menu"];
|
|
2868
|
+
const el = ensureHeaderStyle();
|
|
2869
|
+
const css = menu === void 0 ? "" : `${HEADER_TOKEN_SELECTOR}{--dsw-specific-menu:${toRgba(menu, opacity)}}`;
|
|
2870
|
+
if (el.textContent !== css) el.textContent = css;
|
|
2871
|
+
}
|
|
2872
|
+
let headerStyleEl = null;
|
|
2873
|
+
function ensureHeaderStyle() {
|
|
2874
|
+
if (headerStyleEl?.isConnected) return headerStyleEl;
|
|
2875
|
+
headerStyleEl = document.createElement("style");
|
|
2876
|
+
headerStyleEl.dataset.plugin = "dsh-any-background-header";
|
|
2877
|
+
document.head.appendChild(headerStyleEl);
|
|
2878
|
+
return headerStyleEl;
|
|
2879
|
+
}
|
|
2880
|
+
/** Pin the exempt groups (confirm dialogs and the session-row menu) so no
|
|
2881
|
+
* appearance slider moves them — while KEEPING the active theme color.
|
|
2882
|
+
*
|
|
2883
|
+
* "Default" here means "not faded, not blurred", NOT "host-palette original":
|
|
2884
|
+
* an earlier version restored the :root host colors, which also stripped the
|
|
2885
|
+
* picked theme color and made the menu look un-themed. The correct source is
|
|
2886
|
+
* the same one every other slider uses (the plugin palette when there is one,
|
|
2887
|
+
* else the host's resolved tokens) with alpha pinned to 1 — so the surface
|
|
2888
|
+
* keeps whatever color the theme currently dictates and only loses the slider's
|
|
2889
|
+
* translucency and blur.
|
|
2890
|
+
*
|
|
2891
|
+
* Emitted as REAL literals into a dedicated stylesheet, never as
|
|
2892
|
+
* `var(--x, var(--x))`: a self-referencing fallback is a CSS cycle that
|
|
2893
|
+
* computes to the guaranteed-invalid value and turns every consuming
|
|
2894
|
+
* `background:var(--dsw-alias-bg-layer-2)` fully transparent. Literals also
|
|
2895
|
+
* mean that when no color can be resolved we emit NO declaration at all, so
|
|
2896
|
+
* the surface keeps the re-scoped value rather than going transparent. */
|
|
2897
|
+
function applyExemptDefaults() {
|
|
2898
|
+
if (typeof document === "undefined") return;
|
|
2899
|
+
const source = paletteTokens() ?? readHostOpacityTokens();
|
|
2900
|
+
const el = ensureExemptStyle();
|
|
2901
|
+
const decls = [];
|
|
2902
|
+
const add = (token, value) => {
|
|
2903
|
+
if (value === void 0 || value === "") return;
|
|
2904
|
+
decls.push(`${token}:${toRgba(value, 1)}`);
|
|
2905
|
+
};
|
|
2906
|
+
add("--dsw-alias-bg-layer-1", source?.["--dsw-alias-bg-layer-1"]);
|
|
2907
|
+
add("--dsw-alias-bg-layer-2", source?.["--dsw-alias-bg-layer-2"]);
|
|
2908
|
+
add("--dsw-alias-bg-layer-3", source?.["--dsw-alias-bg-layer-3"]);
|
|
2909
|
+
add("--dsw-specific-menu", source?.["--dsw-specific-menu"]);
|
|
2910
|
+
if (decls.length === 0) {
|
|
2911
|
+
if (el.textContent !== "") el.textContent = "";
|
|
2912
|
+
return;
|
|
2913
|
+
}
|
|
2914
|
+
const dialog = "[role=\"dialog\"][aria-modal=\"true\"]:not([aria-labelledby])";
|
|
2915
|
+
const body = decls.join(";");
|
|
2916
|
+
const css = `${dialog},${dialog} *{${body}}[role="menu"]:has([class*="_danger"]){${body}}`;
|
|
2917
|
+
if (el.textContent !== css) el.textContent = css;
|
|
2918
|
+
}
|
|
2919
|
+
let exemptStyleEl = null;
|
|
2920
|
+
function ensureExemptStyle() {
|
|
2921
|
+
if (exemptStyleEl?.isConnected) return exemptStyleEl;
|
|
2922
|
+
exemptStyleEl = document.createElement("style");
|
|
2923
|
+
exemptStyleEl.dataset.plugin = "dsh-any-background-exempt";
|
|
2924
|
+
document.head.appendChild(exemptStyleEl);
|
|
2925
|
+
return exemptStyleEl;
|
|
2926
|
+
}
|
|
2927
|
+
const PRODUCED_RULE = "[data-code-block-content] pre,[data-code-block-banner],[data-composer-chip],[data-changed-files]>button:first-child,[data-terminal],[data-read],[data-context-injection-body],[data-search],[data-web],[class*=\"_ioCard\"]{-webkit-backdrop-filter:var(--dsh-any-blur-prod,none);backdrop-filter:var(--dsh-any-blur-prod,none)}@supports (background:color-mix(in srgb,red 50%,transparent)){.md-code-block{background:transparent!important}.md-code-block>div{background-color:transparent!important}.md-code-block [data-code-block-content] pre{background-color:color-mix(in srgb,var(--dsl-code-block-background,var(--dsw-alias-markdown-code-block,transparent)) var(--dsh-any-prod-pct,100%),transparent)!important}.md-code-block [data-code-block-banner]{background-color:color-mix(in srgb,var(--dsl-code-block-banner-background-color,var(--dsw-alias-markdown-code-block-banner,transparent)) var(--dsh-any-prod-pct,100%),transparent)!important}[data-code-block-content]{--shiki-background:color-mix(in srgb,var(--dsw-alias-markdown-code-block,var(--dsl-code-block-background,transparent)) var(--dsh-any-prod-pct,100%),transparent)}:not(pre)>code{background-color:color-mix(in srgb,var(--dsw-alias-markdown-inline-code,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}[data-composer-chip]>*{background-color:color-mix(in srgb,var(--dsw-alias-interactive-bg-hover,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}[data-terminal]{background-color:color-mix(in srgb,var(--dsw-alias-markdown-code-block,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}[data-terminal] button{background-color:transparent!important}[data-read]{background-color:color-mix(in srgb,var(--dsw-alias-markdown-code-block,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}[data-read]>div:first-child{background-color:color-mix(in srgb,var(--dsw-alias-markdown-code-block-banner,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}[data-context-injection-body]{background-color:color-mix(in srgb,var(--dsw-alias-markdown-code-block,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}[data-search]{background-color:color-mix(in srgb,var(--dsw-alias-markdown-code-block,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}[data-web]{background-color:color-mix(in srgb,var(--dsw-alias-markdown-code-block,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}[class*=\"_ioCard\"]{background-color:color-mix(in srgb,var(--dsw-alias-markdown-code-block,transparent) var(--dsh-any-prod-pct,100%),transparent)!important}}";
|
|
2735
2928
|
const STROKE_RULE = [
|
|
2736
2929
|
`${SETTINGS_PANEL_SEL}{-webkit-text-stroke:var(--dsh-any-stroke-settings-w,0px) var(--dsh-any-stroke-settings-c,transparent);paint-order:stroke fill}`,
|
|
2737
2930
|
"[role=\"menu\"]:not([data-dockkit-tab-menu]),[role=\"listbox\"],body>[role=\"tree\"],body>[role=\"dialog\"]:not([aria-modal=\"true\"]){-webkit-text-stroke:var(--dsh-any-stroke-card-w,0px) var(--dsh-any-stroke-card-c,transparent);paint-order:stroke fill}",
|
|
2738
2931
|
"[data-composer-card],[data-cordis-panel],[data-composer-card] textarea,[data-composer-card] input,[data-composer-card] [contenteditable],[data-cordis-panel] input,[data-cordis-panel] textarea{-webkit-text-stroke:var(--dsh-any-stroke-input-w,0px) var(--dsh-any-stroke-input-c,transparent);paint-order:stroke fill}",
|
|
2739
2932
|
`[data-chat-flow]{-webkit-text-stroke:var(--dsh-any-stroke-chat-w,0px) var(--dsh-any-stroke-chat-c,transparent);paint-order:stroke fill}`,
|
|
2740
2933
|
`[data-conversation-composer-overlay]{-webkit-text-stroke:var(--dsh-any-stroke-trajectory-w,0px) var(--dsh-any-stroke-trajectory-c,transparent);paint-order:stroke fill}`,
|
|
2741
|
-
"[data-code-block-content] pre,[data-code-block-content],[data-code-block-banner],[data-composer-chip],:not(pre)>code{-webkit-text-stroke:var(--dsh-any-stroke-produced-w,0px) var(--dsh-any-stroke-produced-c,transparent);paint-order:stroke fill}",
|
|
2934
|
+
"[data-code-block-content] pre,[data-code-block-content],[data-code-block-banner],[data-composer-chip],:not(pre)>code,[data-changed-files],[data-terminal],[data-read],[data-context-injection-body],[data-search],[data-web],[class*=\"_ioCard\"]{-webkit-text-stroke:var(--dsh-any-stroke-produced-w,0px) var(--dsh-any-stroke-produced-c,transparent);paint-order:stroke fill}",
|
|
2742
2935
|
`[data-dsh-bottom-panel],[data-sidebar-right-panel]{-webkit-text-stroke:var(--dsh-any-stroke-panel-w,0px) var(--dsh-any-stroke-panel-c,transparent);paint-order:stroke fill}`,
|
|
2936
|
+
"[data-dsh-any-header-popover],ul[class*=\"_menu\"],div[role=\"dialog\"][class*=\"_panel\"]:not([aria-modal=\"true\"]),[role=\"menu\"][class*=\"_denseList\"]:not([class*=\"_portal\"]),[role=\"tree\"][class*=\"_menu\"]{-webkit-text-stroke:var(--dsh-any-stroke-header-w,0px) var(--dsh-any-stroke-header-c,transparent);paint-order:stroke fill}",
|
|
2937
|
+
"[data-chat-flow] [role=\"status\"],[data-chat-flow] [data-turn-process],[data-chat-flow] [data-text-shimmer],[data-chat-flow] [style*=\"--dsh-text-shimmer-spread\"]{-webkit-text-stroke-width:0!important;paint-order:normal!important}",
|
|
2743
2938
|
`svg{-webkit-text-stroke-width:0!important;paint-order:normal!important}`,
|
|
2744
2939
|
`::placeholder{-webkit-text-stroke-width:0!important}`
|
|
2745
2940
|
].join("");
|
|
@@ -2753,7 +2948,8 @@ window.__ModuleLoader__.load({
|
|
|
2753
2948
|
"trajectory",
|
|
2754
2949
|
"input",
|
|
2755
2950
|
"panel",
|
|
2756
|
-
"produced"
|
|
2951
|
+
"produced",
|
|
2952
|
+
"header"
|
|
2757
2953
|
];
|
|
2758
2954
|
/** Resolve one group's stroke color key into a concrete CSS color.
|
|
2759
2955
|
* 'auto' contrasts the FONT direction (white fonts → black stroke and vice
|
|
@@ -3167,6 +3363,7 @@ window.__ModuleLoader__.load({
|
|
|
3167
3363
|
applyInputBlur(blurs.input);
|
|
3168
3364
|
applyPanelBlur(blurs.panel);
|
|
3169
3365
|
applyProduced();
|
|
3366
|
+
applyHeaderPopovers();
|
|
3170
3367
|
applyViewCards();
|
|
3171
3368
|
}
|
|
3172
3369
|
/** Produced/artifact surfaces (conversation code blocks + their banner +
|
|
@@ -3207,6 +3404,10 @@ window.__ModuleLoader__.load({
|
|
|
3207
3404
|
applyProduced();
|
|
3208
3405
|
return;
|
|
3209
3406
|
}
|
|
3407
|
+
if (part === "header") {
|
|
3408
|
+
applyHeaderPopovers();
|
|
3409
|
+
return;
|
|
3410
|
+
}
|
|
3210
3411
|
if (part === "chat" || part === "trajectory") {
|
|
3211
3412
|
applyViewCards();
|
|
3212
3413
|
return;
|
|
@@ -3808,6 +4009,9 @@ window.__ModuleLoader__.load({
|
|
|
3808
4009
|
applyTrajectoryOverrides(rTrajectoryOpacity());
|
|
3809
4010
|
}
|
|
3810
4011
|
applyPanelOverrides(rPanelOpacity());
|
|
4012
|
+
applyProduced();
|
|
4013
|
+
applyHeaderPopovers();
|
|
4014
|
+
applyExemptDefaults();
|
|
3811
4015
|
applyPartBlurs(rBlurs());
|
|
3812
4016
|
applyStrokes();
|
|
3813
4017
|
}
|
|
@@ -3844,6 +4048,11 @@ window.__ModuleLoader__.load({
|
|
|
3844
4048
|
document.documentElement.style.removeProperty("--dsh-any-blur-panel");
|
|
3845
4049
|
document.documentElement.style.removeProperty("--dsh-any-blur-prod");
|
|
3846
4050
|
document.documentElement.style.removeProperty("--dsh-any-prod-pct");
|
|
4051
|
+
document.documentElement.style.removeProperty("--dsh-any-blur-header");
|
|
4052
|
+
headerStyleEl?.remove();
|
|
4053
|
+
headerStyleEl = null;
|
|
4054
|
+
exemptStyleEl?.remove();
|
|
4055
|
+
exemptStyleEl = null;
|
|
3847
4056
|
for (const v of Object.values(OPACITY_VARS)) document.documentElement.style.removeProperty(v);
|
|
3848
4057
|
baseTokenKey = "";
|
|
3849
4058
|
lastBgKey = "";
|
|
@@ -5589,12 +5798,16 @@ window.__ModuleLoader__.load({
|
|
|
5589
5798
|
* signal and the body childList observer fires exactly when it appears. The
|
|
5590
5799
|
* panel surfaces we actually style are listed only as reinforcement: they are
|
|
5591
5800
|
* conditionally rendered (collapsed panels drop them), so they must never be
|
|
5592
|
-
* the sole signal.
|
|
5801
|
+
* the sole signal.
|
|
5802
|
+
*
|
|
5803
|
+
* `[data-sidebar-right-panel]` is deliberately ABSENT: on every host generation
|
|
5804
|
+
* it marks the host's own right Sidebar (always present once a session opens),
|
|
5805
|
+
* so counting it would make the better-sidebar verdict permanently true and the
|
|
5806
|
+
* panel slider could never drop back to its native "右方侧边栏" identity. */
|
|
5593
5807
|
const BETTER_SIDEBAR_MARKERS = [
|
|
5594
5808
|
"[data-dsh-better-sidebar]",
|
|
5595
5809
|
"[data-dsh-panel-host]",
|
|
5596
|
-
"[data-dsh-bottom-panel]"
|
|
5597
|
-
"[data-sidebar-right-panel]"
|
|
5810
|
+
"[data-dsh-bottom-panel]"
|
|
5598
5811
|
];
|
|
5599
5812
|
let betterSidebar = false;
|
|
5600
5813
|
const subs = /* @__PURE__ */ new Set();
|
|
@@ -5630,6 +5843,15 @@ window.__ModuleLoader__.load({
|
|
|
5630
5843
|
observer.observe(document.body, { childList: true });
|
|
5631
5844
|
return () => observer.disconnect();
|
|
5632
5845
|
}
|
|
5846
|
+
let nativeTabs = false;
|
|
5847
|
+
const nativeSubs = /* @__PURE__ */ new Set();
|
|
5848
|
+
/** Mark the native right-Sidebar service as confirmed. Sticky — the service
|
|
5849
|
+
* never goes away within a session. */
|
|
5850
|
+
function markNativeSidebarTabs() {
|
|
5851
|
+
if (nativeTabs) return;
|
|
5852
|
+
nativeTabs = true;
|
|
5853
|
+
nativeSubs.forEach((cb) => cb());
|
|
5854
|
+
}
|
|
5633
5855
|
//#endregion
|
|
5634
5856
|
//#region src/client/components/pages/InterfacePage.tsx
|
|
5635
5857
|
const PARTS$1 = [
|
|
@@ -5673,6 +5895,11 @@ window.__ModuleLoader__.load({
|
|
|
5673
5895
|
labelKey: "uiProduced",
|
|
5674
5896
|
Icon: TextIcon
|
|
5675
5897
|
},
|
|
5898
|
+
{
|
|
5899
|
+
isHeader: true,
|
|
5900
|
+
labelKey: "uiHeader",
|
|
5901
|
+
Icon: PanelIcon
|
|
5902
|
+
},
|
|
5676
5903
|
{
|
|
5677
5904
|
isPanel: true,
|
|
5678
5905
|
labelKey: "uiPanelRegion",
|
|
@@ -5683,7 +5910,6 @@ window.__ModuleLoader__.load({
|
|
|
5683
5910
|
const { t, setOps, setBlurs, setSop, setPanelOp, useStore } = p;
|
|
5684
5911
|
useStore((s) => s.metaRev);
|
|
5685
5912
|
const hasBetterSidebar = useBetterSidebar();
|
|
5686
|
-
const parts = PARTS$1.filter((part) => !(part.isPanel && !hasBetterSidebar));
|
|
5687
5913
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
5688
5914
|
className: "dab-head dab-rise",
|
|
5689
5915
|
style: { "--d": 0 },
|
|
@@ -5703,11 +5929,12 @@ window.__ModuleLoader__.load({
|
|
|
5703
5929
|
]
|
|
5704
5930
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5705
5931
|
className: "dab-grid-parts",
|
|
5706
|
-
children:
|
|
5707
|
-
const { labelKey, Icon, isSettings, isChat, isTrajectory, isPanel, isProduced } = part;
|
|
5932
|
+
children: PARTS$1.map((part, i) => {
|
|
5933
|
+
const { labelKey, Icon, isSettings, isChat, isTrajectory, isPanel, isProduced, isHeader } = part;
|
|
5708
5934
|
const opKey = part.opKey;
|
|
5709
|
-
const
|
|
5710
|
-
const
|
|
5935
|
+
const label = isPanel ? t(hasBetterSidebar ? "uiPanelRegion" : "uiPanelNative") : t(labelKey);
|
|
5936
|
+
const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isSettings ? "settings" : isPanel ? "panel" : isProduced ? "produced" : isHeader ? "header" : opKey;
|
|
5937
|
+
const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isSettings ? rSop() : isPanel ? rPanelOpacity() : isProduced ? rProducedOpacity() : isHeader ? rHeaderOpacity() : rOps()[opKey];
|
|
5711
5938
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
5712
5939
|
className: "dab-card dab-card-hover dab-rise",
|
|
5713
5940
|
style: { "--d": i + 1 },
|
|
@@ -5721,7 +5948,7 @@ window.__ModuleLoader__.load({
|
|
|
5721
5948
|
}),
|
|
5722
5949
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5723
5950
|
className: "dab-part-name",
|
|
5724
|
-
children:
|
|
5951
|
+
children: label
|
|
5725
5952
|
}),
|
|
5726
5953
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5727
5954
|
className: "dab-part-badge",
|
|
@@ -5753,6 +5980,9 @@ window.__ModuleLoader__.load({
|
|
|
5753
5980
|
} else if (isProduced) {
|
|
5754
5981
|
cfg.producedOpacity = op;
|
|
5755
5982
|
applyProduced();
|
|
5983
|
+
} else if (isHeader) {
|
|
5984
|
+
cfg.headerOpacity = op;
|
|
5985
|
+
applyHeaderPopovers();
|
|
5756
5986
|
} else {
|
|
5757
5987
|
const ops = { ...rOps() };
|
|
5758
5988
|
ops[opKey] = op;
|
|
@@ -5777,6 +6007,10 @@ window.__ModuleLoader__.load({
|
|
|
5777
6007
|
cfg.producedOpacity = op;
|
|
5778
6008
|
applyProduced();
|
|
5779
6009
|
saveConfig();
|
|
6010
|
+
} else if (isHeader) {
|
|
6011
|
+
cfg.headerOpacity = op;
|
|
6012
|
+
applyHeaderPopovers();
|
|
6013
|
+
saveConfig();
|
|
5780
6014
|
} else {
|
|
5781
6015
|
const ops = { ...rOps() };
|
|
5782
6016
|
ops[opKey] = op;
|
|
@@ -5852,6 +6086,11 @@ window.__ModuleLoader__.load({
|
|
|
5852
6086
|
labelKey: "uiProduced",
|
|
5853
6087
|
Icon: TextIcon
|
|
5854
6088
|
},
|
|
6089
|
+
{
|
|
6090
|
+
key: "header",
|
|
6091
|
+
labelKey: "uiHeader",
|
|
6092
|
+
Icon: PanelIcon
|
|
6093
|
+
},
|
|
5855
6094
|
{
|
|
5856
6095
|
key: "panel",
|
|
5857
6096
|
labelKey: "uiPanelRegion",
|
|
@@ -7224,7 +7463,8 @@ window.__ModuleLoader__.load({
|
|
|
7224
7463
|
trajectory: 0,
|
|
7225
7464
|
input: 0,
|
|
7226
7465
|
panel: 0,
|
|
7227
|
-
produced: 0
|
|
7466
|
+
produced: 0,
|
|
7467
|
+
header: 0
|
|
7228
7468
|
};
|
|
7229
7469
|
/** Presets ship with strokes off — text outlines are an opt-in look. Fresh
|
|
7230
7470
|
* objects per call so a profile restore can never alias another preset's
|
|
@@ -7244,7 +7484,8 @@ window.__ModuleLoader__.load({
|
|
|
7244
7484
|
trajectory: off(),
|
|
7245
7485
|
input: off(),
|
|
7246
7486
|
panel: off(),
|
|
7247
|
-
produced: off()
|
|
7487
|
+
produced: off(),
|
|
7488
|
+
header: off()
|
|
7248
7489
|
};
|
|
7249
7490
|
};
|
|
7250
7491
|
const BUILTIN_PRESETS = [
|
|
@@ -7266,7 +7507,8 @@ window.__ModuleLoader__.load({
|
|
|
7266
7507
|
chatTextOpacity: 0,
|
|
7267
7508
|
trajectoryOpacity: 1,
|
|
7268
7509
|
panelOpacity: 1,
|
|
7269
|
-
producedOpacity: 1
|
|
7510
|
+
producedOpacity: 1,
|
|
7511
|
+
headerOpacity: 1
|
|
7270
7512
|
}
|
|
7271
7513
|
},
|
|
7272
7514
|
{
|
|
@@ -7300,7 +7542,8 @@ window.__ModuleLoader__.load({
|
|
|
7300
7542
|
chatTextOpacity: 0,
|
|
7301
7543
|
trajectoryOpacity: .85,
|
|
7302
7544
|
panelOpacity: .85,
|
|
7303
|
-
producedOpacity: 1
|
|
7545
|
+
producedOpacity: 1,
|
|
7546
|
+
headerOpacity: 1
|
|
7304
7547
|
}
|
|
7305
7548
|
},
|
|
7306
7549
|
{
|
|
@@ -7321,7 +7564,8 @@ window.__ModuleLoader__.load({
|
|
|
7321
7564
|
chatTextOpacity: 0,
|
|
7322
7565
|
trajectoryOpacity: 1,
|
|
7323
7566
|
panelOpacity: 1,
|
|
7324
|
-
producedOpacity: 1
|
|
7567
|
+
producedOpacity: 1,
|
|
7568
|
+
headerOpacity: 1
|
|
7325
7569
|
}
|
|
7326
7570
|
},
|
|
7327
7571
|
{
|
|
@@ -7355,7 +7599,8 @@ window.__ModuleLoader__.load({
|
|
|
7355
7599
|
chatTextOpacity: 0,
|
|
7356
7600
|
trajectoryOpacity: .8,
|
|
7357
7601
|
panelOpacity: .8,
|
|
7358
|
-
producedOpacity: 1
|
|
7602
|
+
producedOpacity: 1,
|
|
7603
|
+
headerOpacity: 1
|
|
7359
7604
|
}
|
|
7360
7605
|
},
|
|
7361
7606
|
{
|
|
@@ -7389,7 +7634,8 @@ window.__ModuleLoader__.load({
|
|
|
7389
7634
|
chatTextOpacity: 0,
|
|
7390
7635
|
trajectoryOpacity: .78,
|
|
7391
7636
|
panelOpacity: .75,
|
|
7392
|
-
producedOpacity: 1
|
|
7637
|
+
producedOpacity: 1,
|
|
7638
|
+
headerOpacity: 1
|
|
7393
7639
|
}
|
|
7394
7640
|
},
|
|
7395
7641
|
{
|
|
@@ -7414,7 +7660,8 @@ window.__ModuleLoader__.load({
|
|
|
7414
7660
|
chatTextOpacity: 0,
|
|
7415
7661
|
trajectoryOpacity: 1,
|
|
7416
7662
|
panelOpacity: 1,
|
|
7417
|
-
producedOpacity: 1
|
|
7663
|
+
producedOpacity: 1,
|
|
7664
|
+
headerOpacity: 1
|
|
7418
7665
|
}
|
|
7419
7666
|
}
|
|
7420
7667
|
];
|
|
@@ -8027,6 +8274,9 @@ window.__ModuleLoader__.load({
|
|
|
8027
8274
|
const read = (0, react.useCallback)(() => locale.getSnapshot().active, [locale]);
|
|
8028
8275
|
return (0, react.useSyncExternalStore)(subscribe, read, read);
|
|
8029
8276
|
}
|
|
8277
|
+
/** Rendered inside a sidebar tab: the five pages, `surface: 'sidebar'` shell.
|
|
8278
|
+
* Shared by the better-sidebar page and the native right-Sidebar tab — both
|
|
8279
|
+
* hand a full-height column that owns its own scroll. */
|
|
8030
8280
|
function ThemeTab({ face, useStore, locale }) {
|
|
8031
8281
|
const active = useActiveLocale(locale);
|
|
8032
8282
|
const props = (0, react.useMemo)(() => ({
|
|
@@ -8067,22 +8317,258 @@ window.__ModuleLoader__.load({
|
|
|
8067
8317
|
ctx.inject?.(["betterSidebar"], (scope) => {
|
|
8068
8318
|
const service = scope.betterSidebar;
|
|
8069
8319
|
if (service === void 0) return;
|
|
8320
|
+
const suppress = suppressesBetterSidebar();
|
|
8321
|
+
if (suppress === true) return;
|
|
8322
|
+
let disposeTab = null;
|
|
8323
|
+
const unsubscribeHost = suppress === null ? subscribeHostInfo(() => {
|
|
8324
|
+
if (suppressesBetterSidebar() === true) {
|
|
8325
|
+
disposeTab?.();
|
|
8326
|
+
disposeTab = null;
|
|
8327
|
+
unsubscribeHost();
|
|
8328
|
+
}
|
|
8329
|
+
}) : () => {};
|
|
8070
8330
|
const face = opts.face();
|
|
8071
|
-
scope.effect(() =>
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8331
|
+
scope.effect(() => {
|
|
8332
|
+
disposeTab = service.registerTab({
|
|
8333
|
+
id: "dsh-any-background:theme",
|
|
8334
|
+
title: () => t("nav"),
|
|
8335
|
+
icon: (size) => (0, react.createElement)(SunIcon, { size }),
|
|
8336
|
+
order: ORDER,
|
|
8337
|
+
single: true,
|
|
8338
|
+
component: () => (0, react.createElement)(ThemeTab, {
|
|
8339
|
+
face,
|
|
8340
|
+
useStore,
|
|
8341
|
+
locale
|
|
8342
|
+
})
|
|
8343
|
+
}) ?? null;
|
|
8344
|
+
return () => {
|
|
8345
|
+
unsubscribeHost();
|
|
8346
|
+
disposeTab?.();
|
|
8347
|
+
disposeTab = null;
|
|
8348
|
+
};
|
|
8349
|
+
});
|
|
8083
8350
|
});
|
|
8084
8351
|
}
|
|
8085
8352
|
//#endregion
|
|
8353
|
+
//#region src/client/sidebar/native-tab.tsx
|
|
8354
|
+
/**
|
|
8355
|
+
* dsh-any-background — native right-Sidebar integration (DSH 0.1.6+).
|
|
8356
|
+
*
|
|
8357
|
+
* DSH 0.1.6 ships an official right Sidebar (`dsh-client-ui-sidebar-right`)
|
|
8358
|
+
* with a public two-stage extension path: a static tab type into
|
|
8359
|
+
* `ctx.sidebarRightTabs` — whose `guide` entry draws a card on the Sidebar's
|
|
8360
|
+
* guide page — and a body under the keyed `sidebar.right.pane.tab` seat. This
|
|
8361
|
+
* module registers the plugin's appearance pages through that path, so the
|
|
8362
|
+
* official Sidebar gains a "主题" card that opens the very same five pages the
|
|
8363
|
+
* settings panel shows (one implementation, one state store; editing in either
|
|
8364
|
+
* place shows up in the other).
|
|
8365
|
+
*
|
|
8366
|
+
* The dependency is optional at every level, mirroring `sidebar/tab.tsx`:
|
|
8367
|
+
* · the registry is waited on with `ctx.inject`, so a host without the
|
|
8368
|
+
* right Sidebar (or an older DSH) silently registers nothing, and a
|
|
8369
|
+
* Sidebar that initializes after this plugin still gets the card;
|
|
8370
|
+
* · the service shape is restated as a minimal local contract instead of
|
|
8371
|
+
* imported — a value import would be rejected by the host's client-bundle
|
|
8372
|
+
* purity gate, and even a type-only import would make the package a
|
|
8373
|
+
* build-time dependency for everyone who does not run it.
|
|
8374
|
+
*
|
|
8375
|
+
* When dsh-better-sidebar is installed it brings its own "主题" page (registered
|
|
8376
|
+
* by `sidebar/tab.tsx`), which would duplicate this card on the same guide
|
|
8377
|
+
* page. The native card therefore yields: it is not registered while
|
|
8378
|
+
* better-sidebar is detected, and it withdraws itself if better-sidebar mounts
|
|
8379
|
+
* later (the presence verdict is sticky-true, so no re-registration path is
|
|
8380
|
+
* needed). The Interface page's panel slider follows the same split:
|
|
8381
|
+
* "右方侧边栏" natively, "bettersidebar" when that plugin is present.
|
|
8382
|
+
*/
|
|
8383
|
+
/** The tab implementation's identity, and the key the body registers under. */
|
|
8384
|
+
const NATIVE_TAB_ID = "dsh-any-background:theme";
|
|
8385
|
+
/** The page kind: what `openTab` names and the guide entry opens. */
|
|
8386
|
+
const NATIVE_TAB_KIND = "danybg-theme";
|
|
8387
|
+
/**
|
|
8388
|
+
* Register the appearance pages with the native right Sidebar, if one exists.
|
|
8389
|
+
*
|
|
8390
|
+
* Call from the client `apply`. Both registrations sit inside the injected
|
|
8391
|
+
* scope's effects, so unloading the plugin (or HMR) withdraws them — without
|
|
8392
|
+
* that, the next activation would throw on the duplicate id.
|
|
8393
|
+
* @param ctx - client context.
|
|
8394
|
+
* @param opts.face - lazy accessor for the shared business face.
|
|
8395
|
+
* @param opts.store - the plugin's store instance, or null on a host where the
|
|
8396
|
+
* store module never resolved (in that case there is nothing to bind and no
|
|
8397
|
+
* page is registered).
|
|
8398
|
+
*/
|
|
8399
|
+
function registerNativeSidebarTab(ctx, opts) {
|
|
8400
|
+
const { store } = opts;
|
|
8401
|
+
if (store === null || typeof store.getSnapshot !== "function" || typeof store.subscribe !== "function") {
|
|
8402
|
+
console.warn("dsh-any-background: no observable store instance on this host; the native sidebar page stays unregistered");
|
|
8403
|
+
return;
|
|
8404
|
+
}
|
|
8405
|
+
const locale = ctx.locale;
|
|
8406
|
+
const t = locale.bind(NS);
|
|
8407
|
+
const useStore = createStoreHook(store);
|
|
8408
|
+
ctx.inject?.(["sidebarRightTabs"], (scope) => {
|
|
8409
|
+
const tabs = scope.sidebarRightTabs;
|
|
8410
|
+
if (tabs === void 0 || typeof tabs.register !== "function") return;
|
|
8411
|
+
markNativeSidebarTabs();
|
|
8412
|
+
const face = opts.face();
|
|
8413
|
+
const ThemeBody = () => (0, react.createElement)(ThemeTab, {
|
|
8414
|
+
face,
|
|
8415
|
+
useStore,
|
|
8416
|
+
locale
|
|
8417
|
+
});
|
|
8418
|
+
scope.effect(() => {
|
|
8419
|
+
const yieldTo = () => suppressesBetterSidebar() === false && rBetterSidebar();
|
|
8420
|
+
if (yieldTo()) return;
|
|
8421
|
+
let disposeTab = null;
|
|
8422
|
+
const withdraw = () => {
|
|
8423
|
+
disposeTab?.();
|
|
8424
|
+
disposeTab = null;
|
|
8425
|
+
};
|
|
8426
|
+
const unsubscribeBetter = subscribe(() => {
|
|
8427
|
+
if (yieldTo()) withdraw();
|
|
8428
|
+
});
|
|
8429
|
+
const unsubscribeHost = subscribeHostInfo(() => {
|
|
8430
|
+
if (yieldTo()) withdraw();
|
|
8431
|
+
});
|
|
8432
|
+
disposeTab = tabs.register({
|
|
8433
|
+
id: NATIVE_TAB_ID,
|
|
8434
|
+
kind: NATIVE_TAB_KIND,
|
|
8435
|
+
title: () => t("nav"),
|
|
8436
|
+
guide: [{
|
|
8437
|
+
id: "theme",
|
|
8438
|
+
order: 55,
|
|
8439
|
+
title: () => t("nav"),
|
|
8440
|
+
description: () => t("guideDesc"),
|
|
8441
|
+
icon: SunIcon
|
|
8442
|
+
}]
|
|
8443
|
+
});
|
|
8444
|
+
return () => {
|
|
8445
|
+
unsubscribeBetter();
|
|
8446
|
+
unsubscribeHost();
|
|
8447
|
+
withdraw();
|
|
8448
|
+
};
|
|
8449
|
+
}, "dsh-any-background: native sidebar theme tab");
|
|
8450
|
+
scope.effect(() => ctx.slots.inject("sidebar.right.pane.tab", () => ctx.slots.register({
|
|
8451
|
+
name: "sidebar.right.pane.tab",
|
|
8452
|
+
key: NATIVE_TAB_ID
|
|
8453
|
+
}, ThemeBody)), "dsh-any-background: native sidebar theme body");
|
|
8454
|
+
});
|
|
8455
|
+
}
|
|
8456
|
+
//#endregion
|
|
8457
|
+
//#region src/client/header-tag.ts
|
|
8458
|
+
/**
|
|
8459
|
+
* Header-surface tagging.
|
|
8460
|
+
*
|
|
8461
|
+
* WHY A RUNTIME TAG IS NEEDED
|
|
8462
|
+
* The session-header dropdowns (open-in-app, session-log, Agent Team, the job
|
|
8463
|
+
* list, the subagent lineage tree) render their popover through the Menu/tree
|
|
8464
|
+
* primitives, which PORTAL the list to `document.body`. A portaled list is not a
|
|
8465
|
+
* DOM descendant of the header — no ancestor selector can reach it — and the
|
|
8466
|
+
* primitive emits no `id`/`aria-controls` back-link to its anchor either. Pure
|
|
8467
|
+
* CSS class matching was the remaining option, but 0.1.7 broke the shapes this
|
|
8468
|
+
* plugin relied on: open-in-app moved from in-place to `portal` (so the old
|
|
8469
|
+
* `:not(_portal)` discriminator no longer selected it), and the session row menu
|
|
8470
|
+
* became a dynamic `sidebar.workspaces.session.menu.item` slot whose rows are no
|
|
8471
|
+
* longer guaranteed to include a destructive one.
|
|
8472
|
+
*
|
|
8473
|
+
* THE SIGNAL
|
|
8474
|
+
* The slot renderer stamps every registered slot with `data-slot="<key>"`
|
|
8475
|
+
* (ui-renderer `scoped-slots.tsx`), and the session header's own slots are
|
|
8476
|
+
* `conversation.session.header{,.actions,.utilities,.corner,.lineage}` — present
|
|
8477
|
+
* on 0.1.5 through 0.1.7 alike. Those anchors live in the header subtree, so the
|
|
8478
|
+
* plugin can detect when a header trigger is expanded.
|
|
8479
|
+
*
|
|
8480
|
+
* WHY NOT GEOMETRY
|
|
8481
|
+
* A tempting link is the inline position the primitive writes on a portaled list
|
|
8482
|
+
* (`style="left: …; top: …"`). It was tried and REJECTED: an `align="end"` list
|
|
8483
|
+
* is flush to the trigger's right edge while the trigger itself sits at the far
|
|
8484
|
+
* right of the header, so the two boxes often do not overlap horizontally (in
|
|
8485
|
+
* the reported DOM the list is at `left:1012` with the trigger near x=1400). Any
|
|
8486
|
+
* purely geometric proximity test therefore misses real header menus.
|
|
8487
|
+
*
|
|
8488
|
+
* THE ACTUAL RULE (structural, no geometry, no timing)
|
|
8489
|
+
* A header dropdown can only be open while its trigger reports
|
|
8490
|
+
* `aria-expanded="true"`, and opening one is what mounts the popover. So a
|
|
8491
|
+
* popover tag is maintained as: "there is at least one expanded header trigger,
|
|
8492
|
+
* AND this popover is not owned by another group". Popovers are only ever
|
|
8493
|
+
* tagged/released on a change of that combined state, which makes the tag
|
|
8494
|
+
* self-consistent and idempotent.
|
|
8495
|
+
*
|
|
8496
|
+
* The one hazard is a popover that is open for an unrelated reason (a composer
|
|
8497
|
+
* menu, a hover card) *while* a header trigger stays expanded. Such a popover
|
|
8498
|
+
* is not a candidate: it is excluded by `ownsForeignSurface`, which skips any
|
|
8499
|
+
* popover carrying markers of a different slider group. In practice header
|
|
8500
|
+
* dropdowns are transient (opening one closes the others), so this is a guard
|
|
8501
|
+
* rather than the common path.
|
|
8502
|
+
*
|
|
8503
|
+
* @module
|
|
8504
|
+
*/
|
|
8505
|
+
/** Marker attribute the stylesheet keys on. */
|
|
8506
|
+
const HEADER_POPOVER_ATTR = "data-dsh-any-header-popover";
|
|
8507
|
+
/** Slot anchors that identify the session header's own surfaces. */
|
|
8508
|
+
const HEADER_SLOT_SELECTOR = [
|
|
8509
|
+
"[data-slot=\"conversation.session.header\"]",
|
|
8510
|
+
"[data-slot=\"conversation.session.header.actions\"]",
|
|
8511
|
+
"[data-slot=\"conversation.session.header.utilities\"]",
|
|
8512
|
+
"[data-slot=\"conversation.session.header.corner\"]",
|
|
8513
|
+
"[data-slot=\"conversation.session.header.lineage\"]"
|
|
8514
|
+
].join(",");
|
|
8515
|
+
/** Portaled popovers a header trigger can own. */
|
|
8516
|
+
const POPOVER_SELECTOR = "[role=\"menu\"], [role=\"tree\"], [role=\"dialog\"]";
|
|
8517
|
+
/** Whether any header slot anchor has an expanded trigger. */
|
|
8518
|
+
function headerTriggerOpen() {
|
|
8519
|
+
for (const anchor of document.querySelectorAll(HEADER_SLOT_SELECTOR)) if (anchor.querySelector("[aria-expanded=\"true\"]") !== null) return true;
|
|
8520
|
+
return false;
|
|
8521
|
+
}
|
|
8522
|
+
/** Surfaces that belong to a different slider group and must never be claimed.
|
|
8523
|
+
* `_denseList` without `_portal` is the in-place card-side dense menu, an
|
|
8524
|
+
* `_ioCard`/`_menu`-classed body-level list belongs elsewhere, and a modal is
|
|
8525
|
+
* its own surface. */
|
|
8526
|
+
function ownsForeignSurface(el) {
|
|
8527
|
+
if (el.getAttribute("aria-modal") === "true") return true;
|
|
8528
|
+
return el.parentElement !== document.body;
|
|
8529
|
+
}
|
|
8530
|
+
let observer = null;
|
|
8531
|
+
let raf = null;
|
|
8532
|
+
/** Recompute tags from the current open state. */
|
|
8533
|
+
function refreshHeaderPopovers() {
|
|
8534
|
+
const open = headerTriggerOpen();
|
|
8535
|
+
const candidates = [...document.querySelectorAll(POPOVER_SELECTOR)].filter((el) => !ownsForeignSurface(el));
|
|
8536
|
+
if (!open) {
|
|
8537
|
+
for (const el of document.querySelectorAll(`[${HEADER_POPOVER_ATTR}]`)) el.removeAttribute(HEADER_POPOVER_ATTR);
|
|
8538
|
+
return;
|
|
8539
|
+
}
|
|
8540
|
+
for (const el of candidates) el.setAttribute(HEADER_POPOVER_ATTR, "");
|
|
8541
|
+
for (const el of document.querySelectorAll(`[${HEADER_POPOVER_ATTR}]`)) if (!candidates.includes(el)) el.removeAttribute(HEADER_POPOVER_ATTR);
|
|
8542
|
+
}
|
|
8543
|
+
function schedule() {
|
|
8544
|
+
if (raf !== null) return;
|
|
8545
|
+
raf = window.requestAnimationFrame(() => {
|
|
8546
|
+
raf = null;
|
|
8547
|
+
refreshHeaderPopovers();
|
|
8548
|
+
});
|
|
8549
|
+
}
|
|
8550
|
+
/** Start tagging. Returns a teardown that stops observing and clears markings. */
|
|
8551
|
+
function startHeaderPopoverTagging() {
|
|
8552
|
+
if (typeof MutationObserver === "undefined" || typeof document === "undefined") return () => {};
|
|
8553
|
+
refreshHeaderPopovers();
|
|
8554
|
+
observer = new MutationObserver(schedule);
|
|
8555
|
+
observer.observe(document.body, {
|
|
8556
|
+
childList: true,
|
|
8557
|
+
subtree: true,
|
|
8558
|
+
attributes: true,
|
|
8559
|
+
attributeFilter: ["aria-expanded"]
|
|
8560
|
+
});
|
|
8561
|
+
return () => {
|
|
8562
|
+
observer?.disconnect();
|
|
8563
|
+
observer = null;
|
|
8564
|
+
if (raf !== null) {
|
|
8565
|
+
window.cancelAnimationFrame(raf);
|
|
8566
|
+
raf = null;
|
|
8567
|
+
}
|
|
8568
|
+
for (const el of document.querySelectorAll(`[${HEADER_POPOVER_ATTR}]`)) el.removeAttribute(HEADER_POPOVER_ATTR);
|
|
8569
|
+
};
|
|
8570
|
+
}
|
|
8571
|
+
//#endregion
|
|
8086
8572
|
//#region src/client/index.tsx
|
|
8087
8573
|
/**
|
|
8088
8574
|
* dsh-any-background — browser half entry.
|
|
@@ -8183,7 +8669,7 @@ window.__ModuleLoader__.load({
|
|
|
8183
8669
|
}, "dsh-any-background: skin dispose");
|
|
8184
8670
|
const styleEl = document.createElement("style");
|
|
8185
8671
|
styleEl.dataset.plugin = "dsh-any-background";
|
|
8186
|
-
styleEl.textContent = `body[data-ds-dark-theme="dsh-any-background"]::before{content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;background:radial-gradient(ellipse 80% 60% at 50% 0%,rgba(255,255,255,0.03) 0%,transparent 60%)}${SETTINGS_STYLE_RULE}${POPOVER_BLUR_RULE}${TRAJECTORY_STYLE_RULE}${INPUT_BLUR_RULE}${MOBILE_HEADER_RULE}${PANEL_TOKEN_RULE}${PANEL_BLUR_RULE}${PRODUCED_RULE}${STROKE_RULE}[data-composer-card] textarea::placeholder,[data-composer-card] input::placeholder,[data-composer-card] [contenteditable]::placeholder,[data-cordis-panel] input::placeholder,[data-cordis-panel] textarea::placeholder,.dab-input::placeholder,.dab-input textarea::placeholder,.dab-input input::placeholder{color:var(--dsh-any-placeholder,var(--dsw-alias-label-caption,#8a8f98))!important;font-style:italic;opacity:.85}`;
|
|
8672
|
+
styleEl.textContent = `body[data-ds-dark-theme="dsh-any-background"]::before{content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;background:radial-gradient(ellipse 80% 60% at 50% 0%,rgba(255,255,255,0.03) 0%,transparent 60%)}${SETTINGS_STYLE_RULE}${POPOVER_BLUR_RULE}${TRAJECTORY_STYLE_RULE}${INPUT_BLUR_RULE}${MOBILE_HEADER_RULE}${PANEL_TOKEN_RULE}${PANEL_PROMOTION_RULE}${PANEL_BLUR_RULE}${PRODUCED_RULE}${STROKE_RULE}${HEADER_POPOVER_RULE}${EXEMPT_DEFAULT_RULE}[data-composer-card] textarea::placeholder,[data-composer-card] input::placeholder,[data-composer-card] [contenteditable]::placeholder,[data-cordis-panel] input::placeholder,[data-cordis-panel] textarea::placeholder,.dab-input::placeholder,.dab-input textarea::placeholder,.dab-input input::placeholder{color:var(--dsh-any-placeholder,var(--dsw-alias-label-caption,#8a8f98))!important;font-style:italic;opacity:.85}`;
|
|
8187
8673
|
document.head.appendChild(styleEl);
|
|
8188
8674
|
ctx.effect(() => () => {
|
|
8189
8675
|
styleEl?.parentNode?.removeChild(styleEl);
|
|
@@ -8461,6 +8947,7 @@ window.__ModuleLoader__.load({
|
|
|
8461
8947
|
teardownWp();
|
|
8462
8948
|
}, "dsh-any-background: wp cleanup");
|
|
8463
8949
|
ctx.effect(() => startBetterSidebarWatch(), "dsh-any-background: better-sidebar watch");
|
|
8950
|
+
ctx.effect(() => startHeaderPopoverTagging(), "dsh-any-background: header popover tagging");
|
|
8464
8951
|
ctx.effect(() => ctx.on("theme/change", () => {
|
|
8465
8952
|
if (rHasColor() || rBgDark() !== null || rSchemeOverride() !== "auto") {
|
|
8466
8953
|
const snapshot = ctx.theme.getTheme();
|
|
@@ -8953,6 +9440,10 @@ window.__ModuleLoader__.load({
|
|
|
8953
9440
|
face: buildFace,
|
|
8954
9441
|
store: storeInstance
|
|
8955
9442
|
});
|
|
9443
|
+
registerNativeSidebarTab(ctx, {
|
|
9444
|
+
face: buildFace,
|
|
9445
|
+
store: storeInstance
|
|
9446
|
+
});
|
|
8956
9447
|
const navLabel = () => ctx.locale.bind(NS)("nav");
|
|
8957
9448
|
const applyNavIcon = () => {
|
|
8958
9449
|
const nav = document.querySelector("[role=\"dialog\"][aria-modal=\"true\"][aria-labelledby]")?.querySelector("nav");
|