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 (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};