diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx index 0ef484b4be..c0c82d5456 100644 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx @@ -1,7 +1,16 @@ import { createSelector } from '@reduxjs/toolkit'; import { isEqual } from 'lodash-es'; -import { ButtonGroup, Flex, FlexProps, Link } from '@chakra-ui/react'; +import { + ButtonGroup, + Flex, + FlexProps, + Link, + Menu, + MenuButton, + MenuItem, + MenuList, +} from '@chakra-ui/react'; // import { runESRGAN, runFacetool } from 'app/socketio/actions'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; @@ -49,6 +58,8 @@ import { } from 'services/api/endpoints/images'; import { useDebounce } from 'use-debounce'; import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; +import { menuListMotionProps } from 'theme/components/menu'; +import SingleSelectionMenuItems from '../ImageContextMenu/SingleSelectionMenuItems'; const currentImageButtonsSelector = createSelector( [stateSelector, activeTabNameSelector], @@ -345,65 +356,18 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { {...props} > - } - /> - } - > - - } - id="send-to-img2img" - > - {t('parameters.sendToImg2Img')} - - {isCanvasEnabled && ( - } - id="send-to-canvas" - > - {t('parameters.sendToUnifiedCanvas')} - - )} - - {isClipboardAPIAvailable && ( - } - > - {t('parameters.copyImage')} - - )} - } - > - {t('parameters.copyImageToLink')} - - - - } size="sm" w="100%"> - {t('parameters.downloadImage')} - - - - + + } + /> + + {imageDTO && } + + diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/ImageContextMenu.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/ImageContextMenu.tsx index 8d8e7233c2..a903b36caf 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/ImageContextMenu.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/ImageContextMenu.tsx @@ -6,40 +6,15 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { ContextMenu, ContextMenuProps } from 'chakra-ui-contextmenu'; import { MouseEvent, memo, useCallback, useMemo } from 'react'; import { ImageDTO } from 'services/api/types'; +import { menuListMotionProps } from 'theme/components/menu'; import MultipleSelectionMenuItems from './MultipleSelectionMenuItems'; import SingleSelectionMenuItems from './SingleSelectionMenuItems'; -import { MotionProps } from 'framer-motion'; type Props = { imageDTO: ImageDTO | undefined; children: ContextMenuProps['children']; }; -const motionProps: MotionProps = { - variants: { - enter: { - visibility: 'visible', - opacity: 1, - scale: 1, - transition: { - duration: 0.07, - ease: [0.4, 0, 0.2, 1], - }, - }, - exit: { - transitionEnd: { - visibility: 'hidden', - }, - opacity: 0, - scale: 0.8, - transition: { - duration: 0.07, - easings: 'easeOut', - }, - }, - }, -}; - const ImageContextMenu = ({ imageDTO, children }: Props) => { const selector = useMemo( () => @@ -72,7 +47,7 @@ const ImageContextMenu = ({ imageDTO, children }: Props) => { imageDTO ? ( {selectionCount === 1 ? ( diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index 3dea6fea34..95872495df 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -1,5 +1,4 @@ -import { ExternalLinkIcon } from '@chakra-ui/icons'; -import { MenuItem } from '@chakra-ui/react'; +import { Link, MenuItem } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import { useAppToaster } from 'app/components/Toaster'; import { stateSelector } from 'app/store/store'; @@ -18,8 +17,17 @@ import { useCopyImageToClipboard } from 'features/ui/hooks/useCopyImageToClipboa import { setActiveTab } from 'features/ui/store/uiSlice'; import { memo, useCallback, useContext, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { FaCopy, FaFolder, FaShare, FaTrash } from 'react-icons/fa'; -import { IoArrowUndoCircleOutline } from 'react-icons/io5'; +import { + FaAsterisk, + FaCopy, + FaDownload, + FaExternalLinkAlt, + FaFolder, + FaQuoteRight, + FaSeedling, + FaShare, + FaTrash, +} from 'react-icons/fa'; import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages'; import { useGetImageMetadataQuery } from 'services/api/endpoints/images'; import { ImageDTO } from 'services/api/types'; @@ -140,16 +148,21 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { return ( <> - } onClickCapture={handleOpenInNewTab}> - {t('common.openInNewTab')} - + + } + onClickCapture={handleOpenInNewTab} + > + {t('common.openInNewTab')} + + {isClipboardAPIAvailable && ( } onClickCapture={handleCopyImage}> {t('parameters.copyImage')} )} } + icon={} onClickCapture={handleRecallPrompt} isDisabled={ metadata?.positive_prompt === undefined && @@ -160,14 +173,14 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { } + icon={} onClickCapture={handleRecallSeed} isDisabled={metadata?.seed === undefined} > {t('parameters.useSeed')} } + icon={} onClickCapture={handleUseAllParameters} isDisabled={!metadata} > @@ -206,6 +219,11 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { Remove from Board )} + + } w="100%"> + {t('parameters.downloadImage')} + + } diff --git a/invokeai/frontend/web/src/theme/components/menu.ts b/invokeai/frontend/web/src/theme/components/menu.ts index 324720a040..563c5ce6a9 100644 --- a/invokeai/frontend/web/src/theme/components/menu.ts +++ b/invokeai/frontend/web/src/theme/components/menu.ts @@ -1,6 +1,7 @@ import { menuAnatomy } from '@chakra-ui/anatomy'; import { createMultiStyleConfigHelpers } from '@chakra-ui/react'; import { mode } from '@chakra-ui/theme-tools'; +import { MotionProps } from 'framer-motion'; const { definePartsStyle, defineMultiStyleConfig } = createMultiStyleConfigHelpers(menuAnatomy.keys); @@ -21,6 +22,7 @@ const invokeAI = definePartsStyle((props) => ({ }, list: { zIndex: 9999, + color: mode('base.900', 'base.150')(props), bg: mode('base.200', 'base.800')(props), shadow: 'dark-lg', border: 'none', @@ -35,6 +37,9 @@ const invokeAI = definePartsStyle((props) => ({ _focus: { bg: mode('base.400', 'base.600')(props), }, + svg: { + opacity: 0.5, + }, }, })); @@ -46,3 +51,28 @@ export const menuTheme = defineMultiStyleConfig({ variant: 'invokeAI', }, }); + +export const menuListMotionProps: MotionProps = { + variants: { + enter: { + visibility: 'visible', + opacity: 1, + scale: 1, + transition: { + duration: 0.07, + ease: [0.4, 0, 0.2, 1], + }, + }, + exit: { + transitionEnd: { + visibility: 'hidden', + }, + opacity: 0, + scale: 0.8, + transition: { + duration: 0.07, + easings: 'easeOut', + }, + }, + }, +};