mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): improve accordion ux
- Accordions now may be opened or closed regardless of whether or not their contents are enabled or active - Accordions have a short text indicator alerting the user if their contents are enabled, either a simple `Enabled` or, for accordions like LoRA or ControlNet, `X Active` if any are active
This commit is contained in:
parent
6ce867feb4
commit
e41e8606b5
@ -4,22 +4,25 @@ import {
|
|||||||
Collapse,
|
Collapse,
|
||||||
Flex,
|
Flex,
|
||||||
Spacer,
|
Spacer,
|
||||||
Switch,
|
Text,
|
||||||
useColorMode,
|
useColorMode,
|
||||||
|
useDisclosure,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { PropsWithChildren, memo } from 'react';
|
import { PropsWithChildren, memo } from 'react';
|
||||||
import { mode } from 'theme/util/mode';
|
import { mode } from 'theme/util/mode';
|
||||||
|
|
||||||
export type IAIToggleCollapseProps = PropsWithChildren & {
|
export type IAIToggleCollapseProps = PropsWithChildren & {
|
||||||
label: string;
|
label: string;
|
||||||
isOpen: boolean;
|
activeLabel?: string;
|
||||||
onToggle: () => void;
|
defaultIsOpen?: boolean;
|
||||||
withSwitch?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const IAICollapse = (props: IAIToggleCollapseProps) => {
|
const IAICollapse = (props: IAIToggleCollapseProps) => {
|
||||||
const { label, isOpen, onToggle, children, withSwitch = false } = props;
|
const { label, activeLabel, children, defaultIsOpen = false } = props;
|
||||||
|
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen });
|
||||||
const { colorMode } = useColorMode();
|
const { colorMode } = useColorMode();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Flex
|
<Flex
|
||||||
@ -28,6 +31,7 @@ const IAICollapse = (props: IAIToggleCollapseProps) => {
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
p: 2,
|
p: 2,
|
||||||
px: 4,
|
px: 4,
|
||||||
|
gap: 2,
|
||||||
borderTopRadius: 'base',
|
borderTopRadius: 'base',
|
||||||
borderBottomRadius: isOpen ? 0 : 'base',
|
borderBottomRadius: isOpen ? 0 : 'base',
|
||||||
bg: isOpen
|
bg: isOpen
|
||||||
@ -48,19 +52,40 @@ const IAICollapse = (props: IAIToggleCollapseProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
|
<AnimatePresence>
|
||||||
|
{activeLabel && (
|
||||||
|
<motion.div
|
||||||
|
key="statusText"
|
||||||
|
initial={{
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
opacity: 1,
|
||||||
|
transition: { duration: 0.1 },
|
||||||
|
}}
|
||||||
|
exit={{
|
||||||
|
opacity: 0,
|
||||||
|
transition: { duration: 0.1 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
sx={{ color: 'accent.500', _dark: { color: 'accent.300' } }}
|
||||||
|
>
|
||||||
|
{activeLabel}
|
||||||
|
</Text>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
{withSwitch && <Switch isChecked={isOpen} pointerEvents="none" />}
|
<ChevronUpIcon
|
||||||
{!withSwitch && (
|
sx={{
|
||||||
<ChevronUpIcon
|
w: '1rem',
|
||||||
sx={{
|
h: '1rem',
|
||||||
w: '1rem',
|
transform: isOpen ? 'rotate(0deg)' : 'rotate(180deg)',
|
||||||
h: '1rem',
|
transitionProperty: 'common',
|
||||||
transform: isOpen ? 'rotate(0deg)' : 'rotate(180deg)',
|
transitionDuration: 'normal',
|
||||||
transitionProperty: 'common',
|
}}
|
||||||
transitionDuration: 'normal',
|
/>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
<Collapse in={isOpen} animateOpacity style={{ overflow: 'unset' }}>
|
<Collapse in={isOpen} animateOpacity style={{ overflow: 'unset' }}>
|
||||||
<Box
|
<Box
|
||||||
|
@ -36,7 +36,6 @@ const IAISwitch = (props: Props) => {
|
|||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
width={width}
|
width={width}
|
||||||
display="flex"
|
display="flex"
|
||||||
gap={4}
|
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
{...formControlProps}
|
{...formControlProps}
|
||||||
>
|
>
|
||||||
@ -47,6 +46,7 @@ const IAISwitch = (props: Props) => {
|
|||||||
sx={{
|
sx={{
|
||||||
cursor: isDisabled ? 'not-allowed' : 'pointer',
|
cursor: isDisabled ? 'not-allowed' : 'pointer',
|
||||||
...formLabelProps?.sx,
|
...formLabelProps?.sx,
|
||||||
|
pe: 4,
|
||||||
}}
|
}}
|
||||||
{...formLabelProps}
|
{...formLabelProps}
|
||||||
>
|
>
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
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 IAISwitch from 'common/components/IAISwitch';
|
||||||
|
import { isControlNetEnabledToggled } from 'features/controlNet/store/controlNetSlice';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => {
|
||||||
|
const { isEnabled } = state.controlNet;
|
||||||
|
|
||||||
|
return { isEnabled };
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
const ParamControlNetFeatureToggle = () => {
|
||||||
|
const { isEnabled } = useAppSelector(selector);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const handleChange = useCallback(() => {
|
||||||
|
dispatch(isControlNetEnabledToggled());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAISwitch
|
||||||
|
label="Enable ControlNet"
|
||||||
|
isChecked={isEnabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ParamControlNetFeatureToggle;
|
@ -0,0 +1,15 @@
|
|||||||
|
import { filter } from 'lodash-es';
|
||||||
|
import { ControlNetConfig } from '../store/controlNetSlice';
|
||||||
|
|
||||||
|
export const getValidControlNets = (
|
||||||
|
controlNets: Record<string, ControlNetConfig>
|
||||||
|
) => {
|
||||||
|
const validControlNets = filter(
|
||||||
|
controlNets,
|
||||||
|
(c) =>
|
||||||
|
c.isEnabled &&
|
||||||
|
(Boolean(c.processedControlImage) ||
|
||||||
|
(c.processorType === 'none' && Boolean(c.controlImage)))
|
||||||
|
);
|
||||||
|
return validControlNets;
|
||||||
|
};
|
@ -1,40 +1,30 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { isEnabledToggled } from '../store/slice';
|
|
||||||
import ParamDynamicPromptsMaxPrompts from './ParamDynamicPromptsMaxPrompts';
|
|
||||||
import ParamDynamicPromptsCombinatorial from './ParamDynamicPromptsCombinatorial';
|
import ParamDynamicPromptsCombinatorial from './ParamDynamicPromptsCombinatorial';
|
||||||
import { Flex } from '@chakra-ui/react';
|
import ParamDynamicPromptsToggle from './ParamDynamicPromptsEnabled';
|
||||||
|
import ParamDynamicPromptsMaxPrompts from './ParamDynamicPromptsMaxPrompts';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
(state) => {
|
(state) => {
|
||||||
const { isEnabled } = state.dynamicPrompts;
|
const { isEnabled } = state.dynamicPrompts;
|
||||||
|
|
||||||
return { isEnabled };
|
return { activeLabel: isEnabled ? 'Enabled' : undefined };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const ParamDynamicPromptsCollapse = () => {
|
const ParamDynamicPromptsCollapse = () => {
|
||||||
const dispatch = useAppDispatch();
|
const { activeLabel } = useAppSelector(selector);
|
||||||
const { isEnabled } = useAppSelector(selector);
|
|
||||||
|
|
||||||
const handleToggleIsEnabled = useCallback(() => {
|
|
||||||
dispatch(isEnabledToggled());
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse label="Dynamic Prompts" activeLabel={activeLabel}>
|
||||||
isOpen={isEnabled}
|
|
||||||
onToggle={handleToggleIsEnabled}
|
|
||||||
label="Dynamic Prompts"
|
|
||||||
withSwitch
|
|
||||||
>
|
|
||||||
<Flex sx={{ gap: 2, flexDir: 'column' }}>
|
<Flex sx={{ gap: 2, flexDir: 'column' }}>
|
||||||
|
<ParamDynamicPromptsToggle />
|
||||||
<ParamDynamicPromptsCombinatorial />
|
<ParamDynamicPromptsCombinatorial />
|
||||||
<ParamDynamicPromptsMaxPrompts />
|
<ParamDynamicPromptsMaxPrompts />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { combinatorialToggled } from '../store/slice';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { combinatorialToggled } from '../store/slice';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
(state) => {
|
(state) => {
|
||||||
const { combinatorial } = state.dynamicPrompts;
|
const { combinatorial, isEnabled } = state.dynamicPrompts;
|
||||||
|
|
||||||
return { combinatorial };
|
return { combinatorial, isDisabled: !isEnabled };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const ParamDynamicPromptsCombinatorial = () => {
|
const ParamDynamicPromptsCombinatorial = () => {
|
||||||
const { combinatorial } = useAppSelector(selector);
|
const { combinatorial, isDisabled } = useAppSelector(selector);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const handleChange = useCallback(() => {
|
const handleChange = useCallback(() => {
|
||||||
@ -26,6 +26,7 @@ const ParamDynamicPromptsCombinatorial = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<IAISwitch
|
<IAISwitch
|
||||||
|
isDisabled={isDisabled}
|
||||||
label="Combinatorial Generation"
|
label="Combinatorial Generation"
|
||||||
isChecked={combinatorial}
|
isChecked={combinatorial}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
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 IAISwitch from 'common/components/IAISwitch';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { isEnabledToggled } from '../store/slice';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => {
|
||||||
|
const { isEnabled } = state.dynamicPrompts;
|
||||||
|
|
||||||
|
return { isEnabled };
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
const ParamDynamicPromptsToggle = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { isEnabled } = useAppSelector(selector);
|
||||||
|
|
||||||
|
const handleToggleIsEnabled = useCallback(() => {
|
||||||
|
dispatch(isEnabledToggled());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAISwitch
|
||||||
|
label="Enable Dynamic Prompts"
|
||||||
|
isChecked={isEnabled}
|
||||||
|
onChange={handleToggleIsEnabled}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ParamDynamicPromptsToggle;
|
@ -1,25 +1,31 @@
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAISlider from 'common/components/IAISlider';
|
|
||||||
import { maxPromptsChanged, maxPromptsReset } from '../store/slice';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
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 { useCallback } from 'react';
|
||||||
|
import { maxPromptsChanged, maxPromptsReset } from '../store/slice';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
(state) => {
|
(state) => {
|
||||||
const { maxPrompts, combinatorial } = state.dynamicPrompts;
|
const { maxPrompts, combinatorial, isEnabled } = state.dynamicPrompts;
|
||||||
const { min, sliderMax, inputMax } =
|
const { min, sliderMax, inputMax } =
|
||||||
state.config.sd.dynamicPrompts.maxPrompts;
|
state.config.sd.dynamicPrompts.maxPrompts;
|
||||||
|
|
||||||
return { maxPrompts, min, sliderMax, inputMax, combinatorial };
|
return {
|
||||||
|
maxPrompts,
|
||||||
|
min,
|
||||||
|
sliderMax,
|
||||||
|
inputMax,
|
||||||
|
isDisabled: !isEnabled || !combinatorial,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const ParamDynamicPromptsMaxPrompts = () => {
|
const ParamDynamicPromptsMaxPrompts = () => {
|
||||||
const { maxPrompts, min, sliderMax, inputMax, combinatorial } =
|
const { maxPrompts, min, sliderMax, inputMax, isDisabled } =
|
||||||
useAppSelector(selector);
|
useAppSelector(selector);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
@ -37,7 +43,7 @@ const ParamDynamicPromptsMaxPrompts = () => {
|
|||||||
return (
|
return (
|
||||||
<IAISlider
|
<IAISlider
|
||||||
label="Max Prompts"
|
label="Max Prompts"
|
||||||
isDisabled={!combinatorial}
|
isDisabled={isDisabled}
|
||||||
min={min}
|
min={min}
|
||||||
max={sliderMax}
|
max={sliderMax}
|
||||||
value={maxPrompts}
|
value={maxPrompts}
|
||||||
|
@ -1,14 +1,30 @@
|
|||||||
import { Flex, useDisclosure } from '@chakra-ui/react';
|
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 IAICollapse from 'common/components/IAICollapse';
|
||||||
|
import { size } from 'lodash-es';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import ParamLoraList from './ParamLoraList';
|
import ParamLoraList from './ParamLoraList';
|
||||||
import ParamLoraSelect from './ParamLoraSelect';
|
import ParamLoraSelect from './ParamLoraSelect';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => {
|
||||||
|
const loraCount = size(state.lora.loras);
|
||||||
|
return {
|
||||||
|
activeLabel: loraCount > 0 ? `${loraCount} Active` : undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
const ParamLoraCollapse = () => {
|
const ParamLoraCollapse = () => {
|
||||||
const { isOpen, onToggle } = useDisclosure();
|
const { activeLabel } = useAppSelector(selector);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse label="LoRAs" isOpen={isOpen} onToggle={onToggle}>
|
<IAICollapse label={'LoRA'} activeLabel={activeLabel}>
|
||||||
<Flex sx={{ flexDir: 'column', gap: 2 }}>
|
<Flex sx={{ flexDir: 'column', gap: 2 }}>
|
||||||
<ParamLoraSelect />
|
<ParamLoraSelect />
|
||||||
<ParamLoraList />
|
<ParamLoraList />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { filter } from 'lodash-es';
|
import { getValidControlNets } from 'features/controlNet/util/getValidControlNets';
|
||||||
import { CollectInvocation, ControlNetInvocation } from 'services/api/types';
|
import { CollectInvocation, ControlNetInvocation } from 'services/api/types';
|
||||||
import { NonNullableGraph } from '../types/types';
|
import { NonNullableGraph } from '../types/types';
|
||||||
import { CONTROL_NET_COLLECT } from './graphBuilders/constants';
|
import { CONTROL_NET_COLLECT } from './graphBuilders/constants';
|
||||||
@ -11,13 +11,7 @@ export const addControlNetToLinearGraph = (
|
|||||||
): void => {
|
): void => {
|
||||||
const { isEnabled: isControlNetEnabled, controlNets } = state.controlNet;
|
const { isEnabled: isControlNetEnabled, controlNets } = state.controlNet;
|
||||||
|
|
||||||
const validControlNets = filter(
|
const validControlNets = getValidControlNets(controlNets);
|
||||||
controlNets,
|
|
||||||
(c) =>
|
|
||||||
c.isEnabled &&
|
|
||||||
(Boolean(c.processedControlImage) ||
|
|
||||||
(c.processorType === 'none' && Boolean(c.controlImage)))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isControlNetEnabled && Boolean(validControlNets.length)) {
|
if (isControlNetEnabled && Boolean(validControlNets.length)) {
|
||||||
if (validControlNets.length > 1) {
|
if (validControlNets.length > 1) {
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
import { Flex, useDisclosure } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import ParamBoundingBoxWidth from './ParamBoundingBoxWidth';
|
import { useTranslation } from 'react-i18next';
|
||||||
import ParamBoundingBoxHeight from './ParamBoundingBoxHeight';
|
import ParamBoundingBoxHeight from './ParamBoundingBoxHeight';
|
||||||
|
import ParamBoundingBoxWidth from './ParamBoundingBoxWidth';
|
||||||
|
|
||||||
const ParamBoundingBoxCollapse = () => {
|
const ParamBoundingBoxCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isOpen, onToggle } = useDisclosure();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse label={t('parameters.boundingBoxHeader')}>
|
||||||
label={t('parameters.boundingBoxHeader')}
|
|
||||||
isOpen={isOpen}
|
|
||||||
onToggle={onToggle}
|
|
||||||
>
|
|
||||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||||
<ParamBoundingBoxWidth />
|
<ParamBoundingBoxWidth />
|
||||||
<ParamBoundingBoxHeight />
|
<ParamBoundingBoxHeight />
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Flex, useDisclosure } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@ -6,19 +6,14 @@ import IAICollapse from 'common/components/IAICollapse';
|
|||||||
import ParamInfillMethod from './ParamInfillMethod';
|
import ParamInfillMethod from './ParamInfillMethod';
|
||||||
import ParamInfillTilesize from './ParamInfillTilesize';
|
import ParamInfillTilesize from './ParamInfillTilesize';
|
||||||
import ParamScaleBeforeProcessing from './ParamScaleBeforeProcessing';
|
import ParamScaleBeforeProcessing from './ParamScaleBeforeProcessing';
|
||||||
import ParamScaledWidth from './ParamScaledWidth';
|
|
||||||
import ParamScaledHeight from './ParamScaledHeight';
|
import ParamScaledHeight from './ParamScaledHeight';
|
||||||
|
import ParamScaledWidth from './ParamScaledWidth';
|
||||||
|
|
||||||
const ParamInfillCollapse = () => {
|
const ParamInfillCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isOpen, onToggle } = useDisclosure();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse label={t('parameters.infillScalingHeader')}>
|
||||||
label={t('parameters.infillScalingHeader')}
|
|
||||||
isOpen={isOpen}
|
|
||||||
onToggle={onToggle}
|
|
||||||
>
|
|
||||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||||
<ParamInfillMethod />
|
<ParamInfillMethod />
|
||||||
<ParamInfillTilesize />
|
<ParamInfillTilesize />
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import ParamSeamBlur from './ParamSeamBlur';
|
import ParamSeamBlur from './ParamSeamBlur';
|
||||||
import ParamSeamSize from './ParamSeamSize';
|
import ParamSeamSize from './ParamSeamSize';
|
||||||
import ParamSeamSteps from './ParamSeamSteps';
|
import ParamSeamSteps from './ParamSeamSteps';
|
||||||
import ParamSeamStrength from './ParamSeamStrength';
|
import ParamSeamStrength from './ParamSeamStrength';
|
||||||
import { useDisclosure } from '@chakra-ui/react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
const ParamSeamCorrectionCollapse = () => {
|
const ParamSeamCorrectionCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isOpen, onToggle } = useDisclosure();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse label={t('parameters.seamCorrectionHeader')}>
|
||||||
label={t('parameters.seamCorrectionHeader')}
|
|
||||||
isOpen={isOpen}
|
|
||||||
onToggle={onToggle}
|
|
||||||
>
|
|
||||||
<ParamSeamSize />
|
<ParamSeamSize />
|
||||||
<ParamSeamBlur />
|
<ParamSeamBlur />
|
||||||
<ParamSeamStrength />
|
<ParamSeamStrength />
|
||||||
|
@ -1,41 +1,45 @@
|
|||||||
import { Divider, Flex } from '@chakra-ui/react';
|
import { Divider, Flex } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
|
||||||
import { Fragment, memo, useCallback } from 'react';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
|
import ControlNet from 'features/controlNet/components/ControlNet';
|
||||||
|
import ParamControlNetFeatureToggle from 'features/controlNet/components/parameters/ParamControlNetFeatureToggle';
|
||||||
import {
|
import {
|
||||||
controlNetAdded,
|
controlNetAdded,
|
||||||
controlNetSelector,
|
controlNetSelector,
|
||||||
isControlNetEnabledToggled,
|
|
||||||
} from 'features/controlNet/store/controlNetSlice';
|
} from 'features/controlNet/store/controlNetSlice';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { getValidControlNets } from 'features/controlNet/util/getValidControlNets';
|
||||||
import { map } from 'lodash-es';
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import { map } from 'lodash-es';
|
||||||
import ControlNet from 'features/controlNet/components/ControlNet';
|
import { Fragment, memo, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
controlNetSelector,
|
controlNetSelector,
|
||||||
(controlNet) => {
|
(controlNet) => {
|
||||||
const { controlNets, isEnabled } = controlNet;
|
const { controlNets, isEnabled } = controlNet;
|
||||||
|
|
||||||
return { controlNetsArray: map(controlNets), isEnabled };
|
const validControlNets = getValidControlNets(controlNets);
|
||||||
|
|
||||||
|
const activeLabel =
|
||||||
|
isEnabled && validControlNets.length > 0
|
||||||
|
? `${validControlNets.length} Active`
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return { controlNetsArray: map(controlNets), activeLabel };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const ParamControlNetCollapse = () => {
|
const ParamControlNetCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { controlNetsArray, isEnabled } = useAppSelector(selector);
|
const { controlNetsArray, activeLabel } = useAppSelector(selector);
|
||||||
const isControlNetDisabled = useFeatureStatus('controlNet').isFeatureDisabled;
|
const isControlNetDisabled = useFeatureStatus('controlNet').isFeatureDisabled;
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const handleClickControlNetToggle = useCallback(() => {
|
|
||||||
dispatch(isControlNetEnabledToggled());
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
const handleClickedAddControlNet = useCallback(() => {
|
const handleClickedAddControlNet = useCallback(() => {
|
||||||
dispatch(controlNetAdded({ controlNetId: uuidv4() }));
|
dispatch(controlNetAdded({ controlNetId: uuidv4() }));
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
@ -45,13 +49,9 @@ const ParamControlNetCollapse = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse label="ControlNet" activeLabel={activeLabel}>
|
||||||
label={'ControlNet'}
|
|
||||||
isOpen={isEnabled}
|
|
||||||
onToggle={handleClickControlNetToggle}
|
|
||||||
withSwitch
|
|
||||||
>
|
|
||||||
<Flex sx={{ flexDir: 'column', gap: 3 }}>
|
<Flex sx={{ flexDir: 'column', gap: 3 }}>
|
||||||
|
<ParamControlNetFeatureToggle />
|
||||||
{controlNetsArray.map((c, i) => (
|
{controlNetsArray.map((c, i) => (
|
||||||
<Fragment key={c.controlNetId}>
|
<Fragment key={c.controlNetId}>
|
||||||
{i > 0 && <Divider />}
|
{i > 0 && <Divider />}
|
||||||
|
@ -1,37 +1,39 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { RootState } from 'app/store/store';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
import { memo } from 'react';
|
|
||||||
import { ParamHiresStrength } from './ParamHiresStrength';
|
|
||||||
import { setHiresFix } from 'features/parameters/store/postprocessingSlice';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ParamHiresStrength } from './ParamHiresStrength';
|
||||||
|
import { ParamHiresToggle } from './ParamHiresToggle';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => {
|
||||||
|
const activeLabel = state.postprocessing.hiresFix ? 'Enabled' : undefined;
|
||||||
|
|
||||||
|
return { activeLabel };
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
const ParamHiresCollapse = () => {
|
const ParamHiresCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const hiresFix = useAppSelector(
|
const { activeLabel } = useAppSelector(selector);
|
||||||
(state: RootState) => state.postprocessing.hiresFix
|
|
||||||
);
|
|
||||||
|
|
||||||
const isHiresEnabled = useFeatureStatus('hires').isFeatureEnabled;
|
const isHiresEnabled = useFeatureStatus('hires').isFeatureEnabled;
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const handleToggle = () => dispatch(setHiresFix(!hiresFix));
|
|
||||||
|
|
||||||
if (!isHiresEnabled) {
|
if (!isHiresEnabled) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse label={t('parameters.hiresOptim')} activeLabel={activeLabel}>
|
||||||
label={t('parameters.hiresOptim')}
|
|
||||||
isOpen={hiresFix}
|
|
||||||
onToggle={handleToggle}
|
|
||||||
withSwitch
|
|
||||||
>
|
|
||||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||||
|
<ParamHiresToggle />
|
||||||
<ParamHiresStrength />
|
<ParamHiresStrength />
|
||||||
</Flex>
|
</Flex>
|
||||||
</IAICollapse>
|
</IAICollapse>
|
||||||
|
@ -23,7 +23,6 @@ export const ParamHiresToggle = () => {
|
|||||||
return (
|
return (
|
||||||
<IAISwitch
|
<IAISwitch
|
||||||
label={t('parameters.hiresOptim')}
|
label={t('parameters.hiresOptim')}
|
||||||
fontSize="md"
|
|
||||||
isChecked={hiresFix}
|
isChecked={hiresFix}
|
||||||
onChange={handleChangeHiresFix}
|
onChange={handleChangeHiresFix}
|
||||||
/>
|
/>
|
||||||
|
@ -1,27 +1,33 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { Flex } from '@chakra-ui/react';
|
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 IAICollapse from 'common/components/IAICollapse';
|
||||||
import ParamPerlinNoise from './ParamPerlinNoise';
|
|
||||||
import ParamNoiseThreshold from './ParamNoiseThreshold';
|
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { setShouldUseNoiseSettings } from 'features/parameters/store/generationSlice';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import ParamNoiseThreshold from './ParamNoiseThreshold';
|
||||||
|
import { ParamNoiseToggle } from './ParamNoiseToggle';
|
||||||
|
import ParamPerlinNoise from './ParamPerlinNoise';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => {
|
||||||
|
const { shouldUseNoiseSettings } = state.generation;
|
||||||
|
return {
|
||||||
|
activeLabel: shouldUseNoiseSettings ? 'Enabled' : undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
const ParamNoiseCollapse = () => {
|
const ParamNoiseCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const isNoiseEnabled = useFeatureStatus('noise').isFeatureEnabled;
|
const isNoiseEnabled = useFeatureStatus('noise').isFeatureEnabled;
|
||||||
|
|
||||||
const shouldUseNoiseSettings = useAppSelector(
|
const { activeLabel } = useAppSelector(selector);
|
||||||
(state: RootState) => state.generation.shouldUseNoiseSettings
|
|
||||||
);
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const handleToggle = () =>
|
|
||||||
dispatch(setShouldUseNoiseSettings(!shouldUseNoiseSettings));
|
|
||||||
|
|
||||||
if (!isNoiseEnabled) {
|
if (!isNoiseEnabled) {
|
||||||
return null;
|
return null;
|
||||||
@ -30,11 +36,10 @@ const ParamNoiseCollapse = () => {
|
|||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse
|
||||||
label={t('parameters.noiseSettings')}
|
label={t('parameters.noiseSettings')}
|
||||||
isOpen={shouldUseNoiseSettings}
|
activeLabel={activeLabel}
|
||||||
onToggle={handleToggle}
|
|
||||||
withSwitch
|
|
||||||
>
|
>
|
||||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||||
|
<ParamNoiseToggle />
|
||||||
<ParamPerlinNoise />
|
<ParamPerlinNoise />
|
||||||
<ParamNoiseThreshold />
|
<ParamNoiseThreshold />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,18 +1,31 @@
|
|||||||
import { RootState } from 'app/store/store';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { setThreshold } from 'features/parameters/store/generationSlice';
|
import { setThreshold } from 'features/parameters/store/generationSlice';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => {
|
||||||
|
const { shouldUseNoiseSettings, threshold } = state.generation;
|
||||||
|
return {
|
||||||
|
isDisabled: !shouldUseNoiseSettings,
|
||||||
|
threshold,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
export default function ParamNoiseThreshold() {
|
export default function ParamNoiseThreshold() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const threshold = useAppSelector(
|
const { threshold, isDisabled } = useAppSelector(selector);
|
||||||
(state: RootState) => state.generation.threshold
|
|
||||||
);
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAISlider
|
<IAISlider
|
||||||
|
isDisabled={isDisabled}
|
||||||
label={t('parameters.noiseThreshold')}
|
label={t('parameters.noiseThreshold')}
|
||||||
min={0}
|
min={0}
|
||||||
max={20}
|
max={20}
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
import type { RootState } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
|
import { setShouldUseNoiseSettings } from 'features/parameters/store/generationSlice';
|
||||||
|
import { ChangeEvent } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
export const ParamNoiseToggle = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const shouldUseNoiseSettings = useAppSelector(
|
||||||
|
(state: RootState) => state.generation.shouldUseNoiseSettings
|
||||||
|
);
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
|
||||||
|
dispatch(setShouldUseNoiseSettings(e.target.checked));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAISwitch
|
||||||
|
label="Enable Noise Settings"
|
||||||
|
isChecked={shouldUseNoiseSettings}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -1,16 +1,31 @@
|
|||||||
import { RootState } from 'app/store/store';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { setPerlin } from 'features/parameters/store/generationSlice';
|
import { setPerlin } from 'features/parameters/store/generationSlice';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => {
|
||||||
|
const { shouldUseNoiseSettings, perlin } = state.generation;
|
||||||
|
return {
|
||||||
|
isDisabled: !shouldUseNoiseSettings,
|
||||||
|
perlin,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
export default function ParamPerlinNoise() {
|
export default function ParamPerlinNoise() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const perlin = useAppSelector((state: RootState) => state.generation.perlin);
|
const { perlin, isDisabled } = useAppSelector(selector);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAISlider
|
<IAISlider
|
||||||
|
isDisabled={isDisabled}
|
||||||
label={t('parameters.perlinNoise')}
|
label={t('parameters.perlinNoise')}
|
||||||
min={0}
|
min={0}
|
||||||
max={1}
|
max={1}
|
||||||
|
@ -1,36 +1,46 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { Box, Flex } from '@chakra-ui/react';
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { setSeamless } from 'features/parameters/store/generationSlice';
|
|
||||||
import { memo } from 'react';
|
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
|
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
||||||
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import ParamSeamlessXAxis from './ParamSeamlessXAxis';
|
import ParamSeamlessXAxis from './ParamSeamlessXAxis';
|
||||||
import ParamSeamlessYAxis from './ParamSeamlessYAxis';
|
import ParamSeamlessYAxis from './ParamSeamlessYAxis';
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
|
const getActiveLabel = (seamlessXAxis: boolean, seamlessYAxis: boolean) => {
|
||||||
|
if (seamlessXAxis && seamlessYAxis) {
|
||||||
|
return 'X & Y';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seamlessXAxis) {
|
||||||
|
return 'X';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seamlessYAxis) {
|
||||||
|
return 'Y';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
generationSelector,
|
generationSelector,
|
||||||
(generation) => {
|
(generation) => {
|
||||||
const { shouldUseSeamless, seamlessXAxis, seamlessYAxis } = generation;
|
const { seamlessXAxis, seamlessYAxis } = generation;
|
||||||
|
|
||||||
return { shouldUseSeamless, seamlessXAxis, seamlessYAxis };
|
const activeLabel = getActiveLabel(seamlessXAxis, seamlessYAxis);
|
||||||
|
return { activeLabel };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const ParamSeamlessCollapse = () => {
|
const ParamSeamlessCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { shouldUseSeamless } = useAppSelector(selector);
|
const { activeLabel } = useAppSelector(selector);
|
||||||
|
|
||||||
const isSeamlessEnabled = useFeatureStatus('seamless').isFeatureEnabled;
|
const isSeamlessEnabled = useFeatureStatus('seamless').isFeatureEnabled;
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const handleToggle = () => dispatch(setSeamless(!shouldUseSeamless));
|
|
||||||
|
|
||||||
if (!isSeamlessEnabled) {
|
if (!isSeamlessEnabled) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -38,9 +48,7 @@ const ParamSeamlessCollapse = () => {
|
|||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse
|
||||||
label={t('parameters.seamlessTiling')}
|
label={t('parameters.seamlessTiling')}
|
||||||
isOpen={shouldUseSeamless}
|
activeLabel={activeLabel}
|
||||||
onToggle={handleToggle}
|
|
||||||
withSwitch
|
|
||||||
>
|
>
|
||||||
<Flex sx={{ gap: 5 }}>
|
<Flex sx={{ gap: 5 }}>
|
||||||
<Box flexGrow={1}>
|
<Box flexGrow={1}>
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
import { memo } from 'react';
|
|
||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { memo } from 'react';
|
||||||
import ParamSymmetryHorizontal from './ParamSymmetryHorizontal';
|
import ParamSymmetryHorizontal from './ParamSymmetryHorizontal';
|
||||||
import ParamSymmetryVertical from './ParamSymmetryVertical';
|
import ParamSymmetryVertical from './ParamSymmetryVertical';
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
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 IAICollapse from 'common/components/IAICollapse';
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { setShouldUseSymmetry } from 'features/parameters/store/generationSlice';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import ParamSymmetryToggle from './ParamSymmetryToggle';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => ({
|
||||||
|
activeLabel: state.generation.shouldUseSymmetry ? 'Enabled' : undefined,
|
||||||
|
}),
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
const ParamSymmetryCollapse = () => {
|
const ParamSymmetryCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const shouldUseSymmetry = useAppSelector(
|
const { activeLabel } = useAppSelector(selector);
|
||||||
(state: RootState) => state.generation.shouldUseSymmetry
|
|
||||||
);
|
|
||||||
|
|
||||||
const isSymmetryEnabled = useFeatureStatus('symmetry').isFeatureEnabled;
|
const isSymmetryEnabled = useFeatureStatus('symmetry').isFeatureEnabled;
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const handleToggle = () => dispatch(setShouldUseSymmetry(!shouldUseSymmetry));
|
|
||||||
|
|
||||||
if (!isSymmetryEnabled) {
|
if (!isSymmetryEnabled) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse label={t('parameters.symmetry')} activeLabel={activeLabel}>
|
||||||
label={t('parameters.symmetry')}
|
|
||||||
isOpen={shouldUseSymmetry}
|
|
||||||
onToggle={handleToggle}
|
|
||||||
withSwitch
|
|
||||||
>
|
|
||||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||||
|
<ParamSymmetryToggle />
|
||||||
<ParamSymmetryHorizontal />
|
<ParamSymmetryHorizontal />
|
||||||
<ParamSymmetryVertical />
|
<ParamSymmetryVertical />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -12,6 +12,7 @@ export default function ParamSymmetryToggle() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<IAISwitch
|
<IAISwitch
|
||||||
|
label="Enable Symmetry"
|
||||||
isChecked={shouldUseSymmetry}
|
isChecked={shouldUseSymmetry}
|
||||||
onChange={(e) => dispatch(setShouldUseSymmetry(e.target.checked))}
|
onChange={(e) => dispatch(setShouldUseSymmetry(e.target.checked))}
|
||||||
/>
|
/>
|
||||||
|
@ -1,39 +1,42 @@
|
|||||||
import ParamVariationWeights from './ParamVariationWeights';
|
|
||||||
import ParamVariationAmount from './ParamVariationAmount';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { setShouldGenerateVariations } from 'features/parameters/store/generationSlice';
|
|
||||||
import { Flex } from '@chakra-ui/react';
|
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 IAICollapse from 'common/components/IAICollapse';
|
||||||
import { memo } from 'react';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
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 ParamVariationCollapse = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const shouldGenerateVariations = useAppSelector(
|
const { activeLabel } = useAppSelector(selector);
|
||||||
(state: RootState) => state.generation.shouldGenerateVariations
|
|
||||||
);
|
|
||||||
|
|
||||||
const isVariationEnabled = useFeatureStatus('variation').isFeatureEnabled;
|
const isVariationEnabled = useFeatureStatus('variation').isFeatureEnabled;
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const handleToggle = () =>
|
|
||||||
dispatch(setShouldGenerateVariations(!shouldGenerateVariations));
|
|
||||||
|
|
||||||
if (!isVariationEnabled) {
|
if (!isVariationEnabled) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse
|
<IAICollapse label={t('parameters.variations')} activeLabel={activeLabel}>
|
||||||
label={t('parameters.variations')}
|
|
||||||
isOpen={shouldGenerateVariations}
|
|
||||||
onToggle={handleToggle}
|
|
||||||
withSwitch
|
|
||||||
>
|
|
||||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||||
|
<ParamVariationToggle />
|
||||||
<ParamVariationAmount />
|
<ParamVariationAmount />
|
||||||
<ParamVariationWeights />
|
<ParamVariationWeights />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
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';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
export const ParamVariationToggle = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const shouldGenerateVariations = useAppSelector(
|
||||||
|
(state: RootState) => state.generation.shouldGenerateVariations
|
||||||
|
);
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
|
||||||
|
dispatch(setShouldGenerateVariations(e.target.checked));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAISwitch
|
||||||
|
label="Enable Variations"
|
||||||
|
isChecked={shouldGenerateVariations}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -49,7 +49,6 @@ export interface GenerationState {
|
|||||||
verticalSymmetrySteps: number;
|
verticalSymmetrySteps: number;
|
||||||
model: ModelParam;
|
model: ModelParam;
|
||||||
vae: VAEParam;
|
vae: VAEParam;
|
||||||
shouldUseSeamless: boolean;
|
|
||||||
seamlessXAxis: boolean;
|
seamlessXAxis: boolean;
|
||||||
seamlessYAxis: boolean;
|
seamlessYAxis: boolean;
|
||||||
}
|
}
|
||||||
@ -84,9 +83,8 @@ export const initialGenerationState: GenerationState = {
|
|||||||
verticalSymmetrySteps: 0,
|
verticalSymmetrySteps: 0,
|
||||||
model: '',
|
model: '',
|
||||||
vae: '',
|
vae: '',
|
||||||
shouldUseSeamless: false,
|
seamlessXAxis: false,
|
||||||
seamlessXAxis: true,
|
seamlessYAxis: false,
|
||||||
seamlessYAxis: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: GenerationState = initialGenerationState;
|
const initialState: GenerationState = initialGenerationState;
|
||||||
@ -144,9 +142,6 @@ export const generationSlice = createSlice({
|
|||||||
setImg2imgStrength: (state, action: PayloadAction<number>) => {
|
setImg2imgStrength: (state, action: PayloadAction<number>) => {
|
||||||
state.img2imgStrength = action.payload;
|
state.img2imgStrength = action.payload;
|
||||||
},
|
},
|
||||||
setSeamless: (state, action: PayloadAction<boolean>) => {
|
|
||||||
state.shouldUseSeamless = action.payload;
|
|
||||||
},
|
|
||||||
setSeamlessXAxis: (state, action: PayloadAction<boolean>) => {
|
setSeamlessXAxis: (state, action: PayloadAction<boolean>) => {
|
||||||
state.seamlessXAxis = action.payload;
|
state.seamlessXAxis = action.payload;
|
||||||
},
|
},
|
||||||
@ -268,7 +263,6 @@ export const {
|
|||||||
modelSelected,
|
modelSelected,
|
||||||
vaeSelected,
|
vaeSelected,
|
||||||
setShouldUseNoiseSettings,
|
setShouldUseNoiseSettings,
|
||||||
setSeamless,
|
|
||||||
setSeamlessXAxis,
|
setSeamlessXAxis,
|
||||||
setSeamlessYAxis,
|
setSeamlessYAxis,
|
||||||
} = generationSlice.actions;
|
} = generationSlice.actions;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, Flex, useDisclosure } from '@chakra-ui/react';
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
@ -21,19 +21,25 @@ const selector = createSelector(
|
|||||||
[uiSelector, generationSelector],
|
[uiSelector, generationSelector],
|
||||||
(ui, generation) => {
|
(ui, generation) => {
|
||||||
const { shouldUseSliders } = ui;
|
const { shouldUseSliders } = ui;
|
||||||
const { shouldFitToWidthHeight } = generation;
|
const { shouldFitToWidthHeight, shouldRandomizeSeed } = generation;
|
||||||
|
|
||||||
return { shouldUseSliders, shouldFitToWidthHeight };
|
const activeLabel = !shouldRandomizeSeed ? 'Manual Seed' : undefined;
|
||||||
|
|
||||||
|
return { shouldUseSliders, shouldFitToWidthHeight, activeLabel };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const ImageToImageTabCoreParameters = () => {
|
const ImageToImageTabCoreParameters = () => {
|
||||||
const { shouldUseSliders, shouldFitToWidthHeight } = useAppSelector(selector);
|
const { shouldUseSliders, shouldFitToWidthHeight, activeLabel } =
|
||||||
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true });
|
useAppSelector(selector);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse label={'General'} isOpen={isOpen} onToggle={onToggle}>
|
<IAICollapse
|
||||||
|
label={'General'}
|
||||||
|
activeLabel={activeLabel}
|
||||||
|
defaultIsOpen={true}
|
||||||
|
>
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Box, Flex, useDisclosure } from '@chakra-ui/react';
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
@ -11,25 +12,30 @@ import ParamScheduler from 'features/parameters/components/Parameters/Core/Param
|
|||||||
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
|
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
|
||||||
import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidth';
|
import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidth';
|
||||||
import ParamSeedFull from 'features/parameters/components/Parameters/Seed/ParamSeedFull';
|
import ParamSeedFull from 'features/parameters/components/Parameters/Seed/ParamSeedFull';
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
uiSelector,
|
stateSelector,
|
||||||
(ui) => {
|
({ ui, generation }) => {
|
||||||
const { shouldUseSliders } = ui;
|
const { shouldUseSliders } = ui;
|
||||||
|
const { shouldRandomizeSeed } = generation;
|
||||||
|
|
||||||
return { shouldUseSliders };
|
const activeLabel = !shouldRandomizeSeed ? 'Manual Seed' : undefined;
|
||||||
|
|
||||||
|
return { shouldUseSliders, activeLabel };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const TextToImageTabCoreParameters = () => {
|
const TextToImageTabCoreParameters = () => {
|
||||||
const { shouldUseSliders } = useAppSelector(selector);
|
const { shouldUseSliders, activeLabel } = useAppSelector(selector);
|
||||||
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse label={'General'} isOpen={isOpen} onToggle={onToggle}>
|
<IAICollapse
|
||||||
|
label={'General'}
|
||||||
|
activeLabel={activeLabel}
|
||||||
|
defaultIsOpen={true}
|
||||||
|
>
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Box, Flex, useDisclosure } from '@chakra-ui/react';
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
@ -12,25 +13,30 @@ import ParamScheduler from 'features/parameters/components/Parameters/Core/Param
|
|||||||
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
|
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
|
||||||
import ImageToImageStrength from 'features/parameters/components/Parameters/ImageToImage/ImageToImageStrength';
|
import ImageToImageStrength from 'features/parameters/components/Parameters/ImageToImage/ImageToImageStrength';
|
||||||
import ParamSeedFull from 'features/parameters/components/Parameters/Seed/ParamSeedFull';
|
import ParamSeedFull from 'features/parameters/components/Parameters/Seed/ParamSeedFull';
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
uiSelector,
|
stateSelector,
|
||||||
(ui) => {
|
({ ui, generation }) => {
|
||||||
const { shouldUseSliders } = ui;
|
const { shouldUseSliders } = ui;
|
||||||
|
const { shouldRandomizeSeed } = generation;
|
||||||
|
|
||||||
return { shouldUseSliders };
|
const activeLabel = !shouldRandomizeSeed ? 'Manual Seed' : undefined;
|
||||||
|
|
||||||
|
return { shouldUseSliders, activeLabel };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const UnifiedCanvasCoreParameters = () => {
|
const UnifiedCanvasCoreParameters = () => {
|
||||||
const { shouldUseSliders } = useAppSelector(selector);
|
const { shouldUseSliders, activeLabel } = useAppSelector(selector);
|
||||||
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAICollapse label={'General'} isOpen={isOpen} onToggle={onToggle}>
|
<IAICollapse
|
||||||
|
label={'General'}
|
||||||
|
activeLabel={activeLabel}
|
||||||
|
defaultIsOpen={true}
|
||||||
|
>
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
Loading…
Reference in New Issue
Block a user