mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): update panel lib, move gallery to percentages
This commit is contained in:
parent
47b1fd4bce
commit
10fd4f6a61
@ -94,7 +94,7 @@
|
||||
"react-icons": "^4.12.0",
|
||||
"react-konva": "^18.2.10",
|
||||
"react-redux": "^9.0.4",
|
||||
"react-resizable-panels": "^0.0.55",
|
||||
"react-resizable-panels": "^1.0.5",
|
||||
"react-select": "5.7.7",
|
||||
"react-textarea-autosize": "^8.5.3",
|
||||
"react-use": "^17.4.2",
|
||||
|
@ -132,8 +132,8 @@ dependencies:
|
||||
specifier: ^9.0.4
|
||||
version: 9.0.4(@types/react@18.2.46)(react@18.2.0)(redux@5.0.1)
|
||||
react-resizable-panels:
|
||||
specifier: ^0.0.55
|
||||
version: 0.0.55(react-dom@18.2.0)(react@18.2.0)
|
||||
specifier: ^1.0.5
|
||||
version: 1.0.5(react-dom@18.2.0)(react@18.2.0)
|
||||
react-select:
|
||||
specifier: 5.7.7
|
||||
version: 5.7.7(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -11199,8 +11199,8 @@ packages:
|
||||
use-sidecar: 1.1.2(@types/react@18.2.46)(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/react-resizable-panels@0.0.55(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-J/LTFzUEjJiqwSjVh8gjUXkQDA8MRPjARASfn++d2+KOgA+9UcRYUfE3QBJixer2vkk+ffQ4cq3QzWzzHgqYpQ==}
|
||||
/react-resizable-panels@1.0.5(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-OP0whNQCko+f4BgoptGaeIc7StBRyeMeJ+8r/7rXACBDf9W5EcMWuM32hfqPDMenS2HFy/eZVi/r8XqK+ZIEag==}
|
||||
peerDependencies:
|
||||
react: ^16.14.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0
|
||||
|
@ -5,7 +5,7 @@ import QueueControls from 'features/queue/components/QueueControls';
|
||||
import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
|
||||
import { usePanelStorage } from 'features/ui/hooks/usePanelStorage';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { memo, useCallback, useRef, useState } from 'react';
|
||||
import { memo, useCallback, useRef } from 'react';
|
||||
import type { ImperativePanelGroupHandle } from 'react-resizable-panels';
|
||||
import { Panel, PanelGroup } from 'react-resizable-panels';
|
||||
|
||||
@ -15,8 +15,6 @@ import WorkflowPanel from './workflow/WorkflowPanel';
|
||||
const panelGroupStyles: CSSProperties = { height: '100%', width: '100%' };
|
||||
|
||||
const NodeEditorPanelGroup = () => {
|
||||
const [isTopPanelCollapsed, setIsTopPanelCollapsed] = useState(false);
|
||||
const [isBottomPanelCollapsed, setIsBottomPanelCollapsed] = useState(false);
|
||||
const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
|
||||
const panelStorage = usePanelStorage();
|
||||
const handleDoubleClickHandle = useCallback(() => {
|
||||
@ -37,31 +35,14 @@ const NodeEditorPanelGroup = () => {
|
||||
style={panelGroupStyles}
|
||||
storage={panelStorage}
|
||||
>
|
||||
<Panel
|
||||
id="workflow"
|
||||
collapsible
|
||||
onCollapse={setIsTopPanelCollapsed}
|
||||
minSize={25}
|
||||
>
|
||||
<Panel id="workflow" collapsible minSize={25}>
|
||||
<WorkflowPanel />
|
||||
</Panel>
|
||||
<ResizeHandle
|
||||
direction="vertical"
|
||||
onDoubleClick={handleDoubleClickHandle}
|
||||
collapsedDirection={
|
||||
isTopPanelCollapsed
|
||||
? 'top'
|
||||
: isBottomPanelCollapsed
|
||||
? 'bottom'
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<Panel
|
||||
id="inspector"
|
||||
collapsible
|
||||
onCollapse={setIsBottomPanelCollapsed}
|
||||
minSize={25}
|
||||
>
|
||||
<Panel id="inspector" collapsible minSize={25}>
|
||||
<InspectorPanel />
|
||||
</Panel>
|
||||
</PanelGroup>
|
||||
|
@ -1,27 +1,21 @@
|
||||
import { Flex } from '@chakra-ui/layout';
|
||||
import { Portal } from '@chakra-ui/portal';
|
||||
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
|
||||
import type { RefObject } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MdPhotoLibrary } from 'react-icons/md';
|
||||
import type { ImperativePanelHandle } from 'react-resizable-panels';
|
||||
|
||||
type Props = {
|
||||
isGalleryCollapsed: boolean;
|
||||
galleryPanelRef: RefObject<ImperativePanelHandle>;
|
||||
expandGallery: () => void;
|
||||
};
|
||||
|
||||
const FloatingGalleryButton = ({
|
||||
isGalleryCollapsed,
|
||||
galleryPanelRef,
|
||||
expandGallery,
|
||||
}: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleShowGallery = useCallback(() => {
|
||||
galleryPanelRef.current?.expand();
|
||||
}, [galleryPanelRef]);
|
||||
|
||||
if (!isGalleryCollapsed) {
|
||||
return null;
|
||||
}
|
||||
@ -38,7 +32,7 @@ const FloatingGalleryButton = ({
|
||||
<InvIconButton
|
||||
tooltip="Show Gallery (G)"
|
||||
aria-label={t('accessibility.showGalleryPanel')}
|
||||
onClick={handleShowGallery}
|
||||
onClick={expandGallery}
|
||||
icon={<MdPhotoLibrary />}
|
||||
p={0}
|
||||
px={3}
|
||||
|
@ -95,13 +95,10 @@ const enabledTabsSelector = createMemoizedSelector(
|
||||
}
|
||||
);
|
||||
|
||||
const SIDE_PANEL_MIN_SIZE_PX = 448;
|
||||
const MAIN_PANEL_MIN_SIZE_PX = 448;
|
||||
const GALLERY_PANEL_MIN_SIZE_PX = 360;
|
||||
|
||||
export const NO_GALLERY_TABS: InvokeTabName[] = ['modelManager', 'queue'];
|
||||
export const NO_SIDE_PANEL_TABS: InvokeTabName[] = ['modelManager', 'queue'];
|
||||
const panelStyles: CSSProperties = { height: '100%', width: '100%' };
|
||||
const GALLERY_MIN_SIZE_PCT = 20
|
||||
|
||||
const InvokeTabs = () => {
|
||||
const activeTabIndex = useAppSelector(activeTabIndexSelector);
|
||||
@ -155,53 +152,18 @@ const InvokeTabs = () => {
|
||||
[dispatch, enabledTabs]
|
||||
);
|
||||
|
||||
const {
|
||||
isCollapsed: isSidePanelCollapsed,
|
||||
expand: expandSidePanel,
|
||||
collapse: collapseSidePanel,
|
||||
toggle: toggleSidePanel,
|
||||
} = usePanel(SIDE_PANEL_MIN_SIZE_PX, 'pixels');
|
||||
|
||||
const {
|
||||
ref: galleryPanelRef,
|
||||
minSize: galleryPanelMinSize,
|
||||
isCollapsed: isGalleryPanelCollapsed,
|
||||
setIsCollapsed: setIsGalleryPanelCollapsed,
|
||||
onCollapse: onCollapseGalleryPanel,
|
||||
onExpand: onExpandGalleryPanel,
|
||||
reset: resetGalleryPanel,
|
||||
expand: expandGalleryPanel,
|
||||
collapse: collapseGalleryPanel,
|
||||
toggle: toggleGalleryPanel,
|
||||
} = usePanel(GALLERY_PANEL_MIN_SIZE_PX, 'pixels');
|
||||
} = usePanel(GALLERY_MIN_SIZE_PCT);
|
||||
|
||||
useHotkeys(
|
||||
'f',
|
||||
() => {
|
||||
if (isGalleryPanelCollapsed || isSidePanelCollapsed) {
|
||||
expandGalleryPanel();
|
||||
expandSidePanel();
|
||||
} else {
|
||||
collapseSidePanel();
|
||||
collapseGalleryPanel();
|
||||
}
|
||||
},
|
||||
[dispatch, isGalleryPanelCollapsed, isSidePanelCollapsed]
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
['t', 'o'],
|
||||
() => {
|
||||
toggleSidePanel();
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'g',
|
||||
() => {
|
||||
toggleGalleryPanel();
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
useHotkeys('g', toggleGalleryPanel, []);
|
||||
|
||||
const panelStorage = usePanelStorage();
|
||||
|
||||
@ -219,73 +181,47 @@ const InvokeTabs = () => {
|
||||
{tabs}
|
||||
<Spacer />
|
||||
</InvTabList>
|
||||
{!NO_SIDE_PANEL_TABS.includes(activeTabName) && (
|
||||
<Flex h="full" w={434} flexShrink={0}>
|
||||
{activeTabName === 'nodes' ? (
|
||||
<NodeEditorPanelGroup />
|
||||
) : (
|
||||
<ParametersPanel />
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
<PanelGroup
|
||||
id="app"
|
||||
autoSaveId="app"
|
||||
direction="horizontal"
|
||||
style={panelStyles}
|
||||
storage={panelStorage}
|
||||
units="pixels"
|
||||
>
|
||||
{/* {!NO_SIDE_PANEL_TABS.includes(activeTabName) && (
|
||||
<>
|
||||
<Panel
|
||||
order={0}
|
||||
id="side"
|
||||
ref={sidePanelRef}
|
||||
defaultSize={sidePanelMinSize}
|
||||
minSize={sidePanelMinSize}
|
||||
onCollapse={setIsSidePanelCollapsed}
|
||||
collapsible
|
||||
>
|
||||
{activeTabName === 'nodes' ? (
|
||||
<NodeEditorPanelGroup />
|
||||
) : (
|
||||
<ParametersPanel />
|
||||
)}
|
||||
</Panel>
|
||||
<ResizeHandle
|
||||
onDoubleClick={resetSidePanel}
|
||||
collapsedDirection={isSidePanelCollapsed ? 'left' : undefined}
|
||||
/>
|
||||
<FloatingSidePanelButtons
|
||||
isSidePanelCollapsed={isSidePanelCollapsed}
|
||||
sidePanelRef={sidePanelRef}
|
||||
/>
|
||||
</>
|
||||
)} */}
|
||||
<Panel id="main" order={1} minSize={MAIN_PANEL_MIN_SIZE_PX}>
|
||||
<InvTabPanels style={panelStyles}>{tabPanels}</InvTabPanels>
|
||||
<Panel id="main" order={0} minSize={50}>
|
||||
<Flex w="full" h="full" gap={4}>
|
||||
{!NO_SIDE_PANEL_TABS.includes(activeTabName) && (
|
||||
<Flex h="full" w={434} flexShrink={0}>
|
||||
{activeTabName === 'nodes' ? (
|
||||
<NodeEditorPanelGroup />
|
||||
) : (
|
||||
<ParametersPanel />
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
<InvTabPanels w="full" h="full">
|
||||
{tabPanels}
|
||||
</InvTabPanels>
|
||||
</Flex>
|
||||
</Panel>
|
||||
{!NO_GALLERY_TABS.includes(activeTabName) && (
|
||||
<>
|
||||
<ResizeHandle
|
||||
onDoubleClick={resetGalleryPanel}
|
||||
collapsedDirection={isGalleryPanelCollapsed ? 'right' : undefined}
|
||||
/>
|
||||
<ResizeHandle onDoubleClick={resetGalleryPanel} />
|
||||
<Panel
|
||||
id="gallery"
|
||||
ref={galleryPanelRef}
|
||||
order={2}
|
||||
order={1}
|
||||
defaultSize={galleryPanelMinSize}
|
||||
minSize={galleryPanelMinSize}
|
||||
onCollapse={setIsGalleryPanelCollapsed}
|
||||
onCollapse={onCollapseGalleryPanel}
|
||||
onExpand={onExpandGalleryPanel}
|
||||
collapsible
|
||||
>
|
||||
<ImageGalleryContent />
|
||||
</Panel>
|
||||
<FloatingGalleryButton
|
||||
isGalleryCollapsed={isGalleryPanelCollapsed}
|
||||
galleryPanelRef={galleryPanelRef}
|
||||
expandGallery={expandGalleryPanel}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
@ -36,7 +36,6 @@ const ImageToImageTab = () => {
|
||||
direction="horizontal"
|
||||
style={panelGroupStyles}
|
||||
storage={panelStorage}
|
||||
units="percentages"
|
||||
>
|
||||
<Panel
|
||||
id="imageTab.content.initImage"
|
||||
|
@ -1,16 +1,28 @@
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import type { ImperativePanelHandle, Units } from 'react-resizable-panels';
|
||||
import type {
|
||||
ImperativePanelHandle,
|
||||
PanelOnCollapse,
|
||||
PanelOnExpand,
|
||||
} from 'react-resizable-panels';
|
||||
|
||||
export const usePanel = (minSize: number, units: Units) => {
|
||||
export const usePanel = (minSize: number) => {
|
||||
const ref = useRef<ImperativePanelHandle>(null);
|
||||
|
||||
const [isCollapsed, setIsCollapsed] = useState(() =>
|
||||
Boolean(ref.current?.getCollapsed())
|
||||
Boolean(ref.current?.isCollapsed())
|
||||
);
|
||||
|
||||
const onCollapse = useCallback<PanelOnCollapse>(() => {
|
||||
setIsCollapsed(true);
|
||||
}, []);
|
||||
|
||||
const onExpand = useCallback<PanelOnExpand>(() => {
|
||||
setIsCollapsed(false);
|
||||
}, []);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
if (ref.current?.getCollapsed()) {
|
||||
if (ref.current?.isCollapsed()) {
|
||||
flushSync(() => {
|
||||
ref.current?.expand();
|
||||
});
|
||||
@ -35,15 +47,16 @@ export const usePanel = (minSize: number, units: Units) => {
|
||||
|
||||
const reset = useCallback(() => {
|
||||
flushSync(() => {
|
||||
ref.current?.resize(minSize, units);
|
||||
ref.current?.resize(minSize);
|
||||
});
|
||||
}, [minSize, units]);
|
||||
}, [minSize]);
|
||||
|
||||
return {
|
||||
ref,
|
||||
minSize,
|
||||
isCollapsed,
|
||||
setIsCollapsed,
|
||||
onCollapse,
|
||||
onExpand,
|
||||
reset,
|
||||
toggle,
|
||||
expand,
|
||||
|
Loading…
Reference in New Issue
Block a user