feat(ui): updated layout for small screens

- Move color picker to floating buttons
- Always show floating buttons
- Minor layout tweaks for floating buttons
This commit is contained in:
psychedelicious
2024-10-02 13:30:59 +10:00
committed by Kent Keirsey
parent 43b417be6b
commit c4421241f6
6 changed files with 101 additions and 123 deletions

View File

@@ -11,7 +11,7 @@ import { ToolViewButton } from './ToolViewButton';
export const ToolChooser: React.FC = () => {
return (
<>
<ButtonGroup isAttached>
<ButtonGroup isAttached orientation='vertical'>
<ToolBrushButton />
<ToolEraserButton />
<ToolRectButton />

View File

@@ -1,7 +1,6 @@
/* eslint-disable i18next/no-literal-string */
import { Divider, Flex, Spacer } from '@invoke-ai/ui-library';
import { CanvasSettingsPopover } from 'features/controlLayers/components/Settings/CanvasSettingsPopover';
import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser';
import { ToolColorPicker } from 'features/controlLayers/components/Tool/ToolFillColorPicker';
import { ToolSettings } from 'features/controlLayers/components/Tool/ToolSettings';
import { CanvasToolbarFitBboxToLayersButton } from 'features/controlLayers/components/Toolbar/CanvasToolbarFitBboxToLayersButton';
@@ -31,7 +30,6 @@ export const CanvasToolbar = memo(() => {
return (
<Flex w="full" gap={2} alignItems="center">
<ToolChooser />
<ToolColorPicker />
<ToolSettings />
<Spacer />

View File

@@ -1,14 +1,10 @@
import type { ChakraProps } from '@invoke-ai/ui-library';
import { IconButton } from '@invoke-ai/ui-library';
import { useCancelCurrentQueueItem } from 'features/queue/hooks/useCancelCurrentQueueItem';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiXBold } from 'react-icons/pi';
type Props = {
sx?: ChakraProps['sx'];
};
const CancelCurrentQueueItemIconButton = ({ sx }: Props) => {
const CancelCurrentQueueItemIconButton = () => {
const { t } = useTranslation();
const { cancelQueueItem, isLoading, isDisabled } = useCancelCurrentQueueItem();
@@ -18,10 +14,9 @@ const CancelCurrentQueueItemIconButton = ({ sx }: Props) => {
isLoading={isLoading}
aria-label={t('queue.cancel')}
tooltip={t('queue.cancelTooltip')}
icon={<PiXBold size="16px" />}
icon={<PiXBold />}
onClick={cancelQueueItem}
colorScheme="error"
sx={sx}
/>
);
};

View File

@@ -33,7 +33,7 @@ import { Panel, PanelGroup } from 'react-resizable-panels';
import ParametersPanelUpscale from './ParametersPanels/ParametersPanelUpscale';
import ResizeHandle from './tabs/ResizeHandle';
const panelStyles: CSSProperties = { position: 'relative', height: '100%', width: '100%' };
const panelStyles: CSSProperties = { position: 'relative', height: '100%', width: '100%', minWidth: 0 };
const onLeftPanelCollapse = (isCollapsed: boolean) => $isLeftPanelOpen.set(!isCollapsed);
const onRightPanelCollapse = (isCollapsed: boolean) => $isRightPanelOpen.set(!isCollapsed);
@@ -117,42 +117,40 @@ export const AppContent = memo(() => {
return (
<Flex id="invoke-app-tabs" w="full" h="full" gap={4} p={4}>
<VerticalNavBar />
<Flex position="relative" w="full" h="full" gap={4} minW={0}>
<PanelGroup
ref={imperativePanelGroupRef}
id="app-panel-group"
autoSaveId="app-panel-group"
direction="horizontal"
style={panelStyles}
>
{withLeftPanel && (
<>
<Panel order={0} collapsible style={panelStyles} {...leftPanel.panelProps}>
<Flex flexDir="column" w="full" h="full" gap={2}>
<QueueControls />
<Box position="relative" w="full" h="full">
<LeftPanelContent />
</Box>
</Flex>
</Panel>
<ResizeHandle id="left-main-handle" {...leftPanel.resizeHandleProps} />
</>
)}
<Panel id="main-panel" order={1} minSize={20} style={panelStyles}>
<MainPanelContent />
</Panel>
{withRightPanel && (
<>
<ResizeHandle id="main-right-handle" {...rightPanel.resizeHandleProps} />
<Panel order={2} style={panelStyles} collapsible {...rightPanel.panelProps}>
<RightPanelContent />
</Panel>
</>
)}
</PanelGroup>
{withLeftPanel && <FloatingParametersPanelButtons panelApi={leftPanel} />}
{withRightPanel && <FloatingGalleryButton panelApi={rightPanel} />}
</Flex>
<PanelGroup
ref={imperativePanelGroupRef}
id="app-panel-group"
autoSaveId="app-panel-group"
direction="horizontal"
style={panelStyles}
>
{withLeftPanel && (
<>
<Panel order={0} collapsible style={panelStyles} {...leftPanel.panelProps}>
<Flex flexDir="column" w="full" h="full" gap={2}>
<QueueControls />
<Box position="relative" w="full" h="full">
<LeftPanelContent />
</Box>
</Flex>
</Panel>
<ResizeHandle id="left-main-handle" {...leftPanel.resizeHandleProps} />
</>
)}
<Panel id="main-panel" order={1} minSize={20} style={panelStyles}>
<MainPanelContent />
{withLeftPanel && <FloatingParametersPanelButtons panelApi={leftPanel} />}
{withRightPanel && <FloatingGalleryButton panelApi={rightPanel} />}
</Panel>
{withRightPanel && (
<>
<ResizeHandle id="main-right-handle" {...rightPanel.resizeHandleProps} />
<Panel order={2} style={panelStyles} collapsible {...rightPanel.panelProps}>
<RightPanelContent />
</Panel>
</>
)}
</PanelGroup>
</Flex>
);
});

View File

@@ -1,4 +1,4 @@
import { Flex, IconButton, Portal, Tooltip } from '@invoke-ai/ui-library';
import { Flex, IconButton, Tooltip } from '@invoke-ai/ui-library';
import type { UsePanelReturn } from 'features/ui/hooks/usePanel';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -11,25 +11,17 @@ type Props = {
const FloatingGalleryButton = (props: Props) => {
const { t } = useTranslation();
if (!props.panelApi.isCollapsed) {
return null;
}
return (
<Portal>
<Flex pos="absolute" transform="translate(0, -50%)" minW={8} top="50%" insetInlineEnd="21px" zIndex={11}>
<Tooltip label={t('accessibility.showGalleryPanel')} placement="start">
<IconButton
aria-label={t('accessibility.showGalleryPanel')}
onClick={props.panelApi.expand}
icon={<PiImagesSquareBold size="20px" />}
p={0}
h={48}
borderEndRadius={0}
/>
</Tooltip>
</Flex>
</Portal>
<Flex pos="absolute" transform="translate(0, -50%)" minW={8} top="50%" insetInlineEnd={2} zIndex={11}>
<Tooltip label={t('accessibility.showGalleryPanel')} placement="start">
<IconButton
aria-label={t('accessibility.showGalleryPanel')}
onClick={props.panelApi.toggle}
icon={<PiImagesSquareBold />}
h={48}
/>
</Tooltip>
</Flex>
);
};

View File

@@ -1,10 +1,14 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { ButtonGroup, Flex, Icon, IconButton, Portal, spinAnimation, useShiftModifier } from '@invoke-ai/ui-library';
import { ButtonGroup, Flex, Icon, IconButton, spinAnimation, useShiftModifier } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser';
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
import CancelCurrentQueueItemIconButton from 'features/queue/components/CancelCurrentQueueItemIconButton';
import { useClearQueue } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { QueueButtonTooltip } from 'features/queue/components/QueueButtonTooltip';
import { useInvoke } from 'features/queue/hooks/useInvoke';
import type { UsePanelReturn } from 'features/ui/hooks/usePanel';
import { selectActiveTab } from 'features/ui/store/uiSelectors';
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -16,11 +20,6 @@ import {
} from 'react-icons/pi';
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
const floatingButtonStyles: SystemStyleObject = {
borderStartRadius: 0,
flexGrow: 1,
};
type Props = {
panelApi: UsePanelReturn;
};
@@ -29,6 +28,8 @@ const FloatingSidePanelButtons = (props: Props) => {
const { t } = useTranslation();
const queue = useInvoke();
const shift = useShiftModifier();
const tab = useAppSelector(selectActiveTab);
const imageViewer = useImageViewer();
const clearQueue = useClearQueue();
const { data: queueStatus } = useGetQueueStatusQuery();
@@ -38,62 +39,56 @@ const FloatingSidePanelButtons = (props: Props) => {
return <Icon boxSize={6} as={PiCircleNotchBold} animation={spinAnimation} />;
}
if (shift) {
return <PiLightningFill size="16px" />;
return <PiLightningFill />;
}
return <PiSparkleFill size="16px" />;
return <PiSparkleFill />;
}, [queue.isDisabled, queueStatus?.queue.in_progress, shift]);
if (!props.panelApi.isCollapsed) {
return null;
}
return (
<Portal>
<Flex
pos="absolute"
transform="translate(0, -50%)"
minW={8}
top="50%"
insetInlineStart="63px"
direction="column"
gap={2}
h={48}
zIndex={11}
>
<ButtonGroup orientation="vertical" flexGrow={3}>
<IconButton
tooltip={t('accessibility.showOptionsPanel')}
aria-label={t('accessibility.showOptionsPanel')}
onClick={props.panelApi.expand}
sx={floatingButtonStyles}
icon={<PiSlidersHorizontalBold size="16px" />}
/>
<QueueButtonTooltip prepend={shift}>
<IconButton
aria-label={t('queue.queueBack')}
onClick={shift ? queue.queueFront : queue.queueBack}
isLoading={queue.isLoading}
isDisabled={queue.isDisabled}
icon={queueButtonIcon}
colorScheme="invokeYellow"
sx={floatingButtonStyles}
/>
</QueueButtonTooltip>
<CancelCurrentQueueItemIconButton sx={floatingButtonStyles} />
</ButtonGroup>
<Flex
pos="absolute"
transform="translate(0, -50%)"
top="50%"
insetInlineStart={2}
direction="column"
gap={2}
zIndex={11}
>
{tab === 'canvas' && !imageViewer.isOpen && (
<CanvasManagerProviderGate>
<ToolChooser />
</CanvasManagerProviderGate>
)}
<ButtonGroup orientation="vertical">
<IconButton
isDisabled={clearQueue.isDisabled}
isLoading={clearQueue.isLoading}
aria-label={t('queue.clear')}
tooltip={t('queue.clearTooltip')}
icon={<PiTrashSimpleBold />}
colorScheme="error"
onClick={clearQueue.openDialog}
data-testid={t('queue.clear')}
sx={floatingButtonStyles}
tooltip={t('accessibility.showOptionsPanel')}
aria-label={t('accessibility.showOptionsPanel')}
onClick={props.panelApi.toggle}
icon={<PiSlidersHorizontalBold />}
/>
</Flex>
</Portal>
<QueueButtonTooltip prepend={shift}>
<IconButton
aria-label={t('queue.queueBack')}
onClick={shift ? queue.queueFront : queue.queueBack}
isLoading={queue.isLoading}
isDisabled={queue.isDisabled}
icon={queueButtonIcon}
colorScheme="invokeYellow"
/>
</QueueButtonTooltip>
<CancelCurrentQueueItemIconButton />
</ButtonGroup>
<IconButton
isDisabled={clearQueue.isDisabled}
isLoading={clearQueue.isLoading}
aria-label={t('queue.clear')}
tooltip={t('queue.clearTooltip')}
icon={<PiTrashSimpleBold />}
colorScheme="error"
onClick={clearQueue.openDialog}
data-testid={t('queue.clear')}
/>
</Flex>
);
};