diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 42291b47fb..1d21249278 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -381,7 +381,9 @@ "featuresWillReset": "If you delete this image, those features will immediately be reset.", "galleryImageSize": "Image Size", "gallerySettings": "Gallery Settings", + "go": "Go", "image": "image", + "jump": "Jump", "loading": "Loading", "loadMore": "Load More", "newestFirst": "Newest First", diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx index 7402bb8772..07e33d9085 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx @@ -1,8 +1,10 @@ -import { Button, CompositeNumberInput, Flex, Icon, IconButton, Spacer } from '@invoke-ai/ui-library'; +import { Button, Flex, Icon, IconButton } from '@invoke-ai/ui-library'; import { ELLIPSIS, useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination'; import { useCallback } from 'react'; import { PiCaretLeftBold, PiCaretRightBold, PiDotsThreeBold } from 'react-icons/pi'; +import { JumpTo } from './JumpTo'; + export const GalleryPagination = () => { const { goPrev, goNext, isPrevEnabled, isNextEnabled, pageButtons, goToPage, currentPage, total } = useGalleryPagination(); @@ -15,64 +17,44 @@ export const GalleryPagination = () => { goNext(); }, [goNext]); - const onChangeJumpTo = useCallback( - (v: number) => { - goToPage(v - 1); - }, - [goToPage] - ); - if (!total) { return null; } return ( - - - - - } - onClick={onClickPrev} - isDisabled={!isPrevEnabled} - variant="ghost" - /> - {pageButtons.map((page, i) => { - if (page === ELLIPSIS) { - return ; - } - return ( - - ); - })} - } - onClick={onClickNext} - isDisabled={!isNextEnabled} - variant="ghost" - /> - - - + } + onClick={onClickPrev} + isDisabled={!isPrevEnabled} + variant="ghost" /> + {pageButtons.map((page, i) => { + if (page === ELLIPSIS) { + return ; + } + return ( + + ); + })} + } + onClick={onClickNext} + isDisabled={!isNextEnabled} + variant="ghost" + /> + ); }; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/JumpTo.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/JumpTo.tsx new file mode 100644 index 0000000000..9f268cddb6 --- /dev/null +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/JumpTo.tsx @@ -0,0 +1,77 @@ +import { + Button, + CompositeNumberInput, + Flex, + FormControl, + Popover, + PopoverArrow, + PopoverBody, + PopoverContent, + PopoverTrigger, + useDisclosure, +} from '@invoke-ai/ui-library'; +import { useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination'; +import { useCallback, useEffect, useState } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; +import { useTranslation } from 'react-i18next'; + +export const JumpTo = () => { + const { t } = useTranslation(); + const { goToPage, currentPage, pages } = useGalleryPagination(); + const [newPage, setNewPage] = useState(currentPage); + const { isOpen, onToggle, onClose } = useDisclosure(); + + const onChangeJumpTo = useCallback((v: number) => { + setNewPage(v - 1); + }, []); + + const onClickGo = useCallback(() => { + goToPage(newPage); + onClose(); + }, [newPage, goToPage, onClose]); + + useHotkeys( + 'enter', + () => { + if (isOpen) { + onClickGo(); + } + }, + [isOpen, onClickGo] + ); + + useEffect(() => { + setNewPage(currentPage); + }, [currentPage]); + + return ( + + + + + + + + + + + + + + + + + ); +};