feat(ui): update panel lib, move gallery to percentages

This commit is contained in:
psychedelicious 2023-12-29 15:34:04 +11:00 committed by Kent Keirsey
parent 47b1fd4bce
commit 10fd4f6a61
7 changed files with 57 additions and 134 deletions

View File

@ -94,7 +94,7 @@
"react-icons": "^4.12.0", "react-icons": "^4.12.0",
"react-konva": "^18.2.10", "react-konva": "^18.2.10",
"react-redux": "^9.0.4", "react-redux": "^9.0.4",
"react-resizable-panels": "^0.0.55", "react-resizable-panels": "^1.0.5",
"react-select": "5.7.7", "react-select": "5.7.7",
"react-textarea-autosize": "^8.5.3", "react-textarea-autosize": "^8.5.3",
"react-use": "^17.4.2", "react-use": "^17.4.2",

View File

@ -132,8 +132,8 @@ dependencies:
specifier: ^9.0.4 specifier: ^9.0.4
version: 9.0.4(@types/react@18.2.46)(react@18.2.0)(redux@5.0.1) version: 9.0.4(@types/react@18.2.46)(react@18.2.0)(redux@5.0.1)
react-resizable-panels: react-resizable-panels:
specifier: ^0.0.55 specifier: ^1.0.5
version: 0.0.55(react-dom@18.2.0)(react@18.2.0) version: 1.0.5(react-dom@18.2.0)(react@18.2.0)
react-select: react-select:
specifier: 5.7.7 specifier: 5.7.7
version: 5.7.7(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) 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) use-sidecar: 1.1.2(@types/react@18.2.46)(react@18.2.0)
dev: false dev: false
/react-resizable-panels@0.0.55(react-dom@18.2.0)(react@18.2.0): /react-resizable-panels@1.0.5(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-J/LTFzUEjJiqwSjVh8gjUXkQDA8MRPjARASfn++d2+KOgA+9UcRYUfE3QBJixer2vkk+ffQ4cq3QzWzzHgqYpQ==} resolution: {integrity: sha512-OP0whNQCko+f4BgoptGaeIc7StBRyeMeJ+8r/7rXACBDf9W5EcMWuM32hfqPDMenS2HFy/eZVi/r8XqK+ZIEag==}
peerDependencies: peerDependencies:
react: ^16.14.0 || ^17.0.0 || ^18.0.0 react: ^16.14.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0

View File

