diff --git a/invokeai/frontend/web/src/common/components/IAIDndImage.tsx b/invokeai/frontend/web/src/common/components/IAIDndImage.tsx index b7b2e35342..403a6cd5c5 100644 --- a/invokeai/frontend/web/src/common/components/IAIDndImage.tsx +++ b/invokeai/frontend/web/src/common/components/IAIDndImage.tsx @@ -1,4 +1,11 @@ -import { ChakraProps, Flex, Icon, Image, useColorMode } from '@chakra-ui/react'; +import { + ChakraProps, + Flex, + FlexProps, + Icon, + Image, + useColorMode, +} from '@chakra-ui/react'; import { IAILoadingImageFallback, IAINoContentFallback, @@ -25,7 +32,7 @@ import { TypesafeDroppableData, } from 'features/dnd/types'; -type IAIDndImageProps = { +type IAIDndImageProps = FlexProps & { imageDTO: ImageDTO | undefined; onError?: (event: SyntheticEvent) => void; onLoad?: (event: SyntheticEvent) => void; @@ -47,8 +54,6 @@ type IAIDndImageProps = { useThumbailFallback?: boolean; withHoverOverlay?: boolean; children?: JSX.Element; - onMouseOver?: () => void; - onMouseOut?: () => void; }; const IAIDndImage = (props: IAIDndImageProps) => { @@ -79,14 +84,20 @@ const IAIDndImage = (props: IAIDndImageProps) => { const { colorMode } = useColorMode(); const [isHovered, setIsHovered] = useState(false); - const handleMouseOver = useCallback(() => { - if (onMouseOver) onMouseOver(); - setIsHovered(true); - }, [onMouseOver]); - const handleMouseOut = useCallback(() => { - if (onMouseOut) onMouseOut(); - setIsHovered(false); - }, [onMouseOut]); + const handleMouseOver = useCallback( + (e: MouseEvent) => { + if (onMouseOver) onMouseOver(e); + setIsHovered(true); + }, + [onMouseOver] + ); + const handleMouseOut = useCallback( + (e: MouseEvent) => { + if (onMouseOut) onMouseOut(e); + setIsHovered(false); + }, + [onMouseOut] + ); const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({ postUploadAction, diff --git a/invokeai/frontend/web/src/common/components/IAIDndImageIcon.tsx b/invokeai/frontend/web/src/common/components/IAIDndImageIcon.tsx index 2e16377175..fb7742d088 100644 --- a/invokeai/frontend/web/src/common/components/IAIDndImageIcon.tsx +++ b/invokeai/frontend/web/src/common/components/IAIDndImageIcon.tsx @@ -1,6 +1,6 @@ -import { JSXElementConstructor, ReactElement, memo, MouseEvent } from 'react'; -import IAIIconButton from './IAIIconButton'; import { SystemStyleObject, useColorModeValue } from '@chakra-ui/react'; +import { JSXElementConstructor, MouseEvent, ReactElement, memo } from 'react'; +import IAIIconButton from './IAIIconButton'; type Props = { onClick: (event: MouseEvent) => void; diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx index 901a86fd4e..0683282811 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx @@ -1,10 +1,4 @@ -import { - Box, - Flex, - Spinner, - SystemStyleObject, - useColorModeValue, -} from '@chakra-ui/react'; +import { Box, Flex, Spinner, SystemStyleObject } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import { skipToken } from '@reduxjs/toolkit/dist/query'; import { @@ -16,14 +10,14 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import IAIDndImage from 'common/components/IAIDndImage'; import { memo, useCallback, useMemo, useState } from 'react'; +import { FaUndo } from 'react-icons/fa'; import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { PostUploadAction } from 'services/api/types'; +import IAIDndImageIcon from '../../../common/components/IAIDndImageIcon'; import { ControlNetConfig, controlNetImageChanged, } from '../store/controlNetSlice'; -import { FaUndo } from 'react-icons/fa'; -import IAIDndImageIcon from '../../../common/components/IAIDndImageIcon'; type Props = { controlNet: ControlNetConfig; @@ -101,11 +95,6 @@ const ControlNetImagePreview = (props: Props) => { [controlNetId] ); - const resetIconShadow = useColorModeValue( - `drop-shadow(0px 0px 0.1rem var(--invokeai-colors-base-600))`, - `drop-shadow(0px 0px 0.1rem var(--invokeai-colors-base-800))` - ); - const shouldShowProcessedImage = controlImage && processedControlImage && diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx index a7854f4041..5dbbf011e8 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx @@ -27,9 +27,7 @@ const GalleryImage = (props: HoverableImageProps) => { const dispatch = useAppDispatch(); const { imageName } = props; const { currentData: imageDTO } = useGetImageDTOQuery(imageName); - const shouldShowDeleteButton = useAppSelector( - (state) => state.gallery.shouldShowDeleteButton - ); + const shift = useAppSelector((state) => state.hotkeys.shift); const { handleClick, isSelected, selection, selectionCount } = useMultiselect(imageDTO); @@ -81,6 +79,14 @@ const GalleryImage = (props: HoverableImageProps) => { const [isHovered, setIsHovered] = useState(false); + const handleMouseOver = useCallback(() => { + setIsHovered(true); + }, []); + + const handleMouseOut = useCallback(() => { + setIsHovered(false); + }, []); + const starIcon = useMemo(() => { if (imageDTO?.starred) return ; if (!imageDTO?.starred && isHovered) return ; @@ -112,8 +118,8 @@ const GalleryImage = (props: HoverableImageProps) => { isUploadDisabled={true} thumbnail={true} withHoverOverlay - onMouseOver={() => setIsHovered(true)} - onMouseOut={() => setIsHovered(false)} + onMouseOver={handleMouseOver} + onMouseOut={handleMouseOut} > <> { tooltip={imageDTO.starred ? 'Unstar' : 'Star'} /> - {isHovered && shouldShowDeleteButton && ( + {isHovered && shift && ( } - tooltip={'Delete'} + tooltip="Delete" styleOverrides={{ - bottom: 1, + bottom: 2, top: 'auto', }} /> diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImageGrid.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImageGrid.tsx index 8951fc050a..bacd5c38ad 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImageGrid.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImageGrid.tsx @@ -1,5 +1,5 @@ import { Box, Flex } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors'; @@ -20,8 +20,6 @@ import { useBoardTotal } from 'services/api/hooks/useBoardTotal'; import GalleryImage from './GalleryImage'; import ImageGridItemContainer from './ImageGridItemContainer'; import ImageGridListContainer from './ImageGridListContainer'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { shouldShowDeleteButtonChanged } from '../../store/gallerySlice'; const overlayScrollbarsConfig: UseOverlayScrollbarsParams = { defer: true, @@ -38,7 +36,6 @@ const overlayScrollbarsConfig: UseOverlayScrollbarsParams = { const GalleryImageGrid = () => { const { t } = useTranslation(); - const dispatch = useAppDispatch(); const rootRef = useRef(null); const [scroller, setScroller] = useState(null); const [initialize, osInstance] = useOverlayScrollbars( @@ -88,23 +85,6 @@ const GalleryImageGrid = () => { return () => osInstance()?.destroy(); }, [scroller, initialize, osInstance]); - useHotkeys( - 'shift', - () => { - dispatch(shouldShowDeleteButtonChanged(true)); - }, - [shouldShowDeleteButtonChanged] - ); - - useHotkeys( - 'shift', - () => { - dispatch(shouldShowDeleteButtonChanged(false)); - }, - { keyup: true }, - [shouldShowDeleteButtonChanged] - ); - if (!currentData) { return ( ) => { state.galleryView = action.payload; }, - shouldShowDeleteButtonChanged: (state, action: PayloadAction) => { - state.shouldShowDeleteButton = action.payload; - }, boardSearchTextChanged: (state, action: PayloadAction) => { state.boardSearchText = action.payload; }, @@ -93,7 +89,6 @@ export const { autoAddBoardIdChanged, galleryViewChanged, selectionChanged, - shouldShowDeleteButtonChanged, boardSearchTextChanged, } = gallerySlice.actions; diff --git a/invokeai/frontend/web/src/features/gallery/store/types.ts b/invokeai/frontend/web/src/features/gallery/store/types.ts index 6860f6ea7b..7b707dd303 100644 --- a/invokeai/frontend/web/src/features/gallery/store/types.ts +++ b/invokeai/frontend/web/src/features/gallery/store/types.ts @@ -21,6 +21,5 @@ export type GalleryState = { galleryImageMinimumWidth: number; selectedBoardId: BoardId; galleryView: GalleryView; - shouldShowDeleteButton: boolean; boardSearchText: string; }; diff --git a/invokeai/frontend/web/src/services/api/util.ts b/invokeai/frontend/web/src/services/api/util.ts index 95f2b10653..d69b6a2cde 100644 --- a/invokeai/frontend/web/src/services/api/util.ts +++ b/invokeai/frontend/web/src/services/api/util.ts @@ -26,26 +26,27 @@ export const getIsImageInDateRange = ( for (let index = 0; index < totalCachedImageDtos.length; index++) { const image = totalCachedImageDtos[index]; - if (image?.starred) cachedStarredImages.push(image) - if (!image?.starred) cachedUnstarredImages.push(image) + if (image?.starred) cachedStarredImages.push(image); + if (!image?.starred) cachedUnstarredImages.push(image); } if (imageDTO.starred) { - const lastStarredImage = cachedStarredImages[cachedStarredImages.length - 1]; - // if starring or already starred, want to look in list of starred images + const lastStarredImage = + cachedStarredImages[cachedStarredImages.length - 1]; + // if starring or already starred, want to look in list of starred images if (!lastStarredImage) return true; // no starred images showing, so always show this one const createdDate = new Date(imageDTO.created_at); const oldestDate = new Date(lastStarredImage.created_at); return createdDate >= oldestDate; } else { - const lastUnstarredImage = cachedUnstarredImages[cachedUnstarredImages.length - 1]; + const lastUnstarredImage = + cachedUnstarredImages[cachedUnstarredImages.length - 1]; // if unstarring or already unstarred, want to look in list of unstarred images if (!lastUnstarredImage) return false; // no unstarred images showing, so don't show this one const createdDate = new Date(imageDTO.created_at); const oldestDate = new Date(lastUnstarredImage.created_at); return createdDate >= oldestDate; } - }; export const getCategories = (imageDTO: ImageDTO) => { @@ -67,7 +68,7 @@ export const imagesAdapter = createEntityAdapter({ if (!a.starred && b.starred) { return 1; } - return dateComparator(b.created_at, a.created_at) + return dateComparator(b.created_at, a.created_at); }, });