diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue
index 24e360db6e..3ab5aab13a 100644
--- a/apps/desktop/src/App.vue
+++ b/apps/desktop/src/App.vue
@@ -3877,7 +3877,7 @@ onUnmounted(() => {
diff --git a/apps/desktop/src/composables/__tests__/usePanelResize.spec.ts b/apps/desktop/src/composables/__tests__/usePanelResize.spec.ts
index 8cc6772061..1870d1f763 100644
--- a/apps/desktop/src/composables/__tests__/usePanelResize.spec.ts
+++ b/apps/desktop/src/composables/__tests__/usePanelResize.spec.ts
@@ -80,6 +80,34 @@ describe("usePanelResize", () => {
expect(localStorage.getItem("dbx-ai-panel-width")).toBe("600");
});
+ it("keeps resizable panels wide enough for their toolbar actions", () => {
+ const panel = document.createElement("div");
+ const handle = document.createElement("div");
+ panel.append(handle);
+ document.body.append(panel);
+
+ vi.spyOn(panel, "getBoundingClientRect").mockReturnValue(rect(0, 260));
+
+ const { sidebarWidth, startSidebarResize } = usePanelResize();
+ handle.addEventListener("mousedown", startSidebarResize);
+ handle.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, clientX: 260 }));
+ document.dispatchEvent(new MouseEvent("mousemove", { clientX: 0 }));
+ document.dispatchEvent(new MouseEvent("mouseup"));
+
+ expect(sidebarWidth.value).toBe(240);
+ expect(localStorage.getItem("dbx-sidebar-width")).toBe("240");
+ });
+
+ it("raises persisted panel widths below the toolbar-safe minimum", () => {
+ localStorage.setItem("dbx-sidebar-width", "180");
+ localStorage.setItem("dbx-ai-panel-width", "200");
+
+ const { sidebarWidth, aiPanelWidth } = usePanelResize();
+
+ expect(sidebarWidth.value).toBe(240);
+ expect(aiPanelWidth.value).toBe(240);
+ });
+
it("persists the collapsed vertical tab bar state across composable instances", () => {
const first = usePanelResize();
expect(first.tabBarCollapsed.value).toBe(false);
diff --git a/apps/desktop/src/composables/usePanelResize.ts b/apps/desktop/src/composables/usePanelResize.ts
index 57101dba51..a6d1ecae68 100644
--- a/apps/desktop/src/composables/usePanelResize.ts
+++ b/apps/desktop/src/composables/usePanelResize.ts
@@ -1,10 +1,14 @@
import { ref, type Ref } from "vue";
import { safeLocalStorageGet, safeLocalStorageSet } from "@/lib/backend/safeStorage";
-const PANEL_MIN_WIDTH = 180;
+const PANEL_MIN_WIDTH = 240;
const DEFAULT_PANEL_MAX_WIDTH = 800;
type PanelMaxWidth = number | ((handle: HTMLElement | null) => number);
+function restoredPanelWidth(storageKey: string, fallback: number): number {
+ return Math.max(PANEL_MIN_WIDTH, Number(safeLocalStorageGet(storageKey)) || fallback);
+}
+
function availableAiPanelMaxWidth(handle: HTMLElement | null) {
const panel = handle?.parentElement;
const flexibleContent = panel?.previousElementSibling as HTMLElement | null;
@@ -16,12 +20,12 @@ function availableAiPanelMaxWidth(handle: HTMLElement | null) {
}
export function usePanelResize() {
- const sidebarWidth = ref(Number(safeLocalStorageGet("dbx-sidebar-width")) || 260);
- const aiPanelWidth = ref(Number(safeLocalStorageGet("dbx-ai-panel-width")) || 360);
- const historyWidth = ref(Number(safeLocalStorageGet("dbx-history-width")) || 288);
- const sqlLibraryWidth = ref(Number(safeLocalStorageGet("dbx-sql-library-width")) || 288);
- const sqlFilePanelWidth = ref(Number(safeLocalStorageGet("dbx-sql-file-panel-width")) || 288);
- const tabBarWidth = ref(Number(safeLocalStorageGet("dbx-tab-bar-width")) || 240);
+ const sidebarWidth = ref(restoredPanelWidth("dbx-sidebar-width", 260));
+ const aiPanelWidth = ref(restoredPanelWidth("dbx-ai-panel-width", 360));
+ const historyWidth = ref(restoredPanelWidth("dbx-history-width", 288));
+ const sqlLibraryWidth = ref(restoredPanelWidth("dbx-sql-library-width", 288));
+ const sqlFilePanelWidth = ref(restoredPanelWidth("dbx-sql-file-panel-width", 288));
+ const tabBarWidth = ref(restoredPanelWidth("dbx-tab-bar-width", 240));
const tabBarCollapsed = ref(safeLocalStorageGet("dbx-tab-bar-collapsed") === "true");
function startPanelResize(widthRef: Ref
, storageKey: string, direction: "left" | "right", maxWidth: PanelMaxWidth = DEFAULT_PANEL_MAX_WIDTH) {
diff --git a/apps/desktop/src/lib/__tests__/app/rightSidebarPanels.spec.ts b/apps/desktop/src/lib/__tests__/app/rightSidebarPanels.spec.ts
index 96cab7276e..db90d857f8 100644
--- a/apps/desktop/src/lib/__tests__/app/rightSidebarPanels.spec.ts
+++ b/apps/desktop/src/lib/__tests__/app/rightSidebarPanels.spec.ts
@@ -59,7 +59,7 @@ describe("right sidebar panel entry points", () => {
expect(appSource).toContain("const isAiPanelMaximized = ref(false);");
expect(appSource).toContain(':maximized="isAiPanelMaximized"');
expect(appSource).toContain('@toggle-maximize="toggleAiPanelMaximized"');
- expect(appSource).toContain("isAiPanelMaximized ? 'min-w-0 flex-1' : 'min-w-[180px] max-w-full'");
+ expect(appSource).toContain("isAiPanelMaximized ? 'min-w-0 flex-1' : 'min-w-[240px] max-w-full'");
expect(appSource).toContain('v-show="!isAiPanelMaximized && !isZenMode"');
expect(functionSource("setRightSidebarPanelOpen", "toggleRightSidebarPanel")).toContain("isAiPanelMaximized.value = false;");
});