feat(ui): add layerwrapper component

This commit is contained in:
psychedelicious 2024-05-02 20:52:49 +10:00 committed by Kent Keirsey
parent d55ea318ec
commit d67480d92c
4 changed files with 73 additions and 62 deletions

View File

@ -5,6 +5,7 @@ import { LayerDeleteButton } from 'features/controlLayers/components/LayerCommon
import { LayerMenu } from 'features/controlLayers/components/LayerCommon/LayerMenu'; import { LayerMenu } from 'features/controlLayers/components/LayerCommon/LayerMenu';
import { LayerTitle } from 'features/controlLayers/components/LayerCommon/LayerTitle'; import { LayerTitle } from 'features/controlLayers/components/LayerCommon/LayerTitle';
import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle'; import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle';
import { LayerWrapper } from 'features/controlLayers/components/LayerCommon/LayerWrapper';
import { layerSelected, selectCALayerOrThrow } from 'features/controlLayers/store/controlLayersSlice'; import { layerSelected, selectCALayerOrThrow } from 'features/controlLayers/store/controlLayersSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
@ -17,37 +18,28 @@ type Props = {
export const CALayer = memo(({ layerId }: Props) => { export const CALayer = memo(({ layerId }: Props) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const isSelected = useAppSelector((s) => selectCALayerOrThrow(s.controlLayers.present, layerId).isSelected); const isSelected = useAppSelector((s) => selectCALayerOrThrow(s.controlLayers.present, layerId).isSelected);
const onClickCapture = useCallback(() => { const onClick = useCallback(() => {
// Must be capture so that the layer is selected before deleting/resetting/etc // Must be capture so that the layer is selected before deleting/resetting/etc
dispatch(layerSelected(layerId)); dispatch(layerSelected(layerId));
}, [dispatch, layerId]); }, [dispatch, layerId]);
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true }); const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true });
return ( return (
<Flex <LayerWrapper onClick={onClick} borderColor={isSelected ? 'base.400' : 'base.800'}>
gap={2} <Flex gap={3} alignItems="center" p={3} cursor="pointer" onDoubleClick={onToggle}>
onClickCapture={onClickCapture} <LayerVisibilityToggle layerId={layerId} />
bg={isSelected ? 'base.400' : 'base.800'} <LayerTitle type="control_adapter_layer" />
px={2} <Spacer />
borderRadius="base" <CALayerOpacity layerId={layerId} />
py="1px" <LayerMenu layerId={layerId} />
> <LayerDeleteButton layerId={layerId} />
<Flex flexDir="column" w="full" bg="base.850" borderRadius="base">
<Flex gap={3} alignItems="center" p={3} cursor="pointer" onDoubleClick={onToggle}>
<LayerVisibilityToggle layerId={layerId} />
<LayerTitle type="control_adapter_layer" />
<Spacer />
<CALayerOpacity layerId={layerId} />
<LayerMenu layerId={layerId} />
<LayerDeleteButton layerId={layerId} />
</Flex>
{isOpen && (
<Flex flexDir="column" gap={3} px={3} pb={3}>
<CALayerControlAdapterWrapper layerId={layerId} />
</Flex>
)}
</Flex> </Flex>
</Flex> {isOpen && (
<Flex flexDir="column" gap={3} px={3} pb={3}>
<CALayerControlAdapterWrapper layerId={layerId} />
</Flex>
)}
</LayerWrapper>
); );
}); });

View File

@ -3,6 +3,7 @@ import { IPALayerIPAdapterWrapper } from 'features/controlLayers/components/IPAL
import { LayerDeleteButton } from 'features/controlLayers/components/LayerCommon/LayerDeleteButton'; import { LayerDeleteButton } from 'features/controlLayers/components/LayerCommon/LayerDeleteButton';
import { LayerTitle } from 'features/controlLayers/components/LayerCommon/LayerTitle'; import { LayerTitle } from 'features/controlLayers/components/LayerCommon/LayerTitle';
import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle'; import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle';
import { LayerWrapper } from 'features/controlLayers/components/LayerCommon/LayerWrapper';
import { memo } from 'react'; import { memo } from 'react';
type Props = { type Props = {
@ -12,21 +13,19 @@ type Props = {
export const IPALayer = memo(({ layerId }: Props) => { export const IPALayer = memo(({ layerId }: Props) => {
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true }); const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true });
return ( return (
<Flex gap={2} bg="base.800" borderRadius="base" p="1px" px={2}> <LayerWrapper borderColor="base.800">
<Flex flexDir="column" w="full" bg="base.850" borderRadius="base"> <Flex gap={3} alignItems="center" p={3} cursor="pointer" onDoubleClick={onToggle}>
<Flex gap={3} alignItems="center" p={3} cursor="pointer" onDoubleClick={onToggle}> <LayerVisibilityToggle layerId={layerId} />
<LayerVisibilityToggle layerId={layerId} /> <LayerTitle type="ip_adapter_layer" />
<LayerTitle type="ip_adapter_layer" /> <Spacer />
<Spacer /> <LayerDeleteButton layerId={layerId} />
<LayerDeleteButton layerId={layerId} />
</Flex>
{isOpen && (
<Flex flexDir="column" gap={3} px={3} pb={3}>
<IPALayerIPAdapterWrapper layerId={layerId} />
</Flex>
)}
</Flex> </Flex>
</Flex> {isOpen && (
<Flex flexDir="column" gap={3} px={3} pb={3}>
<IPALayerIPAdapterWrapper layerId={layerId} />
</Flex>
)}
</LayerWrapper>
); );
}); });

