diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageDisplay.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageDisplay.tsx deleted file mode 100644 index f4b707b859..0000000000 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageDisplay.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Flex } from '@invoke-ai/ui-library'; -import { memo } from 'react'; - -import CurrentImageButtons from './CurrentImageButtons'; -import CurrentImagePreview from './CurrentImagePreview'; - -const CurrentImageDisplay = () => { - return ( - - - - - ); -}; - -export default memo(CurrentImageDisplay); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer.tsx deleted file mode 100644 index d1cc108ef2..0000000000 --- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { Button, Flex } from '@invoke-ai/ui-library'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import CurrentImageButtons from 'features/gallery/components/CurrentImage/CurrentImageButtons'; -import CurrentImagePreview from 'features/gallery/components/CurrentImage/CurrentImagePreview'; -import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice'; -import type { InvokeTabName } from 'features/ui/store/tabMap'; -import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { memo, useCallback, useMemo } from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { useTranslation } from 'react-i18next'; -import { PiArrowLeftBold } from 'react-icons/pi'; - -const TAB_NAME_TO_TKEY: Record = { - generation: 'ui.tabs.generation', - canvas: 'ui.tabs.canvas', - workflows: 'ui.tabs.workflows', - models: 'ui.tabs.models', - queue: 'ui.tabs.queue', -}; - -export const ImageViewer = memo(() => { - const { t } = useTranslation(); - const dispatch = useAppDispatch(); - const isOpen = useAppSelector((s) => s.gallery.isImageViewerOpen); - const activeTabName = useAppSelector(activeTabNameSelector); - const activeTabLabel = useMemo( - () => t('gallery.backToEditor', { tab: t(TAB_NAME_TO_TKEY[activeTabName]) }), - [t, activeTabName] - ); - - const onClose = useCallback(() => { - dispatch(isImageViewerOpenChanged(false)); - }, [dispatch]); - - const onOpen = useCallback(() => { - dispatch(isImageViewerOpenChanged(true)); - }, [dispatch]); - - useHotkeys('esc', onClose, { enabled: isOpen }, [isOpen]); - useHotkeys('i', onOpen, { enabled: !isOpen }, [isOpen]); - - if (!isOpen) { - return null; - } - - return ( - - - - - - ); -}); - -ImageViewer.displayName = 'ImageViewer'; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/BackToEditorButton.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/BackToEditorButton.tsx new file mode 100644 index 0000000000..660840b568 --- /dev/null +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/BackToEditorButton.tsx @@ -0,0 +1,24 @@ +import { Button } from '@invoke-ai/ui-library'; +import { useAppSelector } from 'app/store/storeHooks'; +import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; +import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { PiArrowLeftBold } from 'react-icons/pi'; + +import { TAB_NAME_TO_TKEY, useImageViewer } from './useImageViewer'; + +export const BackToEditorButton = () => { + const { t } = useTranslation(); + const { onClose } = useImageViewer(); + const activeTabName = useAppSelector(activeTabNameSelector); + const tooltip = useMemo( + () => t('gallery.backToEditor', { tab: t(TAB_NAME_TO_TKEY[activeTabName]) }), + [t, activeTabName] + ); + + return ( + + ); +}; diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImageButtons.tsx similarity index 51% rename from invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx rename to invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImageButtons.tsx index 2e4519af5e..f93f48e51b 100644 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImageButtons.tsx @@ -1,7 +1,6 @@ -import { ButtonGroup, Flex, IconButton, Menu, MenuButton, MenuList } from '@invoke-ai/ui-library'; +import { ButtonGroup, IconButton, Menu, MenuButton, MenuList } from '@invoke-ai/ui-library'; import { createSelector } from '@reduxjs/toolkit'; import { skipToken } from '@reduxjs/toolkit/query'; -import { useAppToaster } from 'app/components/Toaster'; import { upscaleRequested } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { iiLayerAdded } from 'features/controlLayers/store/controlLayersSlice'; @@ -17,7 +16,6 @@ import ParamUpscalePopover from 'features/parameters/components/Upscale/ParamUps import { useIsQueueMutationInProgress } from 'features/queue/hooks/useIsQueueMutationInProgress'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { selectSystemSlice } from 'features/system/store/systemSlice'; -import { setShouldShowImageDetails, setShouldShowProgressInViewer } from 'features/ui/store/uiSlice'; import { useGetAndLoadEmbeddedWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadEmbeddedWorkflow'; import { memo, useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; @@ -27,8 +25,6 @@ import { PiAsteriskBold, PiDotsThreeOutlineFill, PiFlowArrowBold, - PiHourglassHighBold, - PiInfoBold, PiPlantBold, PiQuotesBold, PiRulerBold, @@ -48,15 +44,12 @@ const selectShouldDisableToolbarButtons = createSelector( const CurrentImageButtons = () => { const dispatch = useAppDispatch(); const isConnected = useAppSelector((s) => s.system.isConnected); - const shouldShowImageDetails = useAppSelector((s) => s.ui.shouldShowImageDetails); - const shouldShowProgressInViewer = useAppSelector((s) => s.ui.shouldShowProgressInViewer); const lastSelectedImage = useAppSelector(selectLastSelectedImage); const selection = useAppSelector((s) => s.gallery.selection); const shouldDisableToolbarButtons = useAppSelector(selectShouldDisableToolbarButtons); const isUpscalingEnabled = useFeatureStatus('upscaling'); const isQueueMutationInProgress = useIsQueueMutationInProgress(); - const toaster = useAppToaster(); const { t } = useTranslation(); const { currentData: imageDTO } = useGetImageDTOQuery(lastSelectedImage?.image_name ?? skipToken); @@ -120,28 +113,6 @@ const CurrentImageButtons = () => { [isUpscalingEnabled, imageDTO, shouldDisableToolbarButtons, isConnected] ); - const handleClickShowImageDetails = useCallback( - () => dispatch(setShouldShowImageDetails(!shouldShowImageDetails)), - [dispatch, shouldShowImageDetails] - ); - - useHotkeys( - 'i', - () => { - if (imageDTO) { - handleClickShowImageDetails(); - } else { - toaster({ - title: t('toast.metadataLoadFailed'), - status: 'error', - duration: 2500, - isClosable: true, - }); - } - }, - [imageDTO, shouldShowImageDetails, toaster] - ); - useHotkeys( 'delete', () => { @@ -150,106 +121,80 @@ const CurrentImageButtons = () => { [dispatch, imageDTO] ); - const handleClickProgressImagesToggle = useCallback(() => { - dispatch(setShouldShowProgressInViewer(!shouldShowProgressInViewer)); - }, [dispatch, shouldShowProgressInViewer]); - return ( <> - - - - } - /> - {imageDTO && } - - + + + } + /> + {imageDTO && } + + - - } - tooltip={`${t('nodes.loadWorkflow')} (W)`} - aria-label={`${t('nodes.loadWorkflow')} (W)`} - isDisabled={!imageDTO?.has_workflow} - onClick={handleLoadWorkflow} - isLoading={getAndLoadEmbeddedWorkflowResult.isLoading} - /> - } - tooltip={`${t('parameters.remixImage')} (R)`} - aria-label={`${t('parameters.remixImage')} (R)`} - isDisabled={!hasMetadata} - onClick={remix} - /> - } - tooltip={`${t('parameters.usePrompt')} (P)`} - aria-label={`${t('parameters.usePrompt')} (P)`} - isDisabled={!hasPrompts} - onClick={recallPrompts} - /> - } - tooltip={`${t('parameters.useSeed')} (S)`} - aria-label={`${t('parameters.useSeed')} (S)`} - isDisabled={!hasSeed} - onClick={recallSeed} - /> - } - tooltip={`${t('parameters.useSize')} (D)`} - aria-label={`${t('parameters.useSize')} (D)`} - onClick={handleUseSize} - /> - } - tooltip={`${t('parameters.useAll')} (A)`} - aria-label={`${t('parameters.useAll')} (A)`} - isDisabled={!hasMetadata} - onClick={recallAll} - /> - + + } + tooltip={`${t('nodes.loadWorkflow')} (W)`} + aria-label={`${t('nodes.loadWorkflow')} (W)`} + isDisabled={!imageDTO?.has_workflow} + onClick={handleLoadWorkflow} + isLoading={getAndLoadEmbeddedWorkflowResult.isLoading} + /> + } + tooltip={`${t('parameters.remixImage')} (R)`} + aria-label={`${t('parameters.remixImage')} (R)`} + isDisabled={!hasMetadata} + onClick={remix} + /> + } + tooltip={`${t('parameters.usePrompt')} (P)`} + aria-label={`${t('parameters.usePrompt')} (P)`} + isDisabled={!hasPrompts} + onClick={recallPrompts} + /> + } + tooltip={`${t('parameters.useSeed')} (S)`} + aria-label={`${t('parameters.useSeed')} (S)`} + isDisabled={!hasSeed} + onClick={recallSeed} + /> + } + tooltip={`${t('parameters.useSize')} (D)`} + aria-label={`${t('parameters.useSize')} (D)`} + onClick={handleUseSize} + /> + } + tooltip={`${t('parameters.useAll')} (A)`} + aria-label={`${t('parameters.useAll')} (A)`} + isDisabled={!hasMetadata} + onClick={recallAll} + /> + - {isUpscalingEnabled && ( - - {isUpscalingEnabled && } - - )} - - - } - tooltip={`${t('parameters.info')} (I)`} - aria-label={`${t('parameters.info')} (I)`} - isChecked={shouldShowImageDetails} - onClick={handleClickShowImageDetails} - /> + {isUpscalingEnabled && ( + + {isUpscalingEnabled && } + )} - - } - isChecked={shouldShowProgressInViewer} - onClick={handleClickProgressImagesToggle} - /> - - - - - - + + + ); }; diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImagePreview.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx similarity index 98% rename from invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImagePreview.tsx rename to invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx index 02863daa2f..3f54974449 100644 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImagePreview.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx @@ -5,7 +5,6 @@ import { useAppSelector } from 'app/store/storeHooks'; import IAIDndImage from 'common/components/IAIDndImage'; import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import type { TypesafeDraggableData, TypesafeDroppableData } from 'features/dnd/types'; -import ProgressImage from 'features/gallery/components/CurrentImage/ProgressImage'; import ImageMetadataViewer from 'features/gallery/components/ImageMetadataViewer/ImageMetadataViewer'; import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons'; import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors'; @@ -17,6 +16,8 @@ import { useTranslation } from 'react-i18next'; import { PiImageBold } from 'react-icons/pi'; import { useGetImageDTOQuery } from 'services/api/endpoints/images'; +import ProgressImage from './ProgressImage'; + const selectLastSelectedImageName = createSelector( selectLastSelectedImage, (lastSelectedImage) => lastSelectedImage?.image_name diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx new file mode 100644 index 0000000000..9f3e7c5902 --- /dev/null +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx @@ -0,0 +1,90 @@ +import { Flex } from '@invoke-ai/ui-library'; +import { useAppSelector } from 'app/store/storeHooks'; +import { ToggleMetadataViewerButton } from 'features/gallery/components/ImageViewer/ToggleMetadataViewerButton'; +import { ToggleProgressButton } from 'features/gallery/components/ImageViewer/ToggleProgressButton'; +import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; +import type { InvokeTabName } from 'features/ui/store/tabMap'; +import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; +import type { AnimationProps } from 'framer-motion'; +import { AnimatePresence, motion } from 'framer-motion'; +import { memo, useMemo } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; + +import { BackToEditorButton } from './BackToEditorButton'; +import CurrentImageButtons from './CurrentImageButtons'; +import CurrentImagePreview from './CurrentImagePreview'; + +const initial: AnimationProps['initial'] = { + opacity: 0, +}; +const animate: AnimationProps['animate'] = { + opacity: 1, + transition: { duration: 0.07 }, +}; +const exit: AnimationProps['exit'] = { + opacity: 0, + transition: { duration: 0.07 }, +}; + +const VIEWER_ENABLED_TABS: InvokeTabName[] = ['canvas', 'generation', 'workflows']; + +export const ImageViewer = memo(() => { + const { isOpen, onToggle, onClose } = useImageViewer(); + const activeTabName = useAppSelector(activeTabNameSelector); + const isViewerEnabled = useMemo(() => VIEWER_ENABLED_TABS.includes(activeTabName), [activeTabName]); + const shouldShowViewer = useMemo(() => { + if (!isViewerEnabled) { + return false; + } + return isOpen; + }, [isOpen, isViewerEnabled]); + + useHotkeys('shift+s', onToggle, { enabled: isViewerEnabled }, [isViewerEnabled, onToggle]); + useHotkeys('esc', onClose, { enabled: isViewerEnabled }, [isViewerEnabled, onClose]); + + return ( + + {shouldShowViewer && ( + + + + + + + + + + + + + + + + + + + + )} + + ); +}); + +ImageViewer.displayName = 'ImageViewer'; diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/ProgressImage.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ProgressImage.tsx similarity index 100% rename from invokeai/frontend/web/src/features/gallery/components/CurrentImage/ProgressImage.tsx rename to invokeai/frontend/web/src/features/gallery/components/ImageViewer/ProgressImage.tsx diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ToggleMetadataViewerButton.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ToggleMetadataViewerButton.tsx new file mode 100644 index 0000000000..a298ebda56 --- /dev/null +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ToggleMetadataViewerButton.tsx @@ -0,0 +1,42 @@ +import { IconButton } from '@invoke-ai/ui-library'; +import { skipToken } from '@reduxjs/toolkit/query'; +import { useAppToaster } from 'app/components/Toaster'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors'; +import { setShouldShowImageDetails } from 'features/ui/store/uiSlice'; +import { memo, useCallback } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { useTranslation } from 'react-i18next'; +import { PiInfoBold } from 'react-icons/pi'; +import { useGetImageDTOQuery } from 'services/api/endpoints/images'; + +export const ToggleMetadataViewerButton = memo(() => { + const dispatch = useAppDispatch(); + const shouldShowImageDetails = useAppSelector((s) => s.ui.shouldShowImageDetails); + const lastSelectedImage = useAppSelector(selectLastSelectedImage); + const toaster = useAppToaster(); + const { t } = useTranslation(); + + const { currentData: imageDTO } = useGetImageDTOQuery(lastSelectedImage?.image_name ?? skipToken); + + const toggleMetadataViewer = useCallback( + () => dispatch(setShouldShowImageDetails(!shouldShowImageDetails)), + [dispatch, shouldShowImageDetails] + ); + + useHotkeys('i', toggleMetadataViewer, { enabled: Boolean(imageDTO) }, [imageDTO, shouldShowImageDetails, toaster]); + + return ( + } + tooltip={`${t('parameters.info')} (I)`} + aria-label={`${t('parameters.info')} (I)`} + onClick={toggleMetadataViewer} + isDisabled={!imageDTO} + variant="outline" + colorScheme={shouldShowImageDetails ? 'invokeBlue' : 'base'} + /> + ); +}); + +ToggleMetadataViewerButton.displayName = 'ToggleMetadataViewerButton'; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ToggleProgressButton.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ToggleProgressButton.tsx new file mode 100644 index 0000000000..994a8bf10e --- /dev/null +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ToggleProgressButton.tsx @@ -0,0 +1,29 @@ +import { IconButton } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { setShouldShowProgressInViewer } from 'features/ui/store/uiSlice'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { PiHourglassHighBold } from 'react-icons/pi'; + +export const ToggleProgressButton = memo(() => { + const dispatch = useAppDispatch(); + const shouldShowProgressInViewer = useAppSelector((s) => s.ui.shouldShowProgressInViewer); + const { t } = useTranslation(); + + const onClick = useCallback(() => { + dispatch(setShouldShowProgressInViewer(!shouldShowProgressInViewer)); + }, [dispatch, shouldShowProgressInViewer]); + + return ( + } + onClick={onClick} + variant="outline" + colorScheme={shouldShowProgressInViewer ? 'invokeBlue' : 'base'} + /> + ); +}); + +ToggleProgressButton.displayName = 'ToggleProgressButton'; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/useImageViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/useImageViewer.tsx new file mode 100644 index 0000000000..17a9dc9922 --- /dev/null +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/useImageViewer.tsx @@ -0,0 +1,31 @@ +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice'; +import type { InvokeTabName } from 'features/ui/store/tabMap'; +import { useCallback } from 'react'; + +export const TAB_NAME_TO_TKEY: Record = { + generation: 'ui.tabs.generation', + canvas: 'ui.tabs.canvas', + workflows: 'ui.tabs.workflows', + models: 'ui.tabs.models', + queue: 'ui.tabs.queue', +}; + +export const useImageViewer = () => { + const dispatch = useAppDispatch(); + const isOpen = useAppSelector((s) => s.gallery.isImageViewerOpen); + + const onClose = useCallback(() => { + dispatch(isImageViewerOpenChanged(false)); + }, [dispatch]); + + const onOpen = useCallback(() => { + dispatch(isImageViewerOpenChanged(true)); + }, [dispatch]); + + const onToggle = useCallback(() => { + dispatch(isImageViewerOpenChanged(!isOpen)); + }, [dispatch, isOpen]); + + return { isOpen, onOpen, onClose, onToggle }; +}; diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx index 1968c64161..5e37a2d8c8 100644 --- a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx +++ b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx @@ -4,6 +4,7 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { $customNavComponent } from 'app/store/nanostores/customNavComponent'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent'; +import { ImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer'; import NodeEditorPanelGroup from 'features/nodes/components/sidePanel/NodeEditorPanelGroup'; import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent'; import SettingsMenu from 'features/system/components/SettingsModal/SettingsMenu'; @@ -253,10 +254,11 @@ const InvokeTabs = () => { /> )} - + {tabPanels} + {shouldShowGalleryPanel && ( <> diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/NodesTab.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/NodesTab.tsx index 81f0810192..2ee21bfadf 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/NodesTab.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/NodesTab.tsx @@ -1,30 +1,14 @@ -import { Box, Flex } from '@invoke-ai/ui-library'; -import { useAppSelector } from 'app/store/storeHooks'; -import CurrentImageDisplay from 'features/gallery/components/CurrentImage/CurrentImageDisplay'; -import { ImageViewer } from 'features/gallery/components/ImageViewer'; +import { Box } from '@invoke-ai/ui-library'; import NodeEditor from 'features/nodes/components/NodeEditor'; import { memo } from 'react'; import { ReactFlowProvider } from 'reactflow'; const NodesTab = () => { - const mode = useAppSelector((s) => s.workflow.mode); - - if (mode === 'edit') { - return ( - - - - - - - ); - } - return ( - - - + + + ); }; diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImageTab.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImageTab.tsx index df0b8651bc..74845a9ca9 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImageTab.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImageTab.tsx @@ -1,13 +1,11 @@ import { Box } from '@invoke-ai/ui-library'; import { ControlLayersEditor } from 'features/controlLayers/components/ControlLayersEditor'; -import { ImageViewer } from 'features/gallery/components/ImageViewer'; import { memo } from 'react'; const TextToImageTab = () => { return ( - ); }; diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvasTab.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvasTab.tsx index 8c74685d2d..3e0d9b35d4 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvasTab.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvasTab.tsx @@ -6,7 +6,6 @@ import { CANVAS_TAB_TESTID } from 'features/canvas/store/constants'; import { useDroppableTypesafe } from 'features/dnd/hooks/typesafeHooks'; import type { CanvasInitialImageDropData } from 'features/dnd/types'; import { isValidDrop } from 'features/dnd/util/isValidDrop'; -import { ImageViewer } from 'features/gallery/components/ImageViewer'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -42,7 +41,6 @@ const UnifiedCanvasTab = () => { > - {isValidDrop(droppableData, active) && ( )}