dsh-better-left-sidebar 0.1.2 → 0.1.4

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.en.md CHANGED
@@ -23,11 +23,11 @@ A cleaner, better-organized DeepSeek Harness sidebar with support for multiple p
23
23
 
24
24
  ## Features
25
25
 
26
- > `0.1.1` adds compact rail widgets, a configurable clock, grouped settings, and short-window navigation improvements.
26
+ > `0.1.4` makes touch navigation explicit and fixes the overlap between the toggle and compact rail widgets.
27
27
 
28
28
  - **Keep conversations in the foreground**: workspaces and conversations stay in a dedicated wide pane; expanded navigation overlays it instead of squeezing the conversation area.
29
29
  - **Tuck global entry points out of the way**: place the brand, panels, and tools along a narrow left rail to leave more room for browsing sessions.
30
- - **Choose the interaction that fits**: hover or keyboard focus expands the rail by default; click mode pins it open and closes on another click, Escape, or an outside click.
30
+ - **Use navigation comfortably on desktop and touch**: desktop hover or keyboard focus expands by default; touch devices always get an explicit toggle that stays open after a tap and closes on an outside tap, item selection, Escape, or another tap.
31
31
  - **Shape the sidebar around your workflow**: reposition the brand, global navigation, and tools, then review the layout preview before applying it.
32
32
  - **Keep DSH's native actions**: New Session, panels, workspaces, settings, and footer tools keep their DSH entry points and behavior.
33
33
  - **See widgets in the compact rail**: the clock and widgets you choose sit at the bottom of the rail. In settings you can enable, disable, and reorder them, and change the clock's hour cycle, month/day, weekday, and time color.
@@ -51,7 +51,7 @@ Restart DSH after installing.
51
51
  You can also install the matching GitHub Release:
52
52
 
53
53
  ```sh
54
- dsh plugin --profile web add github:exoticknight/dsh-better-left-sidebar#v0.1.2
54
+ dsh plugin --profile web add github:exoticknight/dsh-better-left-sidebar#v0.1.4
55
55
  ```
56
56
 
57
57
  Restart DSH after installing.
@@ -75,7 +75,7 @@ pnpm dev
75
75
  ## Usage
76
76
 
77
77
  1. When enabled, the workspace and conversation list stay open; the far-left rail holds the DSH brand, global panels, and tools.
78
- 2. In the default mode, hover over the rail or keyboard-focus a navigation item to reveal the full navigation. It closes after you leave it. Choose click mode in the plugin settings to pin or close the rail with the toggle button.
78
+ 2. On desktop, hover over the rail or keyboard-focus a navigation item to reveal the full navigation. On touch devices, tap the navigation toggle; it stays open after release and closes when you tap outside, select an item, or press Escape. Click mode is also available in plugin settings.
79
79
  3. Open **Plugins** in the sidebar, then **Better Left Sidebar** to configure expansion, animation, and region placement. Review the preview and select **Save settings** to apply changes. Copy follows DSH's active language; switch between Chinese and English in **Settings → General**.
80
80
  4. Use **[Compact widgets](docs/compact-widgets.md)** on the same settings page to manage the clock and compatible widgets. Expand **Display settings** under the clock to change its hour cycle, date, weekday, and time color. Date and Weekday can both be checked, and the **Effect preview** uses the same width as the rail. A widget that does not fit is marked **Hidden: not enough space**. New registrations are enabled by default, and their order and enablement are saved in the current profile.
81
81
 
@@ -89,7 +89,7 @@ After you select **Save settings**, layout preferences are stored in the current
89
89
 
90
90
  | Option | Default | Meaning |
91
91
  | --- | --- | --- |
92
- | Expansion | `hover` | Expand on hover or keyboard focus; `click` pins the rail open with a toggle. |
92
+ | Expansion | `hover` | Expand on desktop hover or keyboard focus; touch devices always show a navigation toggle. `click` pins the rail open with the toggle. |
93
93
  | Animation | `standard` | Choose soft, fast, or no animation. |
94
94
  | Brand | `navigation-top` | Place the brand at the top of the rail, at the top of the conversation pane, or hide it. |
