mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
chore(ui): delete unused files
This commit is contained in:
parent
71e298b722
commit
5eaea9dd64
@ -1,43 +0,0 @@
|
|||||||
import { Box, Flex, Icon } from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { FaExclamation } from 'react-icons/fa';
|
|
||||||
|
|
||||||
const IAIErrorLoadingImageFallback = () => {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: 'relative',
|
|
||||||
height: 'full',
|
|
||||||
width: 'full',
|
|
||||||
'::before': {
|
|
||||||
content: "''",
|
|
||||||
display: 'block',
|
|
||||||
pt: '100%',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
insetInlineStart: 0,
|
|
||||||
height: 'full',
|
|
||||||
width: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
borderRadius: 'base',
|
|
||||||
bg: 'base.100',
|
|
||||||
color: 'base.500',
|
|
||||||
_dark: {
|
|
||||||
color: 'base.700',
|
|
||||||
bg: 'base.850',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon as={FaExclamation} boxSize={16} opacity={0.7} />
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(IAIErrorLoadingImageFallback);
|
|
@ -1,8 +0,0 @@
|
|||||||
import { chakra } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chakra-enabled <form />
|
|
||||||
*/
|
|
||||||
const IAIForm = chakra.form;
|
|
||||||
|
|
||||||
export default IAIForm;
|
|
@ -1,15 +0,0 @@
|
|||||||
import { FormErrorMessage, FormErrorMessageProps } from '@chakra-ui/react';
|
|
||||||
import { ReactNode } from 'react';
|
|
||||||
|
|
||||||
type IAIFormErrorMessageProps = FormErrorMessageProps & {
|
|
||||||
children: ReactNode | string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function IAIFormErrorMessage(props: IAIFormErrorMessageProps) {
|
|
||||||
const { children, ...rest } = props;
|
|
||||||
return (
|
|
||||||
<FormErrorMessage color="error.400" {...rest}>
|
|
||||||
{children}
|
|
||||||
</FormErrorMessage>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
import { FormHelperText, FormHelperTextProps } from '@chakra-ui/react';
|
|
||||||
import { ReactNode } from 'react';
|
|
||||||
|
|
||||||
type IAIFormHelperTextProps = FormHelperTextProps & {
|
|
||||||
children: ReactNode | string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function IAIFormHelperText(props: IAIFormHelperTextProps) {
|
|
||||||
const { children, ...rest } = props;
|
|
||||||
return (
|
|
||||||
<FormHelperText margin={0} color="base.400" {...rest}>
|
|
||||||
{children}
|
|
||||||
</FormHelperText>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import { Flex, useColorMode } from '@chakra-ui/react';
|
|
||||||
import { ReactElement } from 'react';
|
|
||||||
import { mode } from 'theme/util/mode';
|
|
||||||
|
|
||||||
export function IAIFormItemWrapper({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: ReactElement | ReactElement[];
|
|
||||||
}) {
|
|
||||||
const { colorMode } = useColorMode();
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
padding: 4,
|
|
||||||
rowGap: 4,
|
|
||||||
borderRadius: 'base',
|
|
||||||
width: 'full',
|
|
||||||
bg: mode('base.100', 'base.900')(colorMode),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import {
|
|
||||||
Checkbox,
|
|
||||||
CheckboxProps,
|
|
||||||
FormControl,
|
|
||||||
FormControlProps,
|
|
||||||
FormLabel,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { memo, ReactNode } from 'react';
|
|
||||||
|
|
||||||
type IAIFullCheckboxProps = CheckboxProps & {
|
|
||||||
label: string | ReactNode;
|
|
||||||
formControlProps?: FormControlProps;
|
|
||||||
};
|
|
||||||
|
|
||||||
const IAIFullCheckbox = (props: IAIFullCheckboxProps) => {
|
|
||||||
const { label, formControlProps, ...rest } = props;
|
|
||||||
return (
|
|
||||||
<FormControl {...formControlProps}>
|
|
||||||
<FormLabel>{label}</FormLabel>
|
|
||||||
<Checkbox colorScheme="accent" {...rest} />
|
|
||||||
</FormControl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(IAIFullCheckbox);
|
|
@ -1,23 +0,0 @@
|
|||||||
import { Flex, Icon } from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { FaImage } from 'react-icons/fa';
|
|
||||||
|
|
||||||
const SelectImagePlaceholder = () => {
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
// bg: 'base.800',
|
|
||||||
borderRadius: 'base',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
aspectRatio: '1/1',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon color="base.400" boxSize={32} as={FaImage}></Icon>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(SelectImagePlaceholder);
|
|
@ -1,24 +0,0 @@
|
|||||||
import { useBreakpoint } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export default function useResolution():
|
|
||||||
| 'mobile'
|
|
||||||
| 'tablet'
|
|
||||||
| 'desktop'
|
|
||||||
| 'unknown' {
|
|
||||||
const breakpointValue = useBreakpoint();
|
|
||||||
|
|
||||||
const mobileResolutions = ['base', 'sm'];
|
|
||||||
const tabletResolutions = ['md', 'lg'];
|
|
||||||
const desktopResolutions = ['xl', '2xl'];
|
|
||||||
|
|
||||||
if (mobileResolutions.includes(breakpointValue)) {
|
|
||||||
return 'mobile';
|
|
||||||
}
|
|
||||||
if (tabletResolutions.includes(breakpointValue)) {
|
|
||||||
return 'tablet';
|
|
||||||
}
|
|
||||||
if (desktopResolutions.includes(breakpointValue)) {
|
|
||||||
return 'desktop';
|
|
||||||
}
|
|
||||||
return 'unknown';
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import dateFormat from 'dateformat';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a `now` timestamp with 1s precision, formatted as ISO datetime.
|
|
||||||
*/
|
|
||||||
export const getTimestamp = () =>
|
|
||||||
dateFormat(new Date(), `yyyy-mm-dd'T'HH:MM:ss:lo`);
|
|
@ -1,71 +0,0 @@
|
|||||||
// TODO: Restore variations
|
|
||||||
// Support code from v2.3 in here.
|
|
||||||
|
|
||||||
// export const stringToSeedWeights = (
|
|
||||||
// string: string
|
|
||||||
// ): InvokeAI.SeedWeights | boolean => {
|
|
||||||
// const stringPairs = string.split(',');
|
|
||||||
// const arrPairs = stringPairs.map((p) => p.split(':'));
|
|
||||||
// const pairs = arrPairs.map((p: Array<string>): InvokeAI.SeedWeightPair => {
|
|
||||||
// return { seed: Number(p[0]), weight: Number(p[1]) };
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (!validateSeedWeights(pairs)) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return pairs;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const validateSeedWeights = (
|
|
||||||
// seedWeights: InvokeAI.SeedWeights | string
|
|
||||||
// ): boolean => {
|
|
||||||
// return typeof seedWeights === 'string'
|
|
||||||
// ? Boolean(stringToSeedWeights(seedWeights))
|
|
||||||
// : Boolean(
|
|
||||||
// seedWeights.length &&
|
|
||||||
// !seedWeights.some((pair: InvokeAI.SeedWeightPair) => {
|
|
||||||
// const { seed, weight } = pair;
|
|
||||||
// const isSeedValid = !isNaN(parseInt(seed.toString(), 10));
|
|
||||||
// const isWeightValid =
|
|
||||||
// !isNaN(parseInt(weight.toString(), 10)) &&
|
|
||||||
// weight >= 0 &&
|
|
||||||
// weight <= 1;
|
|
||||||
// return !(isSeedValid && isWeightValid);
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const seedWeightsToString = (
|
|
||||||
// seedWeights: InvokeAI.SeedWeights
|
|
||||||
// ): string => {
|
|
||||||
// return seedWeights.reduce((acc, pair, i, arr) => {
|
|
||||||
// const { seed, weight } = pair;
|
|
||||||
// acc += `${seed}:${weight}`;
|
|
||||||
// if (i !== arr.length - 1) {
|
|
||||||
// acc += ',';
|
|
||||||
// }
|
|
||||||
// return acc;
|
|
||||||
// }, '');
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const seedWeightsToArray = (
|
|
||||||
// seedWeights: InvokeAI.SeedWeights
|
|
||||||
// ): Array<Array<number>> => {
|
|
||||||
// return seedWeights.map((pair: InvokeAI.SeedWeightPair) => [
|
|
||||||
// pair.seed,
|
|
||||||
// pair.weight,
|
|
||||||
// ]);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const stringToSeedWeightsArray = (
|
|
||||||
// string: string
|
|
||||||
// ): Array<Array<number>> => {
|
|
||||||
// const stringPairs = string.split(',');
|
|
||||||
// const arrPairs = stringPairs.map((p) => p.split(':'));
|
|
||||||
// return arrPairs.map(
|
|
||||||
// (p: Array<string>): Array<number> => [parseInt(p[0], 10), parseFloat(p[1])]
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
export default {};
|
|
@ -1,16 +0,0 @@
|
|||||||
import Konva from 'konva';
|
|
||||||
import { IRect } from 'konva/lib/types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a Konva node to a dataURL
|
|
||||||
* @param node - The Konva node to convert to a dataURL
|
|
||||||
* @param boundingBox - The bounding box to crop to
|
|
||||||
* @returns A dataURL of the node cropped to the bounding box
|
|
||||||
*/
|
|
||||||
export const konvaNodeToDataURL = (
|
|
||||||
node: Konva.Node,
|
|
||||||
boundingBox: IRect
|
|
||||||
): string => {
|
|
||||||
// get a dataURL of the bbox'd region
|
|
||||||
return node.toDataURL(boundingBox);
|
|
||||||
};
|
|
@ -1,36 +0,0 @@
|
|||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
|
||||||
import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue';
|
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
import { useControlAdapterControlImage } from '../hooks/useControlAdapterControlImage';
|
|
||||||
import { controlAdapterImageProcessed } from '../store/actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ControlAdapterPreprocessButton = ({ id }: Props) => {
|
|
||||||
const controlImage = useControlAdapterControlImage(id);
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const isReady = useIsReadyToEnqueue();
|
|
||||||
|
|
||||||
const handleProcess = useCallback(() => {
|
|
||||||
dispatch(
|
|
||||||
controlAdapterImageProcessed({
|
|
||||||
id,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}, [id, dispatch]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIButton
|
|
||||||
size="sm"
|
|
||||||
onClick={handleProcess}
|
|
||||||
isDisabled={Boolean(!controlImage) || !isReady}
|
|
||||||
>
|
|
||||||
Preprocess
|
|
||||||
</IAIButton>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ControlAdapterPreprocessButton);
|
|
@ -1,108 +0,0 @@
|
|||||||
import { As, Badge, Flex } from '@chakra-ui/react';
|
|
||||||
import IAIDroppable from 'common/components/IAIDroppable';
|
|
||||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
|
||||||
import { TypesafeDroppableData } from 'features/dnd/types';
|
|
||||||
import { BoardId } from 'features/gallery/store/types';
|
|
||||||
import { ReactNode, memo } from 'react';
|
|
||||||
import BoardContextMenu from '../BoardContextMenu';
|
|
||||||
|
|
||||||
type GenericBoardProps = {
|
|
||||||
board_id: BoardId;
|
|
||||||
droppableData?: TypesafeDroppableData;
|
|
||||||
onClick: () => void;
|
|
||||||
isSelected: boolean;
|
|
||||||
icon: As;
|
|
||||||
label: string;
|
|
||||||
dropLabel?: ReactNode;
|
|
||||||
badgeCount?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const formatBadgeCount = (count: number) =>
|
|
||||||
Intl.NumberFormat('en-US', {
|
|
||||||
notation: 'compact',
|
|
||||||
maximumFractionDigits: 1,
|
|
||||||
}).format(count);
|
|
||||||
|
|
||||||
const GenericBoard = (props: GenericBoardProps) => {
|
|
||||||
const {
|
|
||||||
board_id,
|
|
||||||
droppableData,
|
|
||||||
onClick,
|
|
||||||
isSelected,
|
|
||||||
icon,
|
|
||||||
label,
|
|
||||||
badgeCount,
|
|
||||||
dropLabel,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BoardContextMenu board_id={board_id}>
|
|
||||||
{(ref) => (
|
|
||||||
<Flex
|
|
||||||
ref={ref}
|
|
||||||
sx={{
|
|
||||||
flexDir: 'column',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
cursor: 'pointer',
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
borderRadius: 'base',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Flex
|
|
||||||
onClick={onClick}
|
|
||||||
sx={{
|
|
||||||
position: 'relative',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
borderRadius: 'base',
|
|
||||||
w: 'full',
|
|
||||||
aspectRatio: '1/1',
|
|
||||||
overflow: 'hidden',
|
|
||||||
shadow: isSelected ? 'selected.light' : undefined,
|
|
||||||
_dark: { shadow: isSelected ? 'selected.dark' : undefined },
|
|
||||||
flexShrink: 0,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IAINoContentFallback
|
|
||||||
boxSize={8}
|
|
||||||
icon={icon}
|
|
||||||
sx={{
|
|
||||||
border: '2px solid var(--invokeai-colors-base-200)',
|
|
||||||
_dark: { border: '2px solid var(--invokeai-colors-base-800)' },
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
position: 'absolute',
|
|
||||||
insetInlineEnd: 0,
|
|
||||||
top: 0,
|
|
||||||
p: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{badgeCount !== undefined && (
|
|
||||||
<Badge variant="solid">{formatBadgeCount(badgeCount)}</Badge>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
<IAIDroppable data={droppableData} dropLabel={dropLabel} />
|
|
||||||
</Flex>
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
h: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
fontWeight: isSelected ? 600 : undefined,
|
|
||||||
fontSize: 'sm',
|
|
||||||
color: isSelected ? 'base.900' : 'base.700',
|
|
||||||
_dark: { color: isSelected ? 'base.50' : 'base.200' },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
</BoardContextMenu>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(GenericBoard);
|
|
@ -1,53 +0,0 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
|
||||||
import { boardIdSelected } from 'features/gallery/store/gallerySlice';
|
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
|
||||||
import { useBoardName } from 'services/api/hooks/useBoardName';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
board_id: 'images' | 'assets' | 'no_board';
|
|
||||||
};
|
|
||||||
|
|
||||||
const SystemBoardButton = ({ board_id }: Props) => {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const selector = useMemo(
|
|
||||||
() =>
|
|
||||||
createSelector(
|
|
||||||
[stateSelector],
|
|
||||||
({ gallery }) => {
|
|
||||||
const { selectedBoardId } = gallery;
|
|
||||||
return { isSelected: selectedBoardId === board_id };
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
),
|
|
||||||
[board_id]
|
|
||||||
);
|
|
||||||
|
|
||||||
const { isSelected } = useAppSelector(selector);
|
|
||||||
|
|
||||||
const boardName = useBoardName(board_id);
|
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
|
||||||
dispatch(boardIdSelected({ boardId: board_id }));
|
|
||||||
}, [board_id, dispatch]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIButton
|
|
||||||
onClick={handleClick}
|
|
||||||
size="sm"
|
|
||||||
isChecked={isSelected}
|
|
||||||
sx={{
|
|
||||||
flexGrow: 1,
|
|
||||||
borderRadius: 'base',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{boardName}
|
|
||||||
</IAIButton>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(SystemBoardButton);
|
|
@ -1,22 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { FaEyeSlash } from 'react-icons/fa';
|
|
||||||
|
|
||||||
const CurrentImageHidden = () => {
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
position: 'absolute',
|
|
||||||
color: 'base.400',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FaEyeSlash fontSize="25vh" />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(CurrentImageHidden);
|
|
@ -1,27 +0,0 @@
|
|||||||
import { Flex, Spinner, SpinnerProps } from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
type ImageFallbackSpinnerProps = SpinnerProps;
|
|
||||||
|
|
||||||
const ImageFallbackSpinner = (props: ImageFallbackSpinnerProps) => {
|
|
||||||
const { size = 'xl', ...rest } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
position: 'absolute',
|
|
||||||
color: 'base.400',
|
|
||||||
minH: 36,
|
|
||||||
minW: 36,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Spinner size={size} {...rest} />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ImageFallbackSpinner);
|
|
@ -1,14 +0,0 @@
|
|||||||
import {
|
|
||||||
ClipInputFieldTemplate,
|
|
||||||
ClipInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const ClipInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<ClipInputFieldValue, ClipInputFieldTemplate>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ClipInputFieldComponent);
|
|
@ -1,17 +0,0 @@
|
|||||||
import {
|
|
||||||
CollectionInputFieldTemplate,
|
|
||||||
CollectionInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const CollectionInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<
|
|
||||||
CollectionInputFieldValue,
|
|
||||||
CollectionInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(CollectionInputFieldComponent);
|
|
@ -1,17 +0,0 @@
|
|||||||
import {
|
|
||||||
CollectionItemInputFieldTemplate,
|
|
||||||
CollectionItemInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const CollectionItemInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<
|
|
||||||
CollectionItemInputFieldValue,
|
|
||||||
CollectionItemInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(CollectionItemInputFieldComponent);
|
|
@ -1,17 +0,0 @@
|
|||||||
import {
|
|
||||||
ConditioningInputFieldTemplate,
|
|
||||||
ConditioningInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const ConditioningInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<
|
|
||||||
ConditioningInputFieldValue,
|
|
||||||
ConditioningInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ConditioningInputFieldComponent);
|
|
@ -1,19 +0,0 @@
|
|||||||
import {
|
|
||||||
ControlInputFieldTemplate,
|
|
||||||
ControlInputFieldValue,
|
|
||||||
ControlPolymorphicInputFieldTemplate,
|
|
||||||
ControlPolymorphicInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const ControlInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<
|
|
||||||
ControlInputFieldValue | ControlPolymorphicInputFieldValue,
|
|
||||||
ControlInputFieldTemplate | ControlPolymorphicInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ControlInputFieldComponent);
|
|
@ -1,17 +0,0 @@
|
|||||||
import {
|
|
||||||
DenoiseMaskInputFieldTemplate,
|
|
||||||
DenoiseMaskInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const DenoiseMaskInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<
|
|
||||||
DenoiseMaskInputFieldValue,
|
|
||||||
DenoiseMaskInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(DenoiseMaskInputFieldComponent);
|
|
@ -1,19 +0,0 @@
|
|||||||
import {
|
|
||||||
IPAdapterInputFieldTemplate,
|
|
||||||
IPAdapterInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
IPAdapterPolymorphicInputFieldValue,
|
|
||||||
IPAdapterPolymorphicInputFieldTemplate,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const IPAdapterInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<
|
|
||||||
IPAdapterInputFieldValue | IPAdapterPolymorphicInputFieldValue,
|
|
||||||
IPAdapterInputFieldTemplate | IPAdapterPolymorphicInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(IPAdapterInputFieldComponent);
|
|
@ -1,94 +0,0 @@
|
|||||||
import {
|
|
||||||
ImageCollectionInputFieldTemplate,
|
|
||||||
ImageCollectionInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
|
||||||
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
|
||||||
import { useDroppableTypesafe } from 'features/dnd/hooks/typesafeHooks';
|
|
||||||
import { NodesMultiImageDropData } from 'features/dnd/types';
|
|
||||||
import { isValidDrop } from 'features/dnd/util/isValidDrop';
|
|
||||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
|
||||||
|
|
||||||
const ImageCollectionInputFieldComponent = (
|
|
||||||
props: FieldComponentProps<
|
|
||||||
ImageCollectionInputFieldValue,
|
|
||||||
ImageCollectionInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
const { nodeId, field } = props;
|
|
||||||
|
|
||||||
// const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
// const handleDrop = useCallback(
|
|
||||||
// ({ image_name }: ImageDTO) => {
|
|
||||||
// dispatch(
|
|
||||||
// fieldValueChanged({
|
|
||||||
// nodeId,
|
|
||||||
// fieldName: field.name,
|
|
||||||
// value: uniqBy([...(field.value ?? []), { image_name }], 'image_name'),
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// [dispatch, field.name, field.value, nodeId]
|
|
||||||
// );
|
|
||||||
|
|
||||||
const droppableData: NodesMultiImageDropData = {
|
|
||||||
id: `node-${nodeId}-${field.name}`,
|
|
||||||
actionType: 'SET_MULTI_NODES_IMAGE',
|
|
||||||
context: { nodeId: nodeId, fieldName: field.name },
|
|
||||||
};
|
|
||||||
|
|
||||||
const {
|
|
||||||
isOver,
|
|
||||||
setNodeRef: setDroppableRef,
|
|
||||||
active,
|
|
||||||
} = useDroppableTypesafe({
|
|
||||||
id: `node_${nodeId}`,
|
|
||||||
data: droppableData,
|
|
||||||
});
|
|
||||||
|
|
||||||
// const handleReset = useCallback(() => {
|
|
||||||
// dispatch(
|
|
||||||
// fieldValueChanged({
|
|
||||||
// nodeId,
|
|
||||||
// fieldName: field.name,
|
|
||||||
// value: undefined,
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
// }, [dispatch, field.name, nodeId]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
ref={setDroppableRef}
|
|
||||||
sx={{
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
position: 'relative',
|
|
||||||
minH: '10rem',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{field.value?.map(({ image_name }) => (
|
|
||||||
<ImageSubField key={image_name} imageName={image_name} />
|
|
||||||
))}
|
|
||||||
{isValidDrop(droppableData, active) && <IAIDropOverlay isOver={isOver} />}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ImageCollectionInputFieldComponent);
|
|
||||||
|
|
||||||
type ImageSubFieldProps = { imageName: string };
|
|
||||||
|
|
||||||
const ImageSubField = (props: ImageSubFieldProps) => {
|
|
||||||
const { currentData: image } = useGetImageDTOQuery(props.imageName);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIDndImage imageDTO={image} isDropDisabled={true} isDragDisabled={true} />
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
import {
|
|
||||||
LatentsInputFieldTemplate,
|
|
||||||
LatentsInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
LatentsPolymorphicInputFieldValue,
|
|
||||||
LatentsPolymorphicInputFieldTemplate,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const LatentsInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<
|
|
||||||
LatentsInputFieldValue | LatentsPolymorphicInputFieldValue,
|
|
||||||
LatentsInputFieldTemplate | LatentsPolymorphicInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(LatentsInputFieldComponent);
|
|
@ -1,19 +0,0 @@
|
|||||||
import {
|
|
||||||
T2IAdapterInputFieldTemplate,
|
|
||||||
T2IAdapterInputFieldValue,
|
|
||||||
T2IAdapterPolymorphicInputFieldTemplate,
|
|
||||||
T2IAdapterPolymorphicInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const T2IAdapterInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<
|
|
||||||
T2IAdapterInputFieldValue | T2IAdapterPolymorphicInputFieldValue,
|
|
||||||
T2IAdapterInputFieldTemplate | T2IAdapterPolymorphicInputFieldTemplate
|
|
||||||
>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(T2IAdapterInputFieldComponent);
|
|
@ -1,14 +0,0 @@
|
|||||||
import {
|
|
||||||
UNetInputFieldTemplate,
|
|
||||||
UNetInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const UNetInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<UNetInputFieldValue, UNetInputFieldTemplate>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(UNetInputFieldComponent);
|
|
@ -1,14 +0,0 @@
|
|||||||
import {
|
|
||||||
VaeInputFieldTemplate,
|
|
||||||
VaeInputFieldValue,
|
|
||||||
FieldComponentProps,
|
|
||||||
} from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const VaeInputFieldComponent = (
|
|
||||||
_props: FieldComponentProps<VaeInputFieldValue, VaeInputFieldTemplate>
|
|
||||||
) => {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(VaeInputFieldComponent);
|
|
@ -1,27 +0,0 @@
|
|||||||
import { NODE_MIN_WIDTH } from 'features/nodes/types/constants';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { NodeResizeControl, NodeResizerProps } from 'reactflow';
|
|
||||||
|
|
||||||
// this causes https://github.com/invoke-ai/InvokeAI/issues/4140
|
|
||||||
// not using it for now
|
|
||||||
|
|
||||||
const NodeResizer = (props: NodeResizerProps) => {
|
|
||||||
const { ...rest } = props;
|
|
||||||
return (
|
|
||||||
<NodeResizeControl
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
border: 'none',
|
|
||||||
background: 'transparent',
|
|
||||||
width: 15,
|
|
||||||
height: 15,
|
|
||||||
bottom: 0,
|
|
||||||
right: 0,
|
|
||||||
}}
|
|
||||||
minWidth={NODE_MIN_WIDTH}
|
|
||||||
{...rest}
|
|
||||||
></NodeResizeControl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(NodeResizer);
|
|
@ -1,78 +0,0 @@
|
|||||||
import { Box, Flex } from '@chakra-ui/react';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
|
||||||
import { InvocationTemplate, NodeData } from 'features/nodes/types/types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import NotesTextarea from '../../flow/nodes/Invocation/NotesTextarea';
|
|
||||||
import NodeTitle from '../../flow/nodes/common/NodeTitle';
|
|
||||||
import ScrollableContent from '../ScrollableContent';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
|
||||||
stateSelector,
|
|
||||||
({ nodes }) => {
|
|
||||||
const lastSelectedNodeId =
|
|
||||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
|
||||||
|
|
||||||
const lastSelectedNode = nodes.nodes.find(
|
|
||||||
(node) => node.id === lastSelectedNodeId
|
|
||||||
);
|
|
||||||
|
|
||||||
const lastSelectedNodeTemplate = lastSelectedNode
|
|
||||||
? nodes.nodeTemplates[lastSelectedNode.data.type]
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: lastSelectedNode?.data,
|
|
||||||
template: lastSelectedNodeTemplate,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
const InspectorDetailsTab = () => {
|
|
||||||
const { data, template } = useAppSelector(selector);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
if (!template || !data) {
|
|
||||||
return (
|
|
||||||
<IAINoContentFallback label={t('nodes.noNodeSelected')} icon={null} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Content data={data} template={template} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(InspectorDetailsTab);
|
|
||||||
|
|
||||||
const Content = (props: { data: NodeData; template: InvocationTemplate }) => {
|
|
||||||
const { data } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: 'relative',
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ScrollableContent>
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
flexDir: 'column',
|
|
||||||
position: 'relative',
|
|
||||||
p: 1,
|
|
||||||
gap: 2,
|
|
||||||
w: 'full',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<NodeTitle nodeId={data.id} />
|
|
||||||
<NotesTextarea nodeId={data.id} />
|
|
||||||
</Flex>
|
|
||||||
</ScrollableContent>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
import { Box, Text } from '@chakra-ui/react';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAITextarea from 'common/components/IAITextarea';
|
|
||||||
import { workflowNotesChanged } from 'features/nodes/store/nodesSlice';
|
|
||||||
import { ChangeEvent, memo, useCallback } from 'react';
|
|
||||||
|
|
||||||
const selector = createSelector(stateSelector, ({ nodes }) => {
|
|
||||||
const { notes } = nodes.workflow;
|
|
||||||
|
|
||||||
return {
|
|
||||||
notes,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const WorkflowNotesTab = () => {
|
|
||||||
const { notes } = useAppSelector(selector);
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const handleChangeNotes = useCallback(
|
|
||||||
(e: ChangeEvent<HTMLTextAreaElement>) => {
|
|
||||||
dispatch(workflowNotesChanged(e.target.value));
|
|
||||||
},
|
|
||||||
[dispatch]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box sx={{ pos: 'relative', h: 'full' }}>
|
|
||||||
<IAITextarea
|
|
||||||
onChange={handleChangeNotes}
|
|
||||||
value={notes}
|
|
||||||
fontSize="sm"
|
|
||||||
sx={{ h: 'full', resize: 'none' }}
|
|
||||||
/>
|
|
||||||
<Box sx={{ pos: 'absolute', bottom: 2, right: 2 }}>
|
|
||||||
<Text
|
|
||||||
sx={{
|
|
||||||
fontSize: 'xs',
|
|
||||||
opacity: 0.5,
|
|
||||||
userSelect: 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{notes.length}
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(WorkflowNotesTab);
|
|
@ -1,11 +0,0 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { AnyInvocationType } from 'services/events/types';
|
|
||||||
|
|
||||||
export const makeTemplateSelector = (type: AnyInvocationType) =>
|
|
||||||
createSelector(
|
|
||||||
stateSelector,
|
|
||||||
({ nodes }) => nodes.nodeTemplates[type],
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
@ -1,21 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import ParamBoundingBoxHeight from './ParamBoundingBoxHeight';
|
|
||||||
import ParamBoundingBoxWidth from './ParamBoundingBoxWidth';
|
|
||||||
|
|
||||||
const ParamBoundingBoxCollapse = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAICollapse label={t('parameters.boundingBoxHeader')}>
|
|
||||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
|
||||||
<ParamBoundingBoxWidth />
|
|
||||||
<ParamBoundingBoxHeight />
|
|
||||||
</Flex>
|
|
||||||
</IAICollapse>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ParamBoundingBoxCollapse);
|
|
@ -1,39 +0,0 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAISlider from 'common/components/IAISlider';
|
|
||||||
import { setThreshold } from 'features/parameters/store/generationSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
|
||||||
stateSelector,
|
|
||||||
(state) => {
|
|
||||||
const { threshold } = state.generation;
|
|
||||||
return {
|
|
||||||
threshold,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function ParamNoiseThreshold() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { threshold } = useAppSelector(selector);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISlider
|
|
||||||
label={t('parameters.noiseThreshold')}
|
|
||||||
min={0}
|
|
||||||
max={20}
|
|
||||||
step={0.1}
|
|
||||||
onChange={(v) => dispatch(setThreshold(v))}
|
|
||||||
handleReset={() => dispatch(setThreshold(0))}
|
|
||||||
value={threshold}
|
|
||||||
withInput
|
|
||||||
withReset
|
|
||||||
withSliderMarks
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import IAISlider from 'common/components/IAISlider';
|
|
||||||
import { setPerlin } from 'features/parameters/store/generationSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
|
||||||
stateSelector,
|
|
||||||
(state) => {
|
|
||||||
const { perlin } = state.generation;
|
|
||||||
return {
|
|
||||||
perlin,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function ParamPerlinNoise() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { perlin } = useAppSelector(selector);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISlider
|
|
||||||
label={t('parameters.perlinNoise')}
|
|
||||||
min={0}
|
|
||||||
max={1}
|
|
||||||
step={0.05}
|
|
||||||
onChange={(v) => dispatch(setPerlin(v))}
|
|
||||||
handleReset={() => dispatch(setPerlin(0))}
|
|
||||||
value={perlin}
|
|
||||||
withInput
|
|
||||||
withReset
|
|
||||||
withSliderMarks
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISlider from 'common/components/IAISlider';
|
|
||||||
import { setVariationAmount } from 'features/parameters/store/generationSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export default function ParamVariationAmount() {
|
|
||||||
const variationAmount = useAppSelector(
|
|
||||||
(state: RootState) => state.generation.variationAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
const shouldGenerateVariations = useAppSelector(
|
|
||||||
(state: RootState) => state.generation.shouldGenerateVariations
|
|
||||||
);
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISlider
|
|
||||||
label={t('parameters.variationAmount')}
|
|
||||||
value={variationAmount}
|
|
||||||
step={0.01}
|
|
||||||
min={0}
|
|
||||||
max={1}
|
|
||||||
isDisabled={!shouldGenerateVariations}
|
|
||||||
onChange={(v) => dispatch(setVariationAmount(v))}
|
|
||||||
handleReset={() => dispatch(setVariationAmount(0.1))}
|
|
||||||
withInput
|
|
||||||
withReset
|
|
||||||
withSliderMarks
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
// TODO: variations
|
|
||||||
|
|
||||||
// import { Flex } from '@chakra-ui/react';
|
|
||||||
// import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
// import { stateSelector } from 'app/store/store';
|
|
||||||
// import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
// import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
// import IAICollapse from 'common/components/IAICollapse';
|
|
||||||
// import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
// import { memo } from 'react';
|
|
||||||
// import { useTranslation } from 'react-i18next';
|
|
||||||
// import ParamVariationAmount from './ParamVariationAmount';
|
|
||||||
// import { ParamVariationToggle } from './ParamVariationToggle';
|
|
||||||
// import ParamVariationWeights from './ParamVariationWeights';
|
|
||||||
|
|
||||||
// const selector = createSelector(
|
|
||||||
// stateSelector,
|
|
||||||
// (state) => {
|
|
||||||
// const activeLabel = state.generation.shouldGenerateVariations
|
|
||||||
// ? 'Enabled'
|
|
||||||
// : undefined;
|
|
||||||
|
|
||||||
// return { activeLabel };
|
|
||||||
// },
|
|
||||||
// defaultSelectorOptions
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const ParamVariationCollapse = () => {
|
|
||||||
// const { t } = useTranslation();
|
|
||||||
// const { activeLabel } = useAppSelector(selector);
|
|
||||||
|
|
||||||
// const isVariationEnabled = useFeatureStatus('variation').isFeatureEnabled;
|
|
||||||
|
|
||||||
// if (!isVariationEnabled) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <IAICollapse label={t('parameters.variations')} activeLabel={activeLabel}>
|
|
||||||
// <Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
|
||||||
// <ParamVariationToggle />
|
|
||||||
// <ParamVariationAmount />
|
|
||||||
// <ParamVariationWeights />
|
|
||||||
// </Flex>
|
|
||||||
// </IAICollapse>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export default memo(ParamVariationCollapse);
|
|
||||||
|
|
||||||
export default {};
|
|
@ -1,24 +0,0 @@
|
|||||||
import type { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
|
||||||
import { setShouldGenerateVariations } from 'features/parameters/store/generationSlice';
|
|
||||||
import { ChangeEvent } from 'react';
|
|
||||||
|
|
||||||
export const ParamVariationToggle = () => {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const shouldGenerateVariations = useAppSelector(
|
|
||||||
(state: RootState) => state.generation.shouldGenerateVariations
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
|
|
||||||
dispatch(setShouldGenerateVariations(e.target.checked));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISwitch
|
|
||||||
label="Enable Variations"
|
|
||||||
isChecked={shouldGenerateVariations}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,41 +0,0 @@
|
|||||||
// TODO: variations
|
|
||||||
|
|
||||||
// import { RootState } from 'app/store/store';
|
|
||||||
// import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
// import IAIInput from 'common/components/IAIInput';
|
|
||||||
// import { validateSeedWeights } from 'common/util/seedWeightPairs';
|
|
||||||
// import { setSeedWeights } from 'features/parameters/store/generationSlice';
|
|
||||||
// import { ChangeEvent } from 'react';
|
|
||||||
// import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
// export default function ParamVariationWeights() {
|
|
||||||
// const seedWeights = useAppSelector(
|
|
||||||
// (state: RootState) => state.generation.seedWeights
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const shouldGenerateVariations = useAppSelector(
|
|
||||||
// (state: RootState) => state.generation.shouldGenerateVariations
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const { t } = useTranslation();
|
|
||||||
|
|
||||||
// const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
// const handleChangeSeedWeights = (e: ChangeEvent<HTMLInputElement>) =>
|
|
||||||
// dispatch(setSeedWeights(e.target.value));
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <IAIInput
|
|
||||||
// label={t('parameters.seedWeights')}
|
|
||||||
// value={seedWeights}
|
|
||||||
// isInvalid={
|
|
||||||
// shouldGenerateVariations &&
|
|
||||||
// !(validateSeedWeights(seedWeights) || seedWeights === '')
|
|
||||||
// }
|
|
||||||
// isDisabled={!shouldGenerateVariations}
|
|
||||||
// onChange={handleChangeSeedWeights}
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
export default {};
|
|
@ -1,4 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
|
|
||||||
export const postprocessingSelector = (state: RootState) =>
|
|
||||||
state.postprocessing;
|
|
@ -1,18 +0,0 @@
|
|||||||
import { memo } from 'react';
|
|
||||||
import QueueItemCard from './common/QueueItemCard';
|
|
||||||
import { useGetCurrentQueueItemQuery } from 'services/api/endpoints/queue';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
const CurrentQueueItemCard = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { data: currentQueueItemData } = useGetCurrentQueueItemQuery();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<QueueItemCard
|
|
||||||
label={t('queue.current')}
|
|
||||||
session_queue_item={currentQueueItemData}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(CurrentQueueItemCard);
|
|
@ -1,18 +0,0 @@
|
|||||||
import { memo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useGetNextQueueItemQuery } from 'services/api/endpoints/queue';
|
|
||||||
import QueueItemCard from './common/QueueItemCard';
|
|
||||||
|
|
||||||
const NextQueueItemCard = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { data: nextQueueItemData } = useGetNextQueueItemQuery();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<QueueItemCard
|
|
||||||
label={t('queue.next')}
|
|
||||||
session_queue_item={nextQueueItemData}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(NextQueueItemCard);
|
|
@ -1,41 +0,0 @@
|
|||||||
import { Flex, Skeleton } from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { COLUMN_WIDTHS } from './constants';
|
|
||||||
|
|
||||||
const QueueItemSkeleton = () => {
|
|
||||||
return (
|
|
||||||
<Flex alignItems="center" p={1.5} gap={4} minH={9} h="full" w="full">
|
|
||||||
<Flex
|
|
||||||
w={COLUMN_WIDTHS.number}
|
|
||||||
justifyContent="flex-end"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
|
||||||
<Skeleton w="full" h="full">
|
|
||||||
|
|
||||||
</Skeleton>
|
|
||||||
</Flex>
|
|
||||||
<Flex w={COLUMN_WIDTHS.statusBadge} alignItems="center">
|
|
||||||
<Skeleton w="full" h="full">
|
|
||||||
|
|
||||||
</Skeleton>
|
|
||||||
</Flex>
|
|
||||||
<Flex w={COLUMN_WIDTHS.time} alignItems="center">
|
|
||||||
<Skeleton w="full" h="full">
|
|
||||||
|
|
||||||
</Skeleton>
|
|
||||||
</Flex>
|
|
||||||
<Flex w={COLUMN_WIDTHS.batchId} alignItems="center">
|
|
||||||
<Skeleton w="full" h="full">
|
|
||||||
|
|
||||||
</Skeleton>
|
|
||||||
</Flex>
|
|
||||||
<Flex w={COLUMN_WIDTHS.fieldValues} alignItems="center" flexGrow={1}>
|
|
||||||
<Skeleton w="full" h="full">
|
|
||||||
|
|
||||||
</Skeleton>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(QueueItemSkeleton);
|
|
@ -1,54 +0,0 @@
|
|||||||
import { Flex, Heading, Text } from '@chakra-ui/react';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
|
|
||||||
|
|
||||||
const QueueStatusCard = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { data: queueStatus } = useGetQueueStatusQuery();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
layerStyle="second"
|
|
||||||
borderRadius="base"
|
|
||||||
p={2}
|
|
||||||
flexDir="column"
|
|
||||||
gap={1}
|
|
||||||
w={96}
|
|
||||||
>
|
|
||||||
<Heading size="md">{t('queue.status')}</Heading>
|
|
||||||
<Text>
|
|
||||||
<Text as="span" fontWeight={600}>
|
|
||||||
{t('queue.pending')}:{' '}
|
|
||||||
</Text>
|
|
||||||
{queueStatus?.queue.pending}
|
|
||||||
</Text>
|
|
||||||
<Text>
|
|
||||||
<Text as="span" fontWeight={600}>
|
|
||||||
{t('queue.in_progress')}:{' '}
|
|
||||||
</Text>
|
|
||||||
{queueStatus?.queue.in_progress}
|
|
||||||
</Text>
|
|
||||||
<Text>
|
|
||||||
<Text as="span" fontWeight={600}>
|
|
||||||
{t('queue.completed')}:{' '}
|
|
||||||
</Text>
|
|
||||||
{queueStatus?.queue.completed}
|
|
||||||
</Text>
|
|
||||||
<Text>
|
|
||||||
<Text as="span" fontWeight={600}>
|
|
||||||
{t('queue.failed')}:{' '}
|
|
||||||
</Text>
|
|
||||||
{queueStatus?.queue.failed}
|
|
||||||
</Text>
|
|
||||||
<Text>
|
|
||||||
<Text as="span" fontWeight={600}>
|
|
||||||
{t('queue.canceled')}:{' '}
|
|
||||||
</Text>
|
|
||||||
{queueStatus?.queue.canceled}
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(QueueStatusCard);
|
|
@ -1,52 +0,0 @@
|
|||||||
import { Flex, Heading, Text, Tooltip } from '@chakra-ui/react';
|
|
||||||
import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { components } from 'services/api/schema';
|
|
||||||
|
|
||||||
const QueueItemCard = ({
|
|
||||||
session_queue_item,
|
|
||||||
label,
|
|
||||||
}: {
|
|
||||||
session_queue_item?: components['schemas']['SessionQueueItem'] | null;
|
|
||||||
label: string;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
layerStyle="second"
|
|
||||||
borderRadius="base"
|
|
||||||
w="full"
|
|
||||||
p={2}
|
|
||||||
flexDir="column"
|
|
||||||
gap={1}
|
|
||||||
>
|
|
||||||
<Flex justifyContent="space-between" alignItems="flex-start">
|
|
||||||
<Heading size="md">{label}</Heading>
|
|
||||||
{session_queue_item && (
|
|
||||||
<Tooltip label="Batch ID" placement="top" hasArrow>
|
|
||||||
<Text fontSize="xs">{session_queue_item.batch_id}</Text>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
{session_queue_item && (
|
|
||||||
<ScrollableContent>
|
|
||||||
<Text>Batch Values: </Text>
|
|
||||||
{session_queue_item.field_values &&
|
|
||||||
session_queue_item.field_values
|
|
||||||
.filter((v) => v.node_path !== 'metadata_accumulator')
|
|
||||||
.map(({ node_path, field_name, value }) => (
|
|
||||||
<Text
|
|
||||||
key={`${session_queue_item.item_id}.${node_path}.${field_name}.${value}`}
|
|
||||||
>
|
|
||||||
<Text as="span" fontWeight={600}>
|
|
||||||
{node_path}.{field_name}
|
|
||||||
</Text>
|
|
||||||
: {value}
|
|
||||||
</Text>
|
|
||||||
))}
|
|
||||||
</ScrollableContent>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(QueueItemCard);
|
|
@ -1,28 +0,0 @@
|
|||||||
import { Box } from '@chakra-ui/react';
|
|
||||||
import { memo, useMemo } from 'react';
|
|
||||||
import { SessionQueueItemStatus } from 'services/api/endpoints/queue';
|
|
||||||
|
|
||||||
const STATUSES = {
|
|
||||||
pending: { colorScheme: 'cyan', translationKey: 'queue.pending' },
|
|
||||||
in_progress: { colorScheme: 'yellow', translationKey: 'queue.in_progress' },
|
|
||||||
completed: { colorScheme: 'green', translationKey: 'queue.completed' },
|
|
||||||
failed: { colorScheme: 'red', translationKey: 'queue.failed' },
|
|
||||||
canceled: { colorScheme: 'orange', translationKey: 'queue.canceled' },
|
|
||||||
};
|
|
||||||
|
|
||||||
const QueueStatusDot = ({ status }: { status: SessionQueueItemStatus }) => {
|
|
||||||
const sx = useMemo(
|
|
||||||
() => ({
|
|
||||||
w: 2,
|
|
||||||
h: 2,
|
|
||||||
bg: `${STATUSES[status].colorScheme}.${500}`,
|
|
||||||
_dark: {
|
|
||||||
bg: `${STATUSES[status].colorScheme}.${400}`,
|
|
||||||
},
|
|
||||||
borderRadius: '100%',
|
|
||||||
}),
|
|
||||||
[status]
|
|
||||||
);
|
|
||||||
return <Box sx={sx} />;
|
|
||||||
};
|
|
||||||
export default memo(QueueStatusDot);
|
|
@ -1,4 +0,0 @@
|
|||||||
export const formatNumberShort = (num: number) =>
|
|
||||||
Intl.NumberFormat('en-US', {
|
|
||||||
notation: 'standard',
|
|
||||||
}).format(num);
|
|
@ -1,82 +0,0 @@
|
|||||||
import {
|
|
||||||
Flex,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
Text,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { LOCALSTORAGE_KEYS, LOCALSTORAGE_PREFIX } from 'app/store/constants';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
|
||||||
import { memo, useCallback, useEffect, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
onSettingsModalClose: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ResetWebUIButton = ({ onSettingsModalClose }: Props) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [countdown, setCountdown] = useState(5);
|
|
||||||
|
|
||||||
const {
|
|
||||||
isOpen: isRefreshModalOpen,
|
|
||||||
onOpen: onRefreshModalOpen,
|
|
||||||
onClose: onRefreshModalClose,
|
|
||||||
} = useDisclosure();
|
|
||||||
|
|
||||||
const handleClickResetWebUI = useCallback(() => {
|
|
||||||
// Only remove our keys
|
|
||||||
Object.keys(window.localStorage).forEach((key) => {
|
|
||||||
if (
|
|
||||||
LOCALSTORAGE_KEYS.includes(key) ||
|
|
||||||
key.startsWith(LOCALSTORAGE_PREFIX)
|
|
||||||
) {
|
|
||||||
localStorage.removeItem(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
onSettingsModalClose();
|
|
||||||
onRefreshModalOpen();
|
|
||||||
setInterval(() => setCountdown((prev) => prev - 1), 1000);
|
|
||||||
}, [onSettingsModalClose, onRefreshModalOpen]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (countdown <= 0) {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
}, [countdown]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<IAIButton colorScheme="error" onClick={handleClickResetWebUI}>
|
|
||||||
{t('settings.resetWebUI')}
|
|
||||||
</IAIButton>
|
|
||||||
<Modal
|
|
||||||
closeOnOverlayClick={false}
|
|
||||||
isOpen={isRefreshModalOpen}
|
|
||||||
onClose={onRefreshModalClose}
|
|
||||||
isCentered
|
|
||||||
closeOnEsc={false}
|
|
||||||
>
|
|
||||||
<ModalOverlay backdropFilter="blur(40px)" />
|
|
||||||
<ModalContent>
|
|
||||||
<ModalHeader />
|
|
||||||
<ModalBody>
|
|
||||||
<Flex justifyContent="center">
|
|
||||||
<Text fontSize="lg">
|
|
||||||
<Text>{t('settings.resetComplete')}</Text>
|
|
||||||
<Text>Reloading in {countdown}...</Text>
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
</ModalBody>
|
|
||||||
<ModalFooter />
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ResetWebUIButton);
|
|
@ -1,3 +0,0 @@
|
|||||||
import { createAction } from '@reduxjs/toolkit';
|
|
||||||
|
|
||||||
export const sessionReadyToInvoke = createAction('system/sessionReadyToInvoke');
|
|
@ -1,62 +0,0 @@
|
|||||||
// TODO: split system slice inot this
|
|
||||||
|
|
||||||
// import type { PayloadAction } from '@reduxjs/toolkit';
|
|
||||||
// import { createSlice } from '@reduxjs/toolkit';
|
|
||||||
// import { socketSubscribed, socketUnsubscribed } from 'services/events/actions';
|
|
||||||
|
|
||||||
// export type SessionState = {
|
|
||||||
// /**
|
|
||||||
// * The current socket session id
|
|
||||||
// */
|
|
||||||
// sessionId: string;
|
|
||||||
// /**
|
|
||||||
// * Whether the current session is a canvas session. Needed to manage the staging area.
|
|
||||||
// */
|
|
||||||
// isCanvasSession: boolean;
|
|
||||||
// /**
|
|
||||||
// * When a session is canceled, its ID is stored here until a new session is created.
|
|
||||||
// */
|
|
||||||
// canceledSessionId: string;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const initialSessionState: SessionState = {
|
|
||||||
// sessionId: '',
|
|
||||||
// isCanvasSession: false,
|
|
||||||
// canceledSessionId: '',
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const sessionSlice = createSlice({
|
|
||||||
// name: 'session',
|
|
||||||
// initialState: initialSessionState,
|
|
||||||
// reducers: {
|
|
||||||
// sessionIdChanged: (state, action: PayloadAction<string>) => {
|
|
||||||
// state.sessionId = action.payload;
|
|
||||||
// },
|
|
||||||
// isCanvasSessionChanged: (state, action: PayloadAction<boolean>) => {
|
|
||||||
// state.isCanvasSession = action.payload;
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// extraReducers: (builder) => {
|
|
||||||
// /**
|
|
||||||
// * Socket Subscribed
|
|
||||||
// */
|
|
||||||
// builder.addCase(socketSubscribed, (state, action) => {
|
|
||||||
// state.sessionId = action.payload.sessionId;
|
|
||||||
// state.canceledSessionId = '';
|
|
||||||
// });
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Socket Unsubscribed
|
|
||||||
// */
|
|
||||||
// builder.addCase(socketUnsubscribed, (state) => {
|
|
||||||
// state.sessionId = '';
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// export const { sessionIdChanged, isCanvasSessionChanged } =
|
|
||||||
// sessionSlice.actions;
|
|
||||||
|
|
||||||
// export default sessionSlice.reducer;
|
|
||||||
|
|
||||||
export default {};
|
|
@ -1,22 +0,0 @@
|
|||||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
|
||||||
import { PropsWithChildren, memo } from 'react';
|
|
||||||
const OverlayScrollable = (props: PropsWithChildren) => {
|
|
||||||
return (
|
|
||||||
<OverlayScrollbarsComponent
|
|
||||||
defer
|
|
||||||
style={{ height: '100%', width: '100%' }}
|
|
||||||
options={{
|
|
||||||
scrollbars: {
|
|
||||||
visibility: 'auto',
|
|
||||||
autoHide: 'move',
|
|
||||||
autoHideDelay: 1300,
|
|
||||||
theme: 'os-theme-dark',
|
|
||||||
},
|
|
||||||
overflow: { x: 'hidden' },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</OverlayScrollbarsComponent>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default memo(OverlayScrollable);
|
|
@ -1,3 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
|
|
||||||
export const modelmanagerSelector = (state: RootState) => state.modelmanager;
|
|
@ -1,12 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
import UnifiedCanvasBrushSettings from './UnifiedCanvasBrushSettings';
|
|
||||||
import UnifiedCanvasLimitStrokesToBox from './UnifiedCanvasLimitStrokesToBox';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasBaseBrushSettings() {
|
|
||||||
return (
|
|
||||||
<Flex gap={4} alignItems="center">
|
|
||||||
<UnifiedCanvasBrushSettings />
|
|
||||||
<UnifiedCanvasLimitStrokesToBox />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
import UnifiedCanvasBrushSize from './UnifiedCanvasBrushSize';
|
|
||||||
import UnifiedCanvasColorPicker from './UnifiedCanvasColorPicker';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasBrushSettings() {
|
|
||||||
return (
|
|
||||||
<Flex columnGap={4} alignItems="center">
|
|
||||||
<UnifiedCanvasBrushSize />
|
|
||||||
<UnifiedCanvasColorPicker />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISlider from 'common/components/IAISlider';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { setBrushSize } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasBrushSize() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const brushSize = useAppSelector(
|
|
||||||
(state: RootState) => state.canvas.brushSize
|
|
||||||
);
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const isStaging = useAppSelector(isStagingSelector);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['BracketLeft'],
|
|
||||||
() => {
|
|
||||||
dispatch(setBrushSize(Math.max(brushSize - 5, 5)));
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[brushSize]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['BracketRight'],
|
|
||||||
() => {
|
|
||||||
dispatch(setBrushSize(Math.min(brushSize + 5, 500)));
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[brushSize]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISlider
|
|
||||||
label={t('unifiedCanvas.brushSize')}
|
|
||||||
value={brushSize}
|
|
||||||
withInput
|
|
||||||
onChange={(newSize) => dispatch(setBrushSize(newSize))}
|
|
||||||
sliderNumberInputProps={{ max: 500 }}
|
|
||||||
isCompact
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
|
||||||
|
|
||||||
import { clearMask } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
import { FaTrash } from 'react-icons/fa';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasClearMask() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const handleClearMask = () => dispatch(clearMask());
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIButton
|
|
||||||
size="sm"
|
|
||||||
leftIcon={<FaTrash />}
|
|
||||||
onClick={handleClearMask}
|
|
||||||
tooltip={`${t('unifiedCanvas.clearMask')} (Shift+C)`}
|
|
||||||
>
|
|
||||||
{t('unifiedCanvas.betaClear')}
|
|
||||||
</IAIButton>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,128 +0,0 @@
|
|||||||
import { Box, Flex } from '@chakra-ui/react';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIColorPicker from 'common/components/IAIColorPicker';
|
|
||||||
import IAIPopover from 'common/components/IAIPopover';
|
|
||||||
import {
|
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { setBrushColor, setMaskColor } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { clamp, isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
|
||||||
[canvasSelector, isStagingSelector],
|
|
||||||
(canvas, isStaging) => {
|
|
||||||
const { brushColor, maskColor, layer } = canvas;
|
|
||||||
return {
|
|
||||||
brushColor,
|
|
||||||
maskColor,
|
|
||||||
layer,
|
|
||||||
isStaging,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function UnifiedCanvasColorPicker() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { brushColor, maskColor, layer, isStaging } = useAppSelector(selector);
|
|
||||||
|
|
||||||
const currentColorDisplay = () => {
|
|
||||||
if (layer === 'base') {
|
|
||||||
return `rgba(${brushColor.r},${brushColor.g},${brushColor.b},${brushColor.a})`;
|
|
||||||
}
|
|
||||||
if (layer === 'mask') {
|
|
||||||
return `rgba(${maskColor.r},${maskColor.g},${maskColor.b},${maskColor.a})`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['shift+BracketLeft'],
|
|
||||||
() => {
|
|
||||||
dispatch(
|
|
||||||
setBrushColor({
|
|
||||||
...brushColor,
|
|
||||||
a: clamp(brushColor.a - 0.05, 0.05, 1),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[brushColor]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['shift+BracketRight'],
|
|
||||||
() => {
|
|
||||||
dispatch(
|
|
||||||
setBrushColor({
|
|
||||||
...brushColor,
|
|
||||||
a: clamp(brushColor.a + 0.05, 0.05, 1),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[brushColor]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIPopover
|
|
||||||
triggerComponent={
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: 7,
|
|
||||||
height: 7,
|
|
||||||
minWidth: 7,
|
|
||||||
minHeight: 7,
|
|
||||||
borderRadius: 'full',
|
|
||||||
bg: currentColorDisplay(),
|
|
||||||
cursor: 'pointer',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Flex minWidth={60} direction="column" gap={4} width="100%">
|
|
||||||
{layer === 'base' && (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: '100%',
|
|
||||||
paddingTop: 2,
|
|
||||||
paddingBottom: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IAIColorPicker
|
|
||||||
color={brushColor}
|
|
||||||
onChange={(newColor) => dispatch(setBrushColor(newColor))}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{layer === 'mask' && (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: '100%',
|
|
||||||
paddingTop: 2,
|
|
||||||
paddingBottom: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IAIColorPicker
|
|
||||||
color={maskColor}
|
|
||||||
onChange={(newColor) => dispatch(setMaskColor(newColor))}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
</IAIPopover>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import { setShouldDarkenOutsideBoundingBox } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasDarkenOutsideSelection() {
|
|
||||||
const shouldDarkenOutsideBoundingBox = useAppSelector(
|
|
||||||
(state: RootState) => state.canvas.shouldDarkenOutsideBoundingBox
|
|
||||||
);
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.betaDarkenOutside')}
|
|
||||||
isChecked={shouldDarkenOutsideBoundingBox}
|
|
||||||
onChange={(e) =>
|
|
||||||
dispatch(setShouldDarkenOutsideBoundingBox(e.target.checked))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import { setIsMaskEnabled } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasEnableMask() {
|
|
||||||
const isMaskEnabled = useAppSelector(
|
|
||||||
(state: RootState) => state.canvas.isMaskEnabled
|
|
||||||
);
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const handleToggleEnableMask = () =>
|
|
||||||
dispatch(setIsMaskEnabled(!isMaskEnabled));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={`${t('unifiedCanvas.enableMask')} (H)`}
|
|
||||||
isChecked={isMaskEnabled}
|
|
||||||
onChange={handleToggleEnableMask}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import { setShouldRestrictStrokesToBox } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasLimitStrokesToBox() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const shouldRestrictStrokesToBox = useAppSelector(
|
|
||||||
(state: RootState) => state.canvas.shouldRestrictStrokesToBox
|
|
||||||
);
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.betaLimitToBox')}
|
|
||||||
isChecked={shouldRestrictStrokesToBox}
|
|
||||||
onChange={(e) =>
|
|
||||||
dispatch(setShouldRestrictStrokesToBox(e.target.checked))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
import UnifiedCanvasBrushSettings from './UnifiedCanvasBrushSettings';
|
|
||||||
import UnifiedCanvasClearMask from './UnifiedCanvasClearMask';
|
|
||||||
import UnifiedCanvasEnableMask from './UnifiedCanvasEnableMask';
|
|
||||||
import UnifiedCanvasPreserveMask from './UnifiedCanvasPreserveMask';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasMaskBrushSettings() {
|
|
||||||
return (
|
|
||||||
<Flex gap={4} alignItems="center">
|
|
||||||
<UnifiedCanvasBrushSettings />
|
|
||||||
<UnifiedCanvasEnableMask />
|
|
||||||
<UnifiedCanvasPreserveMask />
|
|
||||||
<UnifiedCanvasClearMask />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/layout';
|
|
||||||
import UnifiedCanvasDarkenOutsideSelection from './UnifiedCanvasDarkenOutsideSelection';
|
|
||||||
import UnifiedCanvasShowGrid from './UnifiedCanvasShowGrid';
|
|
||||||
import UnifiedCanvasSnapToGrid from './UnifiedCanvasSnapToGrid';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasMoveSettings() {
|
|
||||||
return (
|
|
||||||
<Flex alignItems="center" gap={4}>
|
|
||||||
<UnifiedCanvasShowGrid />
|
|
||||||
<UnifiedCanvasSnapToGrid />
|
|
||||||
<UnifiedCanvasDarkenOutsideSelection />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import { setShouldPreserveMaskedArea } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasPreserveMask() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const shouldPreserveMaskedArea = useAppSelector(
|
|
||||||
(state: RootState) => state.canvas.shouldPreserveMaskedArea
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.betaPreserveMasked')}
|
|
||||||
isChecked={shouldPreserveMaskedArea}
|
|
||||||
onChange={(e) => dispatch(setShouldPreserveMaskedArea(e.target.checked))}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import IAIPopover from 'common/components/IAIPopover';
|
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
|
||||||
setShouldAntialias,
|
|
||||||
setShouldAutoSave,
|
|
||||||
setShouldCropToBoundingBoxOnSave,
|
|
||||||
setShouldShowCanvasDebugInfo,
|
|
||||||
setShouldShowIntermediates,
|
|
||||||
} from 'features/canvas/store/canvasSlice';
|
|
||||||
|
|
||||||
import { FaWrench } from 'react-icons/fa';
|
|
||||||
|
|
||||||
import ClearCanvasHistoryButtonModal from 'features/canvas/components/ClearCanvasHistoryButtonModal';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
export const canvasControlsSelector = createSelector(
|
|
||||||
[canvasSelector],
|
|
||||||
(canvas) => {
|
|
||||||
const {
|
|
||||||
shouldAutoSave,
|
|
||||||
shouldCropToBoundingBoxOnSave,
|
|
||||||
shouldShowCanvasDebugInfo,
|
|
||||||
shouldShowIntermediates,
|
|
||||||
shouldAntialias,
|
|
||||||
} = canvas;
|
|
||||||
|
|
||||||
return {
|
|
||||||
shouldAutoSave,
|
|
||||||
shouldCropToBoundingBoxOnSave,
|
|
||||||
shouldShowCanvasDebugInfo,
|
|
||||||
shouldShowIntermediates,
|
|
||||||
shouldAntialias,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const UnifiedCanvasSettings = () => {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const {
|
|
||||||
shouldAutoSave,
|
|
||||||
shouldCropToBoundingBoxOnSave,
|
|
||||||
shouldShowCanvasDebugInfo,
|
|
||||||
shouldShowIntermediates,
|
|
||||||
shouldAntialias,
|
|
||||||
} = useAppSelector(canvasControlsSelector);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIPopover
|
|
||||||
isLazy={false}
|
|
||||||
triggerComponent={
|
|
||||||
<IAIIconButton
|
|
||||||
tooltip={t('unifiedCanvas.canvasSettings')}
|
|
||||||
tooltipProps={{
|
|
||||||
placement: 'bottom',
|
|
||||||
}}
|
|
||||||
aria-label={t('unifiedCanvas.canvasSettings')}
|
|
||||||
icon={<FaWrench />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Flex direction="column" gap={2}>
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.showIntermediates')}
|
|
||||||
isChecked={shouldShowIntermediates}
|
|
||||||
onChange={(e) =>
|
|
||||||
dispatch(setShouldShowIntermediates(e.target.checked))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.autoSaveToGallery')}
|
|
||||||
isChecked={shouldAutoSave}
|
|
||||||
onChange={(e) => dispatch(setShouldAutoSave(e.target.checked))}
|
|
||||||
/>
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.saveBoxRegionOnly')}
|
|
||||||
isChecked={shouldCropToBoundingBoxOnSave}
|
|
||||||
onChange={(e) =>
|
|
||||||
dispatch(setShouldCropToBoundingBoxOnSave(e.target.checked))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.showCanvasDebugInfo')}
|
|
||||||
isChecked={shouldShowCanvasDebugInfo}
|
|
||||||
onChange={(e) =>
|
|
||||||
dispatch(setShouldShowCanvasDebugInfo(e.target.checked))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.antialiasing')}
|
|
||||||
isChecked={shouldAntialias}
|
|
||||||
onChange={(e) => dispatch(setShouldAntialias(e.target.checked))}
|
|
||||||
/>
|
|
||||||
<ClearCanvasHistoryButtonModal />
|
|
||||||
</Flex>
|
|
||||||
</IAIPopover>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(UnifiedCanvasSettings);
|
|
@ -1,22 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import { setShouldShowGrid } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasShowGrid() {
|
|
||||||
const shouldShowGrid = useAppSelector(
|
|
||||||
(state: RootState) => state.canvas.shouldShowGrid
|
|
||||||
);
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('unifiedCanvas.showGrid')}
|
|
||||||
isChecked={shouldShowGrid}
|
|
||||||
onChange={(e) => dispatch(setShouldShowGrid(e.target.checked))}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import { setShouldSnapToGrid } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { ChangeEvent } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasSnapToGrid() {
|
|
||||||
const shouldSnapToGrid = useAppSelector(
|
|
||||||
(state: RootState) => state.canvas.shouldSnapToGrid
|
|
||||||
);
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const handleChangeShouldSnapToGrid = (e: ChangeEvent<HTMLInputElement>) =>
|
|
||||||
dispatch(setShouldSnapToGrid(e.target.checked));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={`${t('unifiedCanvas.snapToGrid')} (N)`}
|
|
||||||
isChecked={shouldSnapToGrid}
|
|
||||||
onChange={handleChangeShouldSnapToGrid}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
|
|
||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import UnifiedCanvasBaseBrushSettings from './UnifiedCanvasToolSettings/UnifiedCanvasBaseBrushSettings';
|
|
||||||
import UnifiedCanvasMaskBrushSettings from './UnifiedCanvasToolSettings/UnifiedCanvasMaskBrushSettings';
|
|
||||||
import UnifiedCanvasMoveSettings from './UnifiedCanvasToolSettings/UnifiedCanvasMoveSettings';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
|
||||||
[canvasSelector],
|
|
||||||
(canvas) => {
|
|
||||||
const { tool, layer } = canvas;
|
|
||||||
return {
|
|
||||||
tool,
|
|
||||||
layer,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function UnifiedCanvasToolSettingsBeta() {
|
|
||||||
const { tool, layer } = useAppSelector(selector);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex height={8} minHeight={8} maxHeight={8} alignItems="center">
|
|
||||||
{layer == 'base' && ['brush', 'eraser', 'colorPicker'].includes(tool) && (
|
|
||||||
<UnifiedCanvasBaseBrushSettings />
|
|
||||||
)}
|
|
||||||
{layer == 'mask' && ['brush', 'eraser', 'colorPicker'].includes(tool) && (
|
|
||||||
<UnifiedCanvasMaskBrushSettings />
|
|
||||||
)}
|
|
||||||
{tool == 'move' && <UnifiedCanvasMoveSettings />}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { canvasCopiedToClipboard } from 'features/canvas/store/actions';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { useCopyImageToClipboard } from 'features/ui/hooks/useCopyImageToClipboard';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaCopy } from 'react-icons/fa';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasCopyToClipboard() {
|
|
||||||
const isStaging = useAppSelector(isStagingSelector);
|
|
||||||
const { isClipboardAPIAvailable } = useCopyImageToClipboard();
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['meta+c', 'ctrl+c'],
|
|
||||||
() => {
|
|
||||||
handleCopyImageToClipboard();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging && isClipboardAPIAvailable,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[isClipboardAPIAvailable]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleCopyImageToClipboard = useCallback(() => {
|
|
||||||
if (!isClipboardAPIAvailable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dispatch(canvasCopiedToClipboard());
|
|
||||||
}, [dispatch, isClipboardAPIAvailable]);
|
|
||||||
|
|
||||||
if (!isClipboardAPIAvailable) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.copyToClipboard')} (Cmd/Ctrl+C)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.copyToClipboard')} (Cmd/Ctrl+C)`}
|
|
||||||
icon={<FaCopy />}
|
|
||||||
onClick={handleCopyImageToClipboard}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { canvasDownloadedAsImage } from 'features/canvas/store/actions';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaDownload } from 'react-icons/fa';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasDownloadImage() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const canvasBaseLayer = getCanvasBaseLayer();
|
|
||||||
|
|
||||||
const isStaging = useAppSelector(isStagingSelector);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['shift+d'],
|
|
||||||
() => {
|
|
||||||
handleDownloadAsImage();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[canvasBaseLayer]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleDownloadAsImage = () => {
|
|
||||||
dispatch(canvasDownloadedAsImage());
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.downloadAsImage')} (Shift+D)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.downloadAsImage')} (Shift+D)`}
|
|
||||||
icon={<FaDownload />}
|
|
||||||
onClick={handleDownloadAsImage}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaUpload } from 'react-icons/fa';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasFileUploader() {
|
|
||||||
const isStaging = useAppSelector(isStagingSelector);
|
|
||||||
|
|
||||||
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
|
|
||||||
postUploadAction: { type: 'SET_CANVAS_INITIAL_IMAGE' },
|
|
||||||
});
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={t('common.upload')}
|
|
||||||
tooltip={t('common.upload')}
|
|
||||||
icon={<FaUpload />}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
{...getUploadButtonProps()}
|
|
||||||
/>
|
|
||||||
<input {...getUploadInputProps()} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
|
||||||
import {
|
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { setIsMaskEnabled, setLayer } from 'features/canvas/store/canvasSlice';
|
|
||||||
import {
|
|
||||||
CanvasLayer,
|
|
||||||
LAYER_NAMES_DICT,
|
|
||||||
} from 'features/canvas/store/canvasTypes';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
|
||||||
[canvasSelector, isStagingSelector],
|
|
||||||
(canvas, isStaging) => {
|
|
||||||
const { layer, isMaskEnabled } = canvas;
|
|
||||||
return { layer, isMaskEnabled, isStaging };
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function UnifiedCanvasLayerSelect() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const { layer, isMaskEnabled, isStaging } = useAppSelector(selector);
|
|
||||||
|
|
||||||
const handleToggleMaskLayer = () => {
|
|
||||||
dispatch(setLayer(layer === 'mask' ? 'base' : 'mask'));
|
|
||||||
};
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['q'],
|
|
||||||
() => {
|
|
||||||
handleToggleMaskLayer();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[layer]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleChangeLayer = (v: string) => {
|
|
||||||
const newLayer = v as CanvasLayer;
|
|
||||||
dispatch(setLayer(newLayer));
|
|
||||||
if (newLayer === 'mask' && !isMaskEnabled) {
|
|
||||||
dispatch(setIsMaskEnabled(true));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<IAIMantineSelect
|
|
||||||
tooltip={`${t('unifiedCanvas.layer')} (Q)`}
|
|
||||||
aria-label={`${t('unifiedCanvas.layer')} (Q)`}
|
|
||||||
value={layer}
|
|
||||||
data={LAYER_NAMES_DICT}
|
|
||||||
onChange={handleChangeLayer}
|
|
||||||
disabled={isStaging}
|
|
||||||
w="full"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { canvasMerged } from 'features/canvas/store/actions';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaLayerGroup } from 'react-icons/fa';
|
|
||||||
export default function UnifiedCanvasMergeVisible() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const isStaging = useAppSelector(isStagingSelector);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['shift+m'],
|
|
||||||
() => {
|
|
||||||
handleMergeVisible();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleMergeVisible = () => {
|
|
||||||
dispatch(canvasMerged());
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.mergeVisible')} (Shift+M)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.mergeVisible')} (Shift+M)`}
|
|
||||||
icon={<FaLayerGroup />}
|
|
||||||
onClick={handleMergeVisible}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { setTool } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaArrowsAlt } from 'react-icons/fa';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasMoveTool() {
|
|
||||||
const tool = useAppSelector((state: RootState) => state.canvas.tool);
|
|
||||||
const isStaging = useAppSelector(isStagingSelector);
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['v'],
|
|
||||||
() => {
|
|
||||||
handleSelectMoveTool();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectMoveTool = () => dispatch(setTool('move'));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.move')} (V)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.move')} (V)`}
|
|
||||||
icon={<FaArrowsAlt />}
|
|
||||||
isChecked={tool === 'move' || isStaging}
|
|
||||||
onClick={handleSelectMoveTool}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaTrash } from 'react-icons/fa';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasResetCanvas() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const isStaging = useAppSelector(isStagingSelector);
|
|
||||||
|
|
||||||
const handleResetCanvas = () => {
|
|
||||||
dispatch(resetCanvas());
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={t('unifiedCanvas.clearCanvas')}
|
|
||||||
tooltip={t('unifiedCanvas.clearCanvas')}
|
|
||||||
icon={<FaTrash />}
|
|
||||||
onClick={handleResetCanvas}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
colorScheme="error"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { useSingleAndDoubleClick } from 'common/hooks/useSingleAndDoubleClick';
|
|
||||||
import { resetCanvasView } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaCrosshairs } from 'react-icons/fa';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasResetView() {
|
|
||||||
const canvasBaseLayer = getCanvasBaseLayer();
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['r'],
|
|
||||||
() => {
|
|
||||||
handleResetCanvasView();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => true,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[canvasBaseLayer]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClickResetCanvasView = useSingleAndDoubleClick(
|
|
||||||
() => handleResetCanvasView(false),
|
|
||||||
() => handleResetCanvasView(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleResetCanvasView = (shouldScaleTo1 = false) => {
|
|
||||||
const canvasBaseLayer = getCanvasBaseLayer();
|
|
||||||
if (!canvasBaseLayer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const clientRect = canvasBaseLayer.getClientRect({
|
|
||||||
skipTransform: true,
|
|
||||||
});
|
|
||||||
dispatch(
|
|
||||||
resetCanvasView({
|
|
||||||
contentRect: clientRect,
|
|
||||||
shouldScaleTo1,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.resetView')} (R)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.resetView')} (R)`}
|
|
||||||
icon={<FaCrosshairs />}
|
|
||||||
onClick={handleClickResetCanvasView}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { canvasSavedToGallery } from 'features/canvas/store/actions';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { FaSave } from 'react-icons/fa';
|
|
||||||
|
|
||||||
export default function UnifiedCanvasSaveToGallery() {
|
|
||||||
const isStaging = useAppSelector(isStagingSelector);
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['shift+s'],
|
|
||||||
() => {
|
|
||||||
handleSaveToGallery();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSaveToGallery = () => {
|
|
||||||
dispatch(canvasSavedToGallery());
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.saveToGallery')} (Shift+S)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.saveToGallery')} (Shift+S)`}
|
|
||||||
icon={<FaSave />}
|
|
||||||
onClick={handleSaveToGallery}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,172 +0,0 @@
|
|||||||
import { ButtonGroup, Flex } from '@chakra-ui/react';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
|
||||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
|
||||||
addEraseRect,
|
|
||||||
addFillRect,
|
|
||||||
setTool,
|
|
||||||
} from 'features/canvas/store/canvasSlice';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
|
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import {
|
|
||||||
FaEraser,
|
|
||||||
FaEyeDropper,
|
|
||||||
FaFillDrip,
|
|
||||||
FaPaintBrush,
|
|
||||||
FaPlus,
|
|
||||||
} from 'react-icons/fa';
|
|
||||||
|
|
||||||
export const selector = createSelector(
|
|
||||||
[stateSelector, isStagingSelector],
|
|
||||||
({ canvas }, isStaging) => {
|
|
||||||
const { tool } = canvas;
|
|
||||||
|
|
||||||
return {
|
|
||||||
tool,
|
|
||||||
isStaging,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
memoizeOptions: {
|
|
||||||
resultEqualityCheck: isEqual,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const UnifiedCanvasToolSelect = () => {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { tool, isStaging } = useAppSelector(selector);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['b'],
|
|
||||||
() => {
|
|
||||||
handleSelectBrushTool();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['e'],
|
|
||||||
() => {
|
|
||||||
handleSelectEraserTool();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[tool]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['c'],
|
|
||||||
() => {
|
|
||||||
handleSelectColorPickerTool();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
},
|
|
||||||
[tool]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['shift+f'],
|
|
||||||
() => {
|
|
||||||
handleFillRect();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['delete', 'backspace'],
|
|
||||||
() => {
|
|
||||||
handleEraseBoundingBox();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => !isStaging,
|
|
||||||
preventDefault: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectBrushTool = useCallback(
|
|
||||||
() => dispatch(setTool('brush')),
|
|
||||||
[dispatch]
|
|
||||||
);
|
|
||||||
const handleSelectEraserTool = useCallback(
|
|
||||||
() => dispatch(setTool('eraser')),
|
|
||||||
[dispatch]
|
|
||||||
);
|
|
||||||
const handleSelectColorPickerTool = useCallback(
|
|
||||||
() => dispatch(setTool('colorPicker')),
|
|
||||||
[dispatch]
|
|
||||||
);
|
|
||||||
const handleFillRect = useCallback(() => dispatch(addFillRect()), [dispatch]);
|
|
||||||
const handleEraseBoundingBox = useCallback(
|
|
||||||
() => dispatch(addEraseRect()),
|
|
||||||
[dispatch]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex flexDirection="column" gap={2}>
|
|
||||||
<ButtonGroup>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.brush')} (B)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.brush')} (B)`}
|
|
||||||
icon={<FaPaintBrush />}
|
|
||||||
isChecked={tool === 'brush' && !isStaging}
|
|
||||||
onClick={handleSelectBrushTool}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
/>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.eraser')} (E)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.eraser')} (B)`}
|
|
||||||
icon={<FaEraser />}
|
|
||||||
isChecked={tool === 'eraser' && !isStaging}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
onClick={handleSelectEraserTool}
|
|
||||||
/>
|
|
||||||
</ButtonGroup>
|
|
||||||
<ButtonGroup>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.fillBoundingBox')} (Shift+F)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.fillBoundingBox')} (Shift+F)`}
|
|
||||||
icon={<FaFillDrip />}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
onClick={handleFillRect}
|
|
||||||
/>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.eraseBoundingBox')} (Del/Backspace)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.eraseBoundingBox')} (Del/Backspace)`}
|
|
||||||
icon={<FaPlus style={{ transform: 'rotate(45deg)' }} />}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
onClick={handleEraseBoundingBox}
|
|
||||||
/>
|
|
||||||
</ButtonGroup>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={`${t('unifiedCanvas.colorPicker')} (C)`}
|
|
||||||
tooltip={`${t('unifiedCanvas.colorPicker')} (C)`}
|
|
||||||
icon={<FaEyeDropper />}
|
|
||||||
isChecked={tool === 'colorPicker' && !isStaging}
|
|
||||||
isDisabled={isStaging}
|
|
||||||
onClick={handleSelectColorPickerTool}
|
|
||||||
width="max-content"
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(UnifiedCanvasToolSelect);
|
|
@ -1,53 +0,0 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import IAICanvasRedoButton from 'features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton';
|
|
||||||
import IAICanvasUndoButton from 'features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import UnifiedCanvasSettings from './UnifiedCanvasToolSettings/UnifiedCanvasSettings';
|
|
||||||
import UnifiedCanvasCopyToClipboard from './UnifiedCanvasToolbar/UnifiedCanvasCopyToClipboard';
|
|
||||||
import UnifiedCanvasDownloadImage from './UnifiedCanvasToolbar/UnifiedCanvasDownloadImage';
|
|
||||||
import UnifiedCanvasFileUploader from './UnifiedCanvasToolbar/UnifiedCanvasFileUploader';
|
|
||||||
import UnifiedCanvasLayerSelect from './UnifiedCanvasToolbar/UnifiedCanvasLayerSelect';
|
|
||||||
import UnifiedCanvasMergeVisible from './UnifiedCanvasToolbar/UnifiedCanvasMergeVisible';
|
|
||||||
import UnifiedCanvasMoveTool from './UnifiedCanvasToolbar/UnifiedCanvasMoveTool';
|
|
||||||
import UnifiedCanvasResetCanvas from './UnifiedCanvasToolbar/UnifiedCanvasResetCanvas';
|
|
||||||
import UnifiedCanvasResetView from './UnifiedCanvasToolbar/UnifiedCanvasResetView';
|
|
||||||
import UnifiedCanvasSaveToGallery from './UnifiedCanvasToolbar/UnifiedCanvasSaveToGallery';
|
|
||||||
import UnifiedCanvasToolSelect from './UnifiedCanvasToolbar/UnifiedCanvasToolSelect';
|
|
||||||
|
|
||||||
const UnifiedCanvasToolbarBeta = () => {
|
|
||||||
return (
|
|
||||||
<Flex flexDirection="column" rowGap={2} width="min-content">
|
|
||||||
<UnifiedCanvasLayerSelect />
|
|
||||||
<UnifiedCanvasToolSelect />
|
|
||||||
|
|
||||||
<Flex gap={2}>
|
|
||||||
<UnifiedCanvasMoveTool />
|
|
||||||
<UnifiedCanvasResetView />
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Flex columnGap={2}>
|
|
||||||
<UnifiedCanvasMergeVisible />
|
|
||||||
<UnifiedCanvasSaveToGallery />
|
|
||||||
</Flex>
|
|
||||||
<Flex columnGap={2}>
|
|
||||||
<UnifiedCanvasCopyToClipboard />
|
|
||||||
<UnifiedCanvasDownloadImage />
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Flex gap={2}>
|
|
||||||
<IAICanvasUndoButton />
|
|
||||||
<IAICanvasRedoButton />
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Flex gap={2}>
|
|
||||||
<UnifiedCanvasFileUploader />
|
|
||||||
<UnifiedCanvasResetCanvas />
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<UnifiedCanvasSettings />
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(UnifiedCanvasToolbarBeta);
|
|
Loading…
Reference in New Issue
Block a user