View File

@ -0,0 +1,21 @@
import type { ChakraProps } from '@invoke-ai/ui-library';
import { Flex } from '@invoke-ai/ui-library';
import type { PropsWithChildren } from 'react';
import { memo } from 'react';
type Props = PropsWithChildren<{
onClick?: () => void;
borderColor: ChakraProps['bg'];
}>;
export const LayerWrapper = memo(({ onClick, borderColor, children }: Props) => {
return (
<Flex gap={2} onClick={onClick} bg={borderColor} px={2} borderRadius="base" py="1px">
<Flex flexDir="column" w="full" bg="base.850" borderRadius="base">
{children}
</Flex>
</Flex>
);
});
LayerWrapper.displayName = 'LayerWrapper';

View File

@ -7,6 +7,7 @@ import { LayerDeleteButton } from 'features/controlLayers/components/LayerCommon
import { LayerMenu } from 'features/controlLayers/components/LayerCommon/LayerMenu'; import { LayerMenu } from 'features/controlLayers/components/LayerCommon/LayerMenu';
import { LayerTitle } from 'features/controlLayers/components/LayerCommon/LayerTitle'; import { LayerTitle } from 'features/controlLayers/components/LayerCommon/LayerTitle';
import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle'; import { LayerVisibilityToggle } from 'features/controlLayers/components/LayerCommon/LayerVisibilityToggle';
import { LayerWrapper } from 'features/controlLayers/components/LayerCommon/LayerWrapper';
import { import {
isRegionalGuidanceLayer, isRegionalGuidanceLayer,
layerSelected, layerSelected,
@ -52,32 +53,30 @@ export const RGLayer = memo(({ layerId }: Props) => {
dispatch(layerSelected(layerId)); dispatch(layerSelected(layerId));
}, [dispatch, layerId]); }, [dispatch, layerId]);
return ( return (
<Flex gap={2} onClick={onClick} bg={isSelected ? color : 'base.800'} px={2} borderRadius="base" py="1px"> <LayerWrapper onClick={onClick} borderColor={isSelected ? color : 'base.800'}>
<Flex flexDir="column" w="full" bg="base.850" borderRadius="base"> <Flex gap={3} alignItems="center" p={3} cursor="pointer" onDoubleClick={onToggle}>
<Flex gap={3} alignItems="center" p={3} cursor="pointer" onDoubleClick={onToggle}> <LayerVisibilityToggle layerId={layerId} />
<LayerVisibilityToggle layerId={layerId} /> <LayerTitle type="regional_guidance_layer" />
<LayerTitle type="regional_guidance_layer" /> <Spacer />
<Spacer /> {autoNegative === 'invert' && (
{autoNegative === 'invert' && ( <Badge color="base.300" bg="transparent" borderWidth={1} userSelect="none">
<Badge color="base.300" bg="transparent" borderWidth={1} userSelect="none"> {t('controlLayers.autoNegative')}
{t('controlLayers.autoNegative')} </Badge>
</Badge>
)}
<RGLayerColorPicker layerId={layerId} />
<RGLayerSettingsPopover layerId={layerId} />
<LayerMenu layerId={layerId} />
<LayerDeleteButton layerId={layerId} />
</Flex>
{isOpen && (
<Flex flexDir="column" gap={3} px={3} pb={3}>
{!hasPositivePrompt && !hasNegativePrompt && !hasIPAdapters && <AddPromptButtons layerId={layerId} />}
{hasPositivePrompt && <RGLayerPositivePrompt layerId={layerId} />}
{hasNegativePrompt && <RGLayerNegativePrompt layerId={layerId} />}
{hasIPAdapters && <RGLayerIPAdapterList layerId={layerId} />}
</Flex>
)} )}
<RGLayerColorPicker layerId={layerId} />
<RGLayerSettingsPopover layerId={layerId} />
<LayerMenu layerId={layerId} />
<LayerDeleteButton layerId={layerId} />
</Flex> </Flex>
</Flex> {isOpen && (
<Flex flexDir="column" gap={3} px={3} pb={3}>
{!hasPositivePrompt && !hasNegativePrompt && !hasIPAdapters && <AddPromptButtons layerId={layerId} />}
{hasPositivePrompt && <RGLayerPositivePrompt layerId={layerId} />}
{hasNegativePrompt && <RGLayerNegativePrompt layerId={layerId} />}
{hasIPAdapters && <RGLayerIPAdapterList layerId={layerId} />}
</Flex>
)}
</LayerWrapper>
); );
}); });