@ -5,7 +5,7 @@ import QueueControls from 'features/queue/components/QueueControls';
import ResizeHandle from 'features/ui/components/tabs/ResizeHandle'; import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
import { usePanelStorage } from 'features/ui/hooks/usePanelStorage'; import { usePanelStorage } from 'features/ui/hooks/usePanelStorage';
import type { CSSProperties } from 'react'; 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 type { ImperativePanelGroupHandle } from 'react-resizable-panels';
import { Panel, PanelGroup } 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 panelGroupStyles: CSSProperties = { height: '100%', width: '100%' };
const NodeEditorPanelGroup = () => { const NodeEditorPanelGroup = () => {
const [isTopPanelCollapsed, setIsTopPanelCollapsed] = useState(false);
const [isBottomPanelCollapsed, setIsBottomPanelCollapsed] = useState(false);
const panelGroupRef = useRef<ImperativePanelGroupHandle>(null); const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
const panelStorage = usePanelStorage(); const panelStorage = usePanelStorage();
const handleDoubleClickHandle = useCallback(() => { const handleDoubleClickHandle = useCallback(() => {
@ -37,31 +35,14 @@ const NodeEditorPanelGroup = () => {
style={panelGroupStyles} style={panelGroupStyles}
storage={panelStorage} storage={panelStorage}
> >
<Panel <Panel id="workflow" collapsible minSize={25}>
id="workflow"
collapsible
onCollapse={setIsTopPanelCollapsed}
minSize={25}
>
<WorkflowPanel /> <WorkflowPanel />
</Panel> </Panel>
<ResizeHandle <ResizeHandle
direction="vertical" direction="vertical"
onDoubleClick={handleDoubleClickHandle} onDoubleClick={handleDoubleClickHandle}
collapsedDirection={
isTopPanelCollapsed
? 'top'
: isBottomPanelCollapsed
? 'bottom'
: undefined
}
/> />
<Panel <Panel id="inspector" collapsible minSize={25}>
id="inspector"
collapsible
onCollapse={setIsBottomPanelCollapsed}
minSize={25}
>
<InspectorPanel /> <InspectorPanel />
</Panel> </Panel>
</PanelGroup> </PanelGroup>

View File

@ -1,27 +1,21 @@
import { Flex } from '@chakra-ui/layout'; import { Flex } from '@chakra-ui/layout';
import { Portal } from '@chakra-ui/portal'; import { Portal } from '@chakra-ui/portal';
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton'; import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import type { RefObject } from 'react'; import { memo } from 'react';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { MdPhotoLibrary } from 'react-icons/md'; import { MdPhotoLibrary } from 'react-icons/md';
import type { ImperativePanelHandle } from 'react-resizable-panels';
type Props = { type Props = {
isGalleryCollapsed: boolean; isGalleryCollapsed: boolean;
galleryPanelRef: RefObject<ImperativePanelHandle>; expandGallery: () => void;
}; };
const FloatingGalleryButton = ({ const FloatingGalleryButton = ({
isGalleryCollapsed, isGalleryCollapsed,
galleryPanelRef, expandGallery,
}: Props) => { }: Props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const handleShowGallery = useCallback(() => {
galleryPanelRef.current?.expand();
}, [galleryPanelRef]);
if (!isGalleryCollapsed) { if (!isGalleryCollapsed) {
return null; return null;
} }
@ -38,7 +32,7 @@ const FloatingGalleryButton = ({
<InvIconButton <InvIconButton
tooltip="Show Gallery (G)" tooltip="Show Gallery (G)"
aria-label={t('accessibility.showGalleryPanel')} aria-label={t('accessibility.showGalleryPanel')}
onClick={handleShowGallery} onClick={expandGallery}
icon={<MdPhotoLibrary />} icon={<MdPhotoLibrary />}
p={0} p={0}
px={3} px={3}

View File

@ -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_GALLERY_TABS: InvokeTabName[] = ['modelManager', 'queue'];
export const NO_SIDE_PANEL_TABS: InvokeTabName[] = ['modelManager', 'queue']; export const NO_SIDE_PANEL_TABS: InvokeTabName[] = ['modelManager', 'queue'];
const panelStyles: CSSProperties = { height: '100%', width: '100%' }; const panelStyles: CSSProperties = { height: '100%', width: '100%' };
const GALLERY_MIN_SIZE_PCT = 20
const InvokeTabs = () => { const InvokeTabs = () => {
const activeTabIndex = useAppSelector(activeTabIndexSelector); const activeTabIndex = useAppSelector(activeTabIndexSelector);
@ -155,53 +152,18 @@ const InvokeTabs = () => {
[dispatch, enabledTabs] [dispatch, enabledTabs]
); );
const {
isCollapsed: isSidePanelCollapsed,
expand: expandSidePanel,
collapse: collapseSidePanel,
toggle: toggleSidePanel,
} = usePanel(SIDE_PANEL_MIN_SIZE_PX, 'pixels');
const { const {
ref: galleryPanelRef, ref: galleryPanelRef,
minSize: galleryPanelMinSize, minSize: galleryPanelMinSize,
isCollapsed: isGalleryPanelCollapsed, isCollapsed: isGalleryPanelCollapsed,
setIsCollapsed: setIsGalleryPanelCollapsed, onCollapse: onCollapseGalleryPanel,
onExpand: onExpandGalleryPanel,
reset: resetGalleryPanel, reset: resetGalleryPanel,
expand: expandGalleryPanel, expand: expandGalleryPanel,
collapse: collapseGalleryPanel,
toggle: toggleGalleryPanel, toggle: toggleGalleryPanel,
} = usePanel(GALLERY_PANEL_MIN_SIZE_PX, 'pixels'); } = usePanel(GALLERY_MIN_SIZE_PCT);
useHotkeys( useHotkeys('g', toggleGalleryPanel, []);
'f',
() => {
if (isGalleryPanelCollapsed || isSidePanelCollapsed) {
expandGalleryPanel();
expandSidePanel();
} else {
collapseSidePanel();
collapseGalleryPanel();
}
},
[dispatch, isGalleryPanelCollapsed, isSidePanelCollapsed]
);
useHotkeys(
['t', 'o'],
() => {
toggleSidePanel();
},
[dispatch]
);
useHotkeys(
'g',
() => {
toggleGalleryPanel();
},
[dispatch]
);
const panelStorage = usePanelStorage(); const panelStorage = usePanelStorage();
@ -219,6 +181,15 @@ const InvokeTabs = () => {
{tabs} {tabs}
<Spacer /> <Spacer />
</InvTabList> </InvTabList>
<PanelGroup
id="app"
autoSaveId="app"
direction="horizontal"
style={panelStyles}
storage={panelStorage}
>
<Panel id="main" order={0} minSize={50}>
<Flex w="full" h="full" gap={4}>
{!NO_SIDE_PANEL_TABS.includes(activeTabName) && ( {!NO_SIDE_PANEL_TABS.includes(activeTabName) && (
<Flex h="full" w={434} flexShrink={0}> <Flex h="full" w={434} flexShrink={0}>
{activeTabName === 'nodes' ? ( {activeTabName === 'nodes' ? (
@ -228,64 +199,29 @@ const InvokeTabs = () => {
)} )}
</Flex> </Flex>
)} )}
<PanelGroup <InvTabPanels w="full" h="full">
id="app" {tabPanels}
autoSaveId="app" </InvTabPanels>
direction="horizontal" </Flex>
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> </Panel>
{!NO_GALLERY_TABS.includes(activeTabName) && ( {!NO_GALLERY_TABS.includes(activeTabName) && (
<> <>
<ResizeHandle <ResizeHandle onDoubleClick={resetGalleryPanel} />
onDoubleClick={resetGalleryPanel}
collapsedDirection={isGalleryPanelCollapsed ? 'right' : undefined}
/>
<Panel <Panel
id="gallery" id="gallery"
ref={galleryPanelRef} ref={galleryPanelRef}
order={2} order={1}
defaultSize={galleryPanelMinSize} defaultSize={galleryPanelMinSize}
minSize={galleryPanelMinSize} minSize={galleryPanelMinSize}
onCollapse={setIsGalleryPanelCollapsed} onCollapse={onCollapseGalleryPanel}
onExpand={onExpandGalleryPanel}
collapsible collapsible
> >
<ImageGalleryContent /> <ImageGalleryContent />
</Panel> </Panel>
<FloatingGalleryButton <FloatingGalleryButton
isGalleryCollapsed={isGalleryPanelCollapsed} isGalleryCollapsed={isGalleryPanelCollapsed}
galleryPanelRef={galleryPanelRef} expandGallery={expandGalleryPanel}
/> />
</> </>
)} )}

View File

@ -36,7 +36,6 @@ const ImageToImageTab = () => {
direction="horizontal" direction="horizontal"
style={panelGroupStyles} style={panelGroupStyles}
storage={panelStorage} storage={panelStorage}
units="percentages"
> >
<Panel <Panel
id="imageTab.content.initImage" id="imageTab.content.initImage"

View File

@ -1,16 +1,28 @@
import { useCallback, useRef, useState } from 'react'; import { useCallback, useRef, useState } from 'react';
import { flushSync } from 'react-dom'; 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 ref = useRef<ImperativePanelHandle>(null);
const [isCollapsed, setIsCollapsed] = useState(() => 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(() => { const toggle = useCallback(() => {
if (ref.current?.getCollapsed()) { if (ref.current?.isCollapsed()) {
flushSync(() => { flushSync(() => {
ref.current?.expand(); ref.current?.expand();
}); });
@ -35,15 +47,16 @@ export const usePanel = (minSize: number, units: Units) => {
const reset = useCallback(() => { const reset = useCallback(() => {
flushSync(() => { flushSync(() => {
ref.current?.resize(minSize, units); ref.current?.resize(minSize);
}); });
}, [minSize, units]); }, [minSize]);
return { return {
ref, ref,
minSize, minSize,
isCollapsed, isCollapsed,
setIsCollapsed, onCollapse,
onExpand,
reset, reset,
toggle, toggle,
expand, expand,