mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-12 17:05:02 -05:00
feat(ui): standardize auto layout structure
This commit is contained in:
@@ -1,48 +1,31 @@
|
||||
import { Button, Flex, IconButton } from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { Flex, IconButton, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useBoardSearchDisclosure } from 'features/gallery/components/Boards/BoardsList/BoardsSearch';
|
||||
import { BoardsSettingsPopover } from 'features/gallery/components/Boards/BoardsSettingsPopover';
|
||||
import { GalleryHeader } from 'features/gallery/components/GalleryHeader';
|
||||
import { selectBoardSearchText } from 'features/gallery/store/gallerySelectors';
|
||||
import { boardSearchTextChanged } from 'features/gallery/store/gallerySlice';
|
||||
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import { useCollapsibleGridviewPanel } from 'features/ui/layouts/use-collapsible-gridview-panel';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCaretDownBold, PiCaretUpBold, PiMagnifyingGlassBold } from 'react-icons/pi';
|
||||
import { PiMagnifyingGlassBold } from 'react-icons/pi';
|
||||
|
||||
export const GalleryTopBar = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const boardSearchText = useAppSelector(selectBoardSearchText);
|
||||
const boardSearchDisclosure = useBoardSearchDisclosure();
|
||||
const { $api } = useAutoLayoutContext();
|
||||
const api = useStore($api);
|
||||
const boardsPanel = useCollapsibleGridviewPanel(api, 'Boards', 'vertical', 256);
|
||||
const isBoardsPanelCollapsed = useStore(boardsPanel.$isCollapsed);
|
||||
|
||||
const onClickBoardSearch = useCallback(() => {
|
||||
if (boardSearchText.length) {
|
||||
dispatch(boardSearchTextChanged(''));
|
||||
}
|
||||
if (!boardSearchDisclosure.isOpen && boardsPanel.$isCollapsed.get()) {
|
||||
boardsPanel.expand();
|
||||
}
|
||||
boardSearchDisclosure.toggle();
|
||||
}, [boardSearchText.length, boardSearchDisclosure, dispatch, boardsPanel]);
|
||||
}, [boardSearchText.length, boardSearchDisclosure, dispatch]);
|
||||
|
||||
return (
|
||||
<Flex alignItems="center" justifyContent="space-between" w="full">
|
||||
<Flex flexGrow={1} flexBasis={0}>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={boardsPanel.toggle}
|
||||
rightIcon={isBoardsPanelCollapsed ? <PiCaretDownBold /> : <PiCaretUpBold />}
|
||||
>
|
||||
{isBoardsPanelCollapsed ? t('boards.viewBoards') : t('boards.hideBoards')}
|
||||
</Button>
|
||||
<Text>Boards</Text>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<GalleryHeader />
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { IconMenuItem } from 'common/components/IconMenuItem';
|
||||
import { useImageDTOContext } from 'features/gallery/contexts/ImageDTOContext';
|
||||
import { imageSelected, imageToCompareChanged } from 'features/gallery/store/gallerySlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiArrowsOutBold } from 'react-icons/pi';
|
||||
|
||||
export const ImageMenuItemOpenInViewer = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const imageDTO = useImageDTOContext();
|
||||
const onClick = useCallback(() => {
|
||||
// TODO
|
||||
imageDTO.image_name;
|
||||
}, [imageDTO]);
|
||||
dispatch(imageToCompareChanged(null));
|
||||
dispatch(imageSelected(imageDTO));
|
||||
// TODO: figure out how to select the closest image viewer...
|
||||
}, [dispatch, imageDTO]);
|
||||
|
||||
return (
|
||||
<IconMenuItem
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useImageContextMenu } from 'features/gallery/components/ImageContextMen
|
||||
import { GalleryImageHoverIcons } from 'features/gallery/components/ImageGrid/GalleryImageHoverIcons';
|
||||
import { getGalleryImageDataTestId } from 'features/gallery/components/ImageGrid/getGalleryImageDataTestId';
|
||||
import { imageToCompareChanged, selectGallerySlice } from 'features/gallery/store/gallerySlice';
|
||||
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import type { MouseEventHandler } from 'react';
|
||||
import { memo, useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
@@ -83,6 +84,7 @@ interface Props {
|
||||
|
||||
export const GalleryImage = memo(({ imageDTO }: Props) => {
|
||||
const store = useAppStore();
|
||||
const autoLayoutContext = useAutoLayoutContext();
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [dragPreviewState, setDragPreviewState] = useState<
|
||||
DndDragPreviewSingleImageState | DndDragPreviewMultipleImageState | null
|
||||
@@ -203,7 +205,8 @@ export const GalleryImage = memo(({ imageDTO }: Props) => {
|
||||
|
||||
const onDoubleClick = useCallback<MouseEventHandler<HTMLDivElement>>(() => {
|
||||
store.dispatch(imageToCompareChanged(null));
|
||||
}, [store]);
|
||||
autoLayoutContext.focusImageViewer();
|
||||
}, [autoLayoutContext, store]);
|
||||
|
||||
const dataTestId = useMemo(() => getGalleryImageDataTestId(imageDTO.image_name), [imageDTO.image_name]);
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { DndImageIcon } from 'features/dnd/DndImageIcon';
|
||||
import { imageSelected, imageToCompareChanged } from 'features/gallery/store/gallerySlice';
|
||||
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiArrowsOutBold } from 'react-icons/pi';
|
||||
@@ -9,12 +12,15 @@ type Props = {
|
||||
};
|
||||
|
||||
export const GalleryImageOpenInViewerIconButton = memo(({ imageDTO }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { focusImageViewer } = useAutoLayoutContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
// TODO
|
||||
imageDTO.image_name;
|
||||
}, [imageDTO]);
|
||||
dispatch(imageToCompareChanged(null));
|
||||
dispatch(imageSelected(imageDTO));
|
||||
focusImageViewer();
|
||||
}, [dispatch, focusImageViewer, imageDTO]);
|
||||
|
||||
return (
|
||||
<DndImageIcon
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
import type { GridviewApi } from 'dockview';
|
||||
import type { DockviewApi, GridviewApi } from 'dockview';
|
||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||
import type { Atom } from 'nanostores';
|
||||
import type { WritableAtom } from 'nanostores';
|
||||
import { atom } from 'nanostores';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { createContext, memo, useCallback, useContext, useMemo } from 'react';
|
||||
import { createContext, memo, useCallback, useContext, useMemo, useState } from 'react';
|
||||
|
||||
import { LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX } from './shared';
|
||||
import {
|
||||
LEFT_PANEL_ID,
|
||||
LEFT_PANEL_MIN_SIZE_PX,
|
||||
RIGHT_PANEL_ID,
|
||||
RIGHT_PANEL_MIN_SIZE_PX,
|
||||
VIEWER_PANEL_ID,
|
||||
} from './shared';
|
||||
|
||||
type AutoLayoutContextValue = {
|
||||
$api: Atom<GridviewApi | null>;
|
||||
toggleLeftPanel: () => void;
|
||||
toggleRightPanel: () => void;
|
||||
toggleBothPanels: () => void;
|
||||
resetPanels: () => void;
|
||||
focusImageViewer: () => void;
|
||||
_$rootPanelApi: WritableAtom<GridviewApi | null>;
|
||||
_$leftPanelApi: WritableAtom<GridviewApi | null>;
|
||||
_$centerPanelApi: WritableAtom<DockviewApi | null>;
|
||||
_$rightPanelApi: WritableAtom<GridviewApi | null>;
|
||||
};
|
||||
|
||||
const AutoLayoutContext = createContext<AutoLayoutContextValue | null>(null);
|
||||
@@ -42,9 +53,22 @@ const getIsCollapsed = (api: GridviewApi, panelId: string) => {
|
||||
return panel.maximumWidth === 0;
|
||||
};
|
||||
|
||||
export const AutoLayoutProvider = (props: PropsWithChildren<{ $api: Atom<GridviewApi | null> }>) => {
|
||||
const activatePanel = (api: GridviewApi | DockviewApi, panelId: string) => {
|
||||
const panel = api.getPanel(panelId);
|
||||
if (!panel) {
|
||||
return;
|
||||
}
|
||||
panel.api.setActive();
|
||||
};
|
||||
|
||||
export const AutoLayoutProvider = (props: PropsWithChildren<{ $rootApi: WritableAtom<GridviewApi | null> }>) => {
|
||||
const { $rootApi, children } = props;
|
||||
const $leftApi = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const $centerApi = useState(() => atom<DockviewApi | null>(null))[0];
|
||||
const $rightApi = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
|
||||
const toggleLeftPanel = useCallback(() => {
|
||||
const api = props.$api.get();
|
||||
const api = $rootApi.get();
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
@@ -53,10 +77,10 @@ export const AutoLayoutProvider = (props: PropsWithChildren<{ $api: Atom<Gridvie
|
||||
} else {
|
||||
collapsePanel(api, LEFT_PANEL_ID);
|
||||
}
|
||||
}, [props.$api]);
|
||||
}, [$rootApi]);
|
||||
|
||||
const toggleRightPanel = useCallback(() => {
|
||||
const api = props.$api.get();
|
||||
const api = $rootApi.get();
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
@@ -65,10 +89,10 @@ export const AutoLayoutProvider = (props: PropsWithChildren<{ $api: Atom<Gridvie
|
||||
} else {
|
||||
collapsePanel(api, RIGHT_PANEL_ID);
|
||||
}
|
||||
}, [props.$api]);
|
||||
}, [$rootApi]);
|
||||
|
||||
const toggleBothPanels = useCallback(() => {
|
||||
const api = props.$api.get();
|
||||
const api = $rootApi.get();
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
@@ -81,28 +105,50 @@ export const AutoLayoutProvider = (props: PropsWithChildren<{ $api: Atom<Gridvie
|
||||
collapsePanel(api, RIGHT_PANEL_ID);
|
||||
}
|
||||
});
|
||||
}, [props.$api]);
|
||||
}, [$rootApi]);
|
||||
|
||||
const resetPanels = useCallback(() => {
|
||||
const api = props.$api.get();
|
||||
const api = $rootApi.get();
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
expandPanel(api, LEFT_PANEL_ID, LEFT_PANEL_MIN_SIZE_PX);
|
||||
expandPanel(api, RIGHT_PANEL_ID, RIGHT_PANEL_MIN_SIZE_PX);
|
||||
}, [props.$api]);
|
||||
}, [$rootApi]);
|
||||
|
||||
const focusImageViewer = useCallback(() => {
|
||||
const api = $centerApi.get();
|
||||
if (!api) {
|
||||
return;
|
||||
}
|
||||
activatePanel(api, VIEWER_PANEL_ID);
|
||||
}, [$centerApi]);
|
||||
|
||||
const value = useMemo<AutoLayoutContextValue>(
|
||||
() => ({
|
||||
$api: props.$api,
|
||||
toggleLeftPanel,
|
||||
toggleRightPanel,
|
||||
toggleBothPanels,
|
||||
resetPanels,
|
||||
focusImageViewer,
|
||||
_$rootPanelApi: $rootApi,
|
||||
_$leftPanelApi: $leftApi,
|
||||
_$centerPanelApi: $centerApi,
|
||||
_$rightPanelApi: $rightApi,
|
||||
}),
|
||||
[props.$api, resetPanels, toggleBothPanels, toggleLeftPanel, toggleRightPanel]
|
||||
[
|
||||
$centerApi,
|
||||
$leftApi,
|
||||
$rightApi,
|
||||
$rootApi,
|
||||
focusImageViewer,
|
||||
resetPanels,
|
||||
toggleBothPanels,
|
||||
toggleLeftPanel,
|
||||
toggleRightPanel,
|
||||
]
|
||||
);
|
||||
return <AutoLayoutContext.Provider value={value}>{props.children}</AutoLayoutContext.Provider>;
|
||||
return <AutoLayoutContext.Provider value={value}>{children}</AutoLayoutContext.Provider>;
|
||||
};
|
||||
|
||||
export const useAutoLayoutContext = () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import type { DockviewApi, GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import { DockviewReact, GridviewReact, LayoutPriority, Orientation } from 'dockview';
|
||||
import { CanvasLayersPanel } from 'features/controlLayers/components/CanvasLayersPanelContent';
|
||||
import { CanvasLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/CanvasLaunchpadPanel';
|
||||
@@ -8,7 +8,7 @@ import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer
|
||||
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
||||
import { FloatingCanvasLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
||||
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
||||
import { AutoLayoutProvider, PanelHotkeysLogical } from 'features/ui/layouts/auto-layout-context';
|
||||
import { AutoLayoutProvider, PanelHotkeysLogical, useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
||||
import { dockviewTheme } from 'features/ui/styles/theme';
|
||||
import { atom } from 'nanostores';
|
||||
@@ -17,28 +17,30 @@ import { memo, useCallback, useRef, useState } from 'react';
|
||||
import { CanvasTabLeftPanel } from './CanvasTabLeftPanel';
|
||||
import { CanvasWorkspacePanel } from './CanvasWorkspacePanel';
|
||||
import {
|
||||
BOARDS_PANEL_ID,
|
||||
GALLERY_PANEL_ID,
|
||||
LAUNCHPAD_PANEL_ID,
|
||||
LAYERS_PANEL_ID,
|
||||
LEFT_PANEL_ID,
|
||||
LEFT_PANEL_MIN_SIZE_PX,
|
||||
MAIN_PANEL_ID,
|
||||
PROGRESS_PANEL_ID,
|
||||
RIGHT_PANEL_ID,
|
||||
RIGHT_PANEL_MIN_SIZE_PX,
|
||||
SETTINGS_PANEL_ID,
|
||||
VIEWER_PANEL_ID,
|
||||
WORKSPACE_PANEL_ID,
|
||||
} from './shared';
|
||||
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
|
||||
|
||||
const LAUNCHPAD_PANEL_ID = 'launchpad';
|
||||
const WORKSPACE_PANEL_ID = 'workspace';
|
||||
const VIEWER_PANEL_ID = 'viewer';
|
||||
const PROGRESS_PANEL_ID = 'progress';
|
||||
|
||||
const mainPanelComponents: IDockviewReactProps['components'] = {
|
||||
const centerPanelComponents: IDockviewReactProps['components'] = {
|
||||
[LAUNCHPAD_PANEL_ID]: CanvasLaunchpadPanel,
|
||||
[WORKSPACE_PANEL_ID]: CanvasWorkspacePanel,
|
||||
[VIEWER_PANEL_ID]: ImageViewerPanel,
|
||||
[PROGRESS_PANEL_ID]: GenerationProgressPanel,
|
||||
};
|
||||
|
||||
const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
|
||||
const { api } = event;
|
||||
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
||||
api.addPanel({
|
||||
id: LAUNCHPAD_PANEL_ID,
|
||||
component: LAUNCHPAD_PANEL_ID,
|
||||
@@ -73,24 +75,31 @@ const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
|
||||
});
|
||||
|
||||
api.getPanel(LAUNCHPAD_PANEL_ID)?.api.setActive();
|
||||
|
||||
const disposables = [
|
||||
api.onWillShowOverlay((e) => {
|
||||
if (e.kind === 'header_space' || e.kind === 'tab') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
disposables.forEach((disposable) => {
|
||||
disposable.dispose();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const MainPanel = memo(() => {
|
||||
const CenterPanel = memo(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IDockviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeCenterPanelLayout(event.api);
|
||||
ctx._$centerPanelApi.set(event.api);
|
||||
const disposables = [
|
||||
event.api.onWillShowOverlay((e) => {
|
||||
if (e.kind === 'header_space' || e.kind === 'tab') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
disposables.forEach((disposable) => {
|
||||
disposable.dispose();
|
||||
});
|
||||
};
|
||||
},
|
||||
[ctx._$centerPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<DockviewReact
|
||||
@@ -99,8 +108,8 @@ const MainPanel = memo(() => {
|
||||
disableFloatingGroups={true}
|
||||
dndEdges={false}
|
||||
defaultTabComponent={TabWithoutCloseButton}
|
||||
components={mainPanelComponents}
|
||||
onReady={onReadyMainPanel}
|
||||
components={centerPanelComponents}
|
||||
onReady={onReady}
|
||||
theme={dockviewTheme}
|
||||
/>
|
||||
<FloatingCanvasLeftPanelButtons />
|
||||
@@ -109,11 +118,7 @@ const MainPanel = memo(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
MainPanel.displayName = 'MainPanel';
|
||||
|
||||
const BOARDS_PANEL_ID = 'boards';
|
||||
const GALLERY_PANEL_ID = 'gallery';
|
||||
const LAYERS_PANEL_ID = 'layers';
|
||||
CenterPanel.displayName = 'CenterPanel';
|
||||
|
||||
const rightPanelComponents: IGridviewReactProps['components'] = {
|
||||
[BOARDS_PANEL_ID]: BoardsPanel,
|
||||
@@ -121,7 +126,7 @@ const rightPanelComponents: IGridviewReactProps['components'] = {
|
||||
[LAYERS_PANEL_ID]: CanvasLayersPanel,
|
||||
};
|
||||
|
||||
export const initializeRightLayout = (api: GridviewApi) => {
|
||||
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: GALLERY_PANEL_ID,
|
||||
component: GALLERY_PANEL_ID,
|
||||
@@ -149,31 +154,68 @@ export const initializeRightLayout = (api: GridviewApi) => {
|
||||
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(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeRightPanelLayout(event.api);
|
||||
ctx._$rightPanelApi.set(event.api);
|
||||
},
|
||||
[ctx._$rightPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<GridviewReact
|
||||
className="dockview-theme-invoke"
|
||||
orientation={Orientation.VERTICAL}
|
||||
components={rightPanelComponents}
|
||||
onReady={onReadyRightPanel}
|
||||
onReady={onReady}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
RightPanel.displayName = 'RightPanel';
|
||||
|
||||
export const rootComponents: IGridviewReactProps['components'] = {
|
||||
[LEFT_PANEL_ID]: CanvasTabLeftPanel,
|
||||
[MAIN_PANEL_ID]: MainPanel,
|
||||
const leftPanelComponents: IGridviewReactProps['components'] = {
|
||||
[SETTINGS_PANEL_ID]: CanvasTabLeftPanel,
|
||||
};
|
||||
|
||||
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: SETTINGS_PANEL_ID,
|
||||
component: SETTINGS_PANEL_ID,
|
||||
});
|
||||
};
|
||||
|
||||
const LeftPanel = memo(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeLeftPanelLayout(event.api);
|
||||
ctx._$leftPanelApi.set(event.api);
|
||||
},
|
||||
[ctx._$leftPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<GridviewReact
|
||||
className="dockview-theme-invoke"
|
||||
orientation={Orientation.VERTICAL}
|
||||
components={leftPanelComponents}
|
||||
onReady={onReady}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
LeftPanel.displayName = 'LeftPanel';
|
||||
|
||||
export const rootPanelComponents: IGridviewReactProps['components'] = {
|
||||
[LEFT_PANEL_ID]: LeftPanel,
|
||||
[MAIN_PANEL_ID]: CenterPanel,
|
||||
[RIGHT_PANEL_ID]: RightPanel,
|
||||
};
|
||||
|
||||
export const initializeRootLayout = (api: GridviewApi) => {
|
||||
export const initializeRootPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: MAIN_PANEL_ID,
|
||||
component: MAIN_PANEL_ID,
|
||||
@@ -204,22 +246,22 @@ export const initializeRootLayout = (api: GridviewApi) => {
|
||||
|
||||
export const CanvasTabAutoLayout = memo(() => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const $api = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const $rootPanelApi = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
$api.set(event.api);
|
||||
initializeRootLayout(event.api);
|
||||
$rootPanelApi.set(event.api);
|
||||
initializeRootPanelLayout(event.api);
|
||||
},
|
||||
[$api]
|
||||
[$rootPanelApi]
|
||||
);
|
||||
useResizeMainPanelOnFirstVisit($api, ref);
|
||||
useResizeMainPanelOnFirstVisit($rootPanelApi, ref);
|
||||
|
||||
return (
|
||||
<AutoLayoutProvider $api={$api}>
|
||||
<AutoLayoutProvider $rootApi={$rootPanelApi}>
|
||||
<GridviewReact
|
||||
ref={ref}
|
||||
className="dockview-theme-invoke"
|
||||
components={rootComponents}
|
||||
components={rootPanelComponents}
|
||||
onReady={onReady}
|
||||
orientation={Orientation.VERTICAL}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import type { DockviewApi, GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import { DockviewReact, GridviewReact, LayoutPriority, Orientation } from 'dockview';
|
||||
import { GenerateLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/GenerateLaunchpadPanel';
|
||||
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
|
||||
@@ -7,7 +7,7 @@ import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer
|
||||
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
||||
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
||||
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
||||
import { AutoLayoutProvider, PanelHotkeysLogical } from 'features/ui/layouts/auto-layout-context';
|
||||
import { AutoLayoutProvider, PanelHotkeysLogical, useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
||||
import { dockviewTheme } from 'features/ui/styles/theme';
|
||||
import { atom } from 'nanostores';
|
||||
@@ -15,26 +15,27 @@ import { memo, useCallback, useRef, useState } from 'react';
|
||||
|
||||
import { GenerateTabLeftPanel } from './GenerateTabLeftPanel';
|
||||
import {
|
||||
BOARDS_PANEL_ID,
|
||||
GALLERY_PANEL_ID,
|
||||
LAUNCHPAD_PANEL_ID,
|
||||
LEFT_PANEL_ID,
|
||||
LEFT_PANEL_MIN_SIZE_PX,
|
||||
MAIN_PANEL_ID,
|
||||
PROGRESS_PANEL_ID,
|
||||
RIGHT_PANEL_ID,
|
||||
RIGHT_PANEL_MIN_SIZE_PX,
|
||||
SETTINGS_PANEL_ID,
|
||||
VIEWER_PANEL_ID,
|
||||
} from './shared';
|
||||
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
|
||||
|
||||
const LAUNCHPAD_PANEL_ID = 'launchpad';
|
||||
const VIEWER_PANEL_ID = 'viewer';
|
||||
const PROGRESS_PANEL_ID = 'progress';
|
||||
|
||||
const mainPanelComponents: IDockviewReactProps['components'] = {
|
||||
const centerPanelComponents: IDockviewReactProps['components'] = {
|
||||
[LAUNCHPAD_PANEL_ID]: GenerateLaunchpadPanel,
|
||||
[VIEWER_PANEL_ID]: ImageViewerPanel,
|
||||
[PROGRESS_PANEL_ID]: GenerationProgressPanel,
|
||||
};
|
||||
|
||||
const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
|
||||
const { api } = event;
|
||||
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
||||
api.addPanel({
|
||||
id: LAUNCHPAD_PANEL_ID,
|
||||
component: LAUNCHPAD_PANEL_ID,
|
||||
@@ -60,24 +61,31 @@ const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
|
||||
});
|
||||
|
||||
api.getPanel(LAUNCHPAD_PANEL_ID)?.api.setActive();
|
||||
|
||||
const disposables = [
|
||||
api.onWillShowOverlay((e) => {
|
||||
if (e.kind === 'header_space' || e.kind === 'tab') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
disposables.forEach((disposable) => {
|
||||
disposable.dispose();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const MainPanel = memo(() => {
|
||||
const CenterPanel = memo(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IDockviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeCenterPanelLayout(event.api);
|
||||
ctx._$centerPanelApi.set(event.api);
|
||||
const disposables = [
|
||||
event.api.onWillShowOverlay((e) => {
|
||||
if (e.kind === 'header_space' || e.kind === 'tab') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
disposables.forEach((disposable) => {
|
||||
disposable.dispose();
|
||||
});
|
||||
};
|
||||
},
|
||||
[ctx._$centerPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<DockviewReact
|
||||
@@ -86,8 +94,8 @@ const MainPanel = memo(() => {
|
||||
disableFloatingGroups={true}
|
||||
dndEdges={false}
|
||||
defaultTabComponent={TabWithoutCloseButton}
|
||||
components={mainPanelComponents}
|
||||
onReady={onReadyMainPanel}
|
||||
components={centerPanelComponents}
|
||||
onReady={onReady}
|
||||
theme={dockviewTheme}
|
||||
/>
|
||||
<FloatingLeftPanelButtons />
|
||||
@@ -96,17 +104,14 @@ const MainPanel = memo(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
MainPanel.displayName = 'MainPanel';
|
||||
|
||||
const BOARDS_PANEL_ID = 'boards';
|
||||
const GALLERY_PANEL_ID = 'gallery';
|
||||
CenterPanel.displayName = 'CenterPanel';
|
||||
|
||||
const rightPanelComponents: IGridviewReactProps['components'] = {
|
||||
[BOARDS_PANEL_ID]: BoardsPanel,
|
||||
[GALLERY_PANEL_ID]: GalleryPanel,
|
||||
};
|
||||
|
||||
export const initializeRightLayout = (api: GridviewApi) => {
|
||||
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: GALLERY_PANEL_ID,
|
||||
component: GALLERY_PANEL_ID,
|
||||
@@ -125,31 +130,68 @@ export const initializeRightLayout = (api: GridviewApi) => {
|
||||
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(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeRightPanelLayout(event.api);
|
||||
ctx._$rightPanelApi.set(event.api);
|
||||
},
|
||||
[ctx._$rightPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<GridviewReact
|
||||
className="dockview-theme-invoke"
|
||||
orientation={Orientation.VERTICAL}
|
||||
components={rightPanelComponents}
|
||||
onReady={onReadyRightPanel}
|
||||
onReady={onReady}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
RightPanel.displayName = 'RightPanel';
|
||||
|
||||
export const rootComponents: IGridviewReactProps['components'] = {
|
||||
[LEFT_PANEL_ID]: GenerateTabLeftPanel,
|
||||
[MAIN_PANEL_ID]: MainPanel,
|
||||
const leftPanelComponents: IGridviewReactProps['components'] = {
|
||||
[SETTINGS_PANEL_ID]: GenerateTabLeftPanel,
|
||||
};
|
||||
|
||||
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: SETTINGS_PANEL_ID,
|
||||
component: SETTINGS_PANEL_ID,
|
||||
});
|
||||
};
|
||||
|
||||
const LeftPanel = memo(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeLeftPanelLayout(event.api);
|
||||
ctx._$leftPanelApi.set(event.api);
|
||||
},
|
||||
[ctx._$leftPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<GridviewReact
|
||||
className="dockview-theme-invoke"
|
||||
orientation={Orientation.VERTICAL}
|
||||
components={leftPanelComponents}
|
||||
onReady={onReady}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
LeftPanel.displayName = 'LeftPanel';
|
||||
|
||||
export const rootPanelComponents: IGridviewReactProps['components'] = {
|
||||
[LEFT_PANEL_ID]: LeftPanel,
|
||||
[MAIN_PANEL_ID]: CenterPanel,
|
||||
[RIGHT_PANEL_ID]: RightPanel,
|
||||
};
|
||||
|
||||
export const initializeRootLayout = (api: GridviewApi) => {
|
||||
export const initializeRootPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: MAIN_PANEL_ID,
|
||||
component: MAIN_PANEL_ID,
|
||||
@@ -180,22 +222,22 @@ export const initializeRootLayout = (api: GridviewApi) => {
|
||||
|
||||
export const GenerateTabAutoLayout = memo(() => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const $api = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const $rootPanelApi = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
$api.set(event.api);
|
||||
initializeRootLayout(event.api);
|
||||
$rootPanelApi.set(event.api);
|
||||
initializeRootPanelLayout(event.api);
|
||||
},
|
||||
[$api]
|
||||
[$rootPanelApi]
|
||||
);
|
||||
useResizeMainPanelOnFirstVisit($api, ref);
|
||||
useResizeMainPanelOnFirstVisit($rootPanelApi, ref);
|
||||
|
||||
return (
|
||||
<AutoLayoutProvider $api={$api}>
|
||||
<AutoLayoutProvider $rootApi={$rootPanelApi}>
|
||||
<GridviewReact
|
||||
ref={ref}
|
||||
className="dockview-theme-invoke"
|
||||
components={rootComponents}
|
||||
components={rootPanelComponents}
|
||||
onReady={onReady}
|
||||
orientation={Orientation.VERTICAL}
|
||||
/>
|
||||
|
||||
@@ -2,5 +2,16 @@ export const LEFT_PANEL_ID = 'left';
|
||||
export const MAIN_PANEL_ID = 'main';
|
||||
export const RIGHT_PANEL_ID = 'right';
|
||||
|
||||
export const LAUNCHPAD_PANEL_ID = 'launchpad';
|
||||
export const WORKSPACE_PANEL_ID = 'workspace';
|
||||
export const VIEWER_PANEL_ID = 'viewer';
|
||||
export const PROGRESS_PANEL_ID = 'progress';
|
||||
|
||||
export const BOARDS_PANEL_ID = 'boards';
|
||||
export const GALLERY_PANEL_ID = 'gallery';
|
||||
export const LAYERS_PANEL_ID = 'layers';
|
||||
|
||||
export const SETTINGS_PANEL_ID = 'settings';
|
||||
|
||||
export const LEFT_PANEL_MIN_SIZE_PX = 420;
|
||||
export const RIGHT_PANEL_MIN_SIZE_PX = 420;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import type { DockviewApi, GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import { DockviewReact, GridviewReact, LayoutPriority, Orientation } from 'dockview';
|
||||
import { UpscalingLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/UpscalingLaunchpadPanel';
|
||||
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
|
||||
@@ -7,34 +7,35 @@ import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer
|
||||
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
||||
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
||||
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
||||
import { AutoLayoutProvider, PanelHotkeysLogical } from 'features/ui/layouts/auto-layout-context';
|
||||
import { AutoLayoutProvider, PanelHotkeysLogical, useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
||||
import { dockviewTheme } from 'features/ui/styles/theme';
|
||||
import { atom } from 'nanostores';
|
||||
import { memo, useCallback, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
BOARDS_PANEL_ID,
|
||||
GALLERY_PANEL_ID,
|
||||
LAUNCHPAD_PANEL_ID,
|
||||
LEFT_PANEL_ID,
|
||||
LEFT_PANEL_MIN_SIZE_PX,
|
||||
MAIN_PANEL_ID,
|
||||
PROGRESS_PANEL_ID,
|
||||
RIGHT_PANEL_ID,
|
||||
RIGHT_PANEL_MIN_SIZE_PX,
|
||||
SETTINGS_PANEL_ID,
|
||||
VIEWER_PANEL_ID,
|
||||
} from './shared';
|
||||
import { UpscalingTabLeftPanel } from './UpscalingTabLeftPanel';
|
||||
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
|
||||
|
||||
const LAUNCHPAD_PANEL_ID = 'launchpad';
|
||||
const VIEWER_PANEL_ID = 'viewer';
|
||||
const PROGRESS_PANEL_ID = 'progress';
|
||||
|
||||
const dockviewComponents: IDockviewReactProps['components'] = {
|
||||
const centerComponents: IDockviewReactProps['components'] = {
|
||||
[LAUNCHPAD_PANEL_ID]: UpscalingLaunchpadPanel,
|
||||
[VIEWER_PANEL_ID]: ImageViewerPanel,
|
||||
[PROGRESS_PANEL_ID]: GenerationProgressPanel,
|
||||
};
|
||||
|
||||
const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
|
||||
const { api } = event;
|
||||
const initializeCenterLayout = (api: DockviewApi) => {
|
||||
api.addPanel({
|
||||
id: LAUNCHPAD_PANEL_ID,
|
||||
component: LAUNCHPAD_PANEL_ID,
|
||||
@@ -60,24 +61,30 @@ const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
|
||||
});
|
||||
|
||||
api.getPanel(LAUNCHPAD_PANEL_ID)?.api.setActive();
|
||||
|
||||
const disposables = [
|
||||
api.onWillShowOverlay((e) => {
|
||||
if (e.kind === 'header_space' || e.kind === 'tab') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
disposables.forEach((disposable) => {
|
||||
disposable.dispose();
|
||||
});
|
||||
};
|
||||
};
|
||||
const CenterPanel = memo(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IDockviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeCenterLayout(event.api);
|
||||
ctx._$centerPanelApi.set(event.api);
|
||||
const disposables = [
|
||||
event.api.onWillShowOverlay((e) => {
|
||||
if (e.kind === 'header_space' || e.kind === 'tab') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}),
|
||||
];
|
||||
|
||||
const MainPanel = memo(() => {
|
||||
return () => {
|
||||
disposables.forEach((disposable) => {
|
||||
disposable.dispose();
|
||||
});
|
||||
};
|
||||
},
|
||||
[ctx._$centerPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<DockviewReact
|
||||
@@ -86,8 +93,8 @@ const MainPanel = memo(() => {
|
||||
disableFloatingGroups={true}
|
||||
dndEdges={false}
|
||||
defaultTabComponent={TabWithoutCloseButton}
|
||||
components={dockviewComponents}
|
||||
onReady={onReadyMainPanel}
|
||||
components={centerComponents}
|
||||
onReady={onReady}
|
||||
theme={dockviewTheme}
|
||||
/>
|
||||
<FloatingLeftPanelButtons />
|
||||
@@ -96,17 +103,14 @@ const MainPanel = memo(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
MainPanel.displayName = 'MainPanel';
|
||||
|
||||
const BOARDS_PANEL_ID = 'boards';
|
||||
const GALLERY_PANEL_ID = 'gallery';
|
||||
CenterPanel.displayName = 'CenterPanel';
|
||||
|
||||
const rightPanelComponents: IGridviewReactProps['components'] = {
|
||||
[BOARDS_PANEL_ID]: BoardsPanel,
|
||||
[GALLERY_PANEL_ID]: GalleryPanel,
|
||||
};
|
||||
|
||||
export const initializeRightLayout = (api: GridviewApi) => {
|
||||
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: GALLERY_PANEL_ID,
|
||||
component: GALLERY_PANEL_ID,
|
||||
@@ -126,7 +130,7 @@ export const initializeRightLayout = (api: GridviewApi) => {
|
||||
};
|
||||
|
||||
const onReadyRightPanel: IGridviewReactProps['onReady'] = (event) => {
|
||||
initializeRightLayout(event.api);
|
||||
initializeRightPanelLayout(event.api);
|
||||
};
|
||||
|
||||
const RightPanel = memo(() => {
|
||||
@@ -143,13 +147,46 @@ const RightPanel = memo(() => {
|
||||
});
|
||||
RightPanel.displayName = 'RightPanel';
|
||||
|
||||
export const rootComponents: IGridviewReactProps['components'] = {
|
||||
[LEFT_PANEL_ID]: UpscalingTabLeftPanel,
|
||||
[MAIN_PANEL_ID]: MainPanel,
|
||||
const leftPanelComponents: IGridviewReactProps['components'] = {
|
||||
[SETTINGS_PANEL_ID]: UpscalingTabLeftPanel,
|
||||
};
|
||||
|
||||
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: SETTINGS_PANEL_ID,
|
||||
component: SETTINGS_PANEL_ID,
|
||||
});
|
||||
};
|
||||
|
||||
const LeftPanel = memo(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeLeftPanelLayout(event.api);
|
||||
ctx._$leftPanelApi.set(event.api);
|
||||
},
|
||||
[ctx._$leftPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<GridviewReact
|
||||
className="dockview-theme-invoke"
|
||||
orientation={Orientation.VERTICAL}
|
||||
components={leftPanelComponents}
|
||||
onReady={onReady}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
LeftPanel.displayName = 'LeftPanel';
|
||||
|
||||
export const rootPanelComponents: IGridviewReactProps['components'] = {
|
||||
[LEFT_PANEL_ID]: LeftPanel,
|
||||
[MAIN_PANEL_ID]: CenterPanel,
|
||||
[RIGHT_PANEL_ID]: RightPanel,
|
||||
};
|
||||
|
||||
export const initializeRootLayout = (api: GridviewApi) => {
|
||||
export const initializeRootPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: MAIN_PANEL_ID,
|
||||
component: MAIN_PANEL_ID,
|
||||
@@ -180,22 +217,22 @@ export const initializeRootLayout = (api: GridviewApi) => {
|
||||
|
||||
export const UpscalingTabAutoLayout = memo(() => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const $api = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const $rootPanelApi = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
$api.set(event.api);
|
||||
initializeRootLayout(event.api);
|
||||
$rootPanelApi.set(event.api);
|
||||
initializeRootPanelLayout(event.api);
|
||||
},
|
||||
[$api]
|
||||
[$rootPanelApi]
|
||||
);
|
||||
useResizeMainPanelOnFirstVisit($api, ref);
|
||||
useResizeMainPanelOnFirstVisit($rootPanelApi, ref);
|
||||
|
||||
return (
|
||||
<AutoLayoutProvider $api={$api}>
|
||||
<AutoLayoutProvider $rootApi={$rootPanelApi}>
|
||||
<GridviewReact
|
||||
ref={ref}
|
||||
className="dockview-theme-invoke"
|
||||
components={rootComponents}
|
||||
components={rootPanelComponents}
|
||||
onReady={onReady}
|
||||
orientation={Orientation.VERTICAL}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import type { DockviewApi, GridviewApi, IDockviewReactProps, IGridviewReactProps } from 'dockview';
|
||||
import { DockviewReact, GridviewReact, LayoutPriority, Orientation } from 'dockview';
|
||||
import { WorkflowsLaunchpadPanel } from 'features/controlLayers/components/SimpleSession/WorkflowsLaunchpadPanel';
|
||||
import { BoardsPanel } from 'features/gallery/components/BoardsListPanelContent';
|
||||
@@ -9,35 +9,36 @@ 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, PanelHotkeysLogical } from 'features/ui/layouts/auto-layout-context';
|
||||
import { AutoLayoutProvider, PanelHotkeysLogical, useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
||||
import { dockviewTheme } from 'features/ui/styles/theme';
|
||||
import { atom } from 'nanostores';
|
||||
import { memo, useCallback, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
BOARDS_PANEL_ID,
|
||||
GALLERY_PANEL_ID,
|
||||
LAUNCHPAD_PANEL_ID,
|
||||
LEFT_PANEL_ID,
|
||||
LEFT_PANEL_MIN_SIZE_PX,
|
||||
MAIN_PANEL_ID,
|
||||
PROGRESS_PANEL_ID,
|
||||
RIGHT_PANEL_ID,
|
||||
RIGHT_PANEL_MIN_SIZE_PX,
|
||||
SETTINGS_PANEL_ID,
|
||||
VIEWER_PANEL_ID,
|
||||
WORKSPACE_PANEL_ID,
|
||||
} from './shared';
|
||||
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
|
||||
|
||||
const LAUNCHPAD_PANEL_ID = 'launchpad';
|
||||
const WORKSPACE_PANEL_ID = 'workspace';
|
||||
const VIEWER_PANEL_ID = 'viewer';
|
||||
const PROGRESS_PANEL_ID = 'progress';
|
||||
|
||||
const dockviewComponents: IDockviewReactProps['components'] = {
|
||||
const centerPanelComponents: IDockviewReactProps['components'] = {
|
||||
[LAUNCHPAD_PANEL_ID]: WorkflowsLaunchpadPanel,
|
||||
[WORKSPACE_PANEL_ID]: NodeEditor,
|
||||
[VIEWER_PANEL_ID]: ImageViewerPanel,
|
||||
[PROGRESS_PANEL_ID]: GenerationProgressPanel,
|
||||
};
|
||||
|
||||
const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
|
||||
const { api } = event;
|
||||
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
||||
api.addPanel({
|
||||
id: LAUNCHPAD_PANEL_ID,
|
||||
component: LAUNCHPAD_PANEL_ID,
|
||||
@@ -72,24 +73,31 @@ const onReadyMainPanel: IDockviewReactProps['onReady'] = (event) => {
|
||||
});
|
||||
|
||||
api.getPanel(LAUNCHPAD_PANEL_ID)?.api.setActive();
|
||||
|
||||
const disposables = [
|
||||
api.onWillShowOverlay((e) => {
|
||||
if (e.kind === 'header_space' || e.kind === 'tab') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
disposables.forEach((disposable) => {
|
||||
disposable.dispose();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const MainPanel = memo(() => {
|
||||
const CenterPanel = memo(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IDockviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeCenterPanelLayout(event.api);
|
||||
ctx._$centerPanelApi.set(event.api);
|
||||
const disposables = [
|
||||
event.api.onWillShowOverlay((e) => {
|
||||
if (e.kind === 'header_space' || e.kind === 'tab') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
disposables.forEach((disposable) => {
|
||||
disposable.dispose();
|
||||
});
|
||||
};
|
||||
},
|
||||
[ctx._$centerPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<DockviewReact
|
||||
@@ -98,8 +106,8 @@ const MainPanel = memo(() => {
|
||||
disableFloatingGroups={true}
|
||||
dndEdges={false}
|
||||
defaultTabComponent={TabWithoutCloseButton}
|
||||
components={dockviewComponents}
|
||||
onReady={onReadyMainPanel}
|
||||
components={centerPanelComponents}
|
||||
onReady={onReady}
|
||||
theme={dockviewTheme}
|
||||
/>
|
||||
<FloatingLeftPanelButtons />
|
||||
@@ -108,17 +116,14 @@ const MainPanel = memo(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
MainPanel.displayName = 'MainPanel';
|
||||
|
||||
const BOARDS_PANEL_ID = 'boards';
|
||||
const GALLERY_PANEL_ID = 'gallery';
|
||||
CenterPanel.displayName = 'CenterPanel';
|
||||
|
||||
const rightPanelComponents: IGridviewReactProps['components'] = {
|
||||
[BOARDS_PANEL_ID]: BoardsPanel,
|
||||
[GALLERY_PANEL_ID]: GalleryPanel,
|
||||
};
|
||||
|
||||
export const initializeRightLayout = (api: GridviewApi) => {
|
||||
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: GALLERY_PANEL_ID,
|
||||
component: GALLERY_PANEL_ID,
|
||||
@@ -137,31 +142,68 @@ export const initializeRightLayout = (api: GridviewApi) => {
|
||||
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(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeRightPanelLayout(event.api);
|
||||
ctx._$rightPanelApi.set(event.api);
|
||||
},
|
||||
[ctx._$rightPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<GridviewReact
|
||||
className="dockview-theme-invoke"
|
||||
orientation={Orientation.VERTICAL}
|
||||
components={rightPanelComponents}
|
||||
onReady={onReadyRightPanel}
|
||||
onReady={onReady}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
RightPanel.displayName = 'RightPanel';
|
||||
|
||||
export const rootComponents: IGridviewReactProps['components'] = {
|
||||
[LEFT_PANEL_ID]: WorkflowsTabLeftPanel,
|
||||
[MAIN_PANEL_ID]: MainPanel,
|
||||
const leftPanelComponents: IGridviewReactProps['components'] = {
|
||||
[SETTINGS_PANEL_ID]: WorkflowsTabLeftPanel,
|
||||
};
|
||||
|
||||
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: SETTINGS_PANEL_ID,
|
||||
component: SETTINGS_PANEL_ID,
|
||||
});
|
||||
};
|
||||
|
||||
const LeftPanel = memo(() => {
|
||||
const ctx = useAutoLayoutContext();
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
initializeLeftPanelLayout(event.api);
|
||||
ctx._$leftPanelApi.set(event.api);
|
||||
},
|
||||
[ctx._$leftPanelApi]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<GridviewReact
|
||||
className="dockview-theme-invoke"
|
||||
orientation={Orientation.VERTICAL}
|
||||
components={leftPanelComponents}
|
||||
onReady={onReady}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
LeftPanel.displayName = 'LeftPanel';
|
||||
|
||||
export const rootPanelComponents: IGridviewReactProps['components'] = {
|
||||
[LEFT_PANEL_ID]: LeftPanel,
|
||||
[MAIN_PANEL_ID]: CenterPanel,
|
||||
[RIGHT_PANEL_ID]: RightPanel,
|
||||
};
|
||||
|
||||
export const initializeRootLayout = (api: GridviewApi) => {
|
||||
export const initializeRootPanelLayout = (api: GridviewApi) => {
|
||||
api.addPanel({
|
||||
id: MAIN_PANEL_ID,
|
||||
component: MAIN_PANEL_ID,
|
||||
@@ -192,22 +234,22 @@ export const initializeRootLayout = (api: GridviewApi) => {
|
||||
|
||||
export const WorkflowsTabAutoLayout = memo(() => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const $api = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const $rootPanelApi = useState(() => atom<GridviewApi | null>(null))[0];
|
||||
const onReady = useCallback<IGridviewReactProps['onReady']>(
|
||||
(event) => {
|
||||
$api.set(event.api);
|
||||
initializeRootLayout(event.api);
|
||||
$rootPanelApi.set(event.api);
|
||||
initializeRootPanelLayout(event.api);
|
||||
},
|
||||
[$api]
|
||||
[$rootPanelApi]
|
||||
);
|
||||
useResizeMainPanelOnFirstVisit($api, ref);
|
||||
useResizeMainPanelOnFirstVisit($rootPanelApi, ref);
|
||||
|
||||
return (
|
||||
<AutoLayoutProvider $api={$api}>
|
||||
<AutoLayoutProvider $rootApi={$rootPanelApi}>
|
||||
<GridviewReact
|
||||
ref={ref}
|
||||
className="dockview-theme-invoke"
|
||||
components={rootComponents}
|
||||
components={rootPanelComponents}
|
||||
onReady={onReady}
|
||||
orientation={Orientation.VERTICAL}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user