95
95
  | Global navigation | `rail` | Keep global navigation in the rail or move it above conversations. |
@@ -99,17 +99,17 @@ After you select **Save settings**, layout preferences are stored in the current
99
99
 
100
100
  ## Update, roll back, remove
101
101
 
102
- To update to or reinstall `0.1.2`, remove the plugin and install the exact version:
102
+ To update to or reinstall `0.1.4`, remove the plugin and install the exact version:
103
103
 
104
104
  ```sh
105
105
  dsh plugin --profile web remove dsh-better-left-sidebar
106
106
  ```
107
107
 
108
108
  ```sh
109
- dsh plugin --profile web add dsh-better-left-sidebar@0.1.2
109
+ dsh plugin --profile web add dsh-better-left-sidebar@0.1.4
110
110
  ```
111
111
 
112
- To roll back, replace the version in the install command with `0.1.1`. [View GitHub Releases](https://github.com/exoticknight/dsh-better-left-sidebar/releases).
112
+ To roll back, replace the version in the install command with `0.1.3`. [View GitHub Releases](https://github.com/exoticknight/dsh-better-left-sidebar/releases).
113
113
 
114
114
  Removing the plugin uninstalls its package; conversations and other plugins in the DSH profile remain.
115
115
 
package/README.md CHANGED
@@ -23,11 +23,11 @@
23
23
 
24
24
  ## 功能
25
25
 
26
- > `0.1.1` 加入收起栏小组件、可配置时钟和分组设置,并包含小窗口导航改进。
26
+ > `0.1.4` 为触屏导航提供稳定开关,并修复展开按钮与收起栏小组件的重叠。
27
27
 
28
28
  - **让会话始终留在主位**:工作区和会话列表保留在独立宽栏;展开导航时覆盖在其上,不会挤窄对话区。
29
29
  - **把全局入口收纳起来**:品牌、面板和工具可分布在左侧窄栏,空出更完整的会话浏览区域。
30
- - **鼠标、键盘、点击都能顺手操作**:默认悬停或聚焦时展开;也可切换为点击固定展开,并用再次点击、Esc 或外部点击收起。
30
+ - **桌面与触屏都好操作**:桌面默认悬停或键盘聚焦时展开;触屏设备始终显示导航按钮,轻触后保持展开,直到点击外部、选择导航项、按 Esc 或再次点击按钮。
31
31
  - **按自己的习惯安排侧栏**:调整品牌、全局导航和工具区的位置;保存前可查看布局效果预览。
32
32
  - **保留 DSH 原生操作**:新建会话、面板、工作区、设置和页脚工具仍使用 DSH 自己的入口与处理逻辑。
33
33
  - **在收起栏查看小组件**:时钟和你选择的插件小组件显示在导航栏底部。设置里可以启用、停用、排序,并调整时钟的小时制、月/日、星期和时间颜色。
@@ -51,7 +51,7 @@ dsh plugin --profile web add dsh-better-left-sidebar
51
51
  也可以安装对应版本的 GitHub Release:
52
52
 
53
53
  ```sh
54
- dsh plugin --profile web add github:exoticknight/dsh-better-left-sidebar#v0.1.2
54
+ dsh plugin --profile web add github:exoticknight/dsh-better-left-sidebar#v0.1.4
55
55
  ```
56
56
 
57
57
  安装后重启 DSH。
@@ -75,7 +75,7 @@ pnpm dev
75
75
  ## 使用
76
76
 
77
77
  1. 插件启用后,工作区与会话列表保持展开;最左侧窄栏放置 DSH 品牌、全局面板和工具入口。
78
- 2. 默认将鼠标移入导航栏,或用键盘聚焦导航项,即可展开完整导航;离开导航区域且不再聚焦时自动收起。也可在插件设置中选择“点击展开”,通过点击固定或收起导航。
78
+ 2. 桌面默认将鼠标移入导航栏或键盘聚焦导航项时展开;触屏设备轻触导航按钮即可展开,并在松手后保持,直到点击外部、选择导航项或按 Esc。插件设置也可切换为“点击展开”,由按钮固定或收起导航。
79
79
  3. 打开侧栏的“插件”页,进入“更顺手的左侧栏”配置展开方式、动画和区域位置;修改布局后先看预览,再点“保存设置”。文案跟随 DSH 当前语言;在“设置 → 通用设置”切换简体中文或 English。
80
80
  4. 在同一设置页的“[收起栏小组件](docs/compact-widgets.md)”管理时钟和适配插件的小组件。展开时钟的“显示设置”,可改小时制、日期、星期和时间颜色;日期与星期可同时勾选,旁边的“效果预览”与收起栏同宽。空间不足时,组件行会显示“空间不足,暂未显示”。首次注册默认启用,顺序与启用状态保存在当前 profile。
81
81
 
@@ -89,7 +89,7 @@ pnpm dev
89
89
 
90
90
  | 选项 | 默认值 | 说明 |
91
91
  | --- | --- | --- |
92
- | 展开方式 | `hover` | 悬停或键盘聚焦时展开;也可选 `click`,由按钮固定展开。 |
92
+ | 展开方式 | `hover` | 桌面悬停或键盘聚焦时展开;触屏设备始终提供导航按钮。也可选 `click`,由按钮固定展开。 |
93
93
  | 动画 | `standard` | 选择柔和、快速或关闭动画。 |
94
94
  | 品牌区 | `navigation-top` | 可放在导航栏顶部、对话面板顶部,或隐藏。 |
95
95
  | 全局导航 | `rail` | 可放在左侧导航栏,或移到对话列表上方。 |
@@ -99,17 +99,17 @@ pnpm dev
99
99
 
100
100
  ## 更新、回滚与卸载
101
101
 
102
- 更新到 `0.1.2` 或重新安装时,先移除插件,再安装精确版本:
102
+ 更新到 `0.1.4` 或重新安装时,先移除插件,再安装精确版本:
103
103
 
104
104
  ```sh
105
105
  dsh plugin --profile web remove dsh-better-left-sidebar
106
106
  ```
107
107
 
108
108
  ```sh
109
- dsh plugin --profile web add dsh-better-left-sidebar@0.1.2
109
+ dsh plugin --profile web add dsh-better-left-sidebar@0.1.4
110
110
  ```
111
111
 
112
- 需要回滚时,将安装命令中的版本改为 `0.1.1`。[查看 GitHub Releases](https://github.com/exoticknight/dsh-better-left-sidebar/releases)。
112
+ 需要回滚时,将安装命令中的版本改为 `0.1.3`。[查看 GitHub Releases](https://github.com/exoticknight/dsh-better-left-sidebar/releases)。
113
113
 
114
114
  移除插件只会卸载插件包;当前 DSH profile 中的会话和其他插件会保留。
115
115
 
package/lib/client.js CHANGED
@@ -1573,6 +1573,19 @@ function fallbackTranslate(key) {
1573
1573
  return key;
1574
1574
  }
1575
1575
 
1576
+ // src/client/pointer-intent.ts
1577
+ var NAVIGATION_TOGGLE_SIZE = 36;
1578
+ var NAVIGATION_TOGGLE_GAP = 8;
1579
+ function isHoverPointer(pointerType, hoverAvailable) {
1580
+ return hoverAvailable && (pointerType === "mouse" || pointerType === "pen");
1581
+ }
1582
+ function shouldShowNavigationToggle(expansion, coarsePointerAvailable, hoverAvailable) {
1583
+ return expansion === "click" || coarsePointerAvailable || !hoverAvailable;
1584
+ }
1585
+ function getNavigationToggleReserve(expansion, coarsePointerAvailable, hoverAvailable) {
1586
+ return shouldShowNavigationToggle(expansion, coarsePointerAvailable, hoverAvailable) ? NAVIGATION_TOGGLE_SIZE + NAVIGATION_TOGGLE_GAP : 0;
1587
+ }
1588
+
1576
1589
  // src/client/rail-region.ts
1577
1590
  function isRailRegionEligible(region, preferences) {
1578
1591
  if (region === "brand") return preferences?.brandPosition === "navigation-top";
@@ -1588,7 +1601,7 @@ var POPUP_SELECTOR = '[role="menu"], [role="listbox"], [role="dialog"], [data-me
1588
1601
  var ENTER_DELAY = 160;
1589
1602
  var CLOSE_DELAY = 210;
1590
1603
  var POPUP_PENDING_DELAY = 900;
1591
- function connectInteraction() {
1604
+ function connectInteraction(onToggleReserveChange) {
1592
1605
  let root;
1593
1606
  let preferences;
1594
1607
  let expansion = "hover";
@@ -1610,7 +1623,16 @@ function connectInteraction() {
1610
1623
  let resizeObserver;
1611
1624
  let rootIdOwned = false;
1612
1625
  let documentCleanup;
1626
+ let publishedToggleReserve = 0;
1613
1627
  const classRoot = document.documentElement;
1628
+ const hoverPointer = window.matchMedia("(any-hover: hover)");
1629
+ const coarsePointer = window.matchMedia("(any-pointer: coarse)");
1630
+ const syncToggleReserve = () => {
1631
+ const next = root && preferences ? getNavigationToggleReserve(preferences.expansion, coarsePointer.matches, hoverPointer.matches) : 0;
1632
+ if (publishedToggleReserve === next) return;
1633
+ publishedToggleReserve = next;
1634
+ onToggleReserveChange(next);
1635
+ };
1614
1636
  const isNavTarget = (target) => {
1615
1637
  if (!root || !(target instanceof Element) || !root.contains(target)) return false;
1616
1638
  const region = target.closest(NAV_REGION);
@@ -1622,6 +1644,7 @@ function connectInteraction() {
1622
1644
  for (const popup of associatedPopups) if (popup.isConnected && popup.contains(target)) return true;
1623
1645
  return false;
1624
1646
  };
1647
+ const isKeyboardFocused = (target) => target instanceof HTMLElement && target.matches(":focus-visible");
1625
1648
  const visiblePopups = () => [...document.querySelectorAll(POPUP_SELECTOR)].filter((popup) => {
1626
1649
  const node = popup;
1627
1650
  return !node.hidden && node.getAttribute("aria-hidden") !== "true" && node.getClientRects().length > 0;
@@ -1721,6 +1744,15 @@ function connectInteraction() {
1721
1744
  clearTimer(closeTimer);
1722
1745
  closeTimer = 0;
1723
1746
  };
1747
+ const collapseNavigation = () => {
1748
+ clearEntryTimer();
1749
+ clearCloseTimer();
1750
+ pointerInside = false;
1751
+ focusInside = false;
1752
+ pointerTarget = null;
1753
+ focusTarget = null;
1754
+ setMode("compact");
1755
+ };
1724
1756
  const expandTemporarily = () => {
1725
1757
  clearCloseTimer();
1726
1758
  if (mode !== "pinned") setMode("temporary");
@@ -1755,7 +1787,7 @@ function connectInteraction() {
1755
1787
  const tools = root.querySelector('[data-dsh-better-left-sidebar-region="tools"]');
1756
1788
  const toolReserve = preferences?.toolsPosition === "rail-bottom" && tools ? Math.max(tools.getBoundingClientRect().height, tools.scrollHeight) + 8 : 0;
1757
1789
  toggle.style.left = `${Math.round(rect.left + 10)}px`;
1758
- toggle.style.top = `${Math.max(rect.top + 8, Math.round(rect.bottom - 8 - 36 - toolReserve))}px`;
1790
+ toggle.style.top = `${Math.max(rect.top + 8, Math.round(rect.bottom - NAVIGATION_TOGGLE_GAP - NAVIGATION_TOGGLE_SIZE - toolReserve))}px`;
1759
1791
  };
1760
1792
  const syncToggle = () => {
1761
1793
  if (!toggle) return;
@@ -1764,6 +1796,7 @@ function connectInteraction() {
1764
1796
  const label = translate(pinned ? "closeNavigation" : "expandNavigation");
1765
1797
  toggle.setAttribute("aria-label", label);
1766
1798
  toggle.title = label;
1799
+ if (root?.id) toggle.setAttribute("aria-controls", root.id);
1767
1800
  toggle.setAttribute("aria-expanded", String(expanded));
1768
1801
  toggle.setAttribute("aria-pressed", String(pinned));
1769
1802
  toggle.querySelector("[data-dsh-better-left-sidebar-toggle-chevron]")?.setAttribute(
@@ -1784,8 +1817,9 @@ function connectInteraction() {
1784
1817
  updateTogglePosition();
1785
1818
  };
1786
1819
  const createToggle = () => {
1787
- if (!root || preferences?.expansion !== "click" || toggle) return;
1820
+ if (!root || !preferences || !shouldShowNavigationToggle(preferences.expansion, coarsePointer.matches, hoverPointer.matches) || toggle) return;
1788
1821
  toggle = createNavigationToggle(onToggleClick);
1822
+ toggle.setAttribute("aria-controls", root.id);
1789
1823
  document.body.append(toggle);
1790
1824
  refreshToggleObservation();
1791
1825
  window.addEventListener("resize", updateTogglePosition);
@@ -1802,13 +1836,24 @@ function connectInteraction() {
1802
1836
  window.removeEventListener("resize", updateTogglePosition);
1803
1837
  window.removeEventListener("scroll", updateTogglePosition, true);
1804
1838
  };
1839
+ const refreshToggleAvailability = () => {
1840
+ if (!root || !preferences) {
1841
+ syncToggleReserve();
1842
+ return;
1843
+ }
1844
+ if (shouldShowNavigationToggle(preferences.expansion, coarsePointer.matches, hoverPointer.matches)) {
1845
+ createToggle();
1846
+ syncToggleReserve();
1847
+ return;
1848
+ }
1849
+ if (mode === "pinned") collapseNavigation();
1850
+ removeToggle();
1851
+ syncToggleReserve();
1852
+ };
1853
+ const onPointerCapabilitiesChange = () => refreshToggleAvailability();
1805
1854
  const onToggleClick = () => {
1806
1855
  if (mode === "pinned") {
1807
- clearEntryTimer();
1808
- clearCloseTimer();
1809
- pointerInside = false;
1810
- focusInside = false;
1811
- setMode("compact");
1856
+ collapseNavigation();
1812
1857
  return;
1813
1858
  }
1814
1859
  clearEntryTimer();
@@ -1816,6 +1861,7 @@ function connectInteraction() {
1816
1861
  setMode("pinned");
1817
1862
  };
1818
1863
  const onPointerOver = (event) => {
1864
+ if (!isHoverPointer(event.pointerType, hoverPointer.matches)) return;
1819
1865
  const wasInside = pointerInside;
1820
1866
  pointerTarget = event.target;
1821
1867
  if (isNavTarget(event.target)) {
@@ -1830,6 +1876,7 @@ function connectInteraction() {
1830
1876
  }
1831
1877
  };
1832
1878
  const onPointerOut = (event) => {
1879
+ if (!isHoverPointer(event.pointerType, hoverPointer.matches)) return;
1833
1880
  const nextTarget = event.relatedTarget;
1834
1881
  const entersNavigation = !pointerInside && isNavTarget(nextTarget);
1835
1882
  pointerTarget = nextTarget;
@@ -1838,11 +1885,18 @@ function connectInteraction() {
1838
1885
  else if (!pointerInside) requestClose();
1839
1886
  };
1840
1887
  const onFocusIn = (event) => {
1841
- focusTarget = event.target;
1842
1888
  if (isNavTarget(event.target) || isPopupTarget(event.target)) {
1889
+ if (!isKeyboardFocused(event.target)) {
1890
+ focusTarget = null;
1891
+ focusInside = false;
1892
+ requestClose();
1893
+ return;
1894
+ }
1895
+ focusTarget = event.target;
1843
1896
  focusInside = true;
1844
1897
  expandTemporarily();
1845
1898
  } else {
1899
+ focusTarget = event.target;
1846
1900
  focusInside = false;
1847
1901
  requestClose();
1848
1902
  }
@@ -1858,28 +1912,33 @@ function connectInteraction() {
1858
1912
  if (!trigger || !(isNavTarget(trigger) || isPopupTarget(trigger))) return;
1859
1913
  startPopupTracking(trigger);
1860
1914
  };
1861
- const onClickCapture = (event) => onTriggerIntent(event);
1915
+ const onNavigationSelection = (event) => {
1916
+ if (mode !== "pinned" || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || !(event.target instanceof Element)) return;
1917
+ const target = event.target;
1918
+ if (!isNavTarget(target) && !isPopupTarget(target)) return;
1919
+ const trigger = target.closest("[aria-haspopup], [aria-controls], [aria-expanded]");
1920
+ if (trigger && popupTriggerInScope(trigger)) return;
1921
+ const item = target.closest('a[href], button, [role="link"], [role="menuitem"]');
1922
+ if (!item || !isNavTarget(item) && !isPopupTarget(item)) return;
1923
+ collapseNavigation();
1924
+ };
1925
+ const onClickCapture = (event) => {
1926
+ onTriggerIntent(event);
1927
+ if (mode === "pinned") queueMicrotask(() => onNavigationSelection(event));
1928
+ };
1862
1929
  const onKeyDownCapture = (event) => {
1863
1930
  if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown") onTriggerIntent(event);
1864
1931
  };
1865
1932
  const onDocumentPointerDown = (event) => {
1866
1933
  if (mode !== "pinned" || toggle?.contains(event.target) || isNavTarget(event.target) || isPopupTarget(event.target)) return;
1867
- pointerInside = false;
1868
- focusInside = false;
1869
- focusTarget = null;
1870
- clearEntryTimer();
1871
- clearCloseTimer();
1872
- setMode("compact");
1934
+ collapseNavigation();
1873
1935
  };
1874
1936
  const onDocumentKeyDown = (event) => {
1875
1937
  if (event.key !== "Escape" || mode === "compact" || event.defaultPrevented) return;
1876
1938
  if (popupOwnsInteraction()) return;
1877
- clearEntryTimer();
1878
- clearCloseTimer();
1879
- pointerInside = false;
1880
- focusInside = false;
1881
- focusTarget = null;
1882
- setMode("compact");
1939
+ const restoreToggleFocus = mode === "pinned";
1940
+ collapseNavigation();
1941
+ if (restoreToggleFocus) toggle?.focus();
1883
1942
  };
1884
1943
  const attachDocumentListeners = () => {
1885
1944
  document.addEventListener("pointerover", onPointerOver, true);
@@ -1890,6 +1949,8 @@ function connectInteraction() {
1890
1949
  document.addEventListener("keydown", onKeyDownCapture, true);
1891
1950
  document.addEventListener("pointerdown", onDocumentPointerDown, true);
1892
1951
  document.addEventListener("keydown", onDocumentKeyDown);
1952
+ hoverPointer.addEventListener("change", onPointerCapabilitiesChange);
1953
+ coarsePointer.addEventListener("change", onPointerCapabilitiesChange);
1893
1954
  return () => {
1894
1955
  document.removeEventListener("pointerover", onPointerOver, true);
1895
1956
  document.removeEventListener("pointerout", onPointerOut, true);
@@ -1899,6 +1960,8 @@ function connectInteraction() {
1899
1960
  document.removeEventListener("keydown", onKeyDownCapture, true);
1900
1961
  document.removeEventListener("pointerdown", onDocumentPointerDown, true);
1901
1962
  document.removeEventListener("keydown", onDocumentKeyDown);
1963
+ hoverPointer.removeEventListener("change", onPointerCapabilitiesChange);
1964
+ coarsePointer.removeEventListener("change", onPointerCapabilitiesChange);
1902
1965
  };
1903
1966
  };
1904
1967
  documentCleanup = attachDocumentListeners();
@@ -1917,12 +1980,15 @@ function connectInteraction() {
1917
1980
  focusTarget = null;
1918
1981
  stopPopupTracking();
1919
1982
  setMode("compact");
1920
- if (!root) return;
1983
+ if (!root) {
1984
+ syncToggleReserve();
1985
+ return;
1986
+ }
1921
1987
  if (!root.id) {
1922
1988
  root.id = "dsh-better-left-sidebar-navigation";
1923
1989
  rootIdOwned = true;
1924
1990
  }
1925
- createToggle();
1991
+ refreshToggleAvailability();
1926
1992
  };
1927
1993
  return {
1928
1994
  setRoot,
@@ -1939,8 +2005,7 @@ function connectInteraction() {
1939
2005
  } else {
1940
2006
  refreshStateFromTargets();
1941
2007
  }
1942
- if (next.expansion === "click") createToggle();
1943
- else removeToggle();
2008
+ refreshToggleAvailability();
1944
2009
  syncToggle();
1945
2010
  },
1946
2011
  setCompactWidgetsActive(setActive) {
@@ -2040,6 +2105,7 @@ function connectLayoutAdapter(onRoot, compactWidgets) {
2040
2105
  let resizeObserver;
2041
2106
  let measureFrame = 0;
2042
2107
  let warnedFor = /* @__PURE__ */ new WeakSet();
2108
+ let navigationToggleReserve = 0;
2043
2109
  const readAnchors = (root) => {
2044
2110
  const brand = root.querySelector(DSH.brand);
2045
2111
  const newSession = root.querySelector(DSH.newSession);
@@ -2108,7 +2174,7 @@ function connectLayoutAdapter(onRoot, compactWidgets) {
2108
2174
  const panelHeight = conversationNavigation ? conversationSizing.panelHeight : panelContentHeight;
2109
2175
  const conversationTop = conversationNavigation ? conversationSizing.conversationTop : conversationGlobalTop;
2110
2176
  const navBottomReserve = preferences?.toolsPosition === "rail-bottom" ? toolsHeight + 8 : 8;
2111
- const toggleReserve = preferences?.expansion === "click" ? 44 : 0;
2177
+ const toggleReserve = navigationToggleReserve;
2112
2178
  const footerReserve = preferences?.toolsPosition === "rail-bottom" ? toolsHeight + 8 : 8;
2113
2179
  const widgetBoxes = [...compactWidgets.children].filter((child) => child instanceof HTMLElement);
2114
2180
  for (const box of widgetBoxes) resizeObserver?.observe(box);
@@ -2334,6 +2400,12 @@ function connectLayoutAdapter(onRoot, compactWidgets) {
2334
2400
  compactWidgetsActive = active;
2335
2401
  if (current && preferences) scheduleMeasure();
2336
2402
  },
2403
+ setNavigationToggleReserve(reserve) {
2404
+ const next = Math.max(0, Math.ceil(reserve));
2405
+ if (navigationToggleReserve === next) return;
2406
+ navigationToggleReserve = next;
2407
+ if (current && preferences) scheduleMeasure();
2408
+ },
2337
2409
  dispose() {
2338
2410
  hostObserver?.disconnect();
2339
2411
  hostObserver = void 0;
@@ -3292,8 +3364,8 @@ function apply(ctx) {
3292
3364
  style.textContent = sidebar_default;
3293
3365
  document.head.append(style);
3294
3366
  html.classList.add("dsh-better-left-sidebar");
3295
- const interaction = connectInteraction();
3296
3367
  let layout;
3368
+ const interaction = connectInteraction((reserve) => layout?.setNavigationToggleReserve(reserve));
3297
3369
  const compactWidgets = connectCompactWidgets(ctx, (count, active) => layout?.setCompactWidgets(count, active));
3298
3370
  interaction.setCompactWidgetsActive(compactWidgets.setActive);
3299
3371
  layout = connectLayoutAdapter((root, anchorsChanged) => interaction.setRoot(root, anchorsChanged), compactWidgets.container);
package/lib/index.js CHANGED
@@ -39,7 +39,7 @@ var Config = z.object({
39
39
  var inject = [];
40
40
  function apply(ctx, _config) {
41
41
  ctx.effect(() => {
42
- console.info(`[${name}] ${"0.1.2"} loaded`);
42
+ console.info(`[${name}] ${"0.1.4"} loaded`);
43
43
  return () => console.info(`[${name}] unloaded`);
44
44
  });
45
45
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-better-left-sidebar",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "A cleaner, better-organized DeepSeek Harness sidebar with support for multiple plugin-defined widgets.",
5
5
  "icon": "./icon.svg",
6
6
  "license": "Apache-2.0",