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;"); });