feat(ui): wip img2img layouting

This commit is contained in:
psychedelicious 2023-05-08 12:51:40 +10:00
parent 5365f42a04
commit 864f4bb4af
25 changed files with 338 additions and 110 deletions

View File

@ -102,7 +102,8 @@
"generate": "Generate", "generate": "Generate",
"openInNewTab": "Open in New Tab", "openInNewTab": "Open in New Tab",
"dontAskMeAgain": "Don't ask me again", "dontAskMeAgain": "Don't ask me again",
"areYouSure": "Are you sure?" "areYouSure": "Are you sure?",
"imagePrompt": "Image Prompt"
}, },
"gallery": { "gallery": {
"generations": "Generations", "generations": "Generations",

View File

@ -0,0 +1,7 @@
import { isEqual } from 'lodash-es';
export const defaultSelectorOptions = {
memoizeOptions: {
resultEqualityCheck: isEqual,
},
};

View File

@ -14,6 +14,7 @@ const ImageToImageOverlay = ({ image }: ImageToImageOverlayProps) => {
w: 'full', w: 'full',
h: 'full', h: 'full',
position: 'absolute', position: 'absolute',
pointerEvents: 'none',
}} }}
> >
<Flex <Flex

View File

@ -7,7 +7,7 @@ import { useAppDispatch } from 'app/store/storeHooks';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { clearInitialImage } from 'features/parameters/store/generationSlice'; import { clearInitialImage } from 'features/parameters/store/generationSlice';
const ImageToImageSettingsHeader = () => { const ImagePromptHeading = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
@ -18,7 +18,7 @@ const ImageToImageSettingsHeader = () => {
return ( return (
<Flex w="full" alignItems="center"> <Flex w="full" alignItems="center">
<Text size="sm" fontWeight={500} color="base.300"> <Text size="sm" fontWeight={500} color="base.300">
Image to Image {t('parameters.initialImage')}
</Text> </Text>
<Spacer /> <Spacer />
<ButtonGroup> <ButtonGroup>
@ -38,4 +38,4 @@ const ImageToImageSettingsHeader = () => {
); );
}; };
export default ImageToImageSettingsHeader; export default ImagePromptHeading;

View File

@ -410,7 +410,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
}} }}
{...props} {...props}
> >
<ButtonGroup isAttached={true}> <ButtonGroup size="sm" isAttached={true}>
<IAIPopover <IAIPopover
triggerComponent={ triggerComponent={
<IAIIconButton <IAIIconButton
@ -497,7 +497,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
)} )}
</ButtonGroup> </ButtonGroup>
<ButtonGroup isAttached={true}> <ButtonGroup size="sm" isAttached={true}>
<IAIIconButton <IAIIconButton
icon={<FaQuoteRight />} icon={<FaQuoteRight />}
tooltip={`${t('parameters.usePrompt')} (P)`} tooltip={`${t('parameters.usePrompt')} (P)`}
@ -528,7 +528,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
</ButtonGroup> </ButtonGroup>
{(isUpscalingEnabled || isFaceRestoreEnabled) && ( {(isUpscalingEnabled || isFaceRestoreEnabled) && (
<ButtonGroup isAttached={true}> <ButtonGroup size="sm" isAttached={true}>
{isFaceRestoreEnabled && ( {isFaceRestoreEnabled && (
<IAIPopover <IAIPopover
triggerComponent={ triggerComponent={
@ -593,7 +593,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
</ButtonGroup> </ButtonGroup>
)} )}
<ButtonGroup isAttached={true}> <ButtonGroup size="sm" isAttached={true}>
<IAIIconButton <IAIIconButton
icon={<FaCode />} icon={<FaCode />}
tooltip={`${t('parameters.info')} (I)`} tooltip={`${t('parameters.info')} (I)`}
@ -603,6 +603,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
/> />
</ButtonGroup> </ButtonGroup>
<ButtonGroup size="sm" isAttached={true}>
<IAIIconButton <IAIIconButton
onClick={handleInitiateDelete} onClick={handleInitiateDelete}
icon={<FaTrash />} icon={<FaTrash />}
@ -611,6 +612,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
isDisabled={!image || !isConnected} isDisabled={!image || !isConnected}
colorScheme="error" colorScheme="error"
/> />
</ButtonGroup>
</Flex> </Flex>
{image && ( {image && (
<DeleteImageModal <DeleteImageModal

View File

@ -179,7 +179,17 @@ const ImageGalleryContent = () => {
}, [dispatch, currentCategory]); }, [dispatch, currentCategory]);
return ( return (
<Flex flexDirection="column" w="full" h="full" gap={4}> <Flex
sx={{
gap: 2,
flexDirection: 'column',
h: 'full',
w: 'full',
borderRadius: 'base',
// bg: 'base.850',
// p: 2,
}}
>
<Flex <Flex
ref={resizeObserverRef} ref={resizeObserverRef}
alignItems="center" alignItems="center"

View File

@ -21,13 +21,13 @@ import { useTranslation } from 'react-i18next';
import InitialImagePreview from './InitialImagePreview'; import InitialImagePreview from './InitialImagePreview';
import { useState } from 'react'; import { useState } from 'react';
import { FaUndo, FaUpload } from 'react-icons/fa'; import { FaUndo, FaUpload } from 'react-icons/fa';
import ImageToImageSettingsHeader from 'common/components/ImageToImageSettingsHeader'; import ImagePromptHeading from 'common/components/ImageToImageSettingsHeader';
export default function ImageToImageSettings() { export default function ImageToImageSettings() {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<VStack gap={2} w="full" alignItems="stretch"> <VStack gap={2} w="full" alignItems="stretch">
<ImageToImageSettingsHeader /> <ImagePromptHeading />
<InitialImagePreview /> <InitialImagePreview />
<ImageToImageStrength /> <ImageToImageStrength />
<ImageFit /> <ImageFit />

View File

@ -1,34 +1,50 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISwitch from 'common/components/IAISwitch'; import IAISwitch from 'common/components/IAISwitch';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { isImageToImageEnabledChanged } from 'features/parameters/store/generationSlice'; import { isImageToImageEnabledChanged } from 'features/parameters/store/generationSlice';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { shouldShowImageParametersChanged } from 'features/ui/store/uiSlice';
import { ChangeEvent } from 'react'; import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function ImageToImageToggle() { const selector = createSelector(
const isImageToImageEnabled = useAppSelector( [uiSelector, generationSelector],
(state: RootState) => state.generation.isImageToImageEnabled (ui, generation) => {
const { isImageToImageEnabled } = generation;
const { shouldShowImageParameters } = ui;
return {
isImageToImageEnabled,
shouldShowImageParameters,
};
},
defaultSelectorOptions
); );
export default function ImageToImageToggle() {
const { isImageToImageEnabled, shouldShowImageParameters } =
useAppSelector(selector);
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const handleChange = (e: ChangeEvent<HTMLInputElement>) => const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
dispatch(isImageToImageEnabledChanged(e.target.checked)); dispatch(shouldShowImageParametersChanged(e.target.checked));
return ( return (
<Flex background="base.800" py={1.5} px={4} borderRadius={4}> <Flex py={1.5} px={4} borderRadius={4}>
<IAISwitch <IAISwitch
label={t('common.img2img')} label={t('parameters.initialImage')}
isChecked={isImageToImageEnabled} isChecked={shouldShowImageParameters}
width="full" width="full"
onChange={handleChange} onChange={handleChange}
justifyContent="space-between" justifyContent="space-between"
formLabelProps={{ formLabelProps={{
fontWeight: 'bold', fontWeight: 400,
color: 'base.200',
}} }}
/> />
</Flex> </Flex>

View File

@ -70,7 +70,6 @@ const InitialImagePreview = () => {
return ( return (
<Flex <Flex
sx={{ sx={{
height: 'full',
width: 'full', width: 'full',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
@ -78,8 +77,7 @@ const InitialImagePreview = () => {
}} }}
onDrop={handleDrop} onDrop={handleDrop}
> >
{initialImage?.url && ( <Flex
<Box
sx={{ sx={{
height: 'full', height: 'full',
width: 'full', width: 'full',
@ -87,12 +85,17 @@ const InitialImagePreview = () => {
filter: isImageToImageEnabled ? 'none' : 'auto', filter: isImageToImageEnabled ? 'none' : 'auto',
blur: '5px', blur: '5px',
position: 'relative', position: 'relative',
alignItems: 'center',
justifyContent: 'center',
}} }}
> >
{initialImage?.url && (
<>
<Image <Image
sx={{ sx={{
fit: 'contain', objectFit: 'contain',
borderRadius: 'base', borderRadius: 'base',
maxHeight: 'full',
}} }}
src={getUrl(initialImage?.url)} src={getUrl(initialImage?.url)}
onError={onError} onError={onError}
@ -108,9 +111,10 @@ const InitialImagePreview = () => {
} }
/> />
{isLoaded && <ImageToImageOverlay image={initialImage} />} {isLoaded && <ImageToImageOverlay image={initialImage} />}
</Box> </>
)} )}
{!initialImage?.url && <SelectImagePlaceholder />} {!initialImage?.url && <SelectImagePlaceholder />}
</Flex>
{!isImageToImageEnabled && ( {!isImageToImageEnabled && (
<Flex <Flex
sx={{ sx={{

View File

@ -29,6 +29,8 @@ import { MdCancel, MdCancelScheduleSend } from 'react-icons/md';
import { sessionCanceled } from 'services/thunks/session'; import { sessionCanceled } from 'services/thunks/session';
import { BiChevronDown } from 'react-icons/bi'; import { BiChevronDown } from 'react-icons/bi';
import { FaChevronDown } from 'react-icons/fa';
import { ChevronDownIcon } from '@chakra-ui/icons';
const cancelButtonSelector = createSelector( const cancelButtonSelector = createSelector(
systemSelector, systemSelector,
@ -135,13 +137,12 @@ const CancelButton = (
colorScheme="error" colorScheme="error"
{...rest} {...rest}
/> />
<Menu closeOnSelect={false}> <Menu closeOnSelect={false}>
<MenuButton <MenuButton
as={IAIIconButton} as={IAIIconButton}
tooltip={t('parameters.cancel.setType')} tooltip={t('parameters.cancel.setType')}
aria-label={t('parameters.cancel.setType')} aria-label={t('parameters.cancel.setType')}
icon={<BiChevronDown />} icon={<ChevronDownIcon w="1em" h="1em" />}
paddingX={0} paddingX={0}
paddingY={0} paddingY={0}
colorScheme="error" colorScheme="error"

View File

@ -4,6 +4,8 @@ import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import CancelButton from './CancelButton'; import CancelButton from './CancelButton';
import InvokeButton from './InvokeButton'; import InvokeButton from './InvokeButton';
import LoopbackButton from './Loopback'; import LoopbackButton from './Loopback';
import IAICheckbox from 'common/components/IAICheckbox';
import IAISwitch from 'common/components/IAISwitch';
/** /**
* Buttons to start and cancel image generation. * Buttons to start and cancel image generation.

View File

@ -55,7 +55,6 @@ const ProgressImagePreview = () => {
return ( return (
<> <>
{' '}
<IAIIconButton <IAIIconButton
onClick={() => onClick={() =>
dispatch(setShouldShowProgressImages(!showProgressWindow)) dispatch(setShouldShowProgressImages(!showProgressWindow))

View File

@ -1,6 +1,6 @@
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import ResizableDrawer from './common/ResizableDrawer/ResizableDrawer'; import ResizableDrawer from './common/ResizableDrawer/ResizableDrawer';
import GenerateParameters from './tabs/Create/GenerateParameters'; import CreateBaseSettings from './tabs/Create/CreateBaseSettings';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { activeTabNameSelector, uiSelector } from '../store/uiSelectors'; import { activeTabNameSelector, uiSelector } from '../store/uiSelectors';
import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors';
@ -13,16 +13,26 @@ import { memo } from 'react';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent'; import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
import PinParametersPanelButton from './PinParametersPanelButton'; import PinParametersPanelButton from './PinParametersPanelButton';
import { Panel, PanelGroup } from 'react-resizable-panels';
import CreateSidePanelPinned from './tabs/Create/CreateSidePanelPinned';
import CreateTextParameters from './tabs/Create/CreateBaseSettings';
import ResizeHandle from './tabs/ResizeHandle';
import CreateImageSettings from './tabs/Create/CreateImageSettings';
const selector = createSelector( const selector = createSelector(
[uiSelector, activeTabNameSelector, lightboxSelector], [uiSelector, activeTabNameSelector, lightboxSelector],
(ui, activeTabName, lightbox) => { (ui, activeTabName, lightbox) => {
const { shouldPinParametersPanel, shouldShowParametersPanel } = ui; const {
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = ui;
const { isLightboxOpen } = lightbox; const { isLightboxOpen } = lightbox;
return { return {
shouldPinParametersPanel, shouldPinParametersPanel,
shouldShowParametersPanel, shouldShowParametersPanel,
shouldShowImageParameters,
}; };
}, },
{ {
@ -34,8 +44,11 @@ const selector = createSelector(
const CreateParametersPanel = () => { const CreateParametersPanel = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { shouldPinParametersPanel, shouldShowParametersPanel } = const {
useAppSelector(selector); shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = useAppSelector(selector);
const handleClosePanel = () => { const handleClosePanel = () => {
dispatch(setShouldShowParametersPanel(false)); dispatch(setShouldShowParametersPanel(false));
@ -53,13 +66,7 @@ const CreateParametersPanel = () => {
onClose={handleClosePanel} onClose={handleClosePanel}
minWidth={500} minWidth={500}
> >
<Flex <Flex flexDir="column" position="relative" h="full" w="full">
flexDir="column"
position="relative"
h={{ base: 600, xl: 'full' }}
w={{ sm: 'full', lg: '100vw', xl: 'full' }}
paddingRight={{ base: 8, xl: 0 }}
>
<Flex <Flex
paddingTop={1.5} paddingTop={1.5}
paddingBottom={4} paddingBottom={4}
@ -69,7 +76,37 @@ const CreateParametersPanel = () => {
<InvokeAILogoComponent /> <InvokeAILogoComponent />
<PinParametersPanelButton /> <PinParametersPanelButton />
</Flex> </Flex>
<GenerateParameters /> <PanelGroup
autoSaveId="createTab_floatingParameters"
direction="horizontal"
style={{ height: '100%', width: '100%' }}
>
<>
<Panel
id="createTab_textParameters"
order={0}
defaultSize={25}
minSize={25}
style={{ position: 'relative' }}
>
<CreateTextParameters />
</Panel>
{shouldShowImageParameters && (
<>
<ResizeHandle />
<Panel
id="createTab_imageParameters"
order={1}
defaultSize={25}
minSize={25}
style={{ position: 'relative' }}
>
<CreateImageSettings />
</Panel>
</>
)}
</>
</PanelGroup>
</Flex> </Flex>
</ResizableDrawer> </ResizableDrawer>
); );

View File

@ -39,13 +39,13 @@ import { configSelector } from 'features/system/store/configSelectors';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel'; import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel';
import Scrollable from './common/Scrollable'; import Scrollable from './common/Scrollable';
import GenerateParameters from './tabs/Create/GenerateParameters'; import CreateBaseSettings from './tabs/Create/CreateBaseSettings';
import PinParametersPanelButton from './PinParametersPanelButton'; import PinParametersPanelButton from './PinParametersPanelButton';
import ParametersSlide from './common/ParametersSlide'; import ParametersSlide from './common/ParametersSlide';
import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel'; import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent'; import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
import CreateTabContent from './tabs/Create/GenerateContent'; import CreateTabContent from './tabs/Create/CreateContent';
import ParametersPanel from './ParametersPanel'; import ParametersPanel from './ParametersPanel';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
import CreateTab from './tabs/Create/CreateTab'; import CreateTab from './tabs/Create/CreateTab';

View File

@ -40,7 +40,7 @@ import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants';
import OverlayScrollable from '../../common/OverlayScrollable'; import OverlayScrollable from '../../common/OverlayScrollable';
import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel'; import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel';
const GenerateParameters = () => { const CreateBaseSettings = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const generateAccordionItems: ParametersAccordionItems = useMemo( const generateAccordionItems: ParametersAccordionItems = useMemo(
@ -102,23 +102,22 @@ const GenerateParameters = () => {
<PromptInput /> <PromptInput />
<NegativePromptInput /> <NegativePromptInput />
<ProcessButtons /> <ProcessButtons />
<ImageToImageToggle />
<Flex <Flex
sx={{ sx={{
flexDirection: 'column', flexDirection: 'column',
gap: 2, gap: 2,
bg: 'base.800', bg: 'base.800',
p: 4, p: 4,
pb: 6,
borderRadius: 'base', borderRadius: 'base',
}} }}
> >
<MainSettings /> <MainSettings />
</Flex> </Flex>
<ImageToImageToggle />
<ParametersAccordion accordionItems={generateAccordionItems} /> <ParametersAccordion accordionItems={generateAccordionItems} />
</Flex> </Flex>
</OverlayScrollable> </OverlayScrollable>
); );
}; };
export default memo(GenerateParameters); export default memo(CreateBaseSettings);

View File

@ -10,10 +10,16 @@ const CreateTabContent = () => {
width: '100%', width: '100%',
height: '100%', height: '100%',
borderRadius: 'base', borderRadius: 'base',
bg: 'base.850', // bg: 'base.850',
}}
>
<Flex
sx={{
// p: 2,
width: '100%',
height: '100%',
}} }}
> >
<Flex sx={{ p: 4, width: '100%', height: '100%' }}>
<CurrentImageDisplay /> <CurrentImageDisplay />
</Flex> </Flex>
</Box> </Box>

View File

@ -0,0 +1,53 @@
import { memo } from 'react';
import OverlayScrollable from '../../common/OverlayScrollable';
import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings';
import {
Box,
ButtonGroup,
Collapse,
Flex,
Heading,
HStack,
Image,
Spacer,
useDisclosure,
VStack,
} from '@chakra-ui/react';
import { motion } from 'framer-motion';
import IAIButton from 'common/components/IAIButton';
import ImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageFit';
import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength';
import IAIIconButton from 'common/components/IAIIconButton';
import { useTranslation } from 'react-i18next';
import { useState } from 'react';
import { FaUndo, FaUpload } from 'react-icons/fa';
import ImagePromptHeading from 'common/components/ImageToImageSettingsHeader';
import InitialImagePreview from 'features/parameters/components/AdvancedParameters/ImageToImage/InitialImagePreview';
const CreateImageSettings = () => {
return (
<OverlayScrollable>
<Flex
sx={{
gap: 2,
flexDirection: 'column',
h: 'full',
w: 'full',
position: 'absolute',
borderRadius: 'base',
// bg: 'base.850',
// p: 2,
}}
>
<ImagePromptHeading />
<InitialImagePreview />
<ImageToImageStrength />
<ImageFit />
</Flex>
</OverlayScrollable>
);
};
export default memo(CreateImageSettings);

View File

@ -0,0 +1,69 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { memo } from 'react';
import { Panel } from 'react-resizable-panels';
import CreateTextParameters from './CreateBaseSettings';
import PinParametersPanelButton from '../../PinParametersPanelButton';
import ResizeHandle from '../ResizeHandle';
import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import CreateImageSettings from './CreateImageSettings';
const selector = createSelector(
uiSelector,
(ui) => {
const {
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = ui;
return {
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
};
},
defaultSelectorOptions
);
const CreateSidePanelPinned = () => {
const dispatch = useAppDispatch();
const {
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = useAppSelector(selector);
return (
<>
<Panel
order={0}
defaultSize={25}
minSize={25}
style={{ position: 'relative' }}
>
<CreateTextParameters />
<PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/>
</Panel>
{shouldShowImageParameters && (
<>
<ResizeHandle />
<Panel
order={1}
defaultSize={25}
minSize={25}
style={{ position: 'relative' }}
>
<CreateImageSettings />
</Panel>
</>
)}
<ResizeHandle />
</>
);
};
export default memo(CreateSidePanelPinned);

View File

@ -1,17 +1,20 @@
import { Portal, TabPanel } from '@chakra-ui/react'; import { Portal, TabPanel } from '@chakra-ui/react';
import { memo } from 'react'; import { memo } from 'react';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import GenerateParameters from './GenerateParameters'; import CreateBaseSettings from './CreateBaseSettings';
import PinParametersPanelButton from '../../PinParametersPanelButton'; import PinParametersPanelButton from '../../PinParametersPanelButton';
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent'; import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { uiSelector } from 'features/ui/store/uiSelectors'; import { uiSelector } from 'features/ui/store/uiSelectors';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import CreateTabContent from './GenerateContent'; import CreateTabContent from './CreateContent';
import ResizeHandle from '../ResizeHandle'; import ResizeHandle from '../ResizeHandle';
import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel'; import AnimatedImageToImagePanel from 'features/parameters/components/AnimatedImageToImagePanel';
import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings'; import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings';
import CreateSidePanelPinned from './CreateSidePanelPinned';
import CreateTextParameters from './CreateBaseSettings';
import CreateImageSettings from './CreateImageSettings';
const selector = createSelector(uiSelector, (ui) => { const selector = createSelector(uiSelector, (ui) => {
const { const {
@ -19,6 +22,7 @@ const selector = createSelector(uiSelector, (ui) => {
shouldShowGallery, shouldShowGallery,
shouldPinParametersPanel, shouldPinParametersPanel,
shouldShowParametersPanel, shouldShowParametersPanel,
shouldShowImageParameters,
} = ui; } = ui;
return { return {
@ -26,6 +30,7 @@ const selector = createSelector(uiSelector, (ui) => {
shouldShowGallery, shouldShowGallery,
shouldPinParametersPanel, shouldPinParametersPanel,
shouldShowParametersPanel, shouldShowParametersPanel,
shouldShowImageParameters,
}; };
}); });
@ -36,44 +41,49 @@ const CreateTab = () => {
shouldShowGallery, shouldShowGallery,
shouldPinParametersPanel, shouldPinParametersPanel,
shouldShowParametersPanel, shouldShowParametersPanel,
shouldShowImageParameters,
} = useAppSelector(selector); } = useAppSelector(selector);
return ( return (
<PanelGroup <PanelGroup
autoSaveId="createTab_pinned"
direction="horizontal" direction="horizontal"
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
> >
{shouldPinParametersPanel && shouldShowParametersPanel && ( {shouldPinParametersPanel && shouldShowParametersPanel && (
<> <>
<Panel <Panel
id="createTab_textParameters"
order={0} order={0}
defaultSize={30} defaultSize={25}
minSize={20} minSize={25}
style={{ position: 'relative' }} style={{ position: 'relative' }}
> >
<GenerateParameters /> <CreateTextParameters />
<PinParametersPanelButton <PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }} sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/> />
</Panel> </Panel>
<ResizeHandle /> {shouldShowImageParameters && (
</>
)}
{shouldPinParametersPanel && shouldShowParametersPanel && (
<> <>
<ResizeHandle />
<Panel <Panel
order={0} id="createTab_imageParameters"
defaultSize={30} order={1}
minSize={20} defaultSize={25}
minSize={25}
style={{ position: 'relative' }} style={{ position: 'relative' }}
> >
<ImageToImageSettings /> <CreateImageSettings />
</Panel> </Panel>
</>
)}
<ResizeHandle /> <ResizeHandle />
</> </>
)} )}
<Panel <Panel
order={1} id="createTab_content"
order={2}
minSize={30} minSize={30}
onResize={() => { onResize={() => {
dispatch(requestCanvasRescale()); dispatch(requestCanvasRescale());
@ -84,7 +94,7 @@ const CreateTab = () => {
{shouldPinGallery && shouldShowGallery && ( {shouldPinGallery && shouldShowGallery && (
<> <>
<ResizeHandle /> <ResizeHandle />
<Panel order={2} defaultSize={10} minSize={10}> <Panel id="createTab_gallery" order={3} defaultSize={10} minSize={10}>
<ImageGalleryContent /> <ImageGalleryContent />
</Panel> </Panel>
</> </>

View File

@ -1,8 +1,8 @@
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { memo } from 'react'; import { memo } from 'react';
import CreateTabContent from './GenerateContent'; import CreateTabContent from './CreateContent';
import GenerateParameters from './GenerateParameters'; import CreateBaseSettings from './CreateBaseSettings';
import PinParametersPanelButton from '../../PinParametersPanelButton'; import PinParametersPanelButton from '../../PinParametersPanelButton';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import Scrollable from '../../common/Scrollable'; import Scrollable from '../../common/Scrollable';
@ -35,7 +35,7 @@ const GenerateWorkspace = () => {
}} }}
> >
<Scrollable> <Scrollable>
<GenerateParameters /> <CreateBaseSettings />
</Scrollable> </Scrollable>
<PinParametersPanelButton <PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }} sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
@ -44,7 +44,7 @@ const GenerateWorkspace = () => {
</Flex> </Flex>
) : ( ) : (
<ParametersSlide> <ParametersSlide>
<GenerateParameters /> <CreateBaseSettings />
</ParametersSlide> </ParametersSlide>
)} )}
<CreateTabContent /> <CreateTabContent />

View File

@ -37,6 +37,7 @@ const NodesTab = () => {
return ( return (
<PanelGroup <PanelGroup
autoSaveId="nodesTab"
direction="horizontal" direction="horizontal"
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
> >

View File

@ -8,7 +8,7 @@ const ResizeHandle = () => {
<Flex <Flex
sx={{ w: 6, h: 'full', justifyContent: 'center', alignItems: 'center' }} sx={{ w: 6, h: 'full', justifyContent: 'center', alignItems: 'center' }}
> >
<Box sx={{ w: 0.5, h: 'calc(100% - 1rem)', py: 4, bg: 'base.800' }} /> <Box sx={{ w: 0.5, h: 'calc(100% - 4px)', bg: 'base.850' }} />
</Flex> </Flex>
</PanelResizeHandle> </PanelResizeHandle>
); );

View File

@ -42,6 +42,7 @@ const UnifiedCanvasTab = () => {
return ( return (
<PanelGroup <PanelGroup
autoSaveId="canvasTab"
direction="horizontal" direction="horizontal"
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
> >

View File

@ -24,6 +24,7 @@ export const initialUIState: UIState = {
floatingProgressImageRect: { x: 0, y: 0, width: 0, height: 0 }, floatingProgressImageRect: { x: 0, y: 0, width: 0, height: 0 },
shouldShowProgressImages: false, shouldShowProgressImages: false,
shouldAutoShowProgressImages: false, shouldAutoShowProgressImages: false,
shouldShowImageParameters: false,
}; };
export const uiSlice = createSlice({ export const uiSlice = createSlice({
@ -136,6 +137,12 @@ export const uiSlice = createSlice({
) => { ) => {
state.shouldAutoShowProgressImages = action.payload; state.shouldAutoShowProgressImages = action.payload;
}, },
shouldShowImageParametersChanged: (
state,
action: PayloadAction<boolean>
) => {
state.shouldShowImageParameters = action.payload;
},
}, },
}); });
@ -163,6 +170,7 @@ export const {
floatingProgressImageResized, floatingProgressImageResized,
setShouldShowProgressImages, setShouldShowProgressImages,
setShouldAutoShowProgressImages, setShouldAutoShowProgressImages,
shouldShowImageParametersChanged,
} = uiSlice.actions; } = uiSlice.actions;
export default uiSlice.reducer; export default uiSlice.reducer;

View File

@ -32,4 +32,5 @@ export interface UIState {
floatingProgressImageRect: Rect; floatingProgressImageRect: Rect;
shouldShowProgressImages: boolean; shouldShowProgressImages: boolean;
shouldAutoShowProgressImages: boolean; shouldAutoShowProgressImages: boolean;
shouldShowImageParameters: boolean;
} }