mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
refactor(ui): even more better focus handling
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
import { Box, type BoxProps, type SystemStyleObject } from '@invoke-ai/ui-library';
|
import { Box, type BoxProps, type SystemStyleObject } from '@invoke-ai/ui-library';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { type FocusRegionName, useFocusRegion, useIsRegionFocused } from 'common/hooks/focus';
|
import { type FocusRegionName, useFocusRegion, useIsRegionFocused } from 'common/hooks/focus';
|
||||||
|
import type { IDockviewPanelProps, IGridviewPanelProps } from 'dockview';
|
||||||
import { selectSystemShouldEnableHighlightFocusedRegions } from 'features/system/store/systemSlice';
|
import { selectSystemShouldEnableHighlightFocusedRegions } from 'features/system/store/systemSlice';
|
||||||
|
import type { PanelParameters } from 'features/ui/layouts/auto-layout-context';
|
||||||
|
import type { PropsWithChildren } from 'react';
|
||||||
import { memo, useMemo, useRef } from 'react';
|
import { memo, useMemo, useRef } from 'react';
|
||||||
|
|
||||||
interface FocusRegionWrapperProps extends BoxProps {
|
interface FocusRegionWrapperProps extends BoxProps {
|
||||||
@@ -9,8 +12,11 @@ interface FocusRegionWrapperProps extends BoxProps {
|
|||||||
focusOnMount?: boolean;
|
focusOnMount?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BASE_FOCUS_REGION_STYLES: SystemStyleObject = {
|
export const BASE_FOCUS_REGION_STYLES: SystemStyleObject = {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
w: 'full',
|
||||||
|
h: 'full',
|
||||||
|
p: 2,
|
||||||
'&[data-highlighted="true"]::after': {
|
'&[data-highlighted="true"]::after': {
|
||||||
borderColor: 'invokeBlue.300',
|
borderColor: 'invokeBlue.300',
|
||||||
},
|
},
|
||||||
@@ -23,7 +29,6 @@ const BASE_FOCUS_REGION_STYLES: SystemStyleObject = {
|
|||||||
border: '1px solid',
|
border: '1px solid',
|
||||||
borderColor: 'transparent',
|
borderColor: 'transparent',
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
// transition: 'border-color 0.1s ease-in-out',
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,3 +55,26 @@ export const FocusRegionWrapper = memo((props: FocusRegionWrapperProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
FocusRegionWrapper.displayName = 'FocusRegionWrapper';
|
FocusRegionWrapper.displayName = 'FocusRegionWrapper';
|
||||||
|
|
||||||
|
export const AutoLayoutPanelContainer = memo(
|
||||||
|
(
|
||||||
|
props:
|
||||||
|
| PropsWithChildren<IDockviewPanelProps<PanelParameters>>
|
||||||
|
| PropsWithChildren<IGridviewPanelProps<PanelParameters>>
|
||||||
|
) => {
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const shouldHighlightFocusedRegions = useAppSelector(selectSystemShouldEnableHighlightFocusedRegions);
|
||||||
|
|
||||||
|
useFocusRegion(props.params.focusRegion, ref);
|
||||||
|
|
||||||
|
const isFocused = useIsRegionFocused(props.params.focusRegion);
|
||||||
|
const isHighlighted = isFocused && shouldHighlightFocusedRegions;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box ref={ref} tabIndex={-1} sx={BASE_FOCUS_REGION_STYLES} data-highlighted={isHighlighted}>
|
||||||
|
{props.children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
AutoLayoutPanelContainer.displayName = 'AutoLayoutPanelContainer';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Divider, Flex } from '@invoke-ai/ui-library';
|
import { Divider, Flex } from '@invoke-ai/ui-library';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { CanvasAddEntityButtons } from 'features/controlLayers/components/CanvasAddEntityButtons';
|
import { CanvasAddEntityButtons } from 'features/controlLayers/components/CanvasAddEntityButtons';
|
||||||
import { CanvasEntityList } from 'features/controlLayers/components/CanvasEntityList/CanvasEntityList';
|
import { CanvasEntityList } from 'features/controlLayers/components/CanvasEntityList/CanvasEntityList';
|
||||||
import { EntityListSelectedEntityActionBar } from 'features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBar';
|
import { EntityListSelectedEntityActionBar } from 'features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBar';
|
||||||
@@ -15,14 +14,14 @@ export const CanvasLayersPanel = memo(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CanvasManagerProviderGate>
|
<CanvasManagerProviderGate>
|
||||||
<FocusRegionWrapper region="layers" as={Flex} flexDir="column" gap={2} w="full" h="full" p={2}>
|
<Flex flexDir="column" gap={2} w="full" h="full">
|
||||||
<EntityListSelectedEntityActionBar />
|
<EntityListSelectedEntityActionBar />
|
||||||
<Divider py={0} />
|
<Divider py={0} />
|
||||||
<ParamDenoisingStrength />
|
<ParamDenoisingStrength />
|
||||||
<Divider py={0} />
|
<Divider py={0} />
|
||||||
{!hasEntities && <CanvasAddEntityButtons />}
|
{!hasEntities && <CanvasAddEntityButtons />}
|
||||||
{hasEntities && <CanvasEntityList />}
|
{hasEntities && <CanvasEntityList />}
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
</CanvasManagerProviderGate>
|
</CanvasManagerProviderGate>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
import { Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||||
import { WORKSPACE_PANEL_ID } from 'features/ui/layouts/shared';
|
import { WORKSPACE_PANEL_ID } from 'features/ui/layouts/shared';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
@@ -18,7 +17,7 @@ export const CanvasLaunchpadPanel = memo(() => {
|
|||||||
ctx.focusPanel(WORKSPACE_PANEL_ID);
|
ctx.focusPanel(WORKSPACE_PANEL_ID);
|
||||||
}, [ctx]);
|
}, [ctx]);
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper region="launchpad" as={Flex} flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||||
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
||||||
<Heading mb={4}>{t('ui.launchpad.canvasTitle')}</Heading>
|
<Heading mb={4}>{t('ui.launchpad.canvasTitle')}</Heading>
|
||||||
<Flex flexDir="column" gap={8}>
|
<Flex flexDir="column" gap={8}>
|
||||||
@@ -44,7 +43,7 @@ export const CanvasLaunchpadPanel = memo(() => {
|
|||||||
<LaunchpadUseALayoutImageButton extraAction={focusCanvas} />
|
<LaunchpadUseALayoutImageButton extraAction={focusCanvas} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
CanvasLaunchpadPanel.displayName = 'CanvasLaunchpadPanel';
|
CanvasLaunchpadPanel.displayName = 'CanvasLaunchpadPanel';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Alert, Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
import { Alert, Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { InitialStateMainModelPicker } from 'features/controlLayers/components/SimpleSession/InitialStateMainModelPicker';
|
import { InitialStateMainModelPicker } from 'features/controlLayers/components/SimpleSession/InitialStateMainModelPicker';
|
||||||
import { LaunchpadAddStyleReference } from 'features/controlLayers/components/SimpleSession/LaunchpadAddStyleReference';
|
import { LaunchpadAddStyleReference } from 'features/controlLayers/components/SimpleSession/LaunchpadAddStyleReference';
|
||||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||||
@@ -15,7 +14,7 @@ export const GenerateLaunchpadPanel = memo(() => {
|
|||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper region="launchpad" as={Flex} flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||||
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
||||||
<Heading mb={4}>Generate images from text prompts.</Heading>
|
<Heading mb={4}>Generate images from text prompts.</Heading>
|
||||||
<Flex flexDir="column" gap={8}>
|
<Flex flexDir="column" gap={8}>
|
||||||
@@ -47,7 +46,7 @@ export const GenerateLaunchpadPanel = memo(() => {
|
|||||||
</Alert>
|
</Alert>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
GenerateLaunchpadPanel.displayName = 'GenerateLaunchpad';
|
GenerateLaunchpadPanel.displayName = 'GenerateLaunchpad';
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Button, Flex, Heading, Icon, Text } from '@invoke-ai/ui-library';
|
import { Button, Flex, Heading, Icon, Text } from '@invoke-ai/ui-library';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal';
|
import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal';
|
||||||
import { useLoadWorkflowWithDialog } from 'features/workflowLibrary/components/LoadWorkflowConfirmationAlertDialog';
|
import { useLoadWorkflowWithDialog } from 'features/workflowLibrary/components/LoadWorkflowConfirmationAlertDialog';
|
||||||
import { useNewWorkflow } from 'features/workflowLibrary/components/NewWorkflowConfirmationAlertDialog';
|
import { useNewWorkflow } from 'features/workflowLibrary/components/NewWorkflowConfirmationAlertDialog';
|
||||||
@@ -46,7 +45,7 @@ export const WorkflowsLaunchpadPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper region="launchpad" as={Flex} flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||||
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
||||||
<Heading>{t('ui.launchpad.workflowsTitle')}</Heading>
|
<Heading>{t('ui.launchpad.workflowsTitle')}</Heading>
|
||||||
|
|
||||||
@@ -102,7 +101,7 @@ export const WorkflowsLaunchpadPanel = memo(() => {
|
|||||||
</LaunchpadButton>
|
</LaunchpadButton>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Box, Button, Collapse, Divider, Flex, IconButton } from '@invoke-ai/ui-library';
|
import { Box, Button, Collapse, Divider, Flex, IconButton } from '@invoke-ai/ui-library';
|
||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { useDisclosure } from 'common/hooks/useBoolean';
|
import { useDisclosure } from 'common/hooks/useBoolean';
|
||||||
import { BoardsListWrapper } from 'features/gallery/components/Boards/BoardsList/BoardsListWrapper';
|
import { BoardsListWrapper } from 'features/gallery/components/Boards/BoardsList/BoardsListWrapper';
|
||||||
import { BoardsSearch } from 'features/gallery/components/Boards/BoardsList/BoardsSearch';
|
import { BoardsSearch } from 'features/gallery/components/Boards/BoardsList/BoardsSearch';
|
||||||
@@ -46,7 +45,7 @@ export const BoardsPanel = memo(() => {
|
|||||||
}, [boardSearchText.length, searchDisclosure, collapsibleApi, dispatch]);
|
}, [boardSearchText.length, searchDisclosure, collapsibleApi, dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper region="boards" as={Flex} flexDir="column" w="full" h="full" p={2}>
|
<Flex flexDir="column" w="full" h="full">
|
||||||
<Flex alignItems="center" justifyContent="space-between" w="full">
|
<Flex alignItems="center" justifyContent="space-between" w="full">
|
||||||
<Flex flexGrow={1} flexBasis={0}>
|
<Flex flexGrow={1} flexBasis={0}>
|
||||||
<Button
|
<Button
|
||||||
@@ -82,7 +81,7 @@ export const BoardsPanel = memo(() => {
|
|||||||
</Collapse>
|
</Collapse>
|
||||||
<Divider pt={2} />
|
<Divider pt={2} />
|
||||||
<BoardsListWrapper />
|
<BoardsListWrapper />
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
BoardsPanel.displayName = 'BoardsPanel';
|
BoardsPanel.displayName = 'BoardsPanel';
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { Box, Button, ButtonGroup, Collapse, Divider, Flex, IconButton, Spacer }
|
|||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { useDisclosure } from 'common/hooks/useBoolean';
|
import { useDisclosure } from 'common/hooks/useBoolean';
|
||||||
import { useGallerySearchTerm } from 'features/gallery/components/ImageGrid/useGallerySearchTerm';
|
import { useGallerySearchTerm } from 'features/gallery/components/ImageGrid/useGallerySearchTerm';
|
||||||
import { selectSelectedBoardId } from 'features/gallery/store/gallerySelectors';
|
import { selectSelectedBoardId } from 'features/gallery/store/gallerySelectors';
|
||||||
@@ -68,17 +67,7 @@ export const GalleryPanel = memo(() => {
|
|||||||
const boardName = useBoardName(selectedBoardId);
|
const boardName = useBoardName(selectedBoardId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper
|
<Flex flexDirection="column" alignItems="center" justifyContent="space-between" h="full" w="full" minH={0}>
|
||||||
region="gallery"
|
|
||||||
as={Flex}
|
|
||||||
flexDirection="column"
|
|
||||||
alignItems="center"
|
|
||||||
justifyContent="space-between"
|
|
||||||
h="full"
|
|
||||||
w="full"
|
|
||||||
minH={0}
|
|
||||||
p={2}
|
|
||||||
>
|
|
||||||
<Flex gap={2} fontSize="sm" alignItems="center" w="full">
|
<Flex gap={2} fontSize="sm" alignItems="center" w="full">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -134,7 +123,7 @@ export const GalleryPanel = memo(() => {
|
|||||||
<Flex w="full" h="full" pt={2}>
|
<Flex w="full" h="full" pt={2}>
|
||||||
<NewGallery />
|
<NewGallery />
|
||||||
</Flex>
|
</Flex>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
GalleryPanel.displayName = 'Gallery';
|
GalleryPanel.displayName = 'GalleryPanel';
|
||||||
|
|||||||
@@ -1,23 +1,15 @@
|
|||||||
import { Flex } from '@invoke-ai/ui-library';
|
import { Flex } from '@invoke-ai/ui-library';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { ProgressImage } from 'features/gallery/components/ImageViewer/ProgressImage';
|
import { ProgressImage } from 'features/gallery/components/ImageViewer/ProgressImage';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
import { ProgressIndicator } from './ProgressIndicator';
|
import { ProgressIndicator } from './ProgressIndicator';
|
||||||
|
|
||||||
export const GenerationProgressPanel = memo(() => (
|
export const GenerationProgressPanel = memo(() => {
|
||||||
<FocusRegionWrapper
|
return (
|
||||||
region="progress"
|
<Flex position="relative" flexDir="column" w="full" h="full" overflow="hidden">
|
||||||
as={Flex}
|
<ProgressImage />
|
||||||
position="relative"
|
<ProgressIndicator position="absolute" top={6} right={6} size={8} />
|
||||||
flexDir="column"
|
</Flex>
|
||||||
w="full"
|
);
|
||||||
h="full"
|
});
|
||||||
overflow="hidden"
|
|
||||||
p={2}
|
|
||||||
>
|
|
||||||
<ProgressImage />
|
|
||||||
<ProgressIndicator position="absolute" top={6} right={6} size={8} />
|
|
||||||
</FocusRegionWrapper>
|
|
||||||
));
|
|
||||||
GenerationProgressPanel.displayName = 'GenerationProgressPanel';
|
GenerationProgressPanel.displayName = 'GenerationProgressPanel';
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Divider, Flex } from '@invoke-ai/ui-library';
|
import { Divider, Flex } from '@invoke-ai/ui-library';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { ImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer';
|
import { ImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer';
|
||||||
import { ViewerToolbar } from 'features/gallery/components/ImageViewer/ViewerToolbar';
|
import { ViewerToolbar } from 'features/gallery/components/ImageViewer/ViewerToolbar';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
@@ -9,11 +8,11 @@ import { ImageViewerContextProvider } from './context';
|
|||||||
export const ImageViewerPanel = memo(() => {
|
export const ImageViewerPanel = memo(() => {
|
||||||
return (
|
return (
|
||||||
<ImageViewerContextProvider>
|
<ImageViewerContextProvider>
|
||||||
<FocusRegionWrapper region="viewer" as={Flex} flexDir="column" w="full" h="full" overflow="hidden" p={2} gap={2}>
|
<Flex flexDir="column" w="full" h="full" overflow="hidden" gap={2}>
|
||||||
<ViewerToolbar />
|
<ViewerToolbar />
|
||||||
<Divider />
|
<Divider />
|
||||||
<ImageViewer />
|
<ImageViewer />
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
</ImageViewerContextProvider>
|
</ImageViewerContextProvider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Flex } from '@invoke-ai/ui-library';
|
import { Flex } from '@invoke-ai/ui-library';
|
||||||
import { ReactFlowProvider } from '@xyflow/react';
|
import { ReactFlowProvider } from '@xyflow/react';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||||
import { AddNodeCmdk } from 'features/nodes/components/flow/AddNodeCmdk/AddNodeCmdk';
|
import { AddNodeCmdk } from 'features/nodes/components/flow/AddNodeCmdk/AddNodeCmdk';
|
||||||
import { TopCenterPanel } from 'features/nodes/components/flow/panels/TopPanel/TopCenterPanel';
|
import { TopCenterPanel } from 'features/nodes/components/flow/panels/TopPanel/TopCenterPanel';
|
||||||
@@ -22,9 +21,7 @@ const NodeEditor = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<FocusRegionWrapper
|
<Flex
|
||||||
region="workflows"
|
|
||||||
as={Flex}
|
|
||||||
bg="base.900"
|
bg="base.900"
|
||||||
display="flex"
|
display="flex"
|
||||||
position="relative"
|
position="relative"
|
||||||
@@ -46,7 +43,7 @@ const NodeEditor = () => {
|
|||||||
)}
|
)}
|
||||||
<WorkflowEditorSettings />
|
<WorkflowEditorSettings />
|
||||||
{isLoading && <IAINoContentFallback label={t('nodes.loadingNodes')} icon={PiFlowArrowBold} />}
|
{isLoading && <IAINoContentFallback label={t('nodes.loadingNodes')} icon={PiFlowArrowBold} />}
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Flex } from '@invoke-ai/ui-library';
|
import { Flex } from '@invoke-ai/ui-library';
|
||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { EditModeLeftPanelContent } from 'features/nodes/components/sidePanel/EditModeLeftPanelContent';
|
import { EditModeLeftPanelContent } from 'features/nodes/components/sidePanel/EditModeLeftPanelContent';
|
||||||
import { PublishedWorkflowPanelContent } from 'features/nodes/components/sidePanel/PublishedWorkflowPanelContent';
|
import { PublishedWorkflowPanelContent } from 'features/nodes/components/sidePanel/PublishedWorkflowPanelContent';
|
||||||
import { $isInPublishFlow, useIsWorkflowPublished } from 'features/nodes/components/sidePanel/workflow/publish';
|
import { $isInPublishFlow, useIsWorkflowPublished } from 'features/nodes/components/sidePanel/workflow/publish';
|
||||||
@@ -20,7 +19,7 @@ const WorkflowsTabLeftPanel = () => {
|
|||||||
const isInPublishFlow = useStore($isInPublishFlow);
|
const isInPublishFlow = useStore($isInPublishFlow);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper region="settings" as={Flex} flexDir="column" w="full" h="full" gap={2} p={2}>
|
<Flex flexDir="column" w="full" h="full" gap={2}>
|
||||||
<QueueControls />
|
<QueueControls />
|
||||||
<Flex w="full" h="full" gap={2} flexDir="column">
|
<Flex w="full" h="full" gap={2} flexDir="column">
|
||||||
{isInPublishFlow && <PublishWorkflowPanelContent />}
|
{isInPublishFlow && <PublishWorkflowPanelContent />}
|
||||||
@@ -30,7 +29,7 @@ const WorkflowsTabLeftPanel = () => {
|
|||||||
{!isInPublishFlow && !isPublished && mode === 'edit' && <EditModeLeftPanelContent />}
|
{!isInPublishFlow && !isPublished && mode === 'edit' && <EditModeLeftPanelContent />}
|
||||||
{isPublished && <PublishedWorkflowPanelContent />}
|
{isPublished && <PublishedWorkflowPanelContent />}
|
||||||
</Flex>
|
</Flex>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import { Box, Flex } from '@invoke-ai/ui-library';
|
import { Box, Flex } from '@invoke-ai/ui-library';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import QueueControls from 'features/queue/components/QueueControls';
|
import QueueControls from 'features/queue/components/QueueControls';
|
||||||
import { ParametersPanelCanvas } from 'features/ui/components/ParametersPanels/ParametersPanelCanvas';
|
import { ParametersPanelCanvas } from 'features/ui/components/ParametersPanels/ParametersPanelCanvas';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
export const CanvasTabLeftPanel = memo(() => {
|
export const CanvasTabLeftPanel = memo(() => {
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper region="settings" as={Flex} flexDir="column" w="full" h="full" gap={2} p={2}>
|
<Flex flexDir="column" w="full" h="full" gap={2}>
|
||||||
<QueueControls />
|
<QueueControls />
|
||||||
<Box position="relative" w="full" h="full">
|
<Box position="relative" w="full" h="full">
|
||||||
<ParametersPanelCanvas />
|
<ParametersPanelCanvas />
|
||||||
</Box>
|
</Box>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
CanvasTabLeftPanel.displayName = 'CanvasTabLeftPanel';
|
CanvasTabLeftPanel.displayName = 'CanvasTabLeftPanel';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ContextMenu, Divider, Flex, IconButton, Menu, MenuButton, MenuList } from '@invoke-ai/ui-library';
|
import { ContextMenu, Divider, Flex, IconButton, Menu, MenuButton, MenuList } from '@invoke-ai/ui-library';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import { CanvasAlertsInvocationProgress } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsInvocationProgress';
|
import { CanvasAlertsInvocationProgress } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsInvocationProgress';
|
||||||
import { CanvasAlertsPreserveMask } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsPreserveMask';
|
import { CanvasAlertsPreserveMask } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsPreserveMask';
|
||||||
import { CanvasAlertsSelectedEntityStatus } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsSelectedEntityStatus';
|
import { CanvasAlertsSelectedEntityStatus } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsSelectedEntityStatus';
|
||||||
@@ -56,9 +55,7 @@ export const CanvasWorkspacePanel = memo(() => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper
|
<Flex
|
||||||
region="canvas"
|
|
||||||
as={Flex}
|
|
||||||
borderRadius="base"
|
borderRadius="base"
|
||||||
position="relative"
|
position="relative"
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
@@ -68,7 +65,6 @@ export const CanvasWorkspacePanel = memo(() => {
|
|||||||
alignItems="center"
|
alignItems="center"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
p={2}
|
|
||||||
>
|
>
|
||||||
<CanvasManagerProviderGate>
|
<CanvasManagerProviderGate>
|
||||||
<CanvasToolbar />
|
<CanvasToolbar />
|
||||||
@@ -136,7 +132,7 @@ export const CanvasWorkspacePanel = memo(() => {
|
|||||||
<CanvasManagerProviderGate>
|
<CanvasManagerProviderGate>
|
||||||
<CanvasDropArea />
|
<CanvasDropArea />
|
||||||
</CanvasManagerProviderGate>
|
</CanvasManagerProviderGate>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
CanvasWorkspacePanel.displayName = 'CanvasPanel';
|
CanvasWorkspacePanel.displayName = 'CanvasWorkspacePanel';
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import { Box, Flex } from '@invoke-ai/ui-library';
|
import { Box, Flex } from '@invoke-ai/ui-library';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import QueueControls from 'features/queue/components/QueueControls';
|
import QueueControls from 'features/queue/components/QueueControls';
|
||||||
import { ParametersPanelGenerate } from 'features/ui/components/ParametersPanels/ParametersPanelGenerate';
|
import { ParametersPanelGenerate } from 'features/ui/components/ParametersPanels/ParametersPanelGenerate';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
export const GenerateTabLeftPanel = memo(() => {
|
export const GenerateTabLeftPanel = memo(() => {
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper region="settings" as={Flex} flexDir="column" w="full" h="full" gap={2} p={2}>
|
<Flex flexDir="column" w="full" h="full" gap={2}>
|
||||||
<QueueControls />
|
<QueueControls />
|
||||||
<Box position="relative" w="full" h="full">
|
<Box position="relative" w="full" h="full">
|
||||||
<ParametersPanelGenerate />
|
<ParametersPanelGenerate />
|
||||||
</Box>
|
</Box>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
GenerateTabLeftPanel.displayName = 'GenerateTabLeftPanel';
|
GenerateTabLeftPanel.displayName = 'GenerateTabLeftPanel';
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import { Flex, Text } from '@invoke-ai/ui-library';
|
import { Flex, Text } from '@invoke-ai/ui-library';
|
||||||
|
import { setFocusedRegion } from 'common/hooks/focus';
|
||||||
import { useCallbackOnDragEnter } from 'common/hooks/useCallbackOnDragEnter';
|
import { useCallbackOnDragEnter } from 'common/hooks/useCallbackOnDragEnter';
|
||||||
import type { IDockviewPanelHeaderProps } from 'dockview';
|
import type { IDockviewPanelHeaderProps } from 'dockview';
|
||||||
import { memo, useCallback, useRef } from 'react';
|
import { memo, useCallback, useRef } from 'react';
|
||||||
|
|
||||||
export const TabWithoutCloseButton = memo((props: IDockviewPanelHeaderProps) => {
|
import type { PanelParameters } from './auto-layout-context';
|
||||||
|
|
||||||
|
export const TabWithoutCloseButton = memo((props: IDockviewPanelHeaderProps<PanelParameters>) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const setActive = useCallback(() => {
|
const setActive = useCallback(() => {
|
||||||
if (!props.api.isActive) {
|
if (!props.api.isActive) {
|
||||||
@@ -13,8 +16,12 @@ export const TabWithoutCloseButton = memo((props: IDockviewPanelHeaderProps) =>
|
|||||||
|
|
||||||
useCallbackOnDragEnter(setActive, ref, 300);
|
useCallbackOnDragEnter(setActive, ref, 300);
|
||||||
|
|
||||||
|
const onPointerDown = useCallback(() => {
|
||||||
|
setFocusedRegion(props.params.focusRegion);
|
||||||
|
}, [props.params.focusRegion]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex ref={ref} alignItems="center" h="full">
|
<Flex ref={ref} alignItems="center" h="full" onPointerDown={onPointerDown}>
|
||||||
<Text userSelect="none" px={4}>
|
<Text userSelect="none" px={4}>
|
||||||
{props.api.title ?? props.api.id}
|
{props.api.title ?? props.api.id}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -1,31 +1,40 @@
|
|||||||
import { Flex, Text } from '@invoke-ai/ui-library';
|
import { Flex, Text } from '@invoke-ai/ui-library';
|
||||||
|
import { setFocusedRegion } from 'common/hooks/focus';
|
||||||
import { useCallbackOnDragEnter } from 'common/hooks/useCallbackOnDragEnter';
|
import { useCallbackOnDragEnter } from 'common/hooks/useCallbackOnDragEnter';
|
||||||
import type { IDockviewPanelHeaderProps } from 'dockview';
|
import type { IDockviewPanelHeaderProps } from 'dockview';
|
||||||
import ProgressBar from 'features/system/components/ProgressBar';
|
import ProgressBar from 'features/system/components/ProgressBar';
|
||||||
import { memo, useCallback, useRef } from 'react';
|
import { memo, useCallback, useRef } from 'react';
|
||||||
import { useIsGenerationInProgress } from 'services/api/endpoints/queue';
|
import { useIsGenerationInProgress } from 'services/api/endpoints/queue';
|
||||||
|
|
||||||
export const TabWithoutCloseButtonAndWithProgressIndicator = memo((props: IDockviewPanelHeaderProps) => {
|
import type { PanelParameters } from './auto-layout-context';
|
||||||
const isGenerationInProgress = useIsGenerationInProgress();
|
|
||||||
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
export const TabWithoutCloseButtonAndWithProgressIndicator = memo(
|
||||||
const setActive = useCallback(() => {
|
(props: IDockviewPanelHeaderProps<PanelParameters>) => {
|
||||||
if (!props.api.isActive) {
|
const isGenerationInProgress = useIsGenerationInProgress();
|
||||||
props.api.setActive();
|
|
||||||
}
|
|
||||||
}, [props.api]);
|
|
||||||
|
|
||||||
useCallbackOnDragEnter(setActive, ref, 300);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const setActive = useCallback(() => {
|
||||||
|
if (!props.api.isActive) {
|
||||||
|
props.api.setActive();
|
||||||
|
}
|
||||||
|
}, [props.api]);
|
||||||
|
|
||||||
return (
|
useCallbackOnDragEnter(setActive, ref, 300);
|
||||||
<Flex ref={ref} position="relative" alignItems="center" h="full">
|
|
||||||
<Text userSelect="none" px={4}>
|
const onPointerDown = useCallback(() => {
|
||||||
{props.api.title ?? props.api.id}
|
setFocusedRegion(props.params.focusRegion);
|
||||||
</Text>
|
}, [props.params.focusRegion]);
|
||||||
{isGenerationInProgress && (
|
|
||||||
<ProgressBar position="absolute" bottom={0} left={0} right={0} h={1} borderRadius="none" />
|
return (
|
||||||
)}
|
<Flex ref={ref} position="relative" alignItems="center" h="full" onPointerDown={onPointerDown}>
|
||||||
</Flex>
|
<Text userSelect="none" px={4}>
|
||||||
);
|
{props.api.title ?? props.api.id}
|
||||||
});
|
</Text>
|
||||||
|
{isGenerationInProgress && (
|
||||||
|
<ProgressBar position="absolute" bottom={0} left={0} right={0} h={1} borderRadius="none" />
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
TabWithoutCloseButtonAndWithProgressIndicator.displayName = 'TabWithoutCloseButtonAndWithProgressIndicator';
|
TabWithoutCloseButtonAndWithProgressIndicator.displayName = 'TabWithoutCloseButtonAndWithProgressIndicator';
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import { Box, Flex } from '@invoke-ai/ui-library';
|
import { Box, Flex } from '@invoke-ai/ui-library';
|
||||||
import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper';
|
|
||||||
import QueueControls from 'features/queue/components/QueueControls';
|
import QueueControls from 'features/queue/components/QueueControls';
|
||||||
import { ParametersPanelUpscale } from 'features/ui/components/ParametersPanels/ParametersPanelUpscale';
|
import { ParametersPanelUpscale } from 'features/ui/components/ParametersPanels/ParametersPanelUpscale';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
export const UpscalingTabLeftPanel = memo(() => {
|
export const UpscalingTabLeftPanel = memo(() => {
|
||||||
return (
|
return (
|
||||||
<FocusRegionWrapper region="settings" as={Flex} flexDir="column" w="full" h="full" gap={2} p={2}>
|
<Flex flexDir="column" w="full" h="full" gap={2}>
|
||||||
<QueueControls />
|
<QueueControls />
|
||||||
<Box position="relative" w="full" h="full">
|
<Box position="relative" w="full" h="full">
|
||||||
<ParametersPanelUpscale />
|
<ParametersPanelUpscale />
|
||||||
</Box>
|
</Box>
|
||||||
</FocusRegionWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
UpscalingTabLeftPanel.displayName = 'UpscalingTabLeftPanel';
|
UpscalingTabLeftPanel.displayName = 'UpscalingTabLeftPanel';
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import type { DockviewApi, GridviewApi } from 'dockview';
|
import { AutoLayoutPanelContainer } from 'common/components/FocusRegionWrapper';
|
||||||
|
import type { FocusRegionName } from 'common/hooks/focus';
|
||||||
|
import type { DockviewApi, GridviewApi, IDockviewPanelProps, IGridviewPanelProps } from 'dockview';
|
||||||
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
|
||||||
import { selectActiveTab } from 'features/ui/store/uiSelectors';
|
import { selectActiveTab } from 'features/ui/store/uiSelectors';
|
||||||
import type { TabName } from 'features/ui/store/uiTypes';
|
import type { TabName } from 'features/ui/store/uiTypes';
|
||||||
import type { WritableAtom } from 'nanostores';
|
import type { WritableAtom } from 'nanostores';
|
||||||
import { atom } from 'nanostores';
|
import { atom } from 'nanostores';
|
||||||
import type { PropsWithChildren, RefObject } from 'react';
|
import type { FunctionComponent, PropsWithChildren, RefObject } from 'react';
|
||||||
import { createContext, memo, useCallback, useContext, useMemo, useState } 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 } from './shared';
|
||||||
@@ -208,3 +210,21 @@ export const PanelHotkeysLogical = memo(() => {
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
PanelHotkeysLogical.displayName = 'PanelHotkeysLogical';
|
PanelHotkeysLogical.displayName = 'PanelHotkeysLogical';
|
||||||
|
|
||||||
|
export type PanelParameters = {
|
||||||
|
focusRegion: FocusRegionName;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AutoLayoutGridviewComponents = Record<string, FunctionComponent<IGridviewPanelProps<PanelParameters>>>;
|
||||||
|
export type AutoLayoutDockviewComponents = Record<string, FunctionComponent<IDockviewPanelProps<PanelParameters>>>;
|
||||||
|
export type RootLayoutGridviewComponents = Record<string, FunctionComponent<IGridviewPanelProps<PanelParameters>>>;
|
||||||
|
export type PanelProps = IDockviewPanelProps<PanelParameters> | IGridviewPanelProps<PanelParameters>;
|
||||||
|
|
||||||
|
export const withPanelContainer = (Component: FunctionComponent) =>
|
||||||
|
memo((props: PanelProps) => {
|
||||||
|
return (
|
||||||
|
<AutoLayoutPanelContainer {...props}>
|
||||||
|
<Component />
|
||||||
|
</AutoLayoutPanelContainer>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -15,7 +15,18 @@ import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer
|
|||||||
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
||||||
import { FloatingCanvasLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
import { FloatingCanvasLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
||||||
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
||||||
import { AutoLayoutProvider, PanelHotkeysLogical, useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
import type {
|
||||||
|
AutoLayoutDockviewComponents,
|
||||||
|
AutoLayoutGridviewComponents,
|
||||||
|
PanelParameters,
|
||||||
|
RootLayoutGridviewComponents,
|
||||||
|
} from 'features/ui/layouts/auto-layout-context';
|
||||||
|
import {
|
||||||
|
AutoLayoutProvider,
|
||||||
|
PanelHotkeysLogical,
|
||||||
|
useAutoLayoutContext,
|
||||||
|
withPanelContainer,
|
||||||
|
} from 'features/ui/layouts/auto-layout-context';
|
||||||
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
||||||
import { dockviewTheme } from 'features/ui/styles/theme';
|
import { dockviewTheme } from 'features/ui/styles/theme';
|
||||||
import { atom } from 'nanostores';
|
import { atom } from 'nanostores';
|
||||||
@@ -23,7 +34,6 @@ import { memo, useCallback, useRef, useState } from 'react';
|
|||||||
|
|
||||||
import { CanvasTabLeftPanel } from './CanvasTabLeftPanel';
|
import { CanvasTabLeftPanel } from './CanvasTabLeftPanel';
|
||||||
import { CanvasWorkspacePanel } from './CanvasWorkspacePanel';
|
import { CanvasWorkspacePanel } from './CanvasWorkspacePanel';
|
||||||
import { registerFocusListener } from './layout-focus-bridge';
|
|
||||||
import {
|
import {
|
||||||
BOARD_PANEL_DEFAULT_HEIGHT_PX,
|
BOARD_PANEL_DEFAULT_HEIGHT_PX,
|
||||||
BOARD_PANEL_MIN_HEIGHT_PX,
|
BOARD_PANEL_MIN_HEIGHT_PX,
|
||||||
@@ -56,45 +66,51 @@ const tabComponents = {
|
|||||||
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
|
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
const centerPanelComponents: IDockviewReactProps['components'] = {
|
const centerPanelComponents: AutoLayoutDockviewComponents = {
|
||||||
[LAUNCHPAD_PANEL_ID]: CanvasLaunchpadPanel,
|
[LAUNCHPAD_PANEL_ID]: withPanelContainer(CanvasLaunchpadPanel),
|
||||||
[WORKSPACE_PANEL_ID]: CanvasWorkspacePanel,
|
[WORKSPACE_PANEL_ID]: withPanelContainer(CanvasWorkspacePanel),
|
||||||
[VIEWER_PANEL_ID]: ImageViewerPanel,
|
[VIEWER_PANEL_ID]: withPanelContainer(ImageViewerPanel),
|
||||||
[PROGRESS_PANEL_ID]: GenerationProgressPanel,
|
[PROGRESS_PANEL_ID]: withPanelContainer(GenerationProgressPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
||||||
const launchpadPanel = api.addPanel({
|
const launchpadPanel = api.addPanel<PanelParameters>({
|
||||||
id: LAUNCHPAD_PANEL_ID,
|
id: LAUNCHPAD_PANEL_ID,
|
||||||
component: LAUNCHPAD_PANEL_ID,
|
component: LAUNCHPAD_PANEL_ID,
|
||||||
title: 'Launchpad',
|
title: 'Launchpad',
|
||||||
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
|
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'launchpad',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(launchpadPanel, 'launchpad');
|
|
||||||
|
|
||||||
const workspacePanel = api.addPanel({
|
const workspacePanel = api.addPanel<PanelParameters>({
|
||||||
id: WORKSPACE_PANEL_ID,
|
id: WORKSPACE_PANEL_ID,
|
||||||
component: WORKSPACE_PANEL_ID,
|
component: WORKSPACE_PANEL_ID,
|
||||||
title: 'Canvas',
|
title: 'Canvas',
|
||||||
tabComponent: DEFAULT_TAB_ID,
|
tabComponent: DEFAULT_TAB_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'canvas',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'within',
|
direction: 'within',
|
||||||
referencePanel: launchpadPanel.id,
|
referencePanel: launchpadPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(workspacePanel, 'canvas');
|
|
||||||
|
|
||||||
const viewerPanel = api.addPanel({
|
const viewerPanel = api.addPanel<PanelParameters>({
|
||||||
id: VIEWER_PANEL_ID,
|
id: VIEWER_PANEL_ID,
|
||||||
component: VIEWER_PANEL_ID,
|
component: VIEWER_PANEL_ID,
|
||||||
title: 'Image Viewer',
|
title: 'Image Viewer',
|
||||||
tabComponent: DEFAULT_TAB_ID,
|
tabComponent: DEFAULT_TAB_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'viewer',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'within',
|
direction: 'within',
|
||||||
referencePanel: launchpadPanel.id,
|
referencePanel: launchpadPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(viewerPanel, 'viewer');
|
|
||||||
|
|
||||||
return { launchpadPanel, workspacePanel, viewerPanel } satisfies Record<string, IDockviewPanel>;
|
return { launchpadPanel, workspacePanel, viewerPanel } satisfies Record<string, IDockviewPanel>;
|
||||||
};
|
};
|
||||||
@@ -145,42 +161,48 @@ const CenterPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
CenterPanel.displayName = 'CenterPanel';
|
CenterPanel.displayName = 'CenterPanel';
|
||||||
|
|
||||||
const rightPanelComponents: IGridviewReactProps['components'] = {
|
const rightPanelComponents: AutoLayoutGridviewComponents = {
|
||||||
[BOARDS_PANEL_ID]: BoardsPanel,
|
[BOARDS_PANEL_ID]: withPanelContainer(BoardsPanel),
|
||||||
[GALLERY_PANEL_ID]: GalleryPanel,
|
[GALLERY_PANEL_ID]: withPanelContainer(GalleryPanel),
|
||||||
[LAYERS_PANEL_ID]: CanvasLayersPanel,
|
[LAYERS_PANEL_ID]: withPanelContainer(CanvasLayersPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
||||||
const galleryPanel = api.addPanel({
|
const galleryPanel = api.addPanel<PanelParameters>({
|
||||||
id: GALLERY_PANEL_ID,
|
id: GALLERY_PANEL_ID,
|
||||||
component: GALLERY_PANEL_ID,
|
component: GALLERY_PANEL_ID,
|
||||||
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
||||||
minimumHeight: GALLERY_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: GALLERY_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'gallery',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(galleryPanel, 'gallery');
|
|
||||||
|
|
||||||
const layersPanel = api.addPanel({
|
const layersPanel = api.addPanel<PanelParameters>({
|
||||||
id: LAYERS_PANEL_ID,
|
id: LAYERS_PANEL_ID,
|
||||||
component: LAYERS_PANEL_ID,
|
component: LAYERS_PANEL_ID,
|
||||||
minimumHeight: LAYERS_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: LAYERS_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'layers',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'below',
|
direction: 'below',
|
||||||
referencePanel: galleryPanel.id,
|
referencePanel: galleryPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(layersPanel, 'layers');
|
|
||||||
|
|
||||||
const boardsPanel = api.addPanel({
|
const boardsPanel = api.addPanel<PanelParameters>({
|
||||||
id: BOARDS_PANEL_ID,
|
id: BOARDS_PANEL_ID,
|
||||||
component: BOARDS_PANEL_ID,
|
component: BOARDS_PANEL_ID,
|
||||||
minimumHeight: BOARD_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: BOARD_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'boards',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'above',
|
direction: 'above',
|
||||||
referencePanel: galleryPanel.id,
|
referencePanel: galleryPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(boardsPanel, 'boards');
|
|
||||||
|
|
||||||
boardsPanel.api.setSize({ height: BOARD_PANEL_DEFAULT_HEIGHT_PX, width: RIGHT_PANEL_MIN_SIZE_PX });
|
boardsPanel.api.setSize({ height: BOARD_PANEL_DEFAULT_HEIGHT_PX, width: RIGHT_PANEL_MIN_SIZE_PX });
|
||||||
return { galleryPanel, layersPanel, boardsPanel } satisfies Record<string, IGridviewPanel>;
|
return { galleryPanel, layersPanel, boardsPanel } satisfies Record<string, IGridviewPanel>;
|
||||||
@@ -208,16 +230,18 @@ const RightPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
RightPanel.displayName = 'RightPanel';
|
RightPanel.displayName = 'RightPanel';
|
||||||
|
|
||||||
const leftPanelComponents: IGridviewReactProps['components'] = {
|
const leftPanelComponents: AutoLayoutGridviewComponents = {
|
||||||
[SETTINGS_PANEL_ID]: CanvasTabLeftPanel,
|
[SETTINGS_PANEL_ID]: withPanelContainer(CanvasTabLeftPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
||||||
const settingsPanel = api.addPanel({
|
const settingsPanel = api.addPanel<PanelParameters>({
|
||||||
id: SETTINGS_PANEL_ID,
|
id: SETTINGS_PANEL_ID,
|
||||||
component: SETTINGS_PANEL_ID,
|
component: SETTINGS_PANEL_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'settings',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(settingsPanel, 'settings');
|
|
||||||
|
|
||||||
return { settingsPanel } satisfies Record<string, IGridviewPanel>;
|
return { settingsPanel } satisfies Record<string, IGridviewPanel>;
|
||||||
};
|
};
|
||||||
@@ -244,7 +268,7 @@ const LeftPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
LeftPanel.displayName = 'LeftPanel';
|
LeftPanel.displayName = 'LeftPanel';
|
||||||
|
|
||||||
export const rootPanelComponents: IGridviewReactProps['components'] = {
|
export const rootPanelComponents: RootLayoutGridviewComponents = {
|
||||||
[LEFT_PANEL_ID]: LeftPanel,
|
[LEFT_PANEL_ID]: LeftPanel,
|
||||||
[MAIN_PANEL_ID]: CenterPanel,
|
[MAIN_PANEL_ID]: CenterPanel,
|
||||||
[RIGHT_PANEL_ID]: RightPanel,
|
[RIGHT_PANEL_ID]: RightPanel,
|
||||||
|
|||||||
@@ -14,7 +14,18 @@ import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer
|
|||||||
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
||||||
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
||||||
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
||||||
import { AutoLayoutProvider, PanelHotkeysLogical, useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
import type {
|
||||||
|
AutoLayoutDockviewComponents,
|
||||||
|
AutoLayoutGridviewComponents,
|
||||||
|
PanelParameters,
|
||||||
|
RootLayoutGridviewComponents,
|
||||||
|
} from 'features/ui/layouts/auto-layout-context';
|
||||||
|
import {
|
||||||
|
AutoLayoutProvider,
|
||||||
|
PanelHotkeysLogical,
|
||||||
|
useAutoLayoutContext,
|
||||||
|
withPanelContainer,
|
||||||
|
} from 'features/ui/layouts/auto-layout-context';
|
||||||
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
||||||
import { dockviewTheme } from 'features/ui/styles/theme';
|
import { dockviewTheme } from 'features/ui/styles/theme';
|
||||||
import { atom } from 'nanostores';
|
import { atom } from 'nanostores';
|
||||||
@@ -51,26 +62,32 @@ const tabComponents = {
|
|||||||
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
|
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
const centerPanelComponents: IDockviewReactProps['components'] = {
|
const centerPanelComponents: AutoLayoutDockviewComponents = {
|
||||||
[LAUNCHPAD_PANEL_ID]: GenerateLaunchpadPanel,
|
[LAUNCHPAD_PANEL_ID]: withPanelContainer(GenerateLaunchpadPanel),
|
||||||
[VIEWER_PANEL_ID]: ImageViewerPanel,
|
[VIEWER_PANEL_ID]: withPanelContainer(ImageViewerPanel),
|
||||||
[PROGRESS_PANEL_ID]: GenerationProgressPanel,
|
[PROGRESS_PANEL_ID]: withPanelContainer(GenerationProgressPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
||||||
const launchpadPanel = api.addPanel({
|
const launchpadPanel = api.addPanel<PanelParameters>({
|
||||||
id: LAUNCHPAD_PANEL_ID,
|
id: LAUNCHPAD_PANEL_ID,
|
||||||
component: LAUNCHPAD_PANEL_ID,
|
component: LAUNCHPAD_PANEL_ID,
|
||||||
title: 'Launchpad',
|
title: 'Launchpad',
|
||||||
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
|
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'launchpad',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(launchpadPanel, 'launchpad');
|
registerFocusListener(launchpadPanel, 'launchpad');
|
||||||
|
|
||||||
const viewerPanel = api.addPanel({
|
const viewerPanel = api.addPanel<PanelParameters>({
|
||||||
id: VIEWER_PANEL_ID,
|
id: VIEWER_PANEL_ID,
|
||||||
component: VIEWER_PANEL_ID,
|
component: VIEWER_PANEL_ID,
|
||||||
title: 'Image Viewer',
|
title: 'Image Viewer',
|
||||||
tabComponent: TAB_WITH_PROGRESS_INDICATOR_ID,
|
tabComponent: TAB_WITH_PROGRESS_INDICATOR_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'viewer',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'within',
|
direction: 'within',
|
||||||
referencePanel: launchpadPanel.id,
|
referencePanel: launchpadPanel.id,
|
||||||
@@ -127,24 +144,30 @@ const CenterPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
CenterPanel.displayName = 'CenterPanel';
|
CenterPanel.displayName = 'CenterPanel';
|
||||||
|
|
||||||
const rightPanelComponents: IGridviewReactProps['components'] = {
|
const rightPanelComponents: AutoLayoutGridviewComponents = {
|
||||||
[BOARDS_PANEL_ID]: BoardsPanel,
|
[BOARDS_PANEL_ID]: withPanelContainer(BoardsPanel),
|
||||||
[GALLERY_PANEL_ID]: GalleryPanel,
|
[GALLERY_PANEL_ID]: withPanelContainer(GalleryPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
||||||
const galleryPanel = api.addPanel({
|
const galleryPanel = api.addPanel<PanelParameters>({
|
||||||
id: GALLERY_PANEL_ID,
|
id: GALLERY_PANEL_ID,
|
||||||
component: GALLERY_PANEL_ID,
|
component: GALLERY_PANEL_ID,
|
||||||
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
||||||
minimumHeight: GALLERY_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: GALLERY_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'gallery',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(galleryPanel, 'gallery');
|
registerFocusListener(galleryPanel, 'gallery');
|
||||||
|
|
||||||
const boardsPanel = api.addPanel({
|
const boardsPanel = api.addPanel<PanelParameters>({
|
||||||
id: BOARDS_PANEL_ID,
|
id: BOARDS_PANEL_ID,
|
||||||
component: BOARDS_PANEL_ID,
|
component: BOARDS_PANEL_ID,
|
||||||
minimumHeight: BOARD_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: BOARD_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'boards',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'above',
|
direction: 'above',
|
||||||
referencePanel: galleryPanel.id,
|
referencePanel: galleryPanel.id,
|
||||||
@@ -179,14 +202,17 @@ const RightPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
RightPanel.displayName = 'RightPanel';
|
RightPanel.displayName = 'RightPanel';
|
||||||
|
|
||||||
const leftPanelComponents: IGridviewReactProps['components'] = {
|
const leftPanelComponents: AutoLayoutGridviewComponents = {
|
||||||
[SETTINGS_PANEL_ID]: GenerateTabLeftPanel,
|
[SETTINGS_PANEL_ID]: withPanelContainer(GenerateTabLeftPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
||||||
const settingsPanel = api.addPanel({
|
const settingsPanel = api.addPanel<PanelParameters>({
|
||||||
id: SETTINGS_PANEL_ID,
|
id: SETTINGS_PANEL_ID,
|
||||||
component: SETTINGS_PANEL_ID,
|
component: SETTINGS_PANEL_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'settings',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(settingsPanel, 'settings');
|
registerFocusListener(settingsPanel, 'settings');
|
||||||
|
|
||||||
@@ -215,20 +241,20 @@ const LeftPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
LeftPanel.displayName = 'LeftPanel';
|
LeftPanel.displayName = 'LeftPanel';
|
||||||
|
|
||||||
export const rootPanelComponents: IGridviewReactProps['components'] = {
|
export const rootPanelComponents: RootLayoutGridviewComponents = {
|
||||||
[LEFT_PANEL_ID]: LeftPanel,
|
[LEFT_PANEL_ID]: LeftPanel,
|
||||||
[MAIN_PANEL_ID]: CenterPanel,
|
[MAIN_PANEL_ID]: CenterPanel,
|
||||||
[RIGHT_PANEL_ID]: RightPanel,
|
[RIGHT_PANEL_ID]: RightPanel,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeRootPanelLayout = (layoutApi: GridviewApi) => {
|
export const initializeRootPanelLayout = (layoutApi: GridviewApi) => {
|
||||||
const mainPanel = layoutApi.addPanel({
|
const mainPanel = layoutApi.addPanel<PanelParameters>({
|
||||||
id: MAIN_PANEL_ID,
|
id: MAIN_PANEL_ID,
|
||||||
component: MAIN_PANEL_ID,
|
component: MAIN_PANEL_ID,
|
||||||
priority: LayoutPriority.High,
|
priority: LayoutPriority.High,
|
||||||
});
|
});
|
||||||
|
|
||||||
const leftPanel = layoutApi.addPanel({
|
const leftPanel = layoutApi.addPanel<PanelParameters>({
|
||||||
id: LEFT_PANEL_ID,
|
id: LEFT_PANEL_ID,
|
||||||
component: LEFT_PANEL_ID,
|
component: LEFT_PANEL_ID,
|
||||||
minimumWidth: LEFT_PANEL_MIN_SIZE_PX,
|
minimumWidth: LEFT_PANEL_MIN_SIZE_PX,
|
||||||
@@ -238,7 +264,7 @@ export const initializeRootPanelLayout = (layoutApi: GridviewApi) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const rightPanel = layoutApi.addPanel({
|
const rightPanel = layoutApi.addPanel<PanelParameters>({
|
||||||
id: RIGHT_PANEL_ID,
|
id: RIGHT_PANEL_ID,
|
||||||
component: RIGHT_PANEL_ID,
|
component: RIGHT_PANEL_ID,
|
||||||
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
||||||
|
|||||||
@@ -14,13 +14,23 @@ import { GenerationProgressPanel } from 'features/gallery/components/ImageViewer
|
|||||||
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
import { ImageViewerPanel } from 'features/gallery/components/ImageViewer/ImageViewerPanel';
|
||||||
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
||||||
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
||||||
import { AutoLayoutProvider, PanelHotkeysLogical, useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
import type {
|
||||||
|
AutoLayoutDockviewComponents,
|
||||||
|
AutoLayoutGridviewComponents,
|
||||||
|
PanelParameters,
|
||||||
|
RootLayoutGridviewComponents,
|
||||||
|
} from 'features/ui/layouts/auto-layout-context';
|
||||||
|
import {
|
||||||
|
AutoLayoutProvider,
|
||||||
|
PanelHotkeysLogical,
|
||||||
|
useAutoLayoutContext,
|
||||||
|
withPanelContainer,
|
||||||
|
} from 'features/ui/layouts/auto-layout-context';
|
||||||
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
||||||
import { dockviewTheme } from 'features/ui/styles/theme';
|
import { dockviewTheme } from 'features/ui/styles/theme';
|
||||||
import { atom } from 'nanostores';
|
import { atom } from 'nanostores';
|
||||||
import { memo, useCallback, useRef, useState } from 'react';
|
import { memo, useCallback, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { registerFocusListener } from './layout-focus-bridge';
|
|
||||||
import {
|
import {
|
||||||
BOARD_PANEL_DEFAULT_HEIGHT_PX,
|
BOARD_PANEL_DEFAULT_HEIGHT_PX,
|
||||||
BOARD_PANEL_MIN_HEIGHT_PX,
|
BOARD_PANEL_MIN_HEIGHT_PX,
|
||||||
@@ -51,32 +61,36 @@ const tabComponents = {
|
|||||||
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
|
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
const centerComponents: IDockviewReactProps['components'] = {
|
const centerComponents: AutoLayoutDockviewComponents = {
|
||||||
[LAUNCHPAD_PANEL_ID]: UpscalingLaunchpadPanel,
|
[LAUNCHPAD_PANEL_ID]: withPanelContainer(UpscalingLaunchpadPanel),
|
||||||
[VIEWER_PANEL_ID]: ImageViewerPanel,
|
[VIEWER_PANEL_ID]: withPanelContainer(ImageViewerPanel),
|
||||||
[PROGRESS_PANEL_ID]: GenerationProgressPanel,
|
[PROGRESS_PANEL_ID]: withPanelContainer(GenerationProgressPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
||||||
const launchpadPanel = api.addPanel({
|
const launchpadPanel = api.addPanel<PanelParameters>({
|
||||||
id: LAUNCHPAD_PANEL_ID,
|
id: LAUNCHPAD_PANEL_ID,
|
||||||
component: LAUNCHPAD_PANEL_ID,
|
component: LAUNCHPAD_PANEL_ID,
|
||||||
title: 'Launchpad',
|
title: 'Launchpad',
|
||||||
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
|
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'launchpad',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(launchpadPanel, 'launchpad');
|
|
||||||
|
|
||||||
const viewerPanel = api.addPanel({
|
const viewerPanel = api.addPanel<PanelParameters>({
|
||||||
id: VIEWER_PANEL_ID,
|
id: VIEWER_PANEL_ID,
|
||||||
component: VIEWER_PANEL_ID,
|
component: VIEWER_PANEL_ID,
|
||||||
title: 'Image Viewer',
|
title: 'Image Viewer',
|
||||||
tabComponent: TAB_WITH_PROGRESS_INDICATOR_ID,
|
tabComponent: TAB_WITH_PROGRESS_INDICATOR_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'viewer',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'within',
|
direction: 'within',
|
||||||
referencePanel: launchpadPanel.id,
|
referencePanel: launchpadPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(viewerPanel, 'viewer');
|
|
||||||
|
|
||||||
return { launchpadPanel, viewerPanel } satisfies Record<string, IDockviewPanel>;
|
return { launchpadPanel, viewerPanel } satisfies Record<string, IDockviewPanel>;
|
||||||
};
|
};
|
||||||
@@ -127,30 +141,34 @@ const CenterPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
CenterPanel.displayName = 'CenterPanel';
|
CenterPanel.displayName = 'CenterPanel';
|
||||||
|
|
||||||
const rightPanelComponents: IGridviewReactProps['components'] = {
|
const rightPanelComponents: AutoLayoutGridviewComponents = {
|
||||||
[BOARDS_PANEL_ID]: BoardsPanel,
|
[BOARDS_PANEL_ID]: withPanelContainer(BoardsPanel),
|
||||||
[GALLERY_PANEL_ID]: GalleryPanel,
|
[GALLERY_PANEL_ID]: withPanelContainer(GalleryPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
||||||
const galleryPanel = api.addPanel({
|
const galleryPanel = api.addPanel<PanelParameters>({
|
||||||
id: GALLERY_PANEL_ID,
|
id: GALLERY_PANEL_ID,
|
||||||
component: GALLERY_PANEL_ID,
|
component: GALLERY_PANEL_ID,
|
||||||
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
||||||
minimumHeight: GALLERY_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: GALLERY_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'gallery',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(galleryPanel, 'gallery');
|
|
||||||
|
|
||||||
const boardsPanel = api.addPanel({
|
const boardsPanel = api.addPanel<PanelParameters>({
|
||||||
id: BOARDS_PANEL_ID,
|
id: BOARDS_PANEL_ID,
|
||||||
component: BOARDS_PANEL_ID,
|
component: BOARDS_PANEL_ID,
|
||||||
minimumHeight: BOARD_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: BOARD_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'boards',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'above',
|
direction: 'above',
|
||||||
referencePanel: galleryPanel.id,
|
referencePanel: galleryPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(boardsPanel, 'boards');
|
|
||||||
|
|
||||||
boardsPanel.api.setSize({ height: BOARD_PANEL_DEFAULT_HEIGHT_PX, width: RIGHT_PANEL_MIN_SIZE_PX });
|
boardsPanel.api.setSize({ height: BOARD_PANEL_DEFAULT_HEIGHT_PX, width: RIGHT_PANEL_MIN_SIZE_PX });
|
||||||
|
|
||||||
@@ -175,16 +193,18 @@ const RightPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
RightPanel.displayName = 'RightPanel';
|
RightPanel.displayName = 'RightPanel';
|
||||||
|
|
||||||
const leftPanelComponents: IGridviewReactProps['components'] = {
|
const leftPanelComponents: AutoLayoutGridviewComponents = {
|
||||||
[SETTINGS_PANEL_ID]: UpscalingTabLeftPanel,
|
[SETTINGS_PANEL_ID]: withPanelContainer(UpscalingTabLeftPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
||||||
const settingsPanel = api.addPanel({
|
const settingsPanel = api.addPanel<PanelParameters>({
|
||||||
id: SETTINGS_PANEL_ID,
|
id: SETTINGS_PANEL_ID,
|
||||||
component: SETTINGS_PANEL_ID,
|
component: SETTINGS_PANEL_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'settings',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(settingsPanel, 'settings');
|
|
||||||
|
|
||||||
return { settingsPanel } satisfies Record<string, IGridviewPanel>;
|
return { settingsPanel } satisfies Record<string, IGridviewPanel>;
|
||||||
};
|
};
|
||||||
@@ -211,7 +231,7 @@ const LeftPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
LeftPanel.displayName = 'LeftPanel';
|
LeftPanel.displayName = 'LeftPanel';
|
||||||
|
|
||||||
export const rootPanelComponents: IGridviewReactProps['components'] = {
|
export const rootPanelComponents: RootLayoutGridviewComponents = {
|
||||||
[LEFT_PANEL_ID]: LeftPanel,
|
[LEFT_PANEL_ID]: LeftPanel,
|
||||||
[MAIN_PANEL_ID]: CenterPanel,
|
[MAIN_PANEL_ID]: CenterPanel,
|
||||||
[RIGHT_PANEL_ID]: RightPanel,
|
[RIGHT_PANEL_ID]: RightPanel,
|
||||||
|
|||||||
@@ -16,7 +16,18 @@ import NodeEditor from 'features/nodes/components/NodeEditor';
|
|||||||
import WorkflowsTabLeftPanel from 'features/nodes/components/sidePanel/WorkflowsTabLeftPanel';
|
import WorkflowsTabLeftPanel from 'features/nodes/components/sidePanel/WorkflowsTabLeftPanel';
|
||||||
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons';
|
||||||
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons';
|
||||||
import { AutoLayoutProvider, PanelHotkeysLogical, useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
import type {
|
||||||
|
AutoLayoutDockviewComponents,
|
||||||
|
AutoLayoutGridviewComponents,
|
||||||
|
PanelParameters,
|
||||||
|
RootLayoutGridviewComponents,
|
||||||
|
} from 'features/ui/layouts/auto-layout-context';
|
||||||
|
import {
|
||||||
|
AutoLayoutProvider,
|
||||||
|
PanelHotkeysLogical,
|
||||||
|
useAutoLayoutContext,
|
||||||
|
withPanelContainer,
|
||||||
|
} from 'features/ui/layouts/auto-layout-context';
|
||||||
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
|
||||||
import { dockviewTheme } from 'features/ui/styles/theme';
|
import { dockviewTheme } from 'features/ui/styles/theme';
|
||||||
import { atom } from 'nanostores';
|
import { atom } from 'nanostores';
|
||||||
@@ -53,45 +64,51 @@ const tabComponents = {
|
|||||||
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
|
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
const centerPanelComponents: IDockviewReactProps['components'] = {
|
const centerPanelComponents: AutoLayoutDockviewComponents = {
|
||||||
[LAUNCHPAD_PANEL_ID]: WorkflowsLaunchpadPanel,
|
[LAUNCHPAD_PANEL_ID]: withPanelContainer(WorkflowsLaunchpadPanel),
|
||||||
[WORKSPACE_PANEL_ID]: NodeEditor,
|
[WORKSPACE_PANEL_ID]: withPanelContainer(NodeEditor),
|
||||||
[VIEWER_PANEL_ID]: ImageViewerPanel,
|
[VIEWER_PANEL_ID]: withPanelContainer(ImageViewerPanel),
|
||||||
[PROGRESS_PANEL_ID]: GenerationProgressPanel,
|
[PROGRESS_PANEL_ID]: withPanelContainer(GenerationProgressPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
const initializeCenterPanelLayout = (api: DockviewApi) => {
|
||||||
const launchpadPanel = api.addPanel({
|
const launchpadPanel = api.addPanel<PanelParameters>({
|
||||||
id: LAUNCHPAD_PANEL_ID,
|
id: LAUNCHPAD_PANEL_ID,
|
||||||
component: LAUNCHPAD_PANEL_ID,
|
component: LAUNCHPAD_PANEL_ID,
|
||||||
title: 'Launchpad',
|
title: 'Launchpad',
|
||||||
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
|
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'launchpad',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(launchpadPanel, 'launchpad');
|
|
||||||
|
|
||||||
const workspacePanel = api.addPanel({
|
const workspacePanel = api.addPanel<PanelParameters>({
|
||||||
id: WORKSPACE_PANEL_ID,
|
id: WORKSPACE_PANEL_ID,
|
||||||
component: WORKSPACE_PANEL_ID,
|
component: WORKSPACE_PANEL_ID,
|
||||||
title: 'Workflow Editor',
|
title: 'Workflow Editor',
|
||||||
tabComponent: DEFAULT_TAB_ID,
|
tabComponent: DEFAULT_TAB_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'workflows',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'within',
|
direction: 'within',
|
||||||
referencePanel: launchpadPanel.id,
|
referencePanel: launchpadPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(workspacePanel, 'workflows');
|
|
||||||
|
|
||||||
const viewerPanel = api.addPanel({
|
const viewerPanel = api.addPanel<PanelParameters>({
|
||||||
id: VIEWER_PANEL_ID,
|
id: VIEWER_PANEL_ID,
|
||||||
component: VIEWER_PANEL_ID,
|
component: VIEWER_PANEL_ID,
|
||||||
title: 'Image Viewer',
|
title: 'Image Viewer',
|
||||||
tabComponent: TAB_WITH_PROGRESS_INDICATOR_ID,
|
tabComponent: TAB_WITH_PROGRESS_INDICATOR_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'viewer',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'within',
|
direction: 'within',
|
||||||
referencePanel: launchpadPanel.id,
|
referencePanel: launchpadPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(viewerPanel, 'viewer');
|
|
||||||
|
|
||||||
return { launchpadPanel, workspacePanel, viewerPanel } satisfies Record<string, IDockviewPanel>;
|
return { launchpadPanel, workspacePanel, viewerPanel } satisfies Record<string, IDockviewPanel>;
|
||||||
};
|
};
|
||||||
@@ -142,30 +159,34 @@ const CenterPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
CenterPanel.displayName = 'CenterPanel';
|
CenterPanel.displayName = 'CenterPanel';
|
||||||
|
|
||||||
const rightPanelComponents: IGridviewReactProps['components'] = {
|
const rightPanelComponents: AutoLayoutGridviewComponents = {
|
||||||
[BOARDS_PANEL_ID]: BoardsPanel,
|
[BOARDS_PANEL_ID]: withPanelContainer(BoardsPanel),
|
||||||
[GALLERY_PANEL_ID]: GalleryPanel,
|
[GALLERY_PANEL_ID]: withPanelContainer(GalleryPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
export const initializeRightPanelLayout = (api: GridviewApi) => {
|
||||||
const galleryPanel = api.addPanel({
|
const galleryPanel = api.addPanel<PanelParameters>({
|
||||||
id: GALLERY_PANEL_ID,
|
id: GALLERY_PANEL_ID,
|
||||||
component: GALLERY_PANEL_ID,
|
component: GALLERY_PANEL_ID,
|
||||||
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
minimumWidth: RIGHT_PANEL_MIN_SIZE_PX,
|
||||||
minimumHeight: GALLERY_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: GALLERY_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'gallery',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(galleryPanel, 'gallery');
|
|
||||||
|
|
||||||
const boardsPanel = api.addPanel({
|
const boardsPanel = api.addPanel<PanelParameters>({
|
||||||
id: BOARDS_PANEL_ID,
|
id: BOARDS_PANEL_ID,
|
||||||
component: BOARDS_PANEL_ID,
|
component: BOARDS_PANEL_ID,
|
||||||
minimumHeight: BOARD_PANEL_MIN_HEIGHT_PX,
|
minimumHeight: BOARD_PANEL_MIN_HEIGHT_PX,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'boards',
|
||||||
|
},
|
||||||
position: {
|
position: {
|
||||||
direction: 'above',
|
direction: 'above',
|
||||||
referencePanel: galleryPanel.id,
|
referencePanel: galleryPanel.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(boardsPanel, 'boards');
|
|
||||||
|
|
||||||
boardsPanel.api.setSize({ height: BOARD_PANEL_DEFAULT_HEIGHT_PX, width: RIGHT_PANEL_MIN_SIZE_PX });
|
boardsPanel.api.setSize({ height: BOARD_PANEL_DEFAULT_HEIGHT_PX, width: RIGHT_PANEL_MIN_SIZE_PX });
|
||||||
|
|
||||||
@@ -194,14 +215,17 @@ const RightPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
RightPanel.displayName = 'RightPanel';
|
RightPanel.displayName = 'RightPanel';
|
||||||
|
|
||||||
const leftPanelComponents: IGridviewReactProps['components'] = {
|
const leftPanelComponents: AutoLayoutGridviewComponents = {
|
||||||
[SETTINGS_PANEL_ID]: WorkflowsTabLeftPanel,
|
[SETTINGS_PANEL_ID]: withPanelContainer(WorkflowsTabLeftPanel),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
export const initializeLeftPanelLayout = (api: GridviewApi) => {
|
||||||
const settingsPanel = api.addPanel({
|
const settingsPanel = api.addPanel<PanelParameters>({
|
||||||
id: SETTINGS_PANEL_ID,
|
id: SETTINGS_PANEL_ID,
|
||||||
component: SETTINGS_PANEL_ID,
|
component: SETTINGS_PANEL_ID,
|
||||||
|
params: {
|
||||||
|
focusRegion: 'settings',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
registerFocusListener(settingsPanel, 'settings');
|
registerFocusListener(settingsPanel, 'settings');
|
||||||
|
|
||||||
@@ -230,7 +254,7 @@ const LeftPanel = memo(() => {
|
|||||||
});
|
});
|
||||||
LeftPanel.displayName = 'LeftPanel';
|
LeftPanel.displayName = 'LeftPanel';
|
||||||
|
|
||||||
export const rootPanelComponents: IGridviewReactProps['components'] = {
|
export const rootPanelComponents: RootLayoutGridviewComponents = {
|
||||||
[LEFT_PANEL_ID]: LeftPanel,
|
[LEFT_PANEL_ID]: LeftPanel,
|
||||||
[MAIN_PANEL_ID]: CenterPanel,
|
[MAIN_PANEL_ID]: CenterPanel,
|
||||||
[RIGHT_PANEL_ID]: RightPanel,
|
[RIGHT_PANEL_ID]: RightPanel,
|
||||||
|
|||||||
Reference in New Issue
Block a user