feat(ui): restore floating panel buttons

This commit is contained in:
psychedelicious
2025-06-20 12:51:02 +10:00
parent b88a258ba5
commit 6b8ff54839
12 changed files with 512 additions and 186 deletions

View File

@@ -10,7 +10,7 @@ import { LaunchpadUseALayoutImageButton } from './LaunchpadUseALayoutImageButton
export const CanvasLaunchpadPanel = memo(() => {
return (
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
<Flex flexDir="column" w="full" h="full" gap={4} px={12} maxW={768} pt="20%">
<Flex flexDir="column" w="full" h="full" gap={4} px={14} maxW={768} pt="20%">
<Heading mb={4}>Edit and refine on Canvas.</Heading>
<Flex flexDir="column" gap={8}>
<Grid gridTemplateColumns="1fr 1fr" gap={8}>

View File

@@ -15,7 +15,7 @@ export const GenerateLaunchpadPanel = memo(() => {
return (
<Flex flexDir="column" h="full" w="full" alignItems="center" justifyContent="center" gap={2}>
<Flex flexDir="column" w="full" h="full" justifyContent="center" gap={4} px={12} maxW={768}>
<Flex flexDir="column" w="full" h="full" justifyContent="center" gap={4} px={14} maxW={768}>
<Heading mb={4}>Generate images from text prompts.</Heading>
<Flex flexDir="column" gap={8}>
<Grid gridTemplateColumns="1fr 1fr" gap={8}>

View File

@@ -4,7 +4,7 @@ import { memo } from 'react';
export const UpscalingLaunchpadPanel = memo(() => {
return (
<Flex flexDir="column" h="full" w="full" alignItems="center" justifyContent="center" gap={2}>
<Flex flexDir="column" w="full" h="full" justifyContent="center" gap={4} px={12} maxW={768}>
<Flex flexDir="column" w="full" h="full" justifyContent="center" gap={4} px={14} maxW={768}>
<Heading mb={4}>Upscale and add detail.</Heading>
</Flex>
</Flex>

View File

@@ -4,7 +4,7 @@ import { memo } from 'react';
export const WorkflowsLaunchpadPanel = memo(() => {
return (
<Flex flexDir="column" h="full" w="full" alignItems="center" justifyContent="center" gap={2}>
<Flex flexDir="column" w="full" h="full" justifyContent="center" gap={4} px={12} maxW={768}>
<Flex flexDir="column" w="full" h="full" justifyContent="center" gap={4} px={14} maxW={768}>
<Heading mb={4}>Go deep with Workflows.</Heading>
</Flex>
</Flex>

View File

@@ -17,7 +17,7 @@ export const GalleryTopBar = memo(() => {
const dispatch = useAppDispatch();
const boardSearchText = useAppSelector(selectBoardSearchText);
const boardSearchDisclosure = useBoardSearchDisclosure();
const $api = useAutoLayoutContext();
const { $api } = useAutoLayoutContext();
const api = useStore($api);
const boardsPanel = useCollapsibleGridviewPanel(api, 'Boards', 'vertical', 256);
const isBoardsPanelCollapsed = useStore(boardsPanel.$isCollapsed);

View File

@@ -1,12 +1,12 @@
import { ButtonGroup, Flex, Icon, IconButton, spinAnimation, Tooltip, useShiftModifier } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser';
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { useDeleteAllExceptCurrentQueueItemDialog } from 'features/queue/components/DeleteAllExceptCurrentQueueItemConfirmationAlertDialog';
import { InvokeButtonTooltip } from 'features/queue/components/InvokeButtonTooltip/InvokeButtonTooltip';
import { useDeleteCurrentQueueItem } from 'features/queue/hooks/useDeleteCurrentQueueItem';
import { useInvoke } from 'features/queue/hooks/useInvoke';
import { selectActiveTab } from 'features/ui/store/uiSelectors';
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -19,18 +19,11 @@ import {
} from 'react-icons/pi';
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
export const FloatingLeftPanelButtons = memo((props: { onToggle: () => void }) => {
const tab = useAppSelector(selectActiveTab);
export const FloatingLeftPanelButtons = memo(() => {
return (
<Flex pos="absolute" transform="translate(0, -50%)" top="50%" insetInlineStart={2} direction="column" gap={2}>
{tab === 'canvas' && (
<CanvasManagerProviderGate>
<ToolChooser />
</CanvasManagerProviderGate>
)}
<ButtonGroup orientation="vertical" h={48}>
<ToggleLeftPanelButton onToggle={props.onToggle} />
<ToggleLeftPanelButton />
<InvokeIconButton />
<DeleteCurrentIconButton />
<DeleteAllExceptCurrentIconButton />
@@ -41,13 +34,37 @@ export const FloatingLeftPanelButtons = memo((props: { onToggle: () => void }) =
FloatingLeftPanelButtons.displayName = 'FloatingLeftPanelButtons';
const ToggleLeftPanelButton = memo((props: { onToggle: () => void }) => {
export const FloatingCanvasLeftPanelButtons = memo(() => {
return (
<Flex pos="absolute" transform="translate(0, -50%)" top="50%" insetInlineStart={2} direction="column" gap={2}>
<CanvasManagerProviderGate>
<ToolChooser />
</CanvasManagerProviderGate>
<ButtonGroup orientation="vertical" h={48}>
<ToggleLeftPanelButton />
<InvokeIconButton />
<DeleteCurrentIconButton />
<DeleteAllExceptCurrentIconButton />
</ButtonGroup>
</Flex>
);
});
FloatingCanvasLeftPanelButtons.displayName = 'FloatingCanvasLeftPanelButtons';
const ToggleLeftPanelButton = memo(() => {
const { toggleLeftPanel } = useAutoLayoutContext();
useRegisteredHotkeys({
category: 'app',
id: 'toggleLeftPanel',
callback: toggleLeftPanel,
});
const { t } = useTranslation();
return (
<Tooltip label={t('accessibility.toggleLeftPanel')} placement="end">
<IconButton
aria-label={t('accessibility.toggleLeftPanel')}
onClick={props.onToggle}
onClick={toggleLeftPanel}
icon={<PiSlidersHorizontalBold />}
flexGrow={1}
/>

View File

@@ -1,24 +1,33 @@
import { Flex, IconButton, Tooltip } from '@invoke-ai/ui-library';
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiImagesSquareBold } from 'react-icons/pi';
export const FloatingRightPanelButtons = memo((props: { onToggle: () => void }) => {
export const FloatingRightPanelButtons = memo(() => {
return (
<Flex pos="absolute" transform="translate(0, -50%)" minW={8} top="50%" insetInlineEnd={2}>
<ToggleRightPanelButton onToggle={props.onToggle} />
<ToggleRightPanelButton />
</Flex>
);
});
FloatingRightPanelButtons.displayName = 'FloatingRightPanelButtons';
const ToggleRightPanelButton = memo((props: { onToggle: () => void }) => {
const ToggleRightPanelButton = memo(() => {
const { t } = useTranslation();
const { toggleRightPanel } = useAutoLayoutContext();
useRegisteredHotkeys({
category: 'app',
id: 'toggleRightPanel',
callback: toggleRightPanel,
});
return (
<Tooltip label={t('accessibility.toggleRightPanel')} placement="start">
<IconButton
aria-label={t('accessibility.toggleRightPanel')}
onClick={props.onToggle}
onClick={toggleRightPanel}
icon={<PiImagesSquareBold />}
h={48}
/>

View File

@@ -1,18 +1,32 @@
import type { GridviewApi } from 'dockview';
import type { Atom } from 'nanostores';
import type { PropsWithChildren } from 'react';
import { createContext, useContext } from 'react';
import { createContext, useContext, useMemo } from 'react';
const AutoLayoutContext = createContext<Atom<GridviewApi | null> | null>(null);
type AutoLayoutContextValue = {
$api: Atom<GridviewApi | null>;
toggleLeftPanel: () => void;
toggleRightPanel: () => void;
};
export const AutoLayoutProvider = (props: PropsWithChildren<{ $api: Atom<GridviewApi | null> }>) => {
return <AutoLayoutContext.Provider value={props.$api}>{props.children}</AutoLayoutContext.Provider>;
const AutoLayoutContext = createContext<AutoLayoutContextValue | null>(null);
export const AutoLayoutProvider = (props: PropsWithChildren<AutoLayoutContextValue>) => {
const value = useMemo<AutoLayoutContextValue>(
() => ({
$api: props.$api,
toggleLeftPanel: props.toggleLeftPanel,
toggleRightPanel: props.toggleRightPanel,
}),
[props.$api, props.toggleLeftPanel, props.toggleRightPanel]
);
return <AutoLayoutContext.Provider value={value}>{props.children}</AutoLayoutContext.Provider>;
};
export const useAutoLayoutContext = () => {
const api = useContext(AutoLayoutContext);
if (!api) {
const value = useContext(AutoLayoutContext);
if (!value) {
throw new Error('useAutoLayoutContext must be used within an AutoLayoutProvider');
}
return api;
return value;
};

View File

@@ -1,11 +1,13 @@
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
import { DockviewReact, GridviewReact, Orientation } from 'dockview';
import { DockviewReact, GridviewReact, LayoutPriority, Orientation } from 'dockview';
import { CanvasLayersPanel } from 'features/controlLayers/components/CanvasLayersPanelContent';
import { CanvasLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/CanvasLaunchpadPanel';
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
import { GalleryPanel } from 'features/gallery/components/Gallery';
import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer/GenerationProgressPanel';
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
import { AutoLayoutProvider } from 'features/ui/layouts/auto-layout-context';
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
import { LEFT_PANEL_MIN_SIZE_PX, RIGHT_PANEL_MIN_SIZE_PX } from 'features/ui/store/uiSlice';
@@ -84,57 +86,40 @@ const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
const MainPanel = memo(() => {
return (
<DockviewReact
disableDnd={true}
locked={true}
disableFloatingGroups={true}
dndEdges={false}
defaultTabComponent={TabWithoutCloseButton}
components={mainPanelComponents}
onReady={onReadyMainPanel}
theme={dockviewTheme}
/>
<>
<DockviewReact
disableDnd={true}
locked={true}
disableFloatingGroups={true}
dndEdges={false}
defaultTabComponent={TabWithoutCloseButton}
components={mainPanelComponents}
onReady={onReadyMainPanel}
theme={dockviewTheme}
/>
<FloatingLeftPanelButtons />
<FloatingRightPanelButtons />
</>
);
});
MainPanel.displayName = 'MainPanel';
const LEFT_PANEL_ID = 'left';
const MAIN_PANEL_ID = 'main';
const BOARDS_PANEL_ID = 'boards';
const GALLERY_PANEL_ID = 'gallery';
const LAYERS_PANEL_ID = 'layers';
export const canvasTabComponents: IGridviewReactProps['components'] = {
[LEFT_PANEL_ID]: CanvasTabLeftPanel,
[MAIN_PANEL_ID]: MainPanel,
const rightPanelComponents: IGridviewReactProps['components'] = {
[BOARDS_PANEL_ID]: BoardsPanel,
[GALLERY_PANEL_ID]: GalleryPanel,
[LAYERS_PANEL_ID]: CanvasLayersPanel,
};
export const initializeLayout = (api: GridviewApi) => {
api.addPanel({
id: MAIN_PANEL_ID,
component: MAIN_PANEL_ID,
});
api.addPanel({
id: LEFT_PANEL_ID,
component: LEFT_PANEL_ID,
minimumWidth: LEFT_PANEL_MIN_SIZE_PX,
position: {
direction: 'left',
referencePanel: MAIN_PANEL_ID,
},
});
export const initializeRightLayout = (api: GridviewApi) => {
api.addPanel({
id: GALLERY_PANEL_ID,
component: GALLERY_PANEL_ID,
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
minimumHeight: 232,
position: {
direction: 'right',
referencePanel: MAIN_PANEL_ID,
},
});
api.addPanel({
id: LAYERS_PANEL_ID,
@@ -154,8 +139,63 @@ export const initializeLayout = (api: GridviewApi) => {
referencePanel: GALLERY_PANEL_ID,
},
});
api.getPanel(LEFT_PANEL_ID)?.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
api.getPanel(BOARDS_PANEL_ID)?.api.setSize({ height: 256, width: RIGHT_PANEL_MIN_SIZE_PX });
};
const onReadyRightPanel: IGridviewReactProps['onReady'] = (event) => {
initializeRightLayout(event.api);
};
const RightPanel = memo(() => {
return (
<>
<GridviewReact
className="dockview-theme-invoke"
orientation={Orientation.VERTICAL}
components={rightPanelComponents}
onReady={onReadyRightPanel}
/>
</>
);
});
RightPanel.displayName = 'RightPanel';
const LEFT_PANEL_ID = 'left';
const MAIN_PANEL_ID = 'main';
const RIGHT_PANEL_ID = 'right';
export const rootComponents: IGridviewReactProps['components'] = {
[LEFT_PANEL_ID]: CanvasTabLeftPanel,
[MAIN_PANEL_ID]: MainPanel,
[RIGHT_PANEL_ID]: RightPanel,
};
export const initializeRootLayout = (api: GridviewApi) => {
api.addPanel({
id: MAIN_PANEL_ID,
component: MAIN_PANEL_ID,
priority: LayoutPriority.High,
});
api.addPanel({
id: LEFT_PANEL_ID,
component: LEFT_PANEL_ID,
minimumWidth: LEFT_PANEL_MIN_SIZE_PX,
position: {
direction: 'left',
referencePanel: MAIN_PANEL_ID,
},
});
api.addPanel({
id: RIGHT_PANEL_ID,
component: RIGHT_PANEL_ID,
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
position: {
direction: 'right',
referencePanel: MAIN_PANEL_ID,
},
});
api.getPanel(LEFT_PANEL_ID)?.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
api.getPanel(RIGHT_PANEL_ID)?.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
api.getPanel(MAIN_PANEL_ID)?.api.setActive();
};
@@ -165,7 +205,7 @@ export const CanvasTabAutoLayout = memo(() => {
const onReady = useCallback<IGridviewReactProps['onReady']>(
(event) => {
$api.set(event.api);
initializeLayout(event.api);
initializeRootLayout(event.api);
},
[$api]
);
@@ -195,13 +235,47 @@ export const CanvasTabAutoLayout = memo(() => {
setSize();
}, [$api]);
useOnFirstVisible(ref, resizeMainPanelOnFirstVisible);
const toggleLeftPanel = useCallback(() => {
const api = $api.get();
if (!api) {
return;
}
const left = api.getPanel(LEFT_PANEL_ID);
if (!left) {
return;
}
if (left.maximumWidth === 0) {
left.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: LEFT_PANEL_MIN_SIZE_PX });
left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
} else {
left.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
left.api.setSize({ width: 0 });
}
}, [$api]);
const toggleRightPanel = useCallback(() => {
const api = $api.get();
if (!api) {
return;
}
const right = api.getPanel(RIGHT_PANEL_ID);
if (!right) {
return;
}
if (right.maximumWidth === 0) {
right.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: RIGHT_PANEL_MIN_SIZE_PX });
right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
} else {
right.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
right.api.setSize({ width: 0 });
}
}, [$api]);
return (
<AutoLayoutProvider $api={$api}>
<AutoLayoutProvider $api={$api} toggleLeftPanel={toggleLeftPanel} toggleRightPanel={toggleRightPanel}>
<GridviewReact
ref={ref}
className="dockview-theme-invoke"
components={canvasTabComponents}
components={rootComponents}
onReady={onReady}
orientation={Orientation.VERTICAL}
/>

View File

@@ -1,10 +1,12 @@
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
import { DockviewReact, GridviewReact, Orientation } from 'dockview';
import { DockviewReact, GridviewReact, LayoutPriority, Orientation } from 'dockview';
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/GenerateLaunchpadPanel';
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
import { GalleryPanel } from 'features/gallery/components/Gallery';
import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer/GenerationProgressPanel';
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
import { AutoLayoutProvider } from 'features/ui/layouts/auto-layout-context';
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
import { LEFT_PANEL_MIN_SIZE_PX, RIGHT_PANEL_MIN_SIZE_PX } from 'features/ui/store/uiSlice';
@@ -71,36 +73,84 @@ const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
const MainPanel = memo(() => {
return (
<DockviewReact
disableDnd={true}
locked={true}
disableFloatingGroups={true}
dndEdges={false}
defaultTabComponent={TabWithoutCloseButton}
components={mainPanelComponents}
onReady={onReadyMainPanel}
theme={dockviewTheme}
/>
<>
<DockviewReact
disableDnd={true}
locked={true}
disableFloatingGroups={true}
dndEdges={false}
defaultTabComponent={TabWithoutCloseButton}
components={mainPanelComponents}
onReady={onReadyMainPanel}
theme={dockviewTheme}
/>
<FloatingLeftPanelButtons />
<FloatingRightPanelButtons />
</>
);
});
MainPanel.displayName = 'MainPanel';
const LEFT_PANEL_ID = 'left';
const MAIN_PANEL_ID = 'main';
const BOARDS_PANEL_ID = 'boards';
const GALLERY_PANEL_ID = 'gallery';
export const generateTabComponents: IGridviewReactProps['components'] = {
[LEFT_PANEL_ID]: GenerateTabLeftPanel,
[MAIN_PANEL_ID]: MainPanel,
const rightPanelComponents: IGridviewReactProps['components'] = {
[BOARDS_PANEL_ID]: BoardsPanel,
[GALLERY_PANEL_ID]: GalleryPanel,
};
export const initializeLayout = (api: GridviewApi) => {
export const initializeRightLayout = (api: GridviewApi) => {
api.addPanel({
id: GALLERY_PANEL_ID,
component: GALLERY_PANEL_ID,
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
minimumHeight: 232,
});
api.addPanel({
id: BOARDS_PANEL_ID,
component: BOARDS_PANEL_ID,
minimumHeight: 36,
position: {
direction: 'above',
referencePanel: GALLERY_PANEL_ID,
},
});
api.getPanel(BOARDS_PANEL_ID)?.api.setSize({ height: 256, width: RIGHT_PANEL_MIN_SIZE_PX });
};
const onReadyRightPanel: IGridviewReactProps['onReady'] = (event) => {
initializeRightLayout(event.api);
};
const RightPanel = memo(() => {
return (
<>
<GridviewReact
className="dockview-theme-invoke"
orientation={Orientation.VERTICAL}
components={rightPanelComponents}
onReady={onReadyRightPanel}
/>
</>
);
});
RightPanel.displayName = 'RightPanel';
const LEFT_PANEL_ID = 'left';
const MAIN_PANEL_ID = 'main';
const RIGHT_PANEL_ID = 'right';
export const rootComponents: IGridviewReactProps['components'] = {
[LEFT_PANEL_ID]: GenerateTabLeftPanel,
[MAIN_PANEL_ID]: MainPanel,
[RIGHT_PANEL_ID]: RightPanel,
};
export const initializeRootLayout = (api: GridviewApi) => {
api.addPanel({
id: MAIN_PANEL_ID,
component: MAIN_PANEL_ID,
priority: LayoutPriority.High,
});
api.addPanel({
id: LEFT_PANEL_ID,
@@ -112,26 +162,16 @@ export const initializeLayout = (api: GridviewApi) => {
},
});
api.addPanel({
id: GALLERY_PANEL_ID,
component: GALLERY_PANEL_ID,
id: RIGHT_PANEL_ID,
component: RIGHT_PANEL_ID,
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
minimumHeight: 232,
position: {
direction: 'right',
referencePanel: MAIN_PANEL_ID,
},
});
api.addPanel({
id: BOARDS_PANEL_ID,
component: BOARDS_PANEL_ID,
minimumHeight: 36,
position: {
direction: 'above',
referencePanel: GALLERY_PANEL_ID,
},
});
api.getPanel(LEFT_PANEL_ID)?.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
api.getPanel(BOARDS_PANEL_ID)?.api.setSize({ height: 256, width: RIGHT_PANEL_MIN_SIZE_PX });
api.getPanel(RIGHT_PANEL_ID)?.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
api.getPanel(MAIN_PANEL_ID)?.api.setActive();
};
@@ -141,7 +181,7 @@ export const GenerateTabAutoLayout = memo(() => {
const onReady = useCallback<IGridviewReactProps['onReady']>(
(event) => {
$api.set(event.api);
initializeLayout(event.api);
initializeRootLayout(event.api);
},
[$api]
);
@@ -171,13 +211,46 @@ export const GenerateTabAutoLayout = memo(() => {
setSize();
}, [$api]);
useOnFirstVisible(ref, resizeMainPanelOnFirstVisible);
const toggleLeftPanel = useCallback(() => {
const api = $api.get();
if (!api) {
return;
}
const left = api.getPanel(LEFT_PANEL_ID);
if (!left) {
return;
}
if (left.maximumWidth === 0) {
left.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: LEFT_PANEL_MIN_SIZE_PX });
left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
} else {
left.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
left.api.setSize({ width: 0 });
}
}, [$api]);
const toggleRightPanel = useCallback(() => {
const api = $api.get();
if (!api) {
return;
}
const right = api.getPanel(RIGHT_PANEL_ID);
if (!right) {
return;
}
if (right.maximumWidth === 0) {
right.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: RIGHT_PANEL_MIN_SIZE_PX });
right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
} else {
right.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
right.api.setSize({ width: 0 });
}
}, [$api]);
return (
<AutoLayoutProvider $api={$api}>
<AutoLayoutProvider $api={$api} toggleLeftPanel={toggleLeftPanel} toggleRightPanel={toggleRightPanel}>
<GridviewReact
ref={ref}
className="dockview-theme-invoke"
components={generateTabComponents}
components={rootComponents}
onReady={onReady}
orientation={Orientation.VERTICAL}
/>

View File

@@ -1,10 +1,12 @@
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
import { DockviewReact, GridviewReact, Orientation } from 'dockview';
import { DockviewReact, GridviewReact, LayoutPriority, Orientation } from 'dockview';
import { UpscalingLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/UpscalingLaunchpadPanel';
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
import { GalleryPanel } from 'features/gallery/components/Gallery';
import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer/GenerationProgressPanel';
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
import { AutoLayoutProvider } from 'features/ui/layouts/auto-layout-context';
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
import { LEFT_PANEL_MIN_SIZE_PX, RIGHT_PANEL_MIN_SIZE_PX } from 'features/ui/store/uiSlice';
@@ -71,58 +73,38 @@ const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
const MainPanel = memo(() => {
return (
<DockviewReact
disableDnd={true}
locked={true}
disableFloatingGroups={true}
dndEdges={false}
defaultTabComponent={TabWithoutCloseButton}
components={dockviewComponents}
onReady={onReadyMainPanel}
theme={dockviewTheme}
/>
<>
<DockviewReact
disableDnd={true}
locked={true}
disableFloatingGroups={true}
dndEdges={false}
defaultTabComponent={TabWithoutCloseButton}
components={dockviewComponents}
onReady={onReadyMainPanel}
theme={dockviewTheme}
/>
<FloatingLeftPanelButtons />
<FloatingRightPanelButtons />
</>
);
});
MainPanel.displayName = 'MainPanel';
const LEFT_PANEL_ID = 'left';
const MAIN_PANEL_ID = 'main';
const BOARDS_PANEL_ID = 'boards';
const GALLERY_PANEL_ID = 'gallery';
export const gridviewComponents: IGridviewReactProps['components'] = {
[LEFT_PANEL_ID]: UpscalingTabLeftPanel,
[MAIN_PANEL_ID]: MainPanel,
const rightPanelComponents: IGridviewReactProps['components'] = {
[BOARDS_PANEL_ID]: BoardsPanel,
[GALLERY_PANEL_ID]: GalleryPanel,
};
export const initializeLayout = (api: GridviewApi) => {
api.addPanel({
id: MAIN_PANEL_ID,
component: MAIN_PANEL_ID,
// priority: LayoutPriority.High,
});
api.addPanel({
id: LEFT_PANEL_ID,
component: LEFT_PANEL_ID,
minimumWidth: LEFT_PANEL_MIN_SIZE_PX,
position: {
direction: 'left',
referencePanel: MAIN_PANEL_ID,
},
// priority: LayoutPriority.High,
});
export const initializeRightLayout = (api: GridviewApi) => {
api.addPanel({
id: GALLERY_PANEL_ID,
component: GALLERY_PANEL_ID,
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
minimumHeight: 232,
position: {
direction: 'right',
referencePanel: MAIN_PANEL_ID,
},
// priority: LayoutPriority.High,
});
api.addPanel({
id: BOARDS_PANEL_ID,
@@ -132,10 +114,64 @@ export const initializeLayout = (api: GridviewApi) => {
direction: 'above',
referencePanel: GALLERY_PANEL_ID,
},
// priority: LayoutPriority.High,
});
api.getPanel(BOARDS_PANEL_ID)?.api.setSize({ height: 256, width: RIGHT_PANEL_MIN_SIZE_PX });
};
const onReadyRightPanel: IGridviewReactProps['onReady'] = (event) => {
initializeRightLayout(event.api);
};
const RightPanel = memo(() => {
return (
<>
<GridviewReact
className="dockview-theme-invoke"
orientation={Orientation.VERTICAL}
components={rightPanelComponents}
onReady={onReadyRightPanel}
/>
</>
);
});
RightPanel.displayName = 'RightPanel';
const LEFT_PANEL_ID = 'left';
const MAIN_PANEL_ID = 'main';
const RIGHT_PANEL_ID = 'right';
export const rootComponents: IGridviewReactProps['components'] = {
[LEFT_PANEL_ID]: UpscalingTabLeftPanel,
[MAIN_PANEL_ID]: MainPanel,
[RIGHT_PANEL_ID]: RightPanel,
};
export const initializeRootLayout = (api: GridviewApi) => {
api.addPanel({
id: MAIN_PANEL_ID,
component: MAIN_PANEL_ID,
priority: LayoutPriority.High,
});
api.addPanel({
id: LEFT_PANEL_ID,
component: LEFT_PANEL_ID,
minimumWidth: LEFT_PANEL_MIN_SIZE_PX,
position: {
direction: 'left',
referencePanel: MAIN_PANEL_ID,
},
});
api.addPanel({
id: RIGHT_PANEL_ID,
component: RIGHT_PANEL_ID,
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
position: {
direction: 'right',
referencePanel: MAIN_PANEL_ID,
},
});
api.getPanel(LEFT_PANEL_ID)?.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
api.getPanel(BOARDS_PANEL_ID)?.api.setSize({ height: 256, width: RIGHT_PANEL_MIN_SIZE_PX });
api.getPanel(RIGHT_PANEL_ID)?.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
api.getPanel(MAIN_PANEL_ID)?.api.setActive();
};
@@ -145,7 +181,7 @@ export const UpscalingTabAutoLayout = memo(() => {
const onReady = useCallback<IGridviewReactProps['onReady']>(
(event) => {
$api.set(event.api);
initializeLayout(event.api);
initializeRootLayout(event.api);
},
[$api]
);
@@ -175,13 +211,46 @@ export const UpscalingTabAutoLayout = memo(() => {
setSize();
}, [$api]);
useOnFirstVisible(ref, resizeMainPanelOnFirstVisible);
const toggleLeftPanel = useCallback(() => {
const api = $api.get();
if (!api) {
return;
}
const left = api.getPanel(LEFT_PANEL_ID);
if (!left) {
return;
}
if (left.maximumWidth === 0) {
left.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: LEFT_PANEL_MIN_SIZE_PX });
left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
} else {
left.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
left.api.setSize({ width: 0 });
}
}, [$api]);
const toggleRightPanel = useCallback(() => {
const api = $api.get();
if (!api) {
return;
}
const right = api.getPanel(RIGHT_PANEL_ID);
if (!right) {
return;
}
if (right.maximumWidth === 0) {
right.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: RIGHT_PANEL_MIN_SIZE_PX });
right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
} else {
right.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
right.api.setSize({ width: 0 });
}
}, [$api]);
return (
<AutoLayoutProvider $api={$api}>
<AutoLayoutProvider $api={$api} toggleLeftPanel={toggleLeftPanel} toggleRightPanel={toggleRightPanel}>
<GridviewReact
ref={ref}
className="dockview-theme-invoke"
components={gridviewComponents}
components={rootComponents}
onReady={onReady}
orientation={Orientation.VERTICAL}
/>

View File

@@ -1,5 +1,5 @@
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
import { DockviewReact, GridviewReact, Orientation } from 'dockview';
import { DockviewReact, GridviewReact, LayoutPriority, Orientation } from 'dockview';
import { WorkflowsLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/WorkflowsLaunchpadPanel';
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
import { GalleryPanel } from 'features/gallery/components/Gallery';
@@ -7,6 +7,8 @@ import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
import NodeEditor from 'features/nodes/components/NodeEditor';
import WorkflowsTabLeftPanel from 'features/nodes/components/sidePanel/WorkflowsTabLeftPanel';
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
import { AutoLayoutProvider } from 'features/ui/layouts/auto-layout-context';
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
import { LEFT_PANEL_MIN_SIZE_PX, RIGHT_PANEL_MIN_SIZE_PX } from 'features/ui/store/uiSlice';
@@ -83,58 +85,38 @@ const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
const MainPanel = memo(() => {
return (
<DockviewReact
disableDnd={true}
locked={true}
disableFloatingGroups={true}
dndEdges={false}
defaultTabComponent={TabWithoutCloseButton}
components={dockviewComponents}
onReady={onReadyMainPanel}
theme={dockviewTheme}
/>
<>
<DockviewReact
disableDnd={true}
locked={true}
disableFloatingGroups={true}
dndEdges={false}
defaultTabComponent={TabWithoutCloseButton}
components={dockviewComponents}
onReady={onReadyMainPanel}
theme={dockviewTheme}
/>
<FloatingLeftPanelButtons />
<FloatingRightPanelButtons />
</>
);
});
MainPanel.displayName = 'MainPanel';
const LEFT_PANEL_ID = 'left';
const MAIN_PANEL_ID = 'main';
const BOARDS_PANEL_ID = 'boards';
const GALLERY_PANEL_ID = 'gallery';
export const gridviewComponents: IGridviewReactProps['components'] = {
[LEFT_PANEL_ID]: WorkflowsTabLeftPanel,
[MAIN_PANEL_ID]: MainPanel,
const rightPanelComponents: IGridviewReactProps['components'] = {
[BOARDS_PANEL_ID]: BoardsPanel,
[GALLERY_PANEL_ID]: GalleryPanel,
};
export const initializeLayout = (api: GridviewApi) => {
api.addPanel({
id: MAIN_PANEL_ID,
component: MAIN_PANEL_ID,
// priority: LayoutPriority.High,
});
api.addPanel({
id: LEFT_PANEL_ID,
component: LEFT_PANEL_ID,
minimumWidth: LEFT_PANEL_MIN_SIZE_PX,
position: {
direction: 'left',
referencePanel: MAIN_PANEL_ID,
},
// priority: LayoutPriority.High,
});
export const initializeRightLayout = (api: GridviewApi) => {
api.addPanel({
id: GALLERY_PANEL_ID,
component: GALLERY_PANEL_ID,
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
minimumHeight: 232,
position: {
direction: 'right',
referencePanel: MAIN_PANEL_ID,
},
// priority: LayoutPriority.High,
});
api.addPanel({
id: BOARDS_PANEL_ID,
@@ -144,10 +126,64 @@ export const initializeLayout = (api: GridviewApi) => {
direction: 'above',
referencePanel: GALLERY_PANEL_ID,
},
// priority: LayoutPriority.High,
});
api.getPanel(BOARDS_PANEL_ID)?.api.setSize({ height: 256, width: RIGHT_PANEL_MIN_SIZE_PX });
};
const onReadyRightPanel: IGridviewReactProps['onReady'] = (event) => {
initializeRightLayout(event.api);
};
const RightPanel = memo(() => {
return (
<>
<GridviewReact
className="dockview-theme-invoke"
orientation={Orientation.VERTICAL}
components={rightPanelComponents}
onReady={onReadyRightPanel}
/>
</>
);
});
RightPanel.displayName = 'RightPanel';
const LEFT_PANEL_ID = 'left';
const MAIN_PANEL_ID = 'main';
const RIGHT_PANEL_ID = 'right';
export const rootComponents: IGridviewReactProps['components'] = {
[LEFT_PANEL_ID]: WorkflowsTabLeftPanel,
[MAIN_PANEL_ID]: MainPanel,
[RIGHT_PANEL_ID]: RightPanel,
};
export const initializeRootLayout = (api: GridviewApi) => {
api.addPanel({
id: MAIN_PANEL_ID,
component: MAIN_PANEL_ID,
priority: LayoutPriority.High,
});
api.addPanel({
id: LEFT_PANEL_ID,
component: LEFT_PANEL_ID,
minimumWidth: LEFT_PANEL_MIN_SIZE_PX,
position: {
direction: 'left',
referencePanel: MAIN_PANEL_ID,
},
});
api.addPanel({
id: RIGHT_PANEL_ID,
component: RIGHT_PANEL_ID,
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
position: {
direction: 'right',
referencePanel: MAIN_PANEL_ID,
},
});
api.getPanel(LEFT_PANEL_ID)?.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
api.getPanel(BOARDS_PANEL_ID)?.api.setSize({ height: 256, width: RIGHT_PANEL_MIN_SIZE_PX });
api.getPanel(RIGHT_PANEL_ID)?.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
api.getPanel(MAIN_PANEL_ID)?.api.setActive();
};
@@ -157,7 +193,7 @@ export const WorkflowsTabAutoLayout = memo(() => {
const onReady = useCallback<IGridviewReactProps['onReady']>(
(event) => {
$api.set(event.api);
initializeLayout(event.api);
initializeRootLayout(event.api);
},
[$api]
);
@@ -187,13 +223,47 @@ export const WorkflowsTabAutoLayout = memo(() => {
setSize();
}, [$api]);
useOnFirstVisible(ref, resizeMainPanelOnFirstVisible);
const toggleLeftPanel = useCallback(() => {
const api = $api.get();
if (!api) {
return;
}
const left = api.getPanel(LEFT_PANEL_ID);
if (!left) {
return;
}
if (left.maximumWidth === 0) {
left.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: LEFT_PANEL_MIN_SIZE_PX });
left.api.setSize({ width: LEFT_PANEL_MIN_SIZE_PX });
} else {
left.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
left.api.setSize({ width: 0 });
}
}, [$api]);
const toggleRightPanel = useCallback(() => {
const api = $api.get();
if (!api) {
return;
}
const right = api.getPanel(RIGHT_PANEL_ID);
if (!right) {
return;
}
if (right.maximumWidth === 0) {
right.api.setConstraints({ maximumWidth: Number.MAX_SAFE_INTEGER, minimumWidth: RIGHT_PANEL_MIN_SIZE_PX });
right.api.setSize({ width: RIGHT_PANEL_MIN_SIZE_PX });
} else {
right.api.setConstraints({ maximumWidth: 0, minimumWidth: 0 });
right.api.setSize({ width: 0 });
}
}, [$api]);
return (
<AutoLayoutProvider $api={$api}>
<AutoLayoutProvider $api={$api} toggleLeftPanel={toggleLeftPanel} toggleRightPanel={toggleRightPanel}>
<GridviewReact
ref={ref}
className="dockview-theme-invoke"
components={gridviewComponents}
components={rootComponents}
onReady={onReady}
orientation={Orientation.VERTICAL}
/>