@iasiv5/dsh-skins 1.5.19 → 1.5.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +82 -3
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -413,6 +413,9 @@
|
|
|
413
413
|
const [r, g, b, a] = channels;
|
|
414
414
|
return { r, g, b, a: Math.min(1, Math.max(0, a)) };
|
|
415
415
|
}
|
|
416
|
+
function sidebarPaintOrderCss(bodyAttribute) {
|
|
417
|
+
return `body[${datasetAttribute(bodyAttribute)}] [class*="_sidebarCol"]{position:relative;z-index:1}`;
|
|
418
|
+
}
|
|
416
419
|
function buildShellAlignmentCss(bodyAttribute, opaqueFills, backdrop) {
|
|
417
420
|
const body = `body[${datasetAttribute(bodyAttribute)}]`;
|
|
418
421
|
const scoped = `html[data-windows-titlebar] ${body}`;
|
|
@@ -450,14 +453,26 @@
|
|
|
450
453
|
if (opaqueFills === null) return "";
|
|
451
454
|
const body = `body[${datasetAttribute(bodyAttribute)}]`;
|
|
452
455
|
const column = ' [data-rightbar-fullscreen] [class*="_rightbarCol"]';
|
|
453
|
-
const
|
|
454
|
-
const
|
|
456
|
+
const emptyPaneGuard = ':not(:has([class*="_paneBody"] > [class*="_empty"]))';
|
|
457
|
+
const openGate = '[data-sidebar-right-open="true"]';
|
|
458
|
+
const dockPanel = ` [data-sidebar-right-panel="fullscreen"]${openGate}${emptyPaneGuard}`;
|
|
459
|
+
const dockPane = ` [data-sidebar-right-panel="fullscreen"]${openGate} [data-dockkit-pane]${emptyPaneGuard}`;
|
|
455
460
|
return [
|
|
456
|
-
"/* dsh-skins fullscreen base (ADR-0020): solid skin-tone base while data-rightbar-fullscreen is set — the fullscreen dockkit PANE paints a translucent bg token where the official theme paints opaque white (DOM-dump evidence), so the pane is the bleed surface; solid matches the official look. Docked column untouched */",
|
|
461
|
+
"/* dsh-skins fullscreen base (ADR-0020): solid skin-tone base while data-rightbar-fullscreen is set — the fullscreen dockkit PANE paints a translucent bg token where the official theme paints opaque white (DOM-dump evidence), so the pane is the bleed surface; solid matches the official look. Docked column untouched. Sheet rules gated on data-sidebar-right-open (stale-fullscreen collapse, ADR-0021 amendment 四) */",
|
|
457
462
|
`${body}${column},${body}${dockPanel},${body}${dockPane}{background-color:${opaqueFills.light}!important}`,
|
|
458
463
|
`${body}[data-ds-dark-theme]${column},${body}[data-ds-dark-theme]${dockPanel},${body}[data-ds-dark-theme]${dockPane}{background-color:${opaqueFills.dark}!important}`
|
|
459
464
|
].join("\n");
|
|
460
465
|
}
|
|
466
|
+
function buildReadingBaseCss(bodyAttribute, opaqueFills) {
|
|
467
|
+
if (opaqueFills === null) return "";
|
|
468
|
+
const body = `body[${datasetAttribute(bodyAttribute)}]`;
|
|
469
|
+
const panel = ' [data-plugin-panel="true"]';
|
|
470
|
+
return [
|
|
471
|
+
"/* dsh-skins reading base (ADR-0022): solid skin-tone base under the plugin panel route container — the live page paints the whole route transparent over the wallpaper while the official theme paints an opaque bg token (DOM-dump evidence 2026-10-30), so text sits on a translucent token x wallpaper composite; solid matches the official look. Element-bound: the route leaves the DOM with the page, no state gate needed. Layer pin per ADR-0021 amendment doctrine (large-area cover rules always carry the pin). */",
|
|
472
|
+
`${body}${panel}{position:relative;z-index:0;background-color:${opaqueFills.light}!important}`,
|
|
473
|
+
`${body}[data-ds-dark-theme]${panel}{position:relative;z-index:0;background-color:${opaqueFills.dark}!important}`
|
|
474
|
+
].join("\n");
|
|
475
|
+
}
|
|
461
476
|
var PRODUCTION_FIELDS = /* @__PURE__ */ new Set([
|
|
462
477
|
"id",
|
|
463
478
|
"label",
|
|
@@ -638,6 +653,54 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
638
653
|
return () => {
|
|
639
654
|
};
|
|
640
655
|
}
|
|
656
|
+
function refreshSkinStyleTags() {
|
|
657
|
+
if (typeof requestAnimationFrame !== "function" || typeof document === "undefined" || document.head?.querySelectorAll === void 0) return;
|
|
658
|
+
const tags = [...document.head.querySelectorAll('style[data-plugin-css^="dsh-skins/"]')];
|
|
659
|
+
if (tags.length === 0) return;
|
|
660
|
+
const saved = tags.map((tag) => ({ id: tag.dataset.pluginCss, content: tag.textContent }));
|
|
661
|
+
for (const tag of tags) tag.remove();
|
|
662
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
663
|
+
for (const { id, content } of saved) {
|
|
664
|
+
if (document.querySelector(`style[data-plugin-css="${id}"]`) !== null) continue;
|
|
665
|
+
const fresh = document.createElement("style");
|
|
666
|
+
fresh.dataset.plugin = "dsh-skins";
|
|
667
|
+
fresh.dataset.pluginCss = id;
|
|
668
|
+
fresh.textContent = content;
|
|
669
|
+
document.head.append(fresh);
|
|
670
|
+
}
|
|
671
|
+
}));
|
|
672
|
+
}
|
|
673
|
+
let rightPanelRepaintHookInstalled = false;
|
|
674
|
+
function installRightPanelRepaintHook() {
|
|
675
|
+
if (rightPanelRepaintHookInstalled || typeof MutationObserver !== "function") return;
|
|
676
|
+
if (typeof document === "undefined" || document.body === void 0 || document.body === null) return;
|
|
677
|
+
rightPanelRepaintHookInstalled = true;
|
|
678
|
+
const observer = new MutationObserver((records) => {
|
|
679
|
+
for (const record of records ?? []) {
|
|
680
|
+
const before = record.oldValue;
|
|
681
|
+
const after = record.target.getAttribute?.("data-sidebar-right-panel");
|
|
682
|
+
if (before !== "fullscreen" || after === "fullscreen") continue;
|
|
683
|
+
const tag = document.querySelector('style[data-plugin-css$=".fullscreen.css"]');
|
|
684
|
+
if (tag === null) continue;
|
|
685
|
+
const id = tag.dataset.pluginCss;
|
|
686
|
+
const content = tag.textContent;
|
|
687
|
+
tag.remove();
|
|
688
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
689
|
+
const fresh = document.createElement("style");
|
|
690
|
+
fresh.dataset.plugin = "dsh-skins";
|
|
691
|
+
fresh.dataset.pluginCss = id;
|
|
692
|
+
fresh.textContent = content;
|
|
693
|
+
document.head.append(fresh);
|
|
694
|
+
}));
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
observer.observe(document.body, {
|
|
698
|
+
subtree: true,
|
|
699
|
+
attributes: true,
|
|
700
|
+
attributeFilter: ["data-sidebar-right-panel"],
|
|
701
|
+
attributeOldValue: true
|
|
702
|
+
});
|
|
703
|
+
}
|
|
641
704
|
function buildEffects(skin, effects) {
|
|
642
705
|
if (!ctx) throw new Error("[dsh-skins] mount before apply");
|
|
643
706
|
const body = document.body;
|
|
@@ -688,6 +751,13 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
688
751
|
const tag = styleTag(`dsh-skins/${skin.id}.css`, effects.staticCss);
|
|
689
752
|
stops.push(() => tag.remove());
|
|
690
753
|
}
|
|
754
|
+
{
|
|
755
|
+
const tag = styleTag(
|
|
756
|
+
`dsh-skins/${skin.id}.paintorder.css`,
|
|
757
|
+
sidebarPaintOrderCss(effects.bodyAttribute)
|
|
758
|
+
);
|
|
759
|
+
stops.push(() => tag.remove());
|
|
760
|
+
}
|
|
691
761
|
{
|
|
692
762
|
const fills = effects.tokenOverrides?.["--dsw-specific-sidebar-fill"] ?? null;
|
|
693
763
|
const lightFill = fills === null ? null : parseRgbaChannels(fills.light);
|
|
@@ -710,6 +780,11 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
710
780
|
const fullscreenTag = styleTag(`dsh-skins/${skin.id}.fullscreen.css`, fullscreenCss);
|
|
711
781
|
stops.push(() => fullscreenTag.remove());
|
|
712
782
|
}
|
|
783
|
+
const readingCss = buildReadingBaseCss(effects.bodyAttribute, opaqueFills);
|
|
784
|
+
if (readingCss !== "") {
|
|
785
|
+
const readingTag = styleTag(`dsh-skins/${skin.id}.reading.css`, readingCss);
|
|
786
|
+
stops.push(() => readingTag.remove());
|
|
787
|
+
}
|
|
713
788
|
}
|
|
714
789
|
const backdrop = backdropCss(effects);
|
|
715
790
|
if (backdrop !== null) {
|
|
@@ -801,6 +876,8 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
801
876
|
mounted = { skin, effects, overrides, stop };
|
|
802
877
|
selectedId = skin.id;
|
|
803
878
|
announce(skin.id);
|
|
879
|
+
installRightPanelRepaintHook();
|
|
880
|
+
if (previous !== null) refreshSkinStyleTags();
|
|
804
881
|
return true;
|
|
805
882
|
}
|
|
806
883
|
function restorePrevious(previous, cause) {
|
|
@@ -2024,6 +2101,8 @@ ${references.join("\n")}`,
|
|
|
2024
2101
|
type: "button",
|
|
2025
2102
|
role: "menuitemradio",
|
|
2026
2103
|
"aria-checked": activeId === skin.id,
|
|
2104
|
+
"data-skin-id": skin.id,
|
|
2105
|
+
// ADR-0021/R21: stable hook for tests and headless verification — never match on localized labels
|
|
2027
2106
|
className: `dsh-skins-pop-card${activeId === skin.id ? " dsh-skins-pop-card-on" : ""}`,
|
|
2028
2107
|
onClick: () => {
|
|
2029
2108
|
if (personalizeId !== null && personalizeId !== skin.id) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@iasiv5/dsh-skins",
|
|
3
3
|
"description": "DSH Web 皮肤插件:多套品牌皮肤侧栏热切换。",
|
|
4
4
|
"icon": "./icon.svg",
|
|
5
|
-
"version": "1.5.
|
|
5
|
+
"version": "1.5.21",
|
|
6
6
|
"homepage": "https://github.com/iasiv5/dsh-skins#readme",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"build": "node scripts/build-client.mjs",
|
|
83
83
|
"watch": "node scripts/build-client.mjs --watch",
|
|
84
84
|
"check:lockfile": "pnpm install --frozen-lockfile",
|
|
85
|
-
"test": "pnpm run build && node smoke-test.cjs && node --test tests/*.test.mjs",
|
|
85
|
+
"test": "pnpm run build && node smoke-test.cjs && node scripts/repro-stale-grid-paint.mjs --gate && node scripts/repro-fullscreen-collapse.mjs --gate && node scripts/repro-plugin-panel-readability.mjs --gate && node --test tests/*.test.mjs",
|
|
86
86
|
"verify:readme": "node scripts/verify-readme-pairing.mjs",
|
|
87
87
|
"verify:bundle": "node scripts/verify-bundle-guard.mjs",
|
|
88
88
|
"verify:hooks": "node scripts/verify-upstream-hooks.mjs",
|