dsh-flyout-sidebar 0.1.7 → 0.1.9

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.
Files changed (2) hide show
  1. package/dist/client.js +114 -36
  2. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -62,19 +62,27 @@
62
62
  * --dsw-alias-* 设计令牌,深浅主题自动跟随。
63
63
  */
64
64
  const styleCss = `
65
- html #root {
66
- margin-right: calc(var(--dsh-sidebar-width, 0px) + var(--dsh-flyout-sidebar-width, 0px));
67
- transition: margin-right var(--ds-transition-duration-slow, 200ms) var(--ds-ease-in-out, ease);
68
- }
69
- body[data-dsh-flyout-dragging] #root {
70
- transition: none;
65
+ /* 面板关闭时:corner 触发按钮滑回右上角(占 right 12~48px 区间),左上角
66
+ panel 不动,日志按钮让位留白 —— better-sidebar 折叠态给右上角按钮组
67
+ 让位(right 10→70px)的思路一致,避免两块按钮挤在一起(见下方 64px 规则) */
68
+ /* 面板打开:header 已被 AppFrame grid 推挤到面板左缘(components.tsx 追加
69
+ 轨道),这里只需再留固定 16px 间距,日志按钮与面板保持恒定距离 —— 不能
70
+ 再按面板宽让位一次,否则推挤 + padding 叠加,日志按钮会被推出去两倍
71
+ 面板宽(距面板过远)。用 !important 压过宿主/其它插件的同规则。 */
72
+ body.dsh-flyout-sidebar-open header:has([data-slot="conversation.session.header.utilities"]) {
73
+ padding-right: 16px !important;
74
+ transition: padding-right var(--ds-transition-duration-slow, 200ms) var(--ds-ease-in-out, ease);
71
75
  }
72
- header:has([data-slot="conversation.session.header.utilities"]) {
73
- padding-right: max(28px, calc(60px - var(--dsh-flyout-sidebar-width, 0px)));
76
+ /* 面板收起:日志按钮让位到 64px(= corner 按钮 48px 左缘 + 16px 间距)
77
+ 声明在 open 规则之后,同特异性时保证 open 状态生效。 */
78
+ body:not(.dsh-flyout-sidebar-open) header:has([data-slot="conversation.session.header.utilities"]) {
79
+ padding-right: 64px !important;
74
80
  transition: padding-right var(--ds-transition-duration-slow, 200ms) var(--ds-ease-in-out, ease);
75
81
  }
82
+ body[data-dsh-flyout-dragging] header:has([data-slot="conversation.session.header.utilities"]) {
83
+ transition: none;
84
+ }
76
85
  @media (prefers-reduced-motion: reduce) {
77
- html #root { transition: none; }
78
86
  header:has([data-slot="conversation.session.header.utilities"]) { transition: none; }
79
87
  .artifacts-preview-overlay, .artifacts-panel, .artifacts-corner-btn { transition: none; }
80
88
  }
@@ -211,11 +219,19 @@ body[data-dsh-flyout-dragging] .artifacts-preview-overlay { transition: none; }
211
219
  .artifacts-corner-btn {
212
220
  position: fixed; top: 0; right: calc(var(--dsh-sidebar-width, 0px) + 12px);
213
221
  z-index: 10000; width: 36px; height: 28px; padding: 0;
214
- border: none; background: transparent; color: var(--dsw-alias-label-secondary);
222
+ border: none; background: transparent;
223
+ /* 颜色带多级回退:某些宿主的 --dsw-alias-* 令牌缺失时兜底到常规文字色,
224
+ 保证触发图标始终可见(曾被误报为“图标不显示”)。 */
225
+ color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-tertiary, var(--ds-text-2, #555)));
215
226
  cursor: pointer; align-items: center; justify-content: center; display: inline-flex;
216
227
  transition: transform var(--ds-transition-duration-slow, 200ms) var(--ds-ease-in-out, ease),
217
228
  right var(--ds-transition-duration-slow, 200ms) var(--ds-ease-in-out, ease), color .15s;
218
229
  }
230
+ /* better-sidebar 折叠时其右上角折叠按钮组占 right 10→70px;触发按钮避开它,
231
+ 否则两者重叠抢点击(坐标约定见 better-sidebar layout.css 的 78px 注释)。 */
232
+ body[data-dsh-sidebar-collapsed] .artifacts-corner-btn {
233
+ right: 78px;
234
+ }
219
235
  /* 面板打开时随面板一起滑出屏右缘(推拉动画的另一半) */
220
236
  .artifacts-corner-btn.artifacts-slid-out {
221
237
  transform: translateX(calc(100% + 24px));
@@ -378,15 +394,17 @@ body[data-ds-dark-theme] .tok-property { color: #ced4da; }
378
394
  }
379
395
  .fs-settings-toggle[data-on="true"]::after { transform: translateX(18px); }
380
396
  `;
