feat(ui): revert tabs to txt2img/img2img

This commit is contained in:
psychedelicious 2023-05-08 22:57:05 +10:00
parent 33c69359c2
commit c4b3a24ed7
41 changed files with 535 additions and 379 deletions

View File

@ -9,7 +9,7 @@ import FloatingGalleryButton from 'features/ui/components/FloatingGalleryButton'
import FloatingParametersPanelButtons from 'features/ui/components/FloatingParametersPanelButtons'; import FloatingParametersPanelButtons from 'features/ui/components/FloatingParametersPanelButtons';
import { Box, Flex, Grid, Portal, useColorMode } from '@chakra-ui/react'; import { Box, Flex, Grid, Portal, useColorMode } from '@chakra-ui/react';
import { APP_HEIGHT, APP_WIDTH } from 'theme/util/constants'; import { APP_HEIGHT, APP_WIDTH } from 'theme/util/constants';
import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel'; import GalleryDrawer from 'features/gallery/components/ImageGalleryPanel';
import Lightbox from 'features/lightbox/components/Lightbox'; import Lightbox from 'features/lightbox/components/Lightbox';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { import {
@ -28,9 +28,7 @@ import { configChanged } from 'features/system/store/configSlice';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { useLogger } from 'app/logging/useLogger'; import { useLogger } from 'app/logging/useLogger';
import ProgressImagePreview from 'features/parameters/components/ProgressImagePreview'; import ProgressImagePreview from 'features/parameters/components/ProgressImagePreview';
import ResizableDrawer from 'features/ui/components/common/ResizableDrawer/ResizableDrawer'; import ParametersDrawer from 'features/ui/components/ParametersDrawer';
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
import CreateParametersDrawer from 'features/ui/components/CreateParametersDrawer';
const DEFAULT_CONFIG = {}; const DEFAULT_CONFIG = {};
@ -91,8 +89,8 @@ const App = ({ config = DEFAULT_CONFIG, children }: Props) => {
</Grid> </Grid>
</ImageUploader> </ImageUploader>
<ImageGalleryPanel /> <GalleryDrawer />
<CreateParametersDrawer /> <ParametersDrawer />
<AnimatePresence> <AnimatePresence>
{!isApplicationReady && !loadingOverridden && ( {!isApplicationReady && !loadingOverridden && (

View File

@ -12,8 +12,9 @@ import { addImageResultReceivedListener } from './listeners/invocationComplete';
import { addImageUploadedListener } from './listeners/imageUploaded'; import { addImageUploadedListener } from './listeners/imageUploaded';
import { addRequestedImageDeletionListener } from './listeners/imageDeleted'; import { addRequestedImageDeletionListener } from './listeners/imageDeleted';
import { addUserInvokedCanvasListener } from './listeners/userInvokedCanvas'; import { addUserInvokedCanvasListener } from './listeners/userInvokedCanvas';
import { addUserInvokedCreateListener } from './listeners/userInvokedCreate';
import { addUserInvokedNodesListener } from './listeners/userInvokedNodes'; import { addUserInvokedNodesListener } from './listeners/userInvokedNodes';
import { addUserInvokedTextToImageListener } from './listeners/userInvokedTextToImage';
import { addUserInvokedImageToImageListener } from './listeners/userInvokedImageToImage';
export const listenerMiddleware = createListenerMiddleware(); export const listenerMiddleware = createListenerMiddleware();
@ -39,5 +40,6 @@ addImageResultReceivedListener();
addRequestedImageDeletionListener(); addRequestedImageDeletionListener();
addUserInvokedCanvasListener(); addUserInvokedCanvasListener();
addUserInvokedCreateListener();
addUserInvokedNodesListener(); addUserInvokedNodesListener();
addUserInvokedTextToImageListener();
addUserInvokedImageToImageListener();

View File

@ -1,6 +1,6 @@
import { startAppListening } from '..'; import { startAppListening } from '..';
import { sessionCreated, sessionInvoked } from 'services/thunks/session'; import { sessionCreated, sessionInvoked } from 'services/thunks/session';
import { buildCanvasGraphAndBlobs } from 'features/nodes/util/buildCanvasGraph'; import { buildCanvasGraphAndBlobs } from 'features/nodes/util/graphBuilders/buildCanvasGraph';
import { log } from 'app/logging/useLogger'; import { log } from 'app/logging/useLogger';
import { canvasGraphBuilt } from 'features/nodes/store/actions'; import { canvasGraphBuilt } from 'features/nodes/store/actions';
import { imageUploaded } from 'services/thunks/image'; import { imageUploaded } from 'services/thunks/image';

View File

@ -0,0 +1,24 @@
import { startAppListening } from '..';
import { buildImageToImageGraph } from 'features/nodes/util/graphBuilders/buildImageToImageGraph';
import { sessionCreated } from 'services/thunks/session';
import { log } from 'app/logging/useLogger';
import { imageToImageGraphBuilt } from 'features/nodes/store/actions';
import { userInvoked } from 'app/store/actions';
const moduleLog = log.child({ namespace: 'invoke' });
export const addUserInvokedImageToImageListener = () => {
startAppListening({
predicate: (action): action is ReturnType<typeof userInvoked> =>
userInvoked.match(action) && action.payload === 'image',
effect: (action, { getState, dispatch }) => {
const state = getState();
const graph = buildImageToImageGraph(state);
dispatch(imageToImageGraphBuilt(graph));
moduleLog({ data: graph }, 'Image to Image graph built');
dispatch(sessionCreated({ graph }));
},
});
};

View File

@ -1,6 +1,6 @@
import { startAppListening } from '..'; import { startAppListening } from '..';
import { sessionCreated } from 'services/thunks/session'; import { sessionCreated } from 'services/thunks/session';
import { buildNodesGraph } from 'features/nodes/util/buildNodesGraph'; import { buildNodesGraph } from 'features/nodes/util/graphBuilders/buildNodesGraph';
import { log } from 'app/logging/useLogger'; import { log } from 'app/logging/useLogger';
import { nodesGraphBuilt } from 'features/nodes/store/actions'; import { nodesGraphBuilt } from 'features/nodes/store/actions';
import { userInvoked } from 'app/store/actions'; import { userInvoked } from 'app/store/actions';

View File

@ -1,22 +1,22 @@
import { startAppListening } from '..'; import { startAppListening } from '..';
import { buildLinearGraph } from 'features/nodes/util/buildLinearGraph'; import { buildTextToImageGraph } from 'features/nodes/util/graphBuilders/buildTextToImageGraph';
import { sessionCreated } from 'services/thunks/session'; import { sessionCreated } from 'services/thunks/session';
import { log } from 'app/logging/useLogger'; import { log } from 'app/logging/useLogger';
import { createGraphBuilt } from 'features/nodes/store/actions'; import { textToImageGraphBuilt } from 'features/nodes/store/actions';
import { userInvoked } from 'app/store/actions'; import { userInvoked } from 'app/store/actions';
const moduleLog = log.child({ namespace: 'invoke' }); const moduleLog = log.child({ namespace: 'invoke' });
export const addUserInvokedCreateListener = () => { export const addUserInvokedTextToImageListener = () => {
startAppListening({ startAppListening({
predicate: (action): action is ReturnType<typeof userInvoked> => predicate: (action): action is ReturnType<typeof userInvoked> =>
userInvoked.match(action) && action.payload === 'text', userInvoked.match(action) && action.payload === 'text',
effect: (action, { getState, dispatch }) => { effect: (action, { getState, dispatch }) => {
const state = getState(); const state = getState();
const graph = buildLinearGraph(state); const graph = buildTextToImageGraph(state);
dispatch(createGraphBuilt(graph)); dispatch(textToImageGraphBuilt(graph));
moduleLog({ data: graph }, 'Create graph built'); moduleLog({ data: graph }, 'Text to Image graph built');
dispatch(sessionCreated({ graph })); dispatch(sessionCreated({ graph }));
}, },

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 ImagePromptHeading = () => { const InitialImageButtons = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
@ -38,4 +38,4 @@ const ImagePromptHeading = () => {
); );
}; };
export default ImagePromptHeading; export default InitialImageButtons;

View File

@ -7,7 +7,7 @@ const SelectImagePlaceholder = () => {
sx={{ sx={{
w: 'full', w: 'full',
h: 'full', h: 'full',
bg: 'base.800', // bg: 'base.800',
borderRadius: 'base', borderRadius: 'base',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',

View File

@ -3,6 +3,7 @@ import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice';
import { import {
setActiveTab,
toggleGalleryPanel, toggleGalleryPanel,
toggleParametersPanel, toggleParametersPanel,
togglePinGalleryPanel, togglePinGalleryPanel,
@ -58,4 +59,20 @@ export const useGlobalHotkeys = () => {
useHotkeys(['shift+g'], () => { useHotkeys(['shift+g'], () => {
dispatch(togglePinGalleryPanel()); dispatch(togglePinGalleryPanel());
}); });
useHotkeys('1', () => {
dispatch(setActiveTab('text'));
});
useHotkeys('2', () => {
dispatch(setActiveTab('image'));
});
useHotkeys('3', () => {
dispatch(setActiveTab('unifiedCanvas'));
});
useHotkeys('4', () => {
dispatch(setActiveTab('nodes'));
});
}; };

View File

@ -441,13 +441,13 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
{t('parameters.sendToUnifiedCanvas')} {t('parameters.sendToUnifiedCanvas')}
</IAIButton> </IAIButton>
<IAIButton {/* <IAIButton
size="sm" size="sm"
onClick={handleCopyImage} onClick={handleCopyImage}
leftIcon={<FaCopy />} leftIcon={<FaCopy />}
> >
{t('parameters.copyImage')} {t('parameters.copyImage')}
</IAIButton> </IAIButton> */}
<IAIButton <IAIButton
size="sm" size="sm"
onClick={handleCopyImageLink} onClick={handleCopyImageLink}

View File

@ -30,18 +30,18 @@ import useResolution from 'common/hooks/useResolution';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { memo } from 'react'; import { memo } from 'react';
const GALLERY_TAB_WIDTHS: Record< // const GALLERY_TAB_WIDTHS: Record<
InvokeTabName, // InvokeTabName,
{ galleryMinWidth: number; galleryMaxWidth: number } // { galleryMinWidth: number; galleryMaxWidth: number }
> = { // > = {
// txt2img: { galleryMinWidth: 200, galleryMaxWidth: 500 }, // txt2img: { galleryMinWidth: 200, galleryMaxWidth: 500 },
// img2img: { galleryMinWidth: 200, galleryMaxWidth: 500 }, // img2img: { galleryMinWidth: 200, galleryMaxWidth: 500 },
generate: { galleryMinWidth: 200, galleryMaxWidth: 500 }, // generate: { galleryMinWidth: 200, galleryMaxWidth: 500 },
unifiedCanvas: { galleryMinWidth: 200, galleryMaxWidth: 200 }, // unifiedCanvas: { galleryMinWidth: 200, galleryMaxWidth: 200 },
nodes: { galleryMinWidth: 200, galleryMaxWidth: 500 }, // nodes: { galleryMinWidth: 200, galleryMaxWidth: 500 },
// postprocessing: { galleryMinWidth: 200, galleryMaxWidth: 500 }, // postprocessing: { galleryMinWidth: 200, galleryMaxWidth: 500 },
// training: { galleryMinWidth: 200, galleryMaxWidth: 500 }, // training: { galleryMinWidth: 200, galleryMaxWidth: 500 },
}; // };
const galleryPanelSelector = createSelector( const galleryPanelSelector = createSelector(
[ [
@ -73,34 +73,34 @@ const galleryPanelSelector = createSelector(
} }
); );
const ImageGalleryPanel = () => { const GalleryDrawer = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { const {
shouldPinGallery, shouldPinGallery,
shouldShowGallery, shouldShowGallery,
galleryImageMinimumWidth, galleryImageMinimumWidth,
activeTabName, // activeTabName,
isStaging, // isStaging,
isResizable, // isResizable,
isLightboxOpen, // isLightboxOpen,
} = useAppSelector(galleryPanelSelector); } = useAppSelector(galleryPanelSelector);
const handleSetShouldPinGallery = () => { // const handleSetShouldPinGallery = () => {
dispatch(togglePinGalleryPanel()); // dispatch(togglePinGalleryPanel());
dispatch(requestCanvasRescale()); // dispatch(requestCanvasRescale());
}; // };
const handleToggleGallery = () => { // const handleToggleGallery = () => {
dispatch(toggleGalleryPanel()); // dispatch(toggleGalleryPanel());
shouldPinGallery && dispatch(requestCanvasRescale()); // shouldPinGallery && dispatch(requestCanvasRescale());
}; // };
const handleCloseGallery = () => { const handleCloseGallery = () => {
dispatch(setShouldShowGallery(false)); dispatch(setShouldShowGallery(false));
shouldPinGallery && dispatch(requestCanvasRescale()); shouldPinGallery && dispatch(requestCanvasRescale());
}; };
const resolution = useResolution(); // const resolution = useResolution();
// useHotkeys( // useHotkeys(
// 'g', // 'g',
@ -229,4 +229,4 @@ const ImageGalleryPanel = () => {
// return renderImageGallery(); // return renderImageGallery();
}; };
export default memo(ImageGalleryPanel); export default memo(GalleryDrawer);

View File

@ -2,7 +2,7 @@ import { Box } from '@chakra-ui/react';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { memo } from 'react'; import { memo } from 'react';
import { buildNodesGraph } from '../util/buildNodesGraph'; import { buildNodesGraph } from '../util/graphBuilders/buildNodesGraph';
const NodeGraphOverlay = () => { const NodeGraphOverlay = () => {
const state = useAppSelector((state: RootState) => state); const state = useAppSelector((state: RootState) => state);

View File

@ -1,12 +1,18 @@
import { createAction, isAnyOf } from '@reduxjs/toolkit'; import { createAction, isAnyOf } from '@reduxjs/toolkit';
import { Graph } from 'services/api'; import { Graph } from 'services/api';
export const createGraphBuilt = createAction<Graph>('nodes/createGraphBuilt'); export const textToImageGraphBuilt = createAction<Graph>(
'nodes/textToImageGraphBuilt'
);
export const imageToImageGraphBuilt = createAction<Graph>(
'nodes/imageToImageGraphBuilt'
);
export const canvasGraphBuilt = createAction<Graph>('nodes/canvasGraphBuilt'); export const canvasGraphBuilt = createAction<Graph>('nodes/canvasGraphBuilt');
export const nodesGraphBuilt = createAction<Graph>('nodes/nodesGraphBuilt'); export const nodesGraphBuilt = createAction<Graph>('nodes/nodesGraphBuilt');
export const isAnyGraphBuilt = isAnyOf( export const isAnyGraphBuilt = isAnyOf(
createGraphBuilt, textToImageGraphBuilt,
imageToImageGraphBuilt,
canvasGraphBuilt, canvasGraphBuilt,
nodesGraphBuilt nodesGraphBuilt
); );

View File

@ -10,17 +10,17 @@ import {
RangeInvocation, RangeInvocation,
TextToImageInvocation, TextToImageInvocation,
} from 'services/api'; } from 'services/api';
import { buildImg2ImgNode } from './linearGraphBuilder/buildImageToImageNode'; import { buildImg2ImgNode } from '../nodeBuilders/buildImageToImageNode';
import { buildTxt2ImgNode } from './linearGraphBuilder/buildTextToImageNode'; import { buildTxt2ImgNode } from '../nodeBuilders/buildTextToImageNode';
import { buildRangeNode } from './linearGraphBuilder/buildRangeNode'; import { buildRangeNode } from '../nodeBuilders/buildRangeNode';
import { buildIterateNode } from './linearGraphBuilder/buildIterateNode'; import { buildIterateNode } from '../nodeBuilders/buildIterateNode';
import { buildEdges } from './linearGraphBuilder/buildEdges'; import { buildEdges } from '../edgeBuilders/buildEdges';
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider'; import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
import { getCanvasData } from 'features/canvas/util/getCanvasData'; import { getCanvasData } from 'features/canvas/util/getCanvasData';
import { getGenerationMode } from './getGenerationMode'; import { getGenerationMode } from '../getGenerationMode';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { log } from 'app/logging/useLogger'; import { log } from 'app/logging/useLogger';
import { buildInpaintNode } from './linearGraphBuilder/buildInpaintNode'; import { buildInpaintNode } from '../nodeBuilders/buildInpaintNode';
const moduleLog = log.child({ namespace: 'buildCanvasGraph' }); const moduleLog = log.child({ namespace: 'buildCanvasGraph' });

View File

@ -1,19 +1,15 @@
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { Graph } from 'services/api'; import { Graph } from 'services/api';
import { buildImg2ImgNode } from './linearGraphBuilder/buildImageToImageNode'; import { buildImg2ImgNode } from '../nodeBuilders/buildImageToImageNode';
import { buildTxt2ImgNode } from './linearGraphBuilder/buildTextToImageNode'; import { buildRangeNode } from '../nodeBuilders/buildRangeNode';
import { buildRangeNode } from './linearGraphBuilder/buildRangeNode'; import { buildIterateNode } from '../nodeBuilders/buildIterateNode';
import { buildIterateNode } from './linearGraphBuilder/buildIterateNode'; import { buildEdges } from '../edgeBuilders/buildEdges';
import { buildEdges } from './linearGraphBuilder/buildEdges';
/** /**
* Builds the Linear workflow graph. * Builds the Linear workflow graph.
*/ */
export const buildLinearGraph = (state: RootState): Graph => { export const buildImageToImageGraph = (state: RootState): Graph => {
// The base node is either a txt2img or img2img node const baseNode = buildImg2ImgNode(state);
const baseNode = state.generation.isImageToImageEnabled
? buildImg2ImgNode(state)
: buildTxt2ImgNode(state);
// We always range and iterate nodes, no matter the iteration count // We always range and iterate nodes, no matter the iteration count
// This is required to provide the correct seeds to the backend engine // This is required to provide the correct seeds to the backend engine

View File

@ -2,7 +2,7 @@ import { Graph } from 'services/api';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { cloneDeep, reduce } from 'lodash-es'; import { cloneDeep, reduce } from 'lodash-es';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { InputFieldValue } from '../types/types'; import { InputFieldValue } from 'features/nodes/types/types';
/** /**
* We need to do special handling for some fields * We need to do special handling for some fields

View File

@ -0,0 +1,35 @@
import { RootState } from 'app/store/store';
import { Graph } from 'services/api';
import { buildTxt2ImgNode } from '../nodeBuilders/buildTextToImageNode';
import { buildRangeNode } from '../nodeBuilders/buildRangeNode';
import { buildIterateNode } from '../nodeBuilders/buildIterateNode';
import { buildEdges } from '../edgeBuilders/buildEdges';
/**
* Builds the Linear workflow graph.
*/
export const buildTextToImageGraph = (state: RootState): Graph => {
const baseNode = buildTxt2ImgNode(state);
// We always range and iterate nodes, no matter the iteration count
// This is required to provide the correct seeds to the backend engine
const rangeNode = buildRangeNode(state);
const iterateNode = buildIterateNode();
// Build the edges for the nodes selected.
const edges = buildEdges(baseNode, rangeNode, iterateNode);
// Assemble!
const graph = {
nodes: {
[rangeNode.id]: rangeNode,
[iterateNode.id]: iterateNode,
[baseNode.id]: baseNode,
},
edges,
};
// TODO: hires fix requires latent space upscaling; we don't have nodes for this yet
return graph;
};

View File

@ -15,8 +15,6 @@ export const buildImg2ImgNode = (
const nodeId = uuidv4(); const nodeId = uuidv4();
const { generation, system, models } = state; const { generation, system, models } = state;
const { selectedModelName } = models;
const { const {
prompt, prompt,
negativePrompt, negativePrompt,
@ -26,10 +24,13 @@ export const buildImg2ImgNode = (
height, height,
cfgScale, cfgScale,
sampler, sampler,
seamless, model,
img2imgStrength: strength, img2imgStrength: strength,
shouldFitToWidthHeight: fit, shouldFitToWidthHeight: fit,
shouldRandomizeSeed, shouldRandomizeSeed,
shouldUseSeamless,
seamlessXAxis,
seamlessYAxis,
} = generation; } = generation;
const initialImage = initialImageSelector(state); const initialImage = initialImageSelector(state);
@ -48,9 +49,7 @@ export const buildImg2ImgNode = (
height, height,
cfg_scale: cfgScale, cfg_scale: cfgScale,
scheduler: sampler as ImageToImageInvocation['scheduler'], scheduler: sampler as ImageToImageInvocation['scheduler'],
seamless, model,
model: selectedModelName,
progress_images: true,
image: initialImage image: initialImage
? { ? {
image_name: initialImage.name, image_name: initialImage.name,

View File

@ -10,8 +10,6 @@ export const buildTxt2ImgNode = (
const nodeId = uuidv4(); const nodeId = uuidv4();
const { generation, models } = state; const { generation, models } = state;
const { selectedModelName } = models;
const { const {
prompt, prompt,
negativePrompt, negativePrompt,
@ -21,8 +19,8 @@ export const buildTxt2ImgNode = (
height, height,
cfgScale: cfg_scale, cfgScale: cfg_scale,
sampler, sampler,
seamless,
shouldRandomizeSeed, shouldRandomizeSeed,
model,
} = generation; } = generation;
const textToImageNode: NonNullable<TextToImageInvocation> = { const textToImageNode: NonNullable<TextToImageInvocation> = {
@ -34,9 +32,7 @@ export const buildTxt2ImgNode = (
height, height,
cfg_scale, cfg_scale,
scheduler: sampler as TextToImageInvocation['scheduler'], scheduler: sampler as TextToImageInvocation['scheduler'],
seamless, model,
model: selectedModelName,
progress_images: true,
}; };
if (!shouldRandomizeSeed) { if (!shouldRandomizeSeed) {

View File

@ -5,7 +5,7 @@ import { setShouldFitToWidthHeight } from 'features/parameters/store/generationS
import { ChangeEvent } from 'react'; import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function ImageFit() { export default function ImageToImageFit() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const shouldFitToWidthHeight = useAppSelector( const shouldFitToWidthHeight = useAppSelector(

View File

@ -13,7 +13,7 @@ import {
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import IAIButton from 'common/components/IAIButton'; import IAIButton from 'common/components/IAIButton';
import ImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageFit'; import ImageToImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageFit';
import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength'; import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength';
import IAIIconButton from 'common/components/IAIIconButton'; import IAIIconButton from 'common/components/IAIIconButton';
@ -21,16 +21,16 @@ 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 ImagePromptHeading from 'common/components/ImageToImageSettingsHeader'; import InitialImageButtons 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">
<ImagePromptHeading /> <InitialImageButtons />
<InitialImagePreview /> <InitialImagePreview />
<ImageToImageStrength /> <ImageToImageStrength />
<ImageFit /> <ImageToImageFit />
</VStack> </VStack>
); );
} }

View File

@ -0,0 +1,36 @@
import { Flex } from '@chakra-ui/react';
import InitialImagePreview from './InitialImagePreview';
import InitialImageButtons from 'common/components/ImageToImageButtons';
const InitialImageDisplay = () => {
return (
<Flex
sx={{
position: 'relative',
flexDirection: 'column',
height: '100%',
width: '100%',
rowGap: 4,
borderRadius: 'base',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Flex
flexDirection="column"
sx={{
w: 'full',
h: 'full',
alignItems: 'center',
justifyContent: 'center',
gap: 4,
}}
>
<InitialImageButtons />
<InitialImagePreview />
</Flex>
</Flex>
);
};
export default InitialImageDisplay;

View File

@ -71,6 +71,7 @@ const InitialImagePreview = () => {
<Flex <Flex
sx={{ sx={{
width: 'full', width: 'full',
height: 'full',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
position: 'relative', position: 'relative',
@ -115,7 +116,7 @@ const InitialImagePreview = () => {
)} )}
{!initialImage?.url && <SelectImagePlaceholder />} {!initialImage?.url && <SelectImagePlaceholder />}
</Flex> </Flex>
{!isImageToImageEnabled && ( {/* {!isImageToImageEnabled && (
<Flex <Flex
sx={{ sx={{
w: 'full', w: 'full',
@ -134,7 +135,7 @@ const InitialImagePreview = () => {
Image to Image is Disabled Image to Image is Disabled
</Text> </Text>
</Flex> </Flex>
)} )} */}
</Flex> </Flex>
); );
}; };

View File

@ -7,9 +7,6 @@ import { memo } from 'react';
import { ParamHiresStrength } from './ParamHiresStrength'; import { ParamHiresStrength } from './ParamHiresStrength';
import { setHiresFix } from 'features/parameters/store/postprocessingSlice'; import { setHiresFix } from 'features/parameters/store/postprocessingSlice';
/**
* Seed & variation options. Includes iteration, seed, seed randomization, variation options.
*/
const ParamHiresCollapse = () => { const ParamHiresCollapse = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const hiresFix = useAppSelector( const hiresFix = useAppSelector(

View File

@ -61,12 +61,12 @@ export const modelsSlice = createSlice({
}, },
}); });
export const selectedModelSelector = (state: RootState) => { // export const selectedModelSelector = (state: RootState) => {
const { selectedModelName } = state.models; // const { selectedModelName } = state.models;
const selectedModel = selectModelsById(state, selectedModelName); // const selectedModel = selectModelsById(state, selectedModelName);
return selectedModel ?? null; // return selectedModel ?? null;
}; // };
export const { export const {
selectAll: selectModelsAll, selectAll: selectModelsAll,

View File

@ -1,115 +0,0 @@
import { isEqual } from 'lodash-es';
import ResizableDrawer from './common/ResizableDrawer/ResizableDrawer';
import TextTabParameters from './tabs/text/TextTabParameters';
import { createSelector } from '@reduxjs/toolkit';
import { activeTabNameSelector, uiSelector } from '../store/uiSelectors';
import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import {
setShouldShowParametersPanel,
toggleParametersPanel,
} from '../store/uiSlice';
import { memo } from 'react';
import { Flex } from '@chakra-ui/react';
import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
import PinParametersPanelButton from './PinParametersPanelButton';
import { Panel, PanelGroup } from 'react-resizable-panels';
import CreateSidePanelPinned from './tabs/text/TextTabSettingsPinned';
import CreateTextParameters from './tabs/text/TextTabParameters';
import ResizeHandle from './tabs/ResizeHandle';
import CreateImageSettings from './tabs/image/ImageTabSettings';
const selector = createSelector(
[uiSelector, activeTabNameSelector, lightboxSelector],
(ui, activeTabName, lightbox) => {
const {
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = ui;
const { isLightboxOpen } = lightbox;
return {
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
};
},
{
memoizeOptions: {
resultEqualityCheck: isEqual,
},
}
);
const CreateParametersPanel = () => {
const dispatch = useAppDispatch();
const {
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = useAppSelector(selector);
const handleClosePanel = () => {
dispatch(setShouldShowParametersPanel(false));
};
if (shouldPinParametersPanel) {
return null;
}
return (
<ResizableDrawer
direction="left"
isResizable={true}
isOpen={shouldShowParametersPanel}
onClose={handleClosePanel}
minWidth={500}
>
<Flex flexDir="column" position="relative" h="full" w="full">
<Flex
paddingTop={1.5}
paddingBottom={4}
justifyContent="space-between"
alignItems="center"
>
<InvokeAILogoComponent />
<PinParametersPanelButton />
</Flex>
<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>
</ResizableDrawer>
);
};
export default memo(CreateParametersPanel);

View File

@ -33,7 +33,6 @@ import { useTranslation } from 'react-i18next';
import { ResourceKey } from 'i18next'; import { ResourceKey } from 'i18next';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import NodeEditor from 'features/nodes/components/NodeEditor'; import NodeEditor from 'features/nodes/components/NodeEditor';
import GenerateWorkspace from './tabs/text/GenerateWorkspace';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { BsLightningChargeFill } from 'react-icons/bs'; import { BsLightningChargeFill } from 'react-icons/bs';
import { configSelector } from 'features/system/store/configSelectors'; import { configSelector } from 'features/system/store/configSelectors';
@ -43,7 +42,7 @@ import Scrollable from './common/Scrollable';
import TextTabParameters from './tabs/text/TextTabParameters'; import TextTabParameters from './tabs/text/TextTabParameters';
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 GalleryDrawer 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 TextTabMain from './tabs/text/TextTabMain'; import TextTabMain from './tabs/text/TextTabMain';
@ -54,6 +53,7 @@ import UnifiedCanvasTab from './tabs/UnifiedCanvas/UnifiedCanvasTab';
import NodesTab from './tabs/Nodes/NodesTab'; import NodesTab from './tabs/Nodes/NodesTab';
import { FaImage } from 'react-icons/fa'; import { FaImage } from 'react-icons/fa';
import ResizeHandle from './tabs/ResizeHandle'; import ResizeHandle from './tabs/ResizeHandle';
import ImageTab from './tabs/image/ImageTab';
export interface InvokeTabInfo { export interface InvokeTabInfo {
id: InvokeTabName; id: InvokeTabName;
@ -70,7 +70,7 @@ const tabs: InvokeTabInfo[] = [
{ {
id: 'image', id: 'image',
icon: <Icon as={FaImage} sx={{ boxSize: 5 }} />, icon: <Icon as={FaImage} sx={{ boxSize: 5 }} />,
content: <TextTab />, content: <ImageTab />,
}, },
{ {
id: 'unifiedCanvas', id: 'unifiedCanvas',
@ -114,22 +114,6 @@ const InvokeTabs = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
useHotkeys('1', () => {
dispatch(setActiveTab('text'));
});
useHotkeys('2', () => {
dispatch(setActiveTab('image'));
});
useHotkeys('3', () => {
dispatch(setActiveTab('unifiedCanvas'));
});
useHotkeys('4', () => {
dispatch(setActiveTab('nodes'));
});
// Lightbox Hotkey // Lightbox Hotkey
useHotkeys( useHotkeys(
'z', 'z',
@ -200,7 +184,7 @@ const InvokeTabs = () => {
direction="horizontal" direction="horizontal"
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
> >
<Panel id="tabContent"> <Panel id="main">
<TabPanels style={{ height: '100%', width: '100%' }}> <TabPanels style={{ height: '100%', width: '100%' }}>
{tabPanels} {tabPanels}
</TabPanels> </TabPanels>
@ -208,7 +192,13 @@ const InvokeTabs = () => {
{shouldPinGallery && shouldShowGallery && ( {shouldPinGallery && shouldShowGallery && (
<> <>
<ResizeHandle /> <ResizeHandle />
<Panel id="gallery" order={3} defaultSize={10} minSize={10}> <Panel
id="gallery"
order={3}
defaultSize={10}
minSize={10}
maxSize={50}
>
<ImageGalleryContent /> <ImageGalleryContent />
</Panel> </Panel>
</> </>

View File

@ -0,0 +1,32 @@
import { useAppSelector } from 'app/store/storeHooks';
import { memo } from 'react';
import { activeTabNameSelector } from '../store/uiSelectors';
import TextTabParametersDrawer from './tabs/text/TextTabParametersDrawer';
import { RootState } from 'app/store/store';
const ParametersDrawer = () => {
const activeTabName = useAppSelector(activeTabNameSelector);
const shouldPinParametersPanel = useAppSelector(
(state: RootState) => state.ui.shouldPinParametersPanel
);
if (shouldPinParametersPanel) {
return null;
}
if (activeTabName === 'text') {
return <TextTabParametersDrawer />;
}
if (activeTabName === 'image') {
return null;
}
if (activeTabName === 'unifiedCanvas') {
return null;
}
return null;
};
export default memo(ParametersDrawer);

View File

@ -7,6 +7,11 @@ 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 ResizeHandle from '../ResizeHandle'; import ResizeHandle from '../ResizeHandle';
import ImageTabParameters from './ImageTabParameters';
import ImageTabImageParameters from './ImageTabImageParameters';
import TextTabMain from '../text/TextTabMain';
import InitialImagePreview from 'features/parameters/components/AdvancedParameters/ImageToImage/InitialImagePreview';
import InitialImageDisplay from 'features/parameters/components/AdvancedParameters/ImageToImage/InitialImageDisplay';
const selector = createSelector(uiSelector, (ui) => { const selector = createSelector(uiSelector, (ui) => {
const { const {
@ -38,20 +43,20 @@ const TextTab = () => {
return ( return (
<PanelGroup <PanelGroup
autoSaveId="textTab" autoSaveId="imageTab"
direction="horizontal" direction="horizontal"
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
> >
{shouldPinParametersPanel && shouldShowParametersPanel && ( {shouldPinParametersPanel && shouldShowParametersPanel && (
<> <>
<Panel <Panel
id="textTab_settings" id="imageTab_parameters"
order={0} order={0}
defaultSize={25} defaultSize={25}
minSize={25} minSize={25}
style={{ position: 'relative' }} style={{ position: 'relative' }}
> >
{/* <TextTabSettings /> */} <ImageTabParameters />
<PinParametersPanelButton <PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }} sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/> />
@ -59,15 +64,34 @@ const TextTab = () => {
<ResizeHandle /> <ResizeHandle />
</> </>
)} )}
<Panel <Panel id="imageTab_content" order={1}>
id="textTab_main" <PanelGroup
order={2} autoSaveId="imageTab_contentWrapper"
minSize={30} direction="horizontal"
onResize={() => { style={{ height: '100%', width: '100%' }}
dispatch(requestCanvasRescale()); >
}} <Panel
> id="imageTab_initImage"
{/* <TextTabMain /> */} order={0}
defaultSize={50}
minSize={25}
style={{ position: 'relative' }}
>
<InitialImageDisplay />
</Panel>
<ResizeHandle />
<Panel
id="imageTab_selectedImage"
order={1}
defaultSize={50}
minSize={25}
onResize={() => {
dispatch(requestCanvasRescale());
}}
>
<TextTabMain />
</Panel>
</PanelGroup>
</Panel> </Panel>
</PanelGroup> </PanelGroup>
); );

View File

@ -0,0 +1,61 @@
import { Box, Flex } from '@chakra-ui/react';
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
import { memo } from 'react';
import OverlayScrollable from '../../common/OverlayScrollable';
import ParamPositiveConditioning from 'features/parameters/components/Parameters/ParamPositiveConditioning';
import ParamNegativeConditioning from 'features/parameters/components/Parameters/ParamNegativeConditioning';
import { createSelector } from '@reduxjs/toolkit';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import ParamIterations from 'features/parameters/components/Parameters/ParamIterations';
import ParamSteps from 'features/parameters/components/Parameters/ParamSteps';
import ParamCFGScale from 'features/parameters/components/Parameters/ParamCFGScale';
import ParamWidth from 'features/parameters/components/Parameters/ParamWidth';
import ParamHeight from 'features/parameters/components/Parameters/ParamHeight';
import ParamScheduler from 'features/parameters/components/Parameters/ParamScheduler';
import ModelSelect from 'features/system/components/ModelSelect';
import ParamSeedCollapse from 'features/parameters/components/Parameters/Seed/ParamSeedCollapse';
import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
import ParamHiresCollapse from 'features/parameters/components/Parameters/Hires/ParamHiresCollapse';
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
import InitialImagePreview from 'features/parameters/components/AdvancedParameters/ImageToImage/InitialImagePreview';
import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength';
import ImageToImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageFit';
import InitialImageButtons from 'common/components/ImageToImageButtons';
const selector = createSelector(
uiSelector,
(ui) => {
const { shouldUseSliders } = ui;
return { shouldUseSliders };
},
defaultSelectorOptions
);
const ImageTabParameters = () => {
const { shouldUseSliders } = useAppSelector(selector);
return (
<OverlayScrollable>
<Flex
sx={{
gap: 2,
flexDirection: 'column',
h: 'full',
w: 'full',
position: 'absolute',
}}
>
<InitialImageButtons />
<InitialImagePreview />
<ImageToImageFit />
</Flex>
</OverlayScrollable>
);
};
export default memo(ImageTabParameters);

View File

@ -0,0 +1,113 @@
import { Box, Flex } from '@chakra-ui/react';
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
import { memo } from 'react';
import OverlayScrollable from '../../common/OverlayScrollable';
import ParamPositiveConditioning from 'features/parameters/components/Parameters/ParamPositiveConditioning';
import ParamNegativeConditioning from 'features/parameters/components/Parameters/ParamNegativeConditioning';
import { createSelector } from '@reduxjs/toolkit';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import ParamIterations from 'features/parameters/components/Parameters/ParamIterations';
import ParamSteps from 'features/parameters/components/Parameters/ParamSteps';
import ParamCFGScale from 'features/parameters/components/Parameters/ParamCFGScale';
import ParamWidth from 'features/parameters/components/Parameters/ParamWidth';
import ParamHeight from 'features/parameters/components/Parameters/ParamHeight';
import ParamScheduler from 'features/parameters/components/Parameters/ParamScheduler';
import ModelSelect from 'features/system/components/ModelSelect';
import ParamSeedCollapse from 'features/parameters/components/Parameters/Seed/ParamSeedCollapse';
import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
import ParamHiresCollapse from 'features/parameters/components/Parameters/Hires/ParamHiresCollapse';
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength';
import ImageToImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageFit';
const selector = createSelector(
uiSelector,
(ui) => {
const { shouldUseSliders } = ui;
return { shouldUseSliders };
},
defaultSelectorOptions
);
const ImageTabParameters = () => {
const { shouldUseSliders } = useAppSelector(selector);
return (
<OverlayScrollable>
<Flex
sx={{
gap: 2,
flexDirection: 'column',
h: 'full',
w: 'full',
position: 'absolute',
}}
>
<ParamPositiveConditioning />
<ParamNegativeConditioning />
<ProcessButtons />
<Flex
sx={{
flexDirection: 'column',
gap: 2,
bg: 'base.800',
p: 4,
borderRadius: 'base',
}}
>
{shouldUseSliders ? (
<Flex sx={{ gap: 3, flexDirection: 'column' }}>
<ParamIterations />
<ParamSteps />
<ParamCFGScale />
<ParamWidth />
<ParamHeight />
<ImageToImageStrength />
<ImageToImageFit />
<Flex gap={3} w="full">
<Box flexGrow={2}>
<ParamScheduler />
</Box>
<Box flexGrow={3}>
<ModelSelect />
</Box>
</Flex>
</Flex>
) : (
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
<Flex gap={3}>
<ParamIterations />
<ParamSteps />
<ParamCFGScale />
</Flex>
<ParamWidth />
<ParamHeight />
<Flex gap={3} w="full">
<Box flexGrow={2}>
<ParamScheduler />
</Box>
<Box flexGrow={3}>
<ModelSelect />
</Box>
</Flex>
<ImageToImageStrength />
<ImageToImageFit />
</Flex>
)}
</Flex>
<ParamSeedCollapse />
<ParamVariationCollapse />
<ParamNoiseCollapse />
<ParamSymmetryCollapse />
<ParamSeamlessCollapse />
</Flex>
</OverlayScrollable>
);
};
export default memo(ImageTabParameters);

View File

@ -1,53 +0,0 @@
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

@ -8,7 +8,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import TextTabMain from './TextTabMain'; import TextTabMain from './TextTabMain';
import ResizeHandle from '../ResizeHandle'; import ResizeHandle from '../ResizeHandle';
import TextTabSettings from './TextTabParameters'; import TextTabParameters from './TextTabParameters';
const selector = createSelector(uiSelector, (ui) => { const selector = createSelector(uiSelector, (ui) => {
const { const {
@ -47,13 +47,13 @@ const TextTab = () => {
{shouldPinParametersPanel && shouldShowParametersPanel && ( {shouldPinParametersPanel && shouldShowParametersPanel && (
<> <>
<Panel <Panel
id="textTab_settings" id="textTab_parameters"
order={0} order={0}
defaultSize={25} defaultSize={25}
minSize={25} minSize={25}
style={{ position: 'relative' }} style={{ position: 'relative' }}
> >
<TextTabSettings /> <TextTabParameters />
<PinParametersPanelButton <PinParametersPanelButton
sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }} sx={{ position: 'absolute', top: 0, insetInlineEnd: 0 }}
/> />
@ -61,14 +61,7 @@ const TextTab = () => {
<ResizeHandle /> <ResizeHandle />
</> </>
)} )}
<Panel <Panel id="textTab_content" order={2} minSize={30}>
id="textTab_main"
order={2}
minSize={30}
onResize={() => {
dispatch(requestCanvasRescale());
}}
>
<TextTabMain /> <TextTabMain />
</Panel> </Panel>
</PanelGroup> </PanelGroup>

View File

@ -1,6 +1,5 @@
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay'; import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay';
import ProgressImagePreview from 'features/parameters/components/ProgressImagePreview';
const TextTabMain = () => { const TextTabMain = () => {
return ( return (

View File

@ -0,0 +1,73 @@
import { isEqual } from 'lodash-es';
import ResizableDrawer from '../../common/ResizableDrawer/ResizableDrawer';
import TextTabParameters from './TextTabParameters';
import { createSelector } from '@reduxjs/toolkit';
import { activeTabNameSelector, uiSelector } from '../../../store/uiSelectors';
import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setShouldShowParametersPanel } from '../../../store/uiSlice';
import { memo } from 'react';
import { Flex } from '@chakra-ui/react';
import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
import PinParametersPanelButton from '../../PinParametersPanelButton';
import { Panel, PanelGroup } from 'react-resizable-panels';
const selector = createSelector(
[uiSelector, activeTabNameSelector, lightboxSelector],
(ui, activeTabName, lightbox) => {
const {
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
} = ui;
const { isLightboxOpen } = lightbox;
return {
activeTabName,
shouldPinParametersPanel,
shouldShowParametersPanel,
shouldShowImageParameters,
};
},
{
memoizeOptions: {
resultEqualityCheck: isEqual,
},
}
);
const TextTabParametersDrawer = () => {
const dispatch = useAppDispatch();
const { shouldPinParametersPanel, shouldShowParametersPanel } =
useAppSelector(selector);
const handleClosePanel = () => {
dispatch(setShouldShowParametersPanel(false));
};
return (
<ResizableDrawer
direction="left"
isResizable={true}
isOpen={shouldShowParametersPanel}
onClose={handleClosePanel}
minWidth={500}
>
<Flex flexDir="column" position="relative" h="full" w="full">
<Flex
paddingTop={1.5}
paddingBottom={4}
justifyContent="space-between"
alignItems="center"
>
<InvokeAILogoComponent />
<PinParametersPanelButton />
</Flex>
<TextTabParameters />
</Flex>
</ResizableDrawer>
);
};
export default memo(TextTabParametersDrawer);

View File

@ -1,69 +0,0 @@
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 './TextTabParameters';
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 '../image/ImageTabSettings';
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

@ -24,7 +24,8 @@
"src/**/*.ts", "src/**/*.ts",
"src/**/*.tsx", "src/**/*.tsx",
"*.d.ts", "*.d.ts",
"src/app/store/middleware/listenerMiddleware" "src/app/store/middleware/listenerMiddleware",
"src/features/nodes/util/edgeBuilders"
], ],
"exclude": ["src/services/fixtures/*", "node_modules", "dist"], "exclude": ["src/services/fixtures/*", "node_modules", "dist"],
"references": [{ "path": "./tsconfig.node.json" }] "references": [{ "path": "./tsconfig.node.json" }]