mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): initial mini controlnet UI, dnd improvements
This commit is contained in:
parent
72b4371804
commit
6b824eb112
@ -61,6 +61,7 @@
|
|||||||
"@chakra-ui/theme-tools": "^2.0.16",
|
"@chakra-ui/theme-tools": "^2.0.16",
|
||||||
"@dagrejs/graphlib": "^2.1.12",
|
"@dagrejs/graphlib": "^2.1.12",
|
||||||
"@dnd-kit/core": "^6.0.8",
|
"@dnd-kit/core": "^6.0.8",
|
||||||
|
"@dnd-kit/modifiers": "^6.0.1",
|
||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
"@emotion/styled": "^11.10.6",
|
"@emotion/styled": "^11.10.6",
|
||||||
"@floating-ui/react-dom": "^2.0.0",
|
"@floating-ui/react-dom": "^2.0.0",
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
KeyboardSensor,
|
KeyboardSensor,
|
||||||
MouseSensor,
|
MouseSensor,
|
||||||
TouchSensor,
|
TouchSensor,
|
||||||
|
pointerWithin,
|
||||||
useSensor,
|
useSensor,
|
||||||
useSensors,
|
useSensors,
|
||||||
} from '@dnd-kit/core';
|
} from '@dnd-kit/core';
|
||||||
@ -13,6 +14,7 @@ import { PropsWithChildren, memo, useCallback, useState } from 'react';
|
|||||||
import OverlayDragImage from './OverlayDragImage';
|
import OverlayDragImage from './OverlayDragImage';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api';
|
||||||
import { isImageDTO } from 'services/types/guards';
|
import { isImageDTO } from 'services/types/guards';
|
||||||
|
import { snapCenterToCursor } from '@dnd-kit/modifiers';
|
||||||
|
|
||||||
type ImageDndContextProps = PropsWithChildren;
|
type ImageDndContextProps = PropsWithChildren;
|
||||||
|
|
||||||
@ -53,9 +55,10 @@ const ImageDndContext = (props: ImageDndContextProps) => {
|
|||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
sensors={sensors}
|
sensors={sensors}
|
||||||
|
collisionDetection={pointerWithin}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
<DragOverlay dropAnimation={null}>
|
<DragOverlay dropAnimation={null} modifiers={[snapCenterToCursor]}>
|
||||||
{draggedImage && <OverlayDragImage image={draggedImage} />}
|
{draggedImage && <OverlayDragImage image={draggedImage} />}
|
||||||
</DragOverlay>
|
</DragOverlay>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Image } from '@chakra-ui/react';
|
import { Box, Image } from '@chakra-ui/react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api';
|
||||||
|
|
||||||
@ -8,6 +8,17 @@ type OverlayDragImageProps = {
|
|||||||
|
|
||||||
const OverlayDragImage = (props: OverlayDragImageProps) => {
|
const OverlayDragImage = (props: OverlayDragImageProps) => {
|
||||||
return (
|
return (
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
userSelect: 'none',
|
||||||
|
cursor: 'grabbing',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Image
|
<Image
|
||||||
sx={{
|
sx={{
|
||||||
maxW: 36,
|
maxW: 36,
|
||||||
@ -17,6 +28,7 @@ const OverlayDragImage = (props: OverlayDragImageProps) => {
|
|||||||
}}
|
}}
|
||||||
src={props.image.thumbnail_url}
|
src={props.image.thumbnail_url}
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,6 +95,7 @@ export type AppFeature =
|
|||||||
* A disable-able Stable Diffusion feature
|
* A disable-able Stable Diffusion feature
|
||||||
*/
|
*/
|
||||||
export type SDFeature =
|
export type SDFeature =
|
||||||
|
| 'controlNet'
|
||||||
| 'noise'
|
| 'noise'
|
||||||
| 'variation'
|
| 'variation'
|
||||||
| 'symmetry'
|
| 'symmetry'
|
||||||
|
@ -109,7 +109,7 @@ const IAICustomSelect = (props: IAICustomSelectProps) => {
|
|||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
zIndex: 1,
|
zIndex: 2,
|
||||||
bg: 'base.800',
|
bg: 'base.800',
|
||||||
borderRadius: 'base',
|
borderRadius: 'base',
|
||||||
border: '1px',
|
border: '1px',
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
import { Flex, FlexProps, Spinner, SpinnerProps } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
type Props = FlexProps & {
|
||||||
|
spinnerProps?: SpinnerProps;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IAIImageFallback = (props: Props) => {
|
||||||
|
const { spinnerProps, ...rest } = props;
|
||||||
|
const { sx, ...restFlexProps } = rest;
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
bg: 'base.900',
|
||||||
|
opacity: 0.7,
|
||||||
|
w: 'full',
|
||||||
|
h: 'full',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
borderRadius: 'base',
|
||||||
|
...sx,
|
||||||
|
}}
|
||||||
|
{...restFlexProps}
|
||||||
|
>
|
||||||
|
<Spinner size="xl" {...spinnerProps} />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
@ -40,7 +40,7 @@ import IAIIconButton, { IAIIconButtonProps } from './IAIIconButton';
|
|||||||
import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
|
import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
|
|
||||||
export type IAIFullSliderProps = {
|
export type IAIFullSliderProps = {
|
||||||
label: string;
|
label?: string;
|
||||||
value: number;
|
value: number;
|
||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
@ -178,9 +178,11 @@ const IAISlider = (props: IAIFullSliderProps) => {
|
|||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
{...sliderFormControlProps}
|
{...sliderFormControlProps}
|
||||||
>
|
>
|
||||||
|
{label && (
|
||||||
<FormLabel {...sliderFormLabelProps} mb={-1}>
|
<FormLabel {...sliderFormLabelProps} mb={-1}>
|
||||||
{label}
|
{label}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
)}
|
||||||
|
|
||||||
<HStack w="100%" gap={2} alignItems="center">
|
<HStack w="100%" gap={2} alignItems="center">
|
||||||
<Slider
|
<Slider
|
||||||
|
@ -1,39 +1,29 @@
|
|||||||
import { memo, useCallback, useState } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { ImageDTO } from 'services/api';
|
|
||||||
import {
|
import {
|
||||||
ControlNet,
|
ControlNet,
|
||||||
controlNetImageChanged,
|
|
||||||
controlNetProcessedImageChanged,
|
controlNetProcessedImageChanged,
|
||||||
controlNetRemoved,
|
controlNetRemoved,
|
||||||
controlNetSelector,
|
|
||||||
} from '../store/controlNetSlice';
|
} from '../store/controlNetSlice';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import ParamControlNetModel from './parameters/ParamControlNetModel';
|
import ParamControlNetModel from './parameters/ParamControlNetModel';
|
||||||
import ParamControlNetWeight from './parameters/ParamControlNetWeight';
|
import ParamControlNetWeight from './parameters/ParamControlNetWeight';
|
||||||
import ParamControlNetBeginStepPct from './parameters/ParamControlNetBeginStepPct';
|
|
||||||
import ParamControlNetEndStepPct from './parameters/ParamControlNetEndStepPct';
|
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Flex,
|
Flex,
|
||||||
Spinner,
|
|
||||||
Tab,
|
Tab,
|
||||||
TabList,
|
TabList,
|
||||||
TabPanel,
|
TabPanel,
|
||||||
TabPanels,
|
TabPanels,
|
||||||
Tabs,
|
Tabs,
|
||||||
|
Text,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import IAISelectableImage from './parameters/IAISelectableImage';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import { FaUndo } from 'react-icons/fa';
|
import { FaUndo } from 'react-icons/fa';
|
||||||
import { TbSquareToggle } from 'react-icons/tb';
|
|
||||||
import ParamControlNetProcessorSelect from './parameters/ParamControlNetProcessorSelect';
|
import ParamControlNetProcessorSelect from './parameters/ParamControlNetProcessorSelect';
|
||||||
import ControlNetProcessorComponent from './ControlNetProcessorComponent';
|
import ControlNetProcessorComponent from './ControlNetProcessorComponent';
|
||||||
import ControlNetPreprocessButton from './ControlNetPreprocessButton';
|
import ControlNetPreprocessButton from './ControlNetPreprocessButton';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import ParamControlNetBeginEnd from './parameters/ParamControlNetBeginEnd';
|
import ParamControlNetBeginEnd from './parameters/ParamControlNetBeginEnd';
|
||||||
import ControlNetImagePreview from './ControlNetImagePreview';
|
import ControlNetImagePreview from './ControlNetImagePreview';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
|
|
||||||
type ControlNetProps = {
|
type ControlNetProps = {
|
||||||
controlNet: ControlNet;
|
controlNet: ControlNet;
|
||||||
|
@ -5,13 +5,12 @@ import {
|
|||||||
controlNetSelector,
|
controlNetSelector,
|
||||||
} from '../store/controlNetSlice';
|
} from '../store/controlNetSlice';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { Box, Flex, Spinner } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import IAISelectableImage from './parameters/IAISelectableImage';
|
import IAIDndImage from './parameters/IAISelectableImage';
|
||||||
import { TbSquareToggle } from 'react-icons/tb';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
import { IAIImageFallback } from 'common/components/IAIImageFallback';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
controlNetSelector,
|
controlNetSelector,
|
||||||
@ -43,24 +42,20 @@ const ControlNetImagePreview = (props: Props) => {
|
|||||||
[controlNetId, dispatch]
|
[controlNetId, dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleControlImageReset = useCallback(() => {
|
|
||||||
dispatch(controlNetImageChanged({ controlNetId, controlImage: null }));
|
|
||||||
}, [controlNetId, dispatch]);
|
|
||||||
|
|
||||||
const shouldShowProcessedImageBackdrop =
|
const shouldShowProcessedImageBackdrop =
|
||||||
Number(controlImage?.width) > Number(processedControlImage?.width) ||
|
Number(controlImage?.width) > Number(processedControlImage?.width) ||
|
||||||
Number(controlImage?.height) > Number(processedControlImage?.height);
|
Number(controlImage?.height) > Number(processedControlImage?.height);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ position: 'relative', aspectRatio: '1/1' }}>
|
<Box
|
||||||
<IAISelectableImage
|
sx={{ position: 'relative', h: 'inherit' }}
|
||||||
|
onMouseOver={() => setShouldShowProcessedImage(false)}
|
||||||
|
onMouseOut={() => setShouldShowProcessedImage(true)}
|
||||||
|
>
|
||||||
|
<IAIDndImage
|
||||||
image={controlImage}
|
image={controlImage}
|
||||||
onChange={handleControlImageChanged}
|
onDrop={handleControlImageChanged}
|
||||||
onReset={handleControlImageReset}
|
|
||||||
isDropDisabled={Boolean(processedControlImage)}
|
isDropDisabled={Boolean(processedControlImage)}
|
||||||
fallback={<ProcessedImageFallback />}
|
|
||||||
withResetIcon
|
|
||||||
resetIconSize="sm"
|
|
||||||
/>
|
/>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{controlImage &&
|
{controlImage &&
|
||||||
@ -108,13 +103,10 @@ const ControlNetImagePreview = (props: Props) => {
|
|||||||
h: 'full',
|
h: 'full',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IAISelectableImage
|
<IAIDndImage
|
||||||
image={processedControlImage}
|
image={processedControlImage}
|
||||||
onChange={handleControlImageChanged}
|
onDrop={handleControlImageChanged}
|
||||||
onReset={handleControlImageReset}
|
payloadImage={controlImage}
|
||||||
withResetIcon
|
|
||||||
resetIconSize="sm"
|
|
||||||
fallback={<ProcessedImageFallback />}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@ -131,18 +123,7 @@ const ControlNetImagePreview = (props: Props) => {
|
|||||||
h: 'full',
|
h: 'full',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ProcessedImageFallback />
|
<IAIImageFallback />
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{processedControlImage && !isProcessingControlImage && (
|
|
||||||
<Box sx={{ position: 'absolute', bottom: 0, insetInlineEnd: 0, p: 2 }}>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label="Hide Preview"
|
|
||||||
icon={<TbSquareToggle />}
|
|
||||||
size="sm"
|
|
||||||
onMouseOver={() => setShouldShowProcessedImage(false)}
|
|
||||||
onMouseOut={() => setShouldShowProcessedImage(true)}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@ -150,19 +131,3 @@ const ControlNetImagePreview = (props: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default memo(ControlNetImagePreview);
|
export default memo(ControlNetImagePreview);
|
||||||
|
|
||||||
const ProcessedImageFallback = () => (
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
bg: 'base.900',
|
|
||||||
opacity: 0.7,
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
borderRadius: 'base',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Spinner size="xl" />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
import {
|
||||||
|
ControlNet,
|
||||||
|
controlNetProcessedImageChanged,
|
||||||
|
controlNetRemoved,
|
||||||
|
} from '../store/controlNetSlice';
|
||||||
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
|
import ParamControlNetModel from './parameters/ParamControlNetModel';
|
||||||
|
import ParamControlNetWeight from './parameters/ParamControlNetWeight';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
Tab,
|
||||||
|
TabList,
|
||||||
|
TabPanel,
|
||||||
|
TabPanels,
|
||||||
|
Tabs,
|
||||||
|
Text,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import { FaUndo } from 'react-icons/fa';
|
||||||
|
import ParamControlNetProcessorSelect from './parameters/ParamControlNetProcessorSelect';
|
||||||
|
import ControlNetProcessorComponent from './ControlNetProcessorComponent';
|
||||||
|
import ControlNetPreprocessButton from './ControlNetPreprocessButton';
|
||||||
|
import ParamControlNetBeginEnd from './parameters/ParamControlNetBeginEnd';
|
||||||
|
import ControlNetImagePreview from './ControlNetImagePreview';
|
||||||
|
|
||||||
|
type ControlNetProps = {
|
||||||
|
controlNet: ControlNet;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ControlNet = (props: ControlNetProps) => {
|
||||||
|
const {
|
||||||
|
controlNetId,
|
||||||
|
isEnabled,
|
||||||
|
model,
|
||||||
|
weight,
|
||||||
|
beginStepPct,
|
||||||
|
endStepPct,
|
||||||
|
controlImage,
|
||||||
|
isControlImageProcessed,
|
||||||
|
processedControlImage,
|
||||||
|
processorNode,
|
||||||
|
} = props.controlNet;
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const handleReset = useCallback(() => {
|
||||||
|
dispatch(
|
||||||
|
controlNetProcessedImageChanged({
|
||||||
|
controlNetId,
|
||||||
|
processedControlImage: null,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}, [controlNetId, dispatch]);
|
||||||
|
|
||||||
|
const handleControlNetRemoved = useCallback(() => {
|
||||||
|
dispatch(controlNetRemoved(controlNetId));
|
||||||
|
}, [controlNetId, dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
gap: 4,
|
||||||
|
p: 2,
|
||||||
|
paddingInlineEnd: 4,
|
||||||
|
bg: 'base.850',
|
||||||
|
borderRadius: 'base',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
h: 36,
|
||||||
|
w: 36,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ControlNetImagePreview
|
||||||
|
controlNetId={controlNetId}
|
||||||
|
controlImage={controlImage}
|
||||||
|
processedControlImage={processedControlImage}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex sx={{ flexDir: 'column', gap: 2, w: 'full', h: 'full' }}>
|
||||||
|
<ParamControlNetModel controlNetId={controlNetId} model={model} />
|
||||||
|
<ParamControlNetWeight
|
||||||
|
controlNetId={controlNetId}
|
||||||
|
weight={weight}
|
||||||
|
mini
|
||||||
|
/>
|
||||||
|
<ParamControlNetBeginEnd
|
||||||
|
controlNetId={controlNetId}
|
||||||
|
beginStepPct={beginStepPct}
|
||||||
|
endStepPct={endStepPct}
|
||||||
|
mini
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ControlNet);
|
@ -4,11 +4,12 @@ import {
|
|||||||
Icon,
|
Icon,
|
||||||
IconButtonProps,
|
IconButtonProps,
|
||||||
Image,
|
Image,
|
||||||
Spinner,
|
|
||||||
Text,
|
Text,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { useDroppable } from '@dnd-kit/core';
|
import { useDraggable, useDroppable } from '@dnd-kit/core';
|
||||||
|
import { useCombinedRefs } from '@dnd-kit/utilities';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import { IAIImageFallback } from 'common/components/IAIImageFallback';
|
||||||
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
|
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
|
||||||
import { useGetUrl } from 'common/util/getUrl';
|
import { useGetUrl } from 'common/util/getUrl';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
@ -18,42 +19,65 @@ import { FaImage, FaTimes } from 'react-icons/fa';
|
|||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
const PLACEHOLDER_MIN_HEIGHT = 48;
|
const PLACEHOLDER_MIN_HEIGHT = 36;
|
||||||
|
|
||||||
type IAISelectableImageProps = {
|
type IAISelectableImageProps = {
|
||||||
image: ImageDTO | null | undefined;
|
image: ImageDTO | null | undefined;
|
||||||
onChange: (image: ImageDTO) => void;
|
onDrop: (image: ImageDTO) => void;
|
||||||
onReset?: () => void;
|
onReset?: () => void;
|
||||||
onError?: (event: SyntheticEvent<HTMLImageElement>) => void;
|
onError?: (event: SyntheticEvent<HTMLImageElement>) => void;
|
||||||
|
onLoad?: (event: SyntheticEvent<HTMLImageElement>) => void;
|
||||||
resetIconSize?: IconButtonProps['size'];
|
resetIconSize?: IconButtonProps['size'];
|
||||||
withResetIcon?: boolean;
|
withResetIcon?: boolean;
|
||||||
withMetadataOverlay?: boolean;
|
withMetadataOverlay?: boolean;
|
||||||
|
isDragDisabled?: boolean;
|
||||||
isDropDisabled?: boolean;
|
isDropDisabled?: boolean;
|
||||||
fallback?: ReactElement;
|
fallback?: ReactElement;
|
||||||
|
payloadImage?: ImageDTO | null | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const IAISelectableImage = (props: IAISelectableImageProps) => {
|
const IAIDndImage = (props: IAISelectableImageProps) => {
|
||||||
const {
|
const {
|
||||||
image,
|
image,
|
||||||
onChange,
|
onDrop,
|
||||||
onReset,
|
onReset,
|
||||||
onError,
|
onError,
|
||||||
resetIconSize = 'md',
|
resetIconSize = 'md',
|
||||||
withResetIcon = false,
|
withResetIcon = false,
|
||||||
withMetadataOverlay = false,
|
withMetadataOverlay = false,
|
||||||
isDropDisabled = false,
|
isDropDisabled = false,
|
||||||
fallback = <ImageFallback />,
|
isDragDisabled = false,
|
||||||
|
fallback = <IAIImageFallback />,
|
||||||
|
payloadImage,
|
||||||
} = props;
|
} = props;
|
||||||
const droppableId = useRef(uuidv4());
|
const dndId = useRef(uuidv4());
|
||||||
const { getUrl } = useGetUrl();
|
const { getUrl } = useGetUrl();
|
||||||
const { isOver, setNodeRef, active } = useDroppable({
|
const {
|
||||||
id: droppableId.current,
|
isOver,
|
||||||
|
setNodeRef: setDroppableRef,
|
||||||
|
active,
|
||||||
|
} = useDroppable({
|
||||||
|
id: dndId.current,
|
||||||
disabled: isDropDisabled,
|
disabled: isDropDisabled,
|
||||||
data: {
|
data: {
|
||||||
handleDrop: onChange,
|
handleDrop: onDrop,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef: setDraggableRef,
|
||||||
|
} = useDraggable({
|
||||||
|
id: dndId.current,
|
||||||
|
data: {
|
||||||
|
image: payloadImage ? payloadImage : image,
|
||||||
|
},
|
||||||
|
disabled: isDragDisabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setNodeRef = useCombinedRefs(setDroppableRef, setDraggableRef);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
@ -62,7 +86,11 @@ const IAISelectableImage = (props: IAISelectableImageProps) => {
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
minW: 36,
|
||||||
|
minH: 36,
|
||||||
}}
|
}}
|
||||||
|
{...attributes}
|
||||||
|
{...listeners}
|
||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
>
|
>
|
||||||
{image && (
|
{image && (
|
||||||
@ -80,8 +108,11 @@ const IAISelectableImage = (props: IAISelectableImageProps) => {
|
|||||||
fallbackStrategy="beforeLoadOrError"
|
fallbackStrategy="beforeLoadOrError"
|
||||||
fallback={fallback}
|
fallback={fallback}
|
||||||
onError={onError}
|
onError={onError}
|
||||||
|
objectFit="contain"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
sx={{
|
sx={{
|
||||||
|
maxW: 'full',
|
||||||
|
maxH: 'full',
|
||||||
borderRadius: 'base',
|
borderRadius: 'base',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -139,7 +170,7 @@ const IAISelectableImage = (props: IAISelectableImageProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(IAISelectableImage);
|
export default memo(IAIDndImage);
|
||||||
|
|
||||||
type DropOverlayProps = {
|
type DropOverlayProps = {
|
||||||
isOver: boolean;
|
isOver: boolean;
|
||||||
@ -179,14 +210,15 @@ const DropOverlay = (props: DropOverlayProps) => {
|
|||||||
w: 'full',
|
w: 'full',
|
||||||
h: 'full',
|
h: 'full',
|
||||||
bg: 'base.900',
|
bg: 'base.900',
|
||||||
opacity: isOver ? 0.9 : 0.7,
|
opacity: 0.7,
|
||||||
borderRadius: 'base',
|
borderRadius: 'base',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
transitionProperty: 'common',
|
transitionProperty: 'common',
|
||||||
transitionDuration: '0.15s',
|
transitionDuration: '0.1s',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@ -194,51 +226,31 @@ const DropOverlay = (props: DropOverlayProps) => {
|
|||||||
left: 0,
|
left: 0,
|
||||||
w: 'full',
|
w: 'full',
|
||||||
h: 'full',
|
h: 'full',
|
||||||
opacity: isOver ? 1 : 0.9,
|
opacity: 1,
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
transitionProperty: 'common',
|
|
||||||
transitionDuration: '0.15s',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text sx={{ fontSize: '2xl', fontWeight: 600, color: 'base.200' }}>
|
|
||||||
Drop Image
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
opacity: isOver ? 1 : 0.7,
|
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
borderColor: 'base.500',
|
borderColor: isOver ? 'base.200' : 'base.500',
|
||||||
borderRadius: 'base',
|
borderRadius: 'base',
|
||||||
borderStyle: 'dashed',
|
borderStyle: 'dashed',
|
||||||
transitionProperty: 'common',
|
transitionProperty: 'common',
|
||||||
transitionDuration: '0.15s',
|
transitionDuration: '0.1s',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
></Flex>
|
>
|
||||||
|
<Text
|
||||||
|
sx={{
|
||||||
|
fontSize: '2xl',
|
||||||
|
fontWeight: 600,
|
||||||
|
transform: isOver ? 'scale(1.1)' : 'scale(1)',
|
||||||
|
color: isOver ? 'base.100' : 'base.500',
|
||||||
|
transitionProperty: 'common',
|
||||||
|
transitionDuration: '0.1s',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Drop
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ImageFallback = () => (
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
minH: PLACEHOLDER_MIN_HEIGHT,
|
|
||||||
color: 'base.400',
|
|
||||||
bg: 'base.850',
|
|
||||||
borderRadius: 'base',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Spinner size="xl" />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
|
@ -23,12 +23,13 @@ type Props = {
|
|||||||
controlNetId: string;
|
controlNetId: string;
|
||||||
beginStepPct: number;
|
beginStepPct: number;
|
||||||
endStepPct: number;
|
endStepPct: number;
|
||||||
|
mini?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatPct = (v: number) => `${Math.round(v * 100)}%`;
|
const formatPct = (v: number) => `${Math.round(v * 100)}%`;
|
||||||
|
|
||||||
const ParamControlNetBeginEnd = (props: Props) => {
|
const ParamControlNetBeginEnd = (props: Props) => {
|
||||||
const { controlNetId, beginStepPct, endStepPct } = props;
|
const { controlNetId, beginStepPct, endStepPct, mini = false } = props;
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -69,6 +70,9 @@ const ParamControlNetBeginEnd = (props: Props) => {
|
|||||||
<Tooltip label={formatPct(endStepPct)} placement="top" hasArrow>
|
<Tooltip label={formatPct(endStepPct)} placement="top" hasArrow>
|
||||||
<RangeSliderThumb index={1} />
|
<RangeSliderThumb index={1} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{!mini && (
|
||||||
|
<>
|
||||||
|
{' '}
|
||||||
<RangeSliderMark
|
<RangeSliderMark
|
||||||
value={0}
|
value={0}
|
||||||
sx={{
|
sx={{
|
||||||
@ -106,8 +110,11 @@ const ParamControlNetBeginEnd = (props: Props) => {
|
|||||||
>
|
>
|
||||||
100%
|
100%
|
||||||
</RangeSliderMark>
|
</RangeSliderMark>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</RangeSlider>
|
</RangeSlider>
|
||||||
|
|
||||||
|
{!mini && (
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
size="sm"
|
size="sm"
|
||||||
aria-label={t('accessibility.reset')}
|
aria-label={t('accessibility.reset')}
|
||||||
@ -115,6 +122,7 @@ const ParamControlNetBeginEnd = (props: Props) => {
|
|||||||
icon={<BiReset />}
|
icon={<BiReset />}
|
||||||
onClick={handleStepPctReset}
|
onClick={handleStepPctReset}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
|
@ -6,10 +6,11 @@ import { memo, useCallback } from 'react';
|
|||||||
type ParamControlNetWeightProps = {
|
type ParamControlNetWeightProps = {
|
||||||
controlNetId: string;
|
controlNetId: string;
|
||||||
weight: number;
|
weight: number;
|
||||||
|
mini?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ParamControlNetWeight = (props: ParamControlNetWeightProps) => {
|
const ParamControlNetWeight = (props: ParamControlNetWeightProps) => {
|
||||||
const { controlNetId, weight } = props;
|
const { controlNetId, weight, mini = false } = props;
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const handleWeightChanged = useCallback(
|
const handleWeightChanged = useCallback(
|
||||||
@ -23,6 +24,20 @@ const ParamControlNetWeight = (props: ParamControlNetWeightProps) => {
|
|||||||
dispatch(controlNetWeightChanged({ controlNetId, weight: 1 }));
|
dispatch(controlNetWeightChanged({ controlNetId, weight: 1 }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (mini) {
|
||||||
|
return (
|
||||||
|
<IAISlider
|
||||||
|
label={'Weight'}
|
||||||
|
sliderFormLabelProps={{ pb: 1 }}
|
||||||
|
value={weight}
|
||||||
|
onChange={handleWeightChanged}
|
||||||
|
min={0}
|
||||||
|
max={1}
|
||||||
|
step={0.01}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAISlider
|
<IAISlider
|
||||||
label="Weight"
|
label="Weight"
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
import { Box, Flex, Image } from '@chakra-ui/react';
|
import { Box, Flex, Image } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { useGetUrl } from 'common/util/getUrl';
|
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
import { gallerySelector } from '../store/gallerySelectors';
|
import { gallerySelector } from '../store/gallerySelectors';
|
||||||
import ImageMetadataViewer from './ImageMetaDataViewer/ImageMetadataViewer';
|
import ImageMetadataViewer from './ImageMetaDataViewer/ImageMetadataViewer';
|
||||||
import NextPrevImageButtons from './NextPrevImageButtons';
|
import NextPrevImageButtons from './NextPrevImageButtons';
|
||||||
import { DragEvent, memo, useCallback, useEffect, useState } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||||
import ImageFallbackSpinner from './ImageFallbackSpinner';
|
|
||||||
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
|
|
||||||
import { configSelector } from '../../system/store/configSelectors';
|
import { configSelector } from '../../system/store/configSelectors';
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
import { imageSelected } from '../store/gallerySlice';
|
import { imageSelected } from '../store/gallerySlice';
|
||||||
import { useDraggable } from '@dnd-kit/core';
|
import IAIDndImage from 'features/controlNet/components/parameters/IAISelectableImage';
|
||||||
|
import { ImageDTO } from 'services/api';
|
||||||
|
import { IAIImageFallback } from 'common/components/IAIImageFallback';
|
||||||
|
|
||||||
export const imagesSelector = createSelector(
|
export const imagesSelector = createSelector(
|
||||||
[uiSelector, gallerySelector, systemSelector],
|
[uiSelector, gallerySelector, systemSelector],
|
||||||
@ -52,17 +51,8 @@ const CurrentImagePreview = () => {
|
|||||||
shouldAntialiasProgressImage,
|
shouldAntialiasProgressImage,
|
||||||
} = useAppSelector(imagesSelector);
|
} = useAppSelector(imagesSelector);
|
||||||
const { shouldFetchImages } = useAppSelector(configSelector);
|
const { shouldFetchImages } = useAppSelector(configSelector);
|
||||||
const { getUrl } = useGetUrl();
|
|
||||||
const toaster = useAppToaster();
|
const toaster = useAppToaster();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const [isLoaded, setIsLoaded] = useState(false);
|
|
||||||
|
|
||||||
const { attributes, listeners, setNodeRef } = useDraggable({
|
|
||||||
id: `currentImage_${image?.image_name}`,
|
|
||||||
data: {
|
|
||||||
image,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleError = useCallback(() => {
|
const handleError = useCallback(() => {
|
||||||
dispatch(imageSelected());
|
dispatch(imageSelected());
|
||||||
@ -75,9 +65,12 @@ const CurrentImagePreview = () => {
|
|||||||
}
|
}
|
||||||
}, [dispatch, toaster, shouldFetchImages]);
|
}, [dispatch, toaster, shouldFetchImages]);
|
||||||
|
|
||||||
useEffect(() => {
|
const handleDrop = useCallback(
|
||||||
setIsLoaded(false);
|
(droppedImage: ImageDTO) => {
|
||||||
}, [image]);
|
dispatch(imageSelected(droppedImage));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
@ -108,42 +101,28 @@ const CurrentImagePreview = () => {
|
|||||||
image && (
|
image && (
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
|
width: 'full',
|
||||||
|
height: 'full',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
position: 'absolute',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Image
|
<IAIDndImage
|
||||||
ref={setNodeRef}
|
image={image}
|
||||||
{...listeners}
|
onDrop={handleDrop}
|
||||||
{...attributes}
|
|
||||||
src={getUrl(image.image_url)}
|
|
||||||
fallbackStrategy="beforeLoadOrError"
|
|
||||||
fallback={<ImageFallbackSpinner />}
|
|
||||||
sx={{
|
|
||||||
objectFit: 'contain',
|
|
||||||
maxWidth: '100%',
|
|
||||||
maxHeight: '100%',
|
|
||||||
height: 'auto',
|
|
||||||
borderRadius: 'base',
|
|
||||||
touchAction: 'none',
|
|
||||||
}}
|
|
||||||
onError={handleError}
|
onError={handleError}
|
||||||
onLoad={() => {
|
fallback={<IAIImageFallback sx={{ bg: 'none' }} />}
|
||||||
setIsLoaded(true);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{isLoaded && <ImageMetadataOverlay image={image} />}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
{shouldShowImageDetails && image && 'metadata' in image && (
|
{shouldShowImageDetails && image && image.metadata && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '0',
|
top: '0',
|
||||||
width: '100%',
|
width: 'full',
|
||||||
height: '100%',
|
height: 'full',
|
||||||
borderRadius: 'base',
|
borderRadius: 'base',
|
||||||
overflow: 'scroll',
|
overflow: 'scroll',
|
||||||
}}
|
}}
|
||||||
@ -151,7 +130,19 @@ const CurrentImagePreview = () => {
|
|||||||
<ImageMetadataViewer image={image} />
|
<ImageMetadataViewer image={image} />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{!shouldShowImageDetails && <NextPrevImageButtons />}
|
{!shouldShowImageDetails && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '0',
|
||||||
|
width: 'full',
|
||||||
|
height: 'full',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<NextPrevImageButtons />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
|
|
||||||
import { FieldComponentProps } from './types';
|
import { FieldComponentProps } from './types';
|
||||||
import IAISelectableImage from 'features/controlNet/components/parameters/IAISelectableImage';
|
import IAIDndImage from 'features/controlNet/components/parameters/IAISelectableImage';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api';
|
||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
|
||||||
@ -51,9 +51,9 @@ const ImageInputFieldComponent = (
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IAISelectableImage
|
<IAIDndImage
|
||||||
image={field.value}
|
image={field.value}
|
||||||
onChange={handleChange}
|
onDrop={handleChange}
|
||||||
onReset={handleReset}
|
onReset={handleReset}
|
||||||
resetIconSize="sm"
|
resetIconSize="sm"
|
||||||
/>
|
/>
|
||||||
|
@ -24,6 +24,8 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|||||||
import { map, startCase } from 'lodash-es';
|
import { map, startCase } from 'lodash-es';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { CloseIcon } from '@chakra-ui/icons';
|
import { CloseIcon } from '@chakra-ui/icons';
|
||||||
|
import ControlNetMini from 'features/controlNet/components/ControlNetMini';
|
||||||
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
controlNetSelector,
|
controlNetSelector,
|
||||||
@ -38,6 +40,7 @@ const selector = createSelector(
|
|||||||
const ParamControlNetCollapse = () => {
|
const ParamControlNetCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { controlNetsArray, isEnabled } = useAppSelector(selector);
|
const { controlNetsArray, isEnabled } = useAppSelector(selector);
|
||||||
|
const isControlNetDisabled = useFeatureStatus('controlNet').isFeatureDisabled;
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const handleClickControlNetToggle = useCallback(() => {
|
const handleClickControlNetToggle = useCallback(() => {
|
||||||
@ -48,6 +51,18 @@ const ParamControlNetCollapse = () => {
|
|||||||
dispatch(controlNetAdded({ controlNetId: uuidv4() }));
|
dispatch(controlNetAdded({ controlNetId: uuidv4() }));
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
|
if (isControlNetDisabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{controlNetsArray.map((c) => (
|
||||||
|
<ControlNetMini key={c.controlNetId} controlNet={c} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse
|
||||||
label={'ControlNet'}
|
label={'ControlNet'}
|
||||||
@ -80,6 +95,7 @@ const ParamControlNetCollapse = () => {
|
|||||||
{controlNetsArray.map((c) => (
|
{controlNetsArray.map((c) => (
|
||||||
<TabPanel key={`tabPanel_${c.controlNetId}`} sx={{ p: 0 }}>
|
<TabPanel key={`tabPanel_${c.controlNetId}`} sx={{ p: 0 }}>
|
||||||
<ControlNet controlNet={c} />
|
<ControlNet controlNet={c} />
|
||||||
|
{/* <ControlNetMini controlNet={c} /> */}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
))}
|
))}
|
||||||
</TabPanels>
|
</TabPanels>
|
||||||
|
@ -12,8 +12,9 @@ import { generationSelector } from 'features/parameters/store/generationSelector
|
|||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import { configSelector } from '../../../../system/store/configSelectors';
|
import { configSelector } from '../../../../system/store/configSelectors';
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
import IAISelectableImage from 'features/controlNet/components/parameters/IAISelectableImage';
|
import IAIDndImage from 'features/controlNet/components/parameters/IAISelectableImage';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api';
|
||||||
|
import { IAIImageFallback } from 'common/components/IAIImageFallback';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[generationSelector],
|
[generationSelector],
|
||||||
@ -73,10 +74,11 @@ const InitialImagePreview = () => {
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IAISelectableImage
|
<IAIDndImage
|
||||||
image={initialImage}
|
image={initialImage}
|
||||||
onChange={handleChange}
|
onDrop={handleChange}
|
||||||
onReset={handleReset}
|
onReset={handleReset}
|
||||||
|
fallback={<IAIImageFallback sx={{ bg: 'none' }} />}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
@ -953,6 +953,14 @@
|
|||||||
"@dnd-kit/utilities" "^3.2.1"
|
"@dnd-kit/utilities" "^3.2.1"
|
||||||
tslib "^2.0.0"
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
"@dnd-kit/modifiers@^6.0.1":
|
||||||
|
version "6.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@dnd-kit/modifiers/-/modifiers-6.0.1.tgz#9e39b25fd6e323659604cc74488fe044d33188c8"
|
||||||
|
integrity sha512-rbxcsg3HhzlcMHVHWDuh9LCjpOVAgqbV78wLGI8tziXY3+qcMQ61qVXIvNKQFuhj75dSfD+o+PYZQ/NUk2A23A==
|
||||||
|
dependencies:
|
||||||
|
"@dnd-kit/utilities" "^3.2.1"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
"@dnd-kit/utilities@^3.2.1":
|
"@dnd-kit/utilities@^3.2.1":
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-3.2.1.tgz#53f9e2016fd2506ec49e404c289392cfff30332a"
|
resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-3.2.1.tgz#53f9e2016fd2506ec49e404c289392cfff30332a"
|
||||||
|
Loading…
Reference in New Issue
Block a user