dsh-any-background 0.2.6 → 0.2.7

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 CHANGED
@@ -44,6 +44,8 @@ window.__ModuleLoader__.load({
44
44
  uiSop: "设置界面透明度",
45
45
  uiChatRegion: "对话文本框",
46
46
  uiTrajectory: "轨迹页",
47
+ uiPanelRegion: "better-sidebar 工作台",
48
+ uiProduced: "产出物/高亮内容",
47
49
  bgTitle: "背景",
48
50
  bgChoose: "选择图片或视频",
49
51
  bgRemove: "移除背景",
@@ -207,6 +209,8 @@ window.__ModuleLoader__.load({
207
209
  uiSop: "Settings interface opacity",
208
210
  uiChatRegion: "Conversation text frame",
209
211
  uiTrajectory: "Trajectory view",
212
+ uiPanelRegion: "better-sidebar workbench",
213
+ uiProduced: "Produced / highlights",
210
214
  bgTitle: "Background",
211
215
  bgChoose: "Choose image or video",
212
216
  bgRemove: "Remove background",
@@ -361,7 +365,9 @@ window.__ModuleLoader__.load({
361
365
  settings: 0,
362
366
  chat: 0,
363
367
  trajectory: 0,
364
- input: 0
368
+ input: 0,
369
+ panel: 0,
370
+ produced: 0
365
371
  },
366
372
  settingsOpacity: 1,
367
373
  wallpaperOpacity: 1,
@@ -387,6 +393,8 @@ window.__ModuleLoader__.load({
387
393
  regenerateOnReload: false,
388
394
  chatTextOpacity: 0,
389
395
  trajectoryOpacity: 1,
396
+ panelOpacity: 1,
397
+ producedOpacity: 1,
390
398
  profiles: [],
391
399
  rotation: {
392
400
  enabled: false,
@@ -523,7 +531,9 @@ window.__ModuleLoader__.load({
523
531
  "settings",
524
532
  "chat",
525
533
  "trajectory",
526
- "input"
534
+ "input",
535
+ "panel",
536
+ "produced"
527
537
  ]) {
528
538
  const v = b[k];
529
539
  out[k] = typeof v === "number" ? Math.min(60, Math.max(0, v)) : DEFAULT_CONFIG.blurs[k];
@@ -539,6 +549,12 @@ window.__ModuleLoader__.load({
539
549
  function rSop() {
540
550
  return clamp01(cfg.settingsOpacity, DEFAULT_CONFIG.settingsOpacity);
541
551
  }
552
+ function rPanelOpacity() {
553
+ return clamp01(cfg.panelOpacity, DEFAULT_CONFIG.panelOpacity);
554
+ }
555
+ function rProducedOpacity() {
556
+ return clamp01(cfg.producedOpacity, DEFAULT_CONFIG.producedOpacity);
557
+ }
542
558
  function rBgState() {
543
559
  return cfg.bgState;
544
560
  }
@@ -599,7 +615,9 @@ window.__ModuleLoader__.load({
599
615
  wallpaperOpacity: rWop(),
600
616
  blur: rBl(),
601
617
  chatTextOpacity: rChatTextOpacity(),
602
- trajectoryOpacity: rTrajectoryOpacity()
618
+ trajectoryOpacity: rTrajectoryOpacity(),
619
+ panelOpacity: rPanelOpacity(),
620
+ producedOpacity: rProducedOpacity()
603
621
  };
604
622
  }
605
623
  /** Apply an appearance snapshot onto cfg (meta fields untouched). */
@@ -618,6 +636,8 @@ window.__ModuleLoader__.load({
618
636
  cfg.blur = typeof ap.blur === "number" ? Math.min(60, Math.max(0, ap.blur)) : DEFAULT_CONFIG.blur;
619
637
  cfg.chatTextOpacity = clamp01(ap.chatTextOpacity, DEFAULT_CONFIG.chatTextOpacity);
620
638
  cfg.trajectoryOpacity = clamp01(ap.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity);
639
+ cfg.panelOpacity = clamp01(ap.panelOpacity, DEFAULT_CONFIG.panelOpacity);
640
+ cfg.producedOpacity = clamp01(ap.producedOpacity, DEFAULT_CONFIG.producedOpacity);
621
641
  }
622
642
  const num = (n, def) => typeof n === "number" ? n : def;
623
643
  const cl = (n, lo, hi, def) => typeof n === "number" ? Math.min(hi, Math.max(lo, n)) : def;
@@ -648,7 +668,9 @@ window.__ModuleLoader__.load({
648
668
  wallpaperOpacity: clamp01(ac.wallpaperOpacity, DEFAULT_CONFIG.wallpaperOpacity),
649
669
  blur: num(ac.blur, DEFAULT_CONFIG.blur),
650
670
  chatTextOpacity: clamp01(ac.chatTextOpacity, DEFAULT_CONFIG.chatTextOpacity),
651
- trajectoryOpacity: clamp01(ac.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity)
671
+ trajectoryOpacity: clamp01(ac.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity),
672
+ panelOpacity: clamp01(ac.panelOpacity, DEFAULT_CONFIG.panelOpacity),
673
+ producedOpacity: clamp01(ac.producedOpacity, DEFAULT_CONFIG.producedOpacity)
652
674
  }
653
675
  });
654
676
  }
@@ -711,7 +733,9 @@ window.__ModuleLoader__.load({
711
733
  "settings",
712
734
  "chat",
713
735
  "trajectory",
714
- "input"
736
+ "input",
737
+ "panel",
738
+ "produced"
715
739
  ]) blurs[k] = num(bl[k], DEFAULT_CONFIG.blurs[k]);
716
740
  const bgType = [
717
741
  "video",
@@ -749,6 +773,8 @@ window.__ModuleLoader__.load({
749
773
  regenerateOnReload: typeof c.regenerateOnReload === "boolean" ? c.regenerateOnReload : DEFAULT_CONFIG.regenerateOnReload,
750
774
  chatTextOpacity: clamp01(c.chatTextOpacity, DEFAULT_CONFIG.chatTextOpacity),
751
775
  trajectoryOpacity: clamp01(c.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity),
776
+ panelOpacity: clamp01(c.panelOpacity, DEFAULT_CONFIG.panelOpacity),
777
+ producedOpacity: clamp01(c.producedOpacity, DEFAULT_CONFIG.producedOpacity),
752
778
  profiles: adoptProfiles(c.profiles),
753
779
  rotation: adoptRotation(c.rotation),
754
780
  schedule: adoptSchedule(c.schedule),
@@ -2418,7 +2444,8 @@ window.__ModuleLoader__.load({
2418
2444
  }
2419
2445
  const SETTINGS_PANEL_SEL = "[role=\"dialog\"][aria-modal=\"true\"][aria-labelledby]";
2420
2446
  const SETTINGS_STYLE_RULE = `${SETTINGS_PANEL_SEL}{background:var(--dsh-any-bg-settings-surface,var(--dsw-alias-bg-layer-2));backdrop-filter:var(--dsh-any-blur-settings,none);--dsw-alias-bg-layer-1:var(--dsh-any-bg-settings-layer-1);--dsw-alias-bg-layer-2:var(--dsh-any-bg-settings-layer-2);--dsw-alias-bg-layer-3:var(--dsh-any-bg-settings-layer-3)}${SETTINGS_PANEL_SEL} .dab-card{backdrop-filter:var(--dsh-any-blur-card-panels,none);-webkit-backdrop-filter:var(--dsh-any-blur-card-panels,none)}`;
2421
- const INPUT_BLUR_RULE = "[data-composer-card],[data-cordis-panel]{-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}[data-cordis-panel]{--dsw-specific-menu:var(--dsh-any-op-menu-cordis)!important}";
2447
+ const POPOVER_BLUR_RULE = "[role=\"menu\"]:not([data-dockkit-tab-menu]),[role=\"listbox\"],body > [role=\"tree\"],body > [role=\"dialog\"]:not([aria-modal=\"true\"]){backdrop-filter:var(--dsh-any-blur-card-panels,none);-webkit-backdrop-filter:var(--dsh-any-blur-card-panels,none)}";
2448
+ const INPUT_BLUR_RULE = "[data-composer-card]{position:relative;isolation:isolate}[data-composer-card]::before{content:\"\";position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}[data-cordis-panel]{-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}[data-cordis-panel]{--dsw-specific-menu:var(--dsh-any-op-menu-cordis)!important}";
2422
2449
  function applyInputBlur(px) {
2423
2450
  if (px > 0) document.documentElement.style.setProperty("--dsh-any-input-blur", `blur(${px}px)`);
2424
2451
  else document.documentElement.style.removeProperty("--dsh-any-input-blur");
@@ -2431,6 +2458,63 @@ window.__ModuleLoader__.load({
2431
2458
  if (px > 0) document.documentElement.style.setProperty("--dsh-any-part-blur-global", `blur(${px}px)`);
2432
2459
  else document.documentElement.style.removeProperty("--dsh-any-part-blur-global");
2433
2460
  }
2461
+ 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);position:fixed!important;z-index:26!important}[data-sidebar-right-panel][data-sidebar-right-panel=\"fullscreen\"]{z-index:40!important}";
2462
+ const PANEL_BLUR_RULE = "[data-dsh-bottom-panel],[data-sidebar-right-panel]{-webkit-backdrop-filter:var(--dsh-any-blur-panel,none);backdrop-filter:var(--dsh-any-blur-panel,none)}";
2463
+ const PRODUCED_RULE = "[data-code-block-content] pre,[data-code-block-banner],[data-composer-chip],:not(pre)>code{-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}}";
2464
+ /** The host's own default colors for the panel layer tokens, used when the
2465
+ * plugin has no palette (no picked color, no wallpaper verdict, no forced
2466
+ * scheme). Without these the panel's re-scope would resolve to invalid vars
2467
+ * and the panel would have no background — reading the host's resolved value
2468
+ * keeps the panel opaque by default and lets the slider retint it like every
2469
+ * other homepage part. Reads from the live `:root` so a custom host skin or
2470
+ * theme override wins. */
2471
+ function readHostLayerTokens() {
2472
+ if (typeof getComputedStyle === "undefined") return null;
2473
+ const root = document.documentElement;
2474
+ const cs = getComputedStyle(root);
2475
+ const base = cs.getPropertyValue("--dsw-alias-bg-base").trim();
2476
+ const layer1 = cs.getPropertyValue("--dsw-alias-bg-layer-1").trim();
2477
+ const layer2 = cs.getPropertyValue("--dsw-alias-bg-layer-2").trim();
2478
+ const layer3 = cs.getPropertyValue("--dsw-alias-bg-layer-3").trim();
2479
+ if (!base && !layer1 && !layer2 && !layer3) return null;
2480
+ return {
2481
+ base,
2482
+ layer1,
2483
+ layer2,
2484
+ layer3
2485
+ };
2486
+ }
2487
+ function applyPanelOverrides(op) {
2488
+ const tokens = paletteTokens();
2489
+ const root = document.documentElement;
2490
+ if (tokens !== null) {
2491
+ const base = tokens["--dsw-alias-bg-base"];
2492
+ const layer1 = tokens["--dsw-alias-bg-layer-1"];
2493
+ const layer2 = tokens["--dsw-alias-bg-layer-2"];
2494
+ const layer3 = tokens["--dsw-alias-bg-layer-3"];
2495
+ if (base !== void 0) root.style.setProperty("--dsh-any-panel-bg-base", toRgba(base, op));
2496
+ if (layer1 !== void 0) root.style.setProperty("--dsh-any-panel-layer-1", toRgba(layer1, op));
2497
+ if (layer2 !== void 0) root.style.setProperty("--dsh-any-panel-layer-2", toRgba(layer2, op));
2498
+ if (layer3 !== void 0) root.style.setProperty("--dsh-any-panel-layer-3", toRgba(layer3, op));
2499
+ return;
2500
+ }
2501
+ const host = readHostLayerTokens();
2502
+ if (host === null) {
2503
+ root.style.setProperty("--dsh-any-panel-bg-base", "transparent");
2504
+ root.style.setProperty("--dsh-any-panel-layer-1", "transparent");
2505
+ root.style.setProperty("--dsh-any-panel-layer-2", "transparent");
2506
+ root.style.setProperty("--dsh-any-panel-layer-3", "transparent");
2507
+ return;
2508
+ }
2509
+ if (host.base) root.style.setProperty("--dsh-any-panel-bg-base", toRgba(host.base, op));
2510
+ if (host.layer1) root.style.setProperty("--dsh-any-panel-layer-1", toRgba(host.layer1, op));
2511
+ if (host.layer2) root.style.setProperty("--dsh-any-panel-layer-2", toRgba(host.layer2, op));
2512
+ if (host.layer3) root.style.setProperty("--dsh-any-panel-layer-3", toRgba(host.layer3, op));
2513
+ }
2514
+ function applyPanelBlur(px) {
2515
+ if (px > 0) document.documentElement.style.setProperty("--dsh-any-blur-panel", `blur(${px}px)`);
2516
+ else document.documentElement.style.removeProperty("--dsh-any-blur-panel");
2517
+ }
2434
2518
  function applySettingsOverrides(op) {
2435
2519
  const [h, s, l] = rColor();
2436
2520
  const tokens = genTokens(h, s, l, rColorScheme()).tokens;
@@ -2548,7 +2632,7 @@ window.__ModuleLoader__.load({
2548
2632
  let frameEl = null;
2549
2633
  let sidebarEl = null;
2550
2634
  let centerEl = null;
2551
- let detailsEl = null;
2635
+ let rightEl = null;
2552
2636
  const PART_BLUR_CLASS = "dab-part-blur";
2553
2637
  const PART_UNDERLAY_CLASS = "dab-part-underlay";
2554
2638
  const PART_BLUR_RULE = `${PART_BLUR_CLASS}{isolation:isolate}.${PART_UNDERLAY_CLASS}{position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;backdrop-filter:var(--dsh-any-part-blur,none);-webkit-backdrop-filter:var(--dsh-any-part-blur,none)}`;
@@ -2560,16 +2644,32 @@ window.__ModuleLoader__.load({
2560
2644
  partBlurStyleEl.textContent = PART_BLUR_RULE;
2561
2645
  document.head.appendChild(partBlurStyleEl);
2562
2646
  }
2647
+ /** Find one direct child of `frame` whose `[data-rightbar-col]` marker matches.
2648
+ * The rightbar is its own grid track, NOT a "details" twin of the center
2649
+ * column, so it must never receive the main-bg tint or blur underlay. */
2650
+ function findRightbarInFrame(frame) {
2651
+ for (let i = 0; i < frame.children.length; i++) {
2652
+ const child = frame.children[i];
2653
+ if (child instanceof HTMLElement && child.dataset.rightbarCol !== void 0) return child;
2654
+ }
2655
+ return null;
2656
+ }
2563
2657
  function discoverParts() {
2564
2658
  const overlay = document.querySelector("[data-shell-overlay]");
2565
2659
  if (overlay === null) return;
2566
2660
  const frame = overlay.parentElement;
2567
2661
  if (frame === null) return;
2568
2662
  frameEl = frame;
2663
+ rightEl = findRightbarInFrame(frame);
2569
2664
  const idx = Array.from(frame.children).indexOf(overlay);
2570
- sidebarEl = frame.children[idx - 3] ?? null;
2571
- centerEl = frame.children[idx - 2] ?? null;
2572
- detailsEl = frame.children[idx - 1] ?? null;
2665
+ if (rightEl !== null) {
2666
+ const rightIdx = Array.from(frame.children).indexOf(rightEl);
2667
+ sidebarEl = frame.children[rightIdx - 2] ?? null;
2668
+ centerEl = frame.children[rightIdx - 1] ?? null;
2669
+ } else {
2670
+ sidebarEl = frame.children[idx - 3] ?? null;
2671
+ centerEl = frame.children[idx - 2] ?? null;
2672
+ }
2573
2673
  }
2574
2674
  function setBlur(el, px) {
2575
2675
  if (el === null) return;
@@ -2601,10 +2701,14 @@ window.__ModuleLoader__.load({
2601
2701
  if (px > 0) document.documentElement.style.setProperty("--dsh-any-blur-settings", `blur(${px}px)`);
2602
2702
  else document.documentElement.style.removeProperty("--dsh-any-blur-settings");
2603
2703
  }
2604
- /** Apply the main-background opacity to the center/details columns instead of
2704
+ /** Apply the main-background opacity to the center column instead of
2605
2705
  * the frame. The frame's translucent bg-base sits UNDER the sidebar, so
2606
2706
  * reducing the main-bg opacity stacked a second alpha onto the sidebar; moving
2607
- * the alpha onto the columns keeps the sidebar owned by its own slider. */
2707
+ * the alpha onto the column keeps the sidebar owned by its own slider. The
2708
+ * rightbar (DSH 0.1.5-rc.1+) is intentionally NOT tinted here — it sits on
2709
+ * its own grid track, paints its own surfaces from its own tokens, and
2710
+ * inheriting the main-bg tint would blend it into the page and make the
2711
+ * right panel disappear. */
2608
2712
  function applyPartOpacities(ops) {
2609
2713
  const tokens = paletteTokens();
2610
2714
  if (tokens === null) return;
@@ -2613,12 +2717,12 @@ window.__ModuleLoader__.load({
2613
2717
  const base = tokens["--dsw-alias-bg-base"];
2614
2718
  frameEl.style.background = "transparent";
2615
2719
  if (centerEl !== null) centerEl.style.background = base !== void 0 ? toRgba(base, ops.bg) : "transparent";
2616
- if (detailsEl !== null) detailsEl.style.background = base !== void 0 ? toRgba(base, ops.bg) : "transparent";
2720
+ if (rightEl !== null) rightEl.style.background = "";
2617
2721
  }
2618
2722
  /** Blur of the option panels inside the settings dialog (.dab-card), owned by
2619
2723
  * the "dialog option panel" (card) blur slider. Written as a plugin-owned
2620
2724
  * variable consumed by SETTINGS_STYLE_RULE — deliberately NOT applied to the
2621
- * homepage center/details columns, which this slider must never touch. */
2725
+ * homepage center column, which this slider must never touch. */
2622
2726
  function applyCardPanelsBlur(px) {
2623
2727
  if (px > 0) document.documentElement.style.setProperty("--dsh-any-blur-card-panels", `blur(${px}px)`);
2624
2728
  else document.documentElement.style.removeProperty("--dsh-any-blur-card-panels");
@@ -2629,13 +2733,31 @@ window.__ModuleLoader__.load({
2629
2733
  setBlur(frameEl, 0);
2630
2734
  setBlur(sidebarEl, blurs.sidebar);
2631
2735
  setBlur(centerEl, blurs.bg);
2632
- setBlur(detailsEl, blurs.bg);
2736
+ setBlur(rightEl, 0);
2633
2737
  applyBgBlurGlobal(blurs.bg);
2634
2738
  applyCardPanelsBlur(blurs.card);
2635
2739
  applySettingsBlur(blurs.settings);
2636
2740
  applyInputBlur(blurs.input);
2741
+ applyPanelBlur(blurs.panel);
2742
+ applyProduced();
2637
2743
  applyViewCards();
2638
2744
  }
2745
+ /** Produced/artifact surfaces (conversation code blocks + their banner +
2746
+ * composer chips): re-write the root blur and the alpha percentage consumed by
2747
+ * PRODUCED_RULE. The percentage is an alpha for the surface's OWN host color —
2748
+ * 1 (100%) reproduces the untouched host look and lowering it fades exactly
2749
+ * that color out — so no palette sampling is involved and the surfaces keep
2750
+ * following the active theme/wallpaper color on their own. */
2751
+ function applyProduced() {
2752
+ const px = rBlurs().produced;
2753
+ const root = document.documentElement;
2754
+ if (px > 0) root.style.setProperty("--dsh-any-blur-prod", `blur(${px}px)`);
2755
+ else root.style.removeProperty("--dsh-any-blur-prod");
2756
+ let opacity = rProducedOpacity();
2757
+ if (opacity < 0) opacity = 0;
2758
+ if (opacity > 1) opacity = 1;
2759
+ root.style.setProperty("--dsh-any-prod-pct", `${Math.round(opacity * 100)}%`);
2760
+ }
2639
2761
  /** Live per-part blur update during slider drag (no full re-apply). */
2640
2762
  function setPartBlur(part, v) {
2641
2763
  if (part === "settings") {
@@ -2650,6 +2772,14 @@ window.__ModuleLoader__.load({
2650
2772
  applyInputBlur(v);
2651
2773
  return;
2652
2774
  }
2775
+ if (part === "panel") {
2776
+ applyPanelBlur(v);
2777
+ return;
2778
+ }
2779
+ if (part === "produced") {
2780
+ applyProduced();
2781
+ return;
2782
+ }
2653
2783
  if (part === "chat" || part === "trajectory") {
2654
2784
  applyViewCards();
2655
2785
  return;
@@ -2657,7 +2787,6 @@ window.__ModuleLoader__.load({
2657
2787
  discoverParts();
2658
2788
  if (part === "bg") {
2659
2789
  setBlur(centerEl, v);
2660
- setBlur(detailsEl, v);
2661
2790
  applyBgBlurGlobal(v);
2662
2791
  } else setBlur(sidebarEl, v);
2663
2792
  }
@@ -2858,7 +2987,7 @@ window.__ModuleLoader__.load({
2858
2987
  function watchParts() {
2859
2988
  if (partsObserver !== null || typeof MutationObserver === "undefined") return;
2860
2989
  partsObserver = new MutationObserver(() => {
2861
- if (frameEl !== null && sidebarEl !== null && centerEl !== null && detailsEl !== null && document.body.contains(frameEl) && viewTargets.every((el) => el !== null && document.body.contains(el))) return;
2990
+ if (frameEl !== null && sidebarEl !== null && centerEl !== null && rightEl !== null && document.body.contains(frameEl) && viewTargets.every((el) => el !== null && document.body.contains(el))) return;
2862
2991
  applyPartBlurs(rBlurs());
2863
2992
  applyPartOpacities(rOps());
2864
2993
  });
@@ -3174,6 +3303,7 @@ window.__ModuleLoader__.load({
3174
3303
  applySettingsOverrides(rSop());
3175
3304
  applyTrajectoryOverrides(rTrajectoryOpacity());
3176
3305
  }
3306
+ applyPanelOverrides(rPanelOpacity());
3177
3307
  applyPartBlurs(rBlurs());
3178
3308
  }
3179
3309
  function teardownWp() {
@@ -3202,6 +3332,13 @@ window.__ModuleLoader__.load({
3202
3332
  document.documentElement.style.removeProperty("--dsh-any-blur-card-panels");
3203
3333
  document.documentElement.style.removeProperty("--dsh-any-input-blur");
3204
3334
  document.documentElement.style.removeProperty("--dsh-any-part-blur-global");
3335
+ document.documentElement.style.removeProperty("--dsh-any-panel-bg-base");
3336
+ document.documentElement.style.removeProperty("--dsh-any-panel-layer-1");
3337
+ document.documentElement.style.removeProperty("--dsh-any-panel-layer-2");
3338
+ document.documentElement.style.removeProperty("--dsh-any-panel-layer-3");
3339
+ document.documentElement.style.removeProperty("--dsh-any-blur-panel");
3340
+ document.documentElement.style.removeProperty("--dsh-any-blur-prod");
3341
+ document.documentElement.style.removeProperty("--dsh-any-prod-pct");
3205
3342
  for (const v of Object.values(OPACITY_VARS)) document.documentElement.style.removeProperty(v);
3206
3343
  baseTokenKey = "";
3207
3344
  lastBgKey = "";
@@ -3215,10 +3352,10 @@ window.__ModuleLoader__.load({
3215
3352
  setBlur(frameEl, 0);
3216
3353
  setBlur(sidebarEl, 0);
3217
3354
  setBlur(centerEl, 0);
3218
- setBlur(detailsEl, 0);
3355
+ setBlur(rightEl, 0);
3219
3356
  if (frameEl !== null) frameEl.style.removeProperty("background");
3220
3357
  if (centerEl !== null) centerEl.style.removeProperty("background");
3221
- if (detailsEl !== null) detailsEl.style.removeProperty("background");
3358
+ if (rightEl !== null) rightEl.style.removeProperty("background");
3222
3359
  stopWatchingParts();
3223
3360
  }
3224
3361
  /** Live wallpaper-opacity updates during slider drag (no full re-apply). */
@@ -3673,6 +3810,12 @@ window.__ModuleLoader__.load({
3673
3810
  })
3674
3811
  ]
3675
3812
  });
3813
+ /** Bottom workbench panel (dsh-better-sidebar): a window with a docked strip. */
3814
+ const PanelIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Glyph, {
3815
+ size,
3816
+ className,
3817
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.4 2.7h11.2v10.6H2.4z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.4 10.1h11.2" })]
3818
+ });
3676
3819
  const SlidersIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Glyph, {
3677
3820
  size,
3678
3821
  className,
@@ -4772,6 +4915,65 @@ window.__ModuleLoader__.load({
4772
4915
  });
4773
4916
  }
4774
4917
  //#endregion
4918
+ //#region src/client/env.ts
4919
+ /**
4920
+ * Host capability detection — which third-party plugins are actually present.
4921
+ *
4922
+ * The host exposes no plugin registry on the client context, so presence is
4923
+ * inferred from the stable DOM markers those plugins mount. Detection runs
4924
+ * once (plugin boot) and is re-armed by a cheap body-level MutationObserver so
4925
+ * a plugin that mounts after this one still flips the cached verdict. The
4926
+ * verdict is sticky-true for the session: whether a detected plugin's surface
4927
+ * is currently collapsed must not hide the settings that govern it.
4928
+ */
4929
+ /** Persistent container + surfaces dsh-better-sidebar mounts when loaded.
4930
+ * `[data-dsh-better-sidebar]` is the plugin's host wrapper — always appended
4931
+ * to document.body on mount — so it is the authoritative "plugin is loaded"
4932
+ * signal and the body childList observer fires exactly when it appears. The
4933
+ * panel surfaces we actually style are listed only as reinforcement: they are
4934
+ * conditionally rendered (collapsed panels drop them), so they must never be
4935
+ * the sole signal. */
4936
+ const BETTER_SIDEBAR_MARKERS = [
4937
+ "[data-dsh-better-sidebar]",
4938
+ "[data-dsh-panel-host]",
4939
+ "[data-dsh-bottom-panel]",
4940
+ "[data-sidebar-right-panel]"
4941
+ ];
4942
+ let betterSidebar = false;
4943
+ const subs = /* @__PURE__ */ new Set();
4944
+ /** Read snapshot of whether the better-sidebar plugin is present. */
4945
+ function rBetterSidebar() {
4946
+ return betterSidebar;
4947
+ }
4948
+ function emit() {
4949
+ subs.forEach((cb) => cb());
4950
+ }
4951
+ function sync() {
4952
+ if (document.querySelector(BETTER_SIDEBAR_MARKERS.join(",")) !== null && !betterSidebar) {
4953
+ betterSidebar = true;
4954
+ emit();
4955
+ }
4956
+ }
4957
+ /** React hook: re-renders the caller when better-sidebar presence changes. */
4958
+ function useBetterSidebar() {
4959
+ return (0, react.useSyncExternalStore)(subscribe, rBetterSidebar);
4960
+ }
4961
+ /** Subscribe to verdict changes. */
4962
+ function subscribe(cb) {
4963
+ subs.add(cb);
4964
+ return () => {
4965
+ subs.delete(cb);
4966
+ };
4967
+ }
4968
+ /** Start detection (probe once, then watch body mounts). Returns an
4969
+ * unsubscribe for plugin teardown. */
4970
+ function startBetterSidebarWatch() {
4971
+ sync();
4972
+ const observer = new MutationObserver(sync);
4973
+ observer.observe(document.body, { childList: true });
4974
+ return () => observer.disconnect();
4975
+ }
4976
+ //#endregion
4775
4977
  //#region src/client/components/pages/InterfacePage.tsx
4776
4978
  const PARTS = [
4777
4979
  {
@@ -4808,10 +5010,22 @@ window.__ModuleLoader__.load({
4808
5010
  isTrajectory: true,
4809
5011
  labelKey: "uiTrajectory",
4810
5012
  Icon: TrajectoryIcon
5013
+ },
5014
+ {
5015
+ isProduced: true,
5016
+ labelKey: "uiProduced",
5017
+ Icon: TextIcon
5018
+ },
5019
+ {
5020
+ isPanel: true,
5021
+ labelKey: "uiPanelRegion",
5022
+ Icon: PanelIcon
4811
5023
  }
4812
5024
  ];
4813
5025
  function InterfacePage({ p }) {
4814
- const { t, setOps, setBlurs, setSop } = p;
5026
+ const { t, setOps, setBlurs, setSop, setPanelOp } = p;
5027
+ const hasBetterSidebar = useBetterSidebar();
5028
+ const parts = PARTS.filter((part) => !(part.isPanel && !hasBetterSidebar));
4815
5029
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
4816
5030
  className: "dab-head dab-rise",
4817
5031
  style: { "--d": 0 },
@@ -4831,11 +5045,11 @@ window.__ModuleLoader__.load({
4831
5045
  ]
4832
5046
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4833
5047
  className: "dab-grid-parts",
4834
- children: PARTS.map((part, i) => {
4835
- const { labelKey, Icon, isSettings, isChat, isTrajectory } = part;
5048
+ children: parts.map((part, i) => {
5049
+ const { labelKey, Icon, isSettings, isChat, isTrajectory, isPanel, isProduced } = part;
4836
5050
  const opKey = part.opKey;
4837
- const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isSettings ? "settings" : opKey;
4838
- const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isSettings ? rSop() : rOps()[opKey];
5051
+ const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isSettings ? "settings" : isPanel ? "panel" : isProduced ? "produced" : opKey;
5052
+ const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isSettings ? rSop() : isPanel ? rPanelOpacity() : isProduced ? rProducedOpacity() : rOps()[opKey];
4839
5053
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4840
5054
  className: "dab-card dab-card-hover dab-rise",
4841
5055
  style: { "--d": i + 1 },
@@ -4875,6 +5089,12 @@ window.__ModuleLoader__.load({
4875
5089
  } else if (isSettings) {
4876
5090
  cfg.settingsOpacity = op;
4877
5091
  applySettingsOverrides(op);
5092
+ } else if (isPanel) {
5093
+ cfg.panelOpacity = op;
5094
+ applyPanelOverrides(op);
5095
+ } else if (isProduced) {
5096
+ cfg.producedOpacity = op;
5097
+ applyProduced();
4878
5098
  } else {
4879
5099
  const ops = { ...rOps() };
4880
5100
  ops[opKey] = op;
@@ -4894,7 +5114,12 @@ window.__ModuleLoader__.load({
4894
5114
  applyTrajectoryOverrides(op);
4895
5115
  saveConfig();
4896
5116
  } else if (isSettings) setSop(op);
4897
- else {
5117
+ else if (isPanel) setPanelOp(op);
5118
+ else if (isProduced) {
5119
+ cfg.producedOpacity = op;
5120
+ applyProduced();
5121
+ saveConfig();
5122
+ } else {
4898
5123
  const ops = { ...rOps() };
4899
5124
  ops[opKey] = op;
4900
5125
  setOps(ops);
@@ -5846,7 +6071,9 @@ window.__ModuleLoader__.load({
5846
6071
  settings: 0,
5847
6072
  chat: 0,
5848
6073
  trajectory: 0,
5849
- input: 0
6074
+ input: 0,
6075
+ panel: 0,
6076
+ produced: 0
5850
6077
  };
5851
6078
  const BUILTIN_PRESETS = [
5852
6079
  {
@@ -5864,7 +6091,9 @@ window.__ModuleLoader__.load({
5864
6091
  wallpaperOpacity: 1,
5865
6092
  blur: 0,
5866
6093
  chatTextOpacity: 0,
5867
- trajectoryOpacity: 1
6094
+ trajectoryOpacity: 1,
6095
+ panelOpacity: 1,
6096
+ producedOpacity: 1
5868
6097
  }
5869
6098
  },
5870
6099
  {
@@ -5888,13 +6117,16 @@ window.__ModuleLoader__.load({
5888
6117
  card: 12,
5889
6118
  settings: 20,
5890
6119
  trajectory: 8,
5891
- input: 14
6120
+ input: 14,
6121
+ panel: 12
5892
6122
  },
5893
6123
  settingsOpacity: .88,
5894
6124
  wallpaperOpacity: 1,
5895
6125
  blur: 0,
5896
6126
  chatTextOpacity: 0,
5897
- trajectoryOpacity: .85
6127
+ trajectoryOpacity: .85,
6128
+ panelOpacity: .85,
6129
+ producedOpacity: 1
5898
6130
  }
5899
6131
  },
5900
6132
  {
@@ -5912,7 +6144,9 @@ window.__ModuleLoader__.load({
5912
6144
  wallpaperOpacity: 1,
5913
6145
  blur: 0,
5914
6146
  chatTextOpacity: 0,
5915
- trajectoryOpacity: 1
6147
+ trajectoryOpacity: 1,
6148
+ panelOpacity: 1,
6149
+ producedOpacity: 1
5916
6150
  }
5917
6151
  },
5918
6152
  {
@@ -5936,13 +6170,16 @@ window.__ModuleLoader__.load({
5936
6170
  card: 14,
5937
6171
  settings: 22,
5938
6172
  trajectory: 10,
5939
- input: 16
6173
+ input: 16,
6174
+ panel: 16
5940
6175
  },
5941
6176
  settingsOpacity: .85,
5942
6177
  wallpaperOpacity: .92,
5943
6178
  blur: 2,
5944
6179
  chatTextOpacity: 0,
5945
- trajectoryOpacity: .8
6180
+ trajectoryOpacity: .8,
6181
+ panelOpacity: .8,
6182
+ producedOpacity: 1
5946
6183
  }
5947
6184
  },
5948
6185
  {
@@ -5966,13 +6203,16 @@ window.__ModuleLoader__.load({
5966
6203
  card: 10,
5967
6204
  settings: 18,
5968
6205
  trajectory: 6,
5969
- input: 20
6206
+ input: 20,
6207
+ panel: 18
5970
6208
  },
5971
6209
  settingsOpacity: .8,
5972
6210
  wallpaperOpacity: 1,
5973
6211
  blur: 0,
5974
6212
  chatTextOpacity: 0,
5975
- trajectoryOpacity: .78
6213
+ trajectoryOpacity: .78,
6214
+ panelOpacity: .75,
6215
+ producedOpacity: 1
5976
6216
  }
5977
6217
  },
5978
6218
  {
@@ -5994,7 +6234,9 @@ window.__ModuleLoader__.load({
5994
6234
  wallpaperOpacity: 1,
5995
6235
  blur: 0,
5996
6236
  chatTextOpacity: 0,
5997
- trajectoryOpacity: 1
6237
+ trajectoryOpacity: 1,
6238
+ panelOpacity: 1,
6239
+ producedOpacity: 1
5998
6240
  }
5999
6241
  }
6000
6242
  ];
@@ -6584,7 +6826,7 @@ window.__ModuleLoader__.load({
6584
6826
  }, "dsh-any-background: skin dispose");
6585
6827
  const styleEl = document.createElement("style");
6586
6828
  styleEl.dataset.plugin = "dsh-any-background";
6587
- 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}${TRAJECTORY_STYLE_RULE}${INPUT_BLUR_RULE}${MOBILE_HEADER_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}`;
6829
+ 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}[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}`;
6588
6830
  document.head.appendChild(styleEl);
6589
6831
  ctx.effect(() => () => {
6590
6832
  styleEl?.parentNode?.removeChild(styleEl);
@@ -6829,6 +7071,7 @@ window.__ModuleLoader__.load({
6829
7071
  ctx.effect(() => () => {
6830
7072
  teardownWp();
6831
7073
  }, "dsh-any-background: wp cleanup");
7074
+ ctx.effect(() => startBetterSidebarWatch(), "dsh-any-background: better-sidebar watch");
6832
7075
  ctx.effect(() => ctx.on("theme/change", () => {
6833
7076
  if (rHasColor() || rBgDark() !== null || rSchemeOverride() !== "auto") {
6834
7077
  const snapshot = ctx.theme.getTheme();
@@ -7006,6 +7249,11 @@ window.__ModuleLoader__.load({
7006
7249
  applySettingsOverrides(v);
7007
7250
  saveConfig();
7008
7251
  },
7252
+ setPanelOp: (v) => {
7253
+ cfg.panelOpacity = v;
7254
+ applyPanelOverrides(v);
7255
+ saveConfig();
7256
+ },
7009
7257
  extractColor: async () => {
7010
7258
  const url = rWp();
7011
7259
  if (!url) return false;