381
- /** 注入样式(幂等:已存在则跳过) */
397
+ /** 注入样式(幂等:内容不一致时替换,使热重载后新样式必然生效) */
382
398
  function insertStyles() {
383
399
  if (typeof document === "undefined") return;
384
400
  const id = "dsh-flyout-sidebar-styles";
385
- if (document.getElementById(id)) return;
386
- const el = document.createElement("style");
387
- el.id = id;
388
- el.textContent = styleCss;
389
- document.head.appendChild(el);
401
+ let el = document.getElementById(id);
402
+ if (!el) {
403
+ el = document.createElement("style");
404
+ el.id = id;
405
+ document.head.appendChild(el);
406
+ }
407
+ if (el.textContent !== styleCss) el.textContent = styleCss;
390
408
  }
391
409
  //#endregion
392
410
  //#region src/shared/ext.js
@@ -859,21 +877,26 @@ body[data-ds-dark-theme] .tok-property { color: #ced4da; }
859
877
  /**
860
878
  * 从宿主拉取插件配置(config 已由 cordis 校验填充默认值)并通知订阅者。
861
879
  * 配置保存在宿主侧,页面内不持久化;面板打开即用最新值。
880
+ *
881
+ * syncDefaultOpen=true(启动首次加载、settings scope 配置变更回调)时,
882
+ * 若本次拉取确实改动了 defaultOpen 字段,则实时同步边栏开合 —— 用户在
883
+ * 设置卡片切换「默认展开」开关后边栏立即跟随展开/收起。面板摊开时例行
884
+ * 拉取(刷新 minPanelWidth 等设置)不传此 flag:只刷新配置,绝不回写
885
+ * 开合状态,否则刚点开的边栏会被 defaultOpen 当场压回(点击无反应)。
862
886
  */
863
- load() {
887
+ load(opts) {
888
+ const syncDefaultOpen = !!(opts && opts.syncDefaultOpen);
864
889
  fetch("/flyout-sidebar/config").then((res) => res.ok ? res.json() : Promise.reject(/* @__PURE__ */ new Error("HTTP " + res.status))).then((out) => {
865
890
  const next = {
866
891
  ...this.data,
867
892
  ...out.config || {}
868
893
  };
894
+ const defaultOpenChanged = typeof next.defaultOpen === "boolean" && next.defaultOpen !== this.data.defaultOpen;
869
895
  this.data = next;
870
896
  for (const fn of this.listeners) try {
871
897
  fn(next);
872
898
  } catch {}
873
- if (typeof next.defaultOpen === "boolean" && next.defaultOpen !== store.open) {
874
- store.open = next.defaultOpen;
875
- setSlide({ slidOut: !next.defaultOpen });
876
- }
899
+ if (syncDefaultOpen && defaultOpenChanged && next.defaultOpen !== store.open) store.setOpen(next.defaultOpen);
877
900
  }).catch(() => {});
878
901
  },
879
902
  subscribe(fn) {
@@ -2415,6 +2438,20 @@ body[data-ds-dark-theme] .tok-property { color: #ced4da; }
2415
2438
  });
2416
2439
  return /* @__PURE__ */ h(Fragment, null, rows);
2417
2440
  }
2441
+ /** 定位 DSH AppFrame:CSS Grid 容器,内联 style 设 gridTemplateColumns,
2442
+ * 第一列即左侧栏宽(折叠时为 0px)。 */
2443
+ function findAppFrame() {
2444
+ const nodes = document.querySelectorAll("#root *");
2445
+ for (let i = 0; i < nodes.length; i++) {
2446
+ const el = nodes[i];
2447
+ const cols = el.style.gridTemplateColumns;
2448
+ if (cols) {
2449
+ const first = cols.split(/\s+/)[0];
2450
+ if (first && first.endsWith("px")) return el;
2451
+ }
2452
+ }
2453
+ return null;
2454
+ }
2418
2455
  function ArtifactsPanel() {
2419
2456
  const open = useOpen();
2420
2457
  const settings = useSettings();
@@ -2620,18 +2657,6 @@ body[data-ds-dark-theme] .tok-property { color: #ced4da; }
2620
2657
  }, []);
2621
2658
  React.useEffect(() => {
2622
2659
  const root = document.documentElement;
2623
- const findAppFrame = () => {
2624
- const nodes = document.querySelectorAll("#root *");
2625
- for (let i = 0; i < nodes.length; i++) {
2626
- const el = nodes[i];
2627
- const cols = el.style.gridTemplateColumns;
2628
- if (cols) {
2629
- const first = cols.split(/\s+/)[0];
2630
- if (first && first.endsWith("px")) return el;
2631
- }
2632
- }
2633
- return null;
2634
- };
2635
2660
  const readAndSet = (frame) => {
2636
2661
  if (!frame) return 0;
2637
2662
  const cols = frame.style.gridTemplateColumns;
@@ -2685,8 +2710,58 @@ body[data-ds-dark-theme] .tok-property { color: #ced4da; }
2685
2710
  React.useEffect(() => {
2686
2711
  const root = document.documentElement;
2687
2712
  root.style.setProperty("--dsh-flyout-sidebar-width", open ? widthPx + "px" : "0px");
2713
+ document.body.classList.toggle("dsh-flyout-sidebar-open", open);
2714
+ const push = {
2715
+ frame: null,
2716
+ suffix: null
2717
+ };
2718
+ const applyPush = (frame, w) => {
2719
+ if (!frame) return;
2720
+ push.frame = frame;
2721
+ let cols = frame.style.gridTemplateColumns || "";
2722
+ if (push.suffix && cols.endsWith(push.suffix)) cols = cols.slice(0, cols.length - push.suffix.length);
2723
+ const next = w > 0 ? cols.trim() !== "" ? cols + " " + w + "px" : w + "px" : cols;
2724
+ push.suffix = w > 0 ? " " + w + "px" : null;
2725
+ if (frame.style.gridTemplateColumns !== next) frame.style.gridTemplateColumns = next;
2726
+ };
2727
+ const observeFrame = (frame) => {
2728
+ if (!frame) return null;
2729
+ const obs = new MutationObserver(() => {
2730
+ if (frame && document.contains(frame)) applyPush(frame, open ? widthPx : 0);
2731
+ });
2732
+ obs.observe(frame, {
2733
+ attributes: true,
2734
+ attributeFilter: ["style"]
2735
+ });
2736
+ return obs;
2737
+ };
2738
+ let frame = findAppFrame();
2739
+ applyPush(frame, open ? widthPx : 0);
2740
+ let styleObs = observeFrame(frame);
2741
+ let subtreeObs = null;
2742
+ if (typeof MutationObserver === "function") {
2743
+ subtreeObs = new MutationObserver(() => {
2744
+ if (!frame || !document.contains(frame)) {
2745
+ styleObs?.disconnect();
2746
+ frame = findAppFrame();
2747
+ if (frame) {
2748
+ applyPush(frame, open ? widthPx : 0);
2749
+ styleObs = observeFrame(frame);
2750
+ }
2751
+ }
2752
+ });
2753
+ subtreeObs.observe(document.body, {
2754
+ childList: true,
2755
+ subtree: true,
2756
+ attributes: false
2757
+ });
2758
+ }
2688
2759
  return () => {
2760
+ styleObs?.disconnect();
2761
+ subtreeObs?.disconnect();
2762
+ applyPush(push.frame, 0);
2689
2763
  root.style.setProperty("--dsh-flyout-sidebar-width", "0px");
2764
+ document.body.classList.remove("dsh-flyout-sidebar-open");
2690
2765
  };
2691
2766
  }, [open, widthPx]);
2692
2767
  React.useEffect(() => {
@@ -2738,16 +2813,19 @@ body[data-ds-dark-theme] .tok-property { color: #ced4da; }
2738
2813
  (ctx.reflect?.inject("layout"))?.toggleSidebar?.();
2739
2814
  } catch {}
2740
2815
  };
2816
+ const startX = e.clientX;
2741
2817
  let lastMouseX = e.clientX;
2742
2818
  let rafId = null;
2743
2819
  let collapseTriggered = false;
2820
+ let draggedLeft = false;
2744
2821
  const tick = () => {
2745
2822
  rafId = requestAnimationFrame(tick);
2746
2823
  const cursorW = window.innerWidth - lastMouseX - rightOffset;
2747
2824
  const sidebarW = getSidebarWidth();
2748
2825
  const maxW = window.innerWidth - sidebarW - rightOffset;
2749
2826
  const w = Math.min(cursorW, maxW);
2750
- if (!collapseTriggered && sidebarW > 0 && cursorW >= maxW - 2) {
2827
+ if (lastMouseX < startX - 8) draggedLeft = true;
2828
+ if (!collapseTriggered && sidebarW > 0 && draggedLeft && cursorW >= maxW - 2) {
2751
2829
  collapseTriggered = true;
2752
2830
  triggerSidebarCollapse();
2753
2831
  }
@@ -3032,7 +3110,7 @@ body[data-ds-dark-theme] .tok-property { color: #ced4da; }
3032
3110
  order: 50,
3033
3111
  label: "Artifacts Panel"
3034
3112
  }, () => /* @__PURE__ */ h(ArtifactsPanel, null)));
3035
- settingsStore.load();
3113
+ settingsStore.load({ syncDefaultOpen: true });
3036
3114
  ctx.inject(["settingsScope"], (sctx) => {
3037
3115
  const binder = sctx.get("settingsScope");
3038
3116
  if (!binder) return;
@@ -3050,7 +3128,7 @@ body[data-ds-dark-theme] .tok-property { color: #ced4da; }
3050
3128
  };
3051
3129
  sctx.effect(() => scope.subscribe(() => {
3052
3130
  publishLocal(scope.getSnapshot());
3053
- settingsStore.load();
3131
+ settingsStore.load({ syncDefaultOpen: true });
3054
3132
  }), "flyout: settings scope");
3055
3133
  const useSettingsSnapshot = (selector) => React.useSyncExternalStore((cb) => {
3056
3134
  localListeners.add(cb);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-flyout-sidebar",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "可弹出侧边栏 · A DeepSeek Harness sidebar that shows artifacts and pops out into a larger web tab.",
5
5
  "license": "MIT",
6
6
  "type": "module",