From 3f41ea574bfa6f28d5a141ce62d87b3c0ff29924 Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Thu, 22 Aug 2024 17:46:02 +1000
Subject: [PATCH] feat(ui): no entities fallback buttons
---
.../components/AddLayerButton.tsx | 11 ++--
.../components/CanvasAddEntityButtons.tsx | 59 +++++++++++++++++++
.../components/CanvasEntityList.tsx | 23 ++++----
.../components/CanvasPanelContent.tsx | 18 ++++++
...seEntityCount.ts => useEntityTypeCount.ts} | 2 +-
.../controlLayers/hooks/useEntityTypeTitle.ts | 4 +-
.../features/controlLayers/store/selectors.ts | 5 +-
.../ParametersPanelTextToImage.tsx | 6 +-
8 files changed, 102 insertions(+), 26 deletions(-)
create mode 100644 invokeai/frontend/web/src/features/controlLayers/components/CanvasAddEntityButtons.tsx
create mode 100644 invokeai/frontend/web/src/features/controlLayers/components/CanvasPanelContent.tsx
rename invokeai/frontend/web/src/features/controlLayers/hooks/{useEntityCount.ts => useEntityTypeCount.ts} (92%)
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/AddLayerButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/AddLayerButton.tsx
index 5eb05fe95b..b9d3b0fc62 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/AddLayerButton.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/AddLayerButton.tsx
@@ -41,13 +41,14 @@ export const AddLayerButton = memo(() => {
icon={}
variant="link"
data-testid="control-layers-add-layer-menu-button"
+ alignSelf="stretch"
/>
-
-
-
-
-
+
+
+
+
+
);
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasAddEntityButtons.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasAddEntityButtons.tsx
new file mode 100644
index 0000000000..b98c0e78d6
--- /dev/null
+++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasAddEntityButtons.tsx
@@ -0,0 +1,59 @@
+import { Button, ButtonGroup, Flex } from '@invoke-ai/ui-library';
+import { useAppDispatch } from 'app/store/storeHooks';
+import { useDefaultControlAdapter, useDefaultIPAdapter } from 'features/controlLayers/hooks/useLayerControlAdapter';
+import {
+ controlLayerAdded,
+ inpaintMaskAdded,
+ ipaAdded,
+ rasterLayerAdded,
+ rgAdded,
+} from 'features/controlLayers/store/canvasV2Slice';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+import { PiPlusBold } from 'react-icons/pi';
+
+export const CanvasAddEntityButtons = memo(() => {
+ const { t } = useTranslation();
+ const dispatch = useAppDispatch();
+ const defaultControlAdapter = useDefaultControlAdapter();
+ const defaultIPAdapter = useDefaultIPAdapter();
+ const addInpaintMask = useCallback(() => {
+ dispatch(inpaintMaskAdded());
+ }, [dispatch]);
+ const addRegionalGuidance = useCallback(() => {
+ dispatch(rgAdded());
+ }, [dispatch]);
+ const addRasterLayer = useCallback(() => {
+ dispatch(rasterLayerAdded({ isSelected: true }));
+ }, [dispatch]);
+ const addControlLayer = useCallback(() => {
+ dispatch(controlLayerAdded({ isSelected: true, overrides: { controlAdapter: defaultControlAdapter } }));
+ }, [defaultControlAdapter, dispatch]);
+ const addIPAdapter = useCallback(() => {
+ dispatch(ipaAdded({ ipAdapter: defaultIPAdapter }));
+ }, [defaultIPAdapter, dispatch]);
+
+ return (
+
+
+ } onClick={addInpaintMask}>
+ {t('controlLayers.inpaintMask', { count: 1 })}
+
+ } onClick={addRegionalGuidance}>
+ {t('controlLayers.regionalGuidance', { count: 1 })}
+
+ } onClick={addRasterLayer}>
+ {t('controlLayers.rasterLayer', { count: 1 })}
+
+ } onClick={addControlLayer}>
+ {t('controlLayers.controlLayer', { count: 1 })}
+
+ } onClick={addIPAdapter}>
+ {t('controlLayers.ipAdapter', { count: 1 })}
+
+
+
+ );
+});
+
+CanvasAddEntityButtons.displayName = 'CanvasAddEntityButtons';
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx
index 3522895db4..2b28bdc61e 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx
@@ -6,23 +6,20 @@ import { InpaintMaskList } from 'features/controlLayers/components/InpaintMask/I
import { IPAdapterList } from 'features/controlLayers/components/IPAdapter/IPAdapterList';
import { RasterLayerEntityList } from 'features/controlLayers/components/RasterLayer/RasterLayerEntityList';
import { RegionalGuidanceEntityList } from 'features/controlLayers/components/RegionalGuidance/RegionalGuidanceEntityList';
-import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { memo } from 'react';
export const CanvasEntityList = memo(() => {
return (
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasPanelContent.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasPanelContent.tsx
new file mode 100644
index 0000000000..3ecf8f2b6d
--- /dev/null
+++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasPanelContent.tsx
@@ -0,0 +1,18 @@
+import { useAppSelector } from 'app/store/storeHooks';
+import { CanvasAddEntityButtons } from 'features/controlLayers/components/CanvasAddEntityButtons';
+import { CanvasEntityList } from 'features/controlLayers/components/CanvasEntityList';
+import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
+import { selectEntityCount } from 'features/controlLayers/store/selectors';
+import { memo } from 'react';
+
+export const CanvasPanelContent = memo(() => {
+ const hasEntities = useAppSelector((s) => selectEntityCount(s) > 0);
+ return (
+
+ {!hasEntities && }
+ {hasEntities && }
+
+ );
+});
+
+CanvasPanelContent.displayName = 'CanvasPanelContent';
diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityCount.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTypeCount.ts
similarity index 92%
rename from invokeai/frontend/web/src/features/controlLayers/hooks/useEntityCount.ts
rename to invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTypeCount.ts
index 9c73cf32b5..f2209af4a9 100644
--- a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityCount.ts
+++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTypeCount.ts
@@ -4,7 +4,7 @@ import { selectCanvasV2Slice } from 'features/controlLayers/store/canvasV2Slice'
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
import { useMemo } from 'react';
-export const useEntityCount = (type: CanvasEntityIdentifier['type']): number => {
+export const useEntityTypeCount = (type: CanvasEntityIdentifier['type']): number => {
const selectEntityCount = useMemo(
() =>
createSelector(selectCanvasV2Slice, (canvasV2) => {
diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTypeTitle.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTypeTitle.ts
index 80a0210f26..c693db533c 100644
--- a/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTypeTitle.ts
+++ b/invokeai/frontend/web/src/features/controlLayers/hooks/useEntityTypeTitle.ts
@@ -1,4 +1,4 @@
-import { useEntityCount } from 'features/controlLayers/hooks/useEntityCount';
+import { useEntityTypeCount } from 'features/controlLayers/hooks/useEntityTypeCount';
import { useEntityTypeIsHidden } from 'features/controlLayers/hooks/useEntityTypeIsHidden';
import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types';
import { useMemo } from 'react';
@@ -8,7 +8,7 @@ export const useEntityTypeTitle = (type: CanvasEntityIdentifier['type']): string
const { t } = useTranslation();
const isHidden = useEntityTypeIsHidden(type);
- const count = useEntityCount(type);
+ const count = useEntityTypeCount(type);
const title = useMemo(() => {
const context = isHidden ? 'hidden' : 'visible';
diff --git a/invokeai/frontend/web/src/features/controlLayers/store/selectors.ts b/invokeai/frontend/web/src/features/controlLayers/store/selectors.ts
index c81856b5df..d78417d55e 100644
--- a/invokeai/frontend/web/src/features/controlLayers/store/selectors.ts
+++ b/invokeai/frontend/web/src/features/controlLayers/store/selectors.ts
@@ -5,9 +5,10 @@ import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
export const selectEntityCount = createSelector(selectCanvasV2Slice, (canvasV2) => {
return (
canvasV2.regions.entities.length +
- // canvasV2.controlAdapters.entities.length +
canvasV2.ipAdapters.entities.length +
- canvasV2.rasterLayers.entities.length
+ canvasV2.rasterLayers.entities.length +
+ canvasV2.controlLayers.entities.length +
+ canvasV2.inpaintMasks.entities.length
);
});
diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelTextToImage.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelTextToImage.tsx
index 43c878d8f2..3faa520471 100644
--- a/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelTextToImage.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelTextToImage.tsx
@@ -4,7 +4,7 @@ import { useStore } from '@nanostores/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
import { AddLayerButton } from 'features/controlLayers/components/AddLayerButton';
-import { CanvasEntityList } from 'features/controlLayers/components/CanvasEntityList';
+import { CanvasPanelContent } from 'features/controlLayers/components/CanvasPanelContent';
import { $isPreviewVisible } from 'features/controlLayers/store/canvasV2Slice';
import { selectEntityCount } from 'features/controlLayers/store/selectors';
import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice';
@@ -90,7 +90,7 @@ const ParametersPanelTextToImage = () => {
gap={2}
onChange={onChangeTabs}
>
-
+
{t('common.settingsLabel')}
@@ -115,7 +115,7 @@ const ParametersPanelTextToImage = () => {
-
+