diff --git a/invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx b/invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx index e2cbfe2c5d2..f5068bb1926 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx @@ -34,6 +34,7 @@ import { DOCKVIEW_TAB_CANVAS_VIEWER_ID, DOCKVIEW_TAB_CANVAS_WORKSPACE_ID, DOCKVIEW_TAB_LAUNCHPAD_ID, + enforceMainPanelMinWidth, GALLERY_PANEL_DEFAULT_HEIGHT_PX, GALLERY_PANEL_ID, GALLERY_PANEL_MIN_HEIGHT_PX, @@ -43,6 +44,7 @@ import { LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX, MAIN_PANEL_ID, + MAIN_PANEL_MIN_SIZE_PX, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX, SETTINGS_PANEL_ID, @@ -261,6 +263,7 @@ const initializeRootPanelLayout = (tab: TabName, api: GridviewApi) => { const main = api.addPanel({ id: MAIN_PANEL_ID, component: MAIN_PANEL_ID, + minimumWidth: MAIN_PANEL_MIN_SIZE_PX, priority: LayoutPriority.High, }); @@ -289,6 +292,7 @@ const initializeRootPanelLayout = (tab: TabName, api: GridviewApi) => { left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX }); right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX }); }); + enforceMainPanelMinWidth(api); }; export const CanvasTabAutoLayout = memo(() => { diff --git a/invokeai/frontend/web/src/features/ui/layouts/generate-tab-auto-layout.tsx b/invokeai/frontend/web/src/features/ui/layouts/generate-tab-auto-layout.tsx index e60c15b5da3..d56953b3b6e 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/generate-tab-auto-layout.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/generate-tab-auto-layout.tsx @@ -32,6 +32,7 @@ import { DOCKVIEW_TAB_ID, DOCKVIEW_TAB_LAUNCHPAD_ID, DOCKVIEW_TAB_PROGRESS_ID, + enforceMainPanelMinWidth, GALLERY_PANEL_DEFAULT_HEIGHT_PX, GALLERY_PANEL_ID, GALLERY_PANEL_MIN_HEIGHT_PX, @@ -39,6 +40,7 @@ import { LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX, MAIN_PANEL_ID, + MAIN_PANEL_MIN_SIZE_PX, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX, SETTINGS_PANEL_ID, @@ -224,6 +226,7 @@ const initializeRootPanelLayout = (tab: TabName, api: GridviewApi) => { const main = api.addPanel({ id: MAIN_PANEL_ID, component: MAIN_PANEL_ID, + minimumWidth: MAIN_PANEL_MIN_SIZE_PX, priority: LayoutPriority.High, }); @@ -250,6 +253,7 @@ const initializeRootPanelLayout = (tab: TabName, api: GridviewApi) => { left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX }); right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX }); }); + enforceMainPanelMinWidth(api); }; export const GenerateTabAutoLayout = memo(() => { diff --git a/invokeai/frontend/web/src/features/ui/layouts/shared.ts b/invokeai/frontend/web/src/features/ui/layouts/shared.ts index 191ccfd82dd..a372bb20854 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/shared.ts +++ b/invokeai/frontend/web/src/features/ui/layouts/shared.ts @@ -1,3 +1,5 @@ +import type { GridviewApi } from 'dockview'; + export const LEFT_PANEL_ID = 'left'; export const MAIN_PANEL_ID = 'main'; export const RIGHT_PANEL_ID = 'right'; @@ -24,6 +26,9 @@ export const DOCKVIEW_TAB_CANVAS_WORKSPACE_ID = 'tab-canvas-workspace'; export const LEFT_PANEL_MIN_SIZE_PX = 420; export const RIGHT_PANEL_MIN_SIZE_PX = 420; +// Keeps the main panel wide enough to fit the floating left/right toggle button +// groups on small screens, so the user can always grab them to expand the side panels. +export const MAIN_PANEL_MIN_SIZE_PX = 128; export const BOARD_PANEL_MIN_HEIGHT_PX = 36; export const BOARD_PANEL_MIN_EXPANDED_HEIGHT_PX = 128; @@ -38,3 +43,22 @@ export const LAYERS_PANEL_MIN_HEIGHT_PX = 36; export const CANVAS_BOARD_PANEL_DEFAULT_HEIGHT_PX = 36; // Collapsed by default on Canvas export const SWITCH_TABS_FAKE_DELAY_MS = 300; + +/** + * Enforce the main panel's minimum width on the root gridview after the + * container has been (re)constructed. The panel's `minimumWidth` set at + * `addPanel` time only applies on a fresh layout — when `registerContainer` + * restores from persisted JSON, the constraints come from that JSON, which + * may pre-date `MAIN_PANEL_MIN_SIZE_PX`. Re-apply it here, and grow the panel + * if its restored size violates the new minimum. + */ +export const enforceMainPanelMinWidth = (api: GridviewApi): void => { + const main = api.getPanel(MAIN_PANEL_ID); + if (!main) { + return; + } + main.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: MAIN_PANEL_MIN_SIZE_PX }); + if (main.api.width < MAIN_PANEL_MIN_SIZE_PX) { + main.api.setSize({ width: MAIN_PANEL_MIN_SIZE_PX }); + } +}; diff --git a/invokeai/frontend/web/src/features/ui/layouts/upscaling-tab-auto-layout.tsx b/invokeai/frontend/web/src/features/ui/layouts/upscaling-tab-auto-layout.tsx index e4f443148ff..a1112a19e24 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/upscaling-tab-auto-layout.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/upscaling-tab-auto-layout.tsx @@ -30,6 +30,7 @@ import { DOCKVIEW_TAB_ID, DOCKVIEW_TAB_LAUNCHPAD_ID, DOCKVIEW_TAB_PROGRESS_ID, + enforceMainPanelMinWidth, GALLERY_PANEL_DEFAULT_HEIGHT_PX, GALLERY_PANEL_ID, GALLERY_PANEL_MIN_HEIGHT_PX, @@ -37,6 +38,7 @@ import { LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX, MAIN_PANEL_ID, + MAIN_PANEL_MIN_SIZE_PX, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX, SETTINGS_PANEL_ID, @@ -223,6 +225,7 @@ const initializeRootPanelLayout = (tab: TabName, api: GridviewApi) => { const main = api.addPanel({ id: MAIN_PANEL_ID, component: MAIN_PANEL_ID, + minimumWidth: MAIN_PANEL_MIN_SIZE_PX, priority: LayoutPriority.High, }); @@ -249,6 +252,7 @@ const initializeRootPanelLayout = (tab: TabName, api: GridviewApi) => { left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX }); right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX }); }); + enforceMainPanelMinWidth(api); }; export const UpscalingTabAutoLayout = memo(() => { diff --git a/invokeai/frontend/web/src/features/ui/layouts/workflows-tab-auto-layout.tsx b/invokeai/frontend/web/src/features/ui/layouts/workflows-tab-auto-layout.tsx index 026b7897283..672f00110c5 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/workflows-tab-auto-layout.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/workflows-tab-auto-layout.tsx @@ -32,6 +32,7 @@ import { DOCKVIEW_TAB_ID, DOCKVIEW_TAB_LAUNCHPAD_ID, DOCKVIEW_TAB_PROGRESS_ID, + enforceMainPanelMinWidth, GALLERY_PANEL_DEFAULT_HEIGHT_PX, GALLERY_PANEL_ID, GALLERY_PANEL_MIN_HEIGHT_PX, @@ -39,6 +40,7 @@ import { LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX, MAIN_PANEL_ID, + MAIN_PANEL_MIN_SIZE_PX, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX, SETTINGS_PANEL_ID, @@ -243,6 +245,7 @@ const initializeRootPanelLayout = (tab: TabName, api: GridviewApi) => { const main = api.addPanel({ id: MAIN_PANEL_ID, component: MAIN_PANEL_ID, + minimumWidth: MAIN_PANEL_MIN_SIZE_PX, priority: LayoutPriority.High, }); @@ -269,6 +272,7 @@ const initializeRootPanelLayout = (tab: TabName, api: GridviewApi) => { left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX }); right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX }); }); + enforceMainPanelMinWidth(api); }; export const WorkflowsTabAutoLayout = memo(() => {