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 cfac6a728a..e751a5e5fb 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx @@ -1,10 +1,23 @@ -import { Button, Flex, IconButton, Text } from '@invoke-ai/ui-library'; -import { useGalleryPagination } from '../../hooks/useGalleryPagination'; -import { PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi'; +import { Button, Flex, IconButton, Spacer, Text } from '@invoke-ai/ui-library'; +import { useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination'; +import { PiCaretDoubleLeftBold, PiCaretDoubleRightBold, PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi'; export const GalleryPagination = () => { - const { goPrev, goNext, isPrevEnabled, isNextEnabled, pageButtons, goToPage, currentPage, rangeDisplay, total } = - useGalleryPagination(); + const { + goPrev, + goNext, + goToFirst, + goToLast, + isFirstEnabled, + isLastEnabled, + isPrevEnabled, + isNextEnabled, + pageButtons, + goToPage, + currentPage, + rangeDisplay, + total, + } = useGalleryPagination(); if (!total) { return ; @@ -12,7 +25,14 @@ export const GalleryPagination = () => { return ( - + + } + onClick={goToFirst} + isDisabled={!isFirstEnabled} + /> { onClick={goPrev} isDisabled={!isPrevEnabled} /> - {pageButtons.map((page) => - typeof page === 'number' ? ( - - ) : ( - ... - ) - )} + + {pageButtons.map((page) => ( + + ))} + { onClick={goNext} isDisabled={!isNextEnabled} /> + } + onClick={goToLast} + isDisabled={!isLastEnabled} + /> {rangeDisplay} Images diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts b/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts index 43777c5606..0045afeab6 100644 --- a/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts +++ b/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts @@ -1,133 +1,119 @@ -import { useMemo, useCallback } from "react"; -import { useAppDispatch, useAppSelector } from "../../../app/store/storeHooks"; -import { useGetBoardAssetsTotalQuery, useGetBoardImagesTotalQuery } from "../../../services/api/endpoints/boards"; -import { useListImagesQuery } from "../../../services/api/endpoints/images"; -import { selectListImagesQueryArgs } from "../store/gallerySelectors"; -import { offsetChanged } from "../store/gallerySlice"; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors'; +import { offsetChanged } from 'features/gallery/store/gallerySlice'; +import { useCallback, useMemo } from 'react'; +import { useListImagesQuery } from 'services/api/endpoints/images'; -export const useGalleryPagination = () => { - const dispatch = useAppDispatch(); - const { offset, limit } = useAppSelector((s) => s.gallery); - const queryArgs = useAppSelector(selectListImagesQueryArgs); +export const useGalleryPagination = (pageButtonsPerSide: number = 2) => { + const dispatch = useAppDispatch(); + const { offset, limit } = useAppSelector((s) => s.gallery); + const queryArgs = useAppSelector(selectListImagesQueryArgs); - const { count, total } = useListImagesQuery(queryArgs, { - selectFromResult: ({ data }) => ({ count: data?.items.length ?? 0, total: data?.total ?? 0 }), - }); + const { count, total } = useListImagesQuery(queryArgs, { + selectFromResult: ({ data }) => ({ count: data?.items.length ?? 0, total: data?.total ?? 0 }), + }); - const currentPage = useMemo(() => Math.ceil(offset / (limit || 0)), [offset, limit]); - const pages = useMemo(() => Math.ceil(total / (limit || 0)), [total, limit]); + const currentPage = useMemo(() => Math.ceil(offset / (limit || 0)), [offset, limit]); + const pages = useMemo(() => Math.ceil(total / (limit || 0)), [total, limit]); - const isNextEnabled = useMemo(() => { - if (!count) { - return false; - } - return currentPage + 1 < pages; - }, [count, currentPage, pages]); - const isPrevEnabled = useMemo(() => { - if (!count) { - return false; - } - return offset > 0; - }, [count, offset]); + const isNextEnabled = useMemo(() => { + if (!count) { + return false; + } + return currentPage + 1 < pages; + }, [count, currentPage, pages]); + const isPrevEnabled = useMemo(() => { + if (!count) { + return false; + } + return offset > 0; + }, [count, offset]); - const goNext = useCallback(() => { - dispatch(offsetChanged(offset + (limit || 0))); - }, [dispatch, offset, limit]); + const goNext = useCallback(() => { + dispatch(offsetChanged(offset + (limit || 0))); + }, [dispatch, offset, limit]); - const goPrev = useCallback(() => { - dispatch(offsetChanged(Math.max(offset - (limit || 0), 0))); - }, [dispatch, offset, limit]); + const goPrev = useCallback(() => { + dispatch(offsetChanged(Math.max(offset - (limit || 0), 0))); + }, [dispatch, offset, limit]); - const goToPage = useCallback( - (page: number) => { - const p = Math.max(0, Math.min(page, pages - 1)); - dispatch(offsetChanged(page * (limit || 0))); - }, - [dispatch, pages, limit] - ); - const goToFirst = useCallback(() => { - dispatch(offsetChanged(0)); - }, [dispatch]); - const goToLast = useCallback(() => { - dispatch(offsetChanged(pages * (limit || 0))); - }, [dispatch, pages, limit]); + const goToPage = useCallback( + (page: number) => { + const p = Math.max(0, Math.min(page, pages - 1)); + dispatch(offsetChanged(page * (limit || 0))); + }, + [dispatch, pages, limit] + ); + const goToFirst = useCallback(() => { + dispatch(offsetChanged(0)); + }, [dispatch]); + const goToLast = useCallback(() => { + dispatch(offsetChanged((pages - 1) * (limit || 0))); + }, [dispatch, pages, limit]); - // calculate the page buttons to display - current page with 3 around it - const pageButtons = useMemo(() => { - const buttons = []; - const maxPageButtons = 3; - let startPage = Math.max(currentPage - (Math.floor(maxPageButtons / 2)), 0); - let endPage = Math.min(startPage + maxPageButtons - 1, pages - 1); + // calculate the page buttons to display - current page with 3 around it + const pageButtons = useMemo(() => { + const buttons = []; + const maxPageButtons = pageButtonsPerSide * 2 + 1; + let startPage = Math.max(currentPage - Math.floor(maxPageButtons / 2), 0); + const endPage = Math.min(startPage + maxPageButtons - 1, pages - 1); - if (endPage - startPage < maxPageButtons - 1) { - startPage = Math.max(endPage - maxPageButtons + 1, 0); - } + if (endPage - startPage < maxPageButtons - 1) { + startPage = Math.max(endPage - maxPageButtons + 1, 0); + } - if (startPage > 0) { - buttons.push(0); - if (startPage > 1) { - buttons.push('...'); - } - } + for (let i = startPage; i <= endPage; i++) { + buttons.push(i); + } - for (let i = startPage; i <= endPage; i++) { - buttons.push(i); - } + return buttons; + }, [currentPage, pageButtonsPerSide, pages]); - if (endPage < pages - 1) { - if (endPage < pages - 2) { - buttons.push('...'); - } - buttons.push(pages - 1); - } + const isFirstEnabled = useMemo(() => currentPage > 0, [currentPage]); + const isLastEnabled = useMemo(() => currentPage < pages - 1, [currentPage, pages]); - return buttons; - }, [currentPage, pages]); + const rangeDisplay = useMemo(() => { + const startItem = currentPage * (limit || 0) + 1; + const endItem = Math.min((currentPage + 1) * (limit || 0), total); + return `${startItem}-${endItem} of ${total}`; + }, [total, currentPage, limit]); - const isFirstEnabled = useMemo(() => currentPage > 0, [currentPage]); - const isLastEnabled = useMemo(() => currentPage < pages - 1, [currentPage, pages]); + const api = useMemo( + () => ({ + count, + total, + currentPage, + pages, + isNextEnabled, + isPrevEnabled, + goNext, + goPrev, + goToPage, + goToFirst, + goToLast, + pageButtons, + isFirstEnabled, + isLastEnabled, + rangeDisplay, + }), + [ + count, + total, + currentPage, + pages, + isNextEnabled, + isPrevEnabled, + goNext, + goPrev, + goToPage, + goToFirst, + goToLast, + pageButtons, + isFirstEnabled, + isLastEnabled, + rangeDisplay, + ] + ); - const rangeDisplay = useMemo(() => { - const startItem = currentPage * (limit || 0) + 1; - const endItem = Math.min((currentPage + 1) * (limit || 0), total); - return `${startItem}-${endItem} of ${total}`; - }, [total, currentPage, limit]); - - const api = useMemo( - () => ({ - count, - total, - currentPage, - pages, - isNextEnabled, - isPrevEnabled, - goNext, - goPrev, - goToPage, - goToFirst, - goToLast, - pageButtons, - isFirstEnabled, - isLastEnabled, - rangeDisplay - }), - [ - count, - total, - currentPage, - pages, - isNextEnabled, - isPrevEnabled, - goNext, - goPrev, - goToPage, - goToFirst, - goToLast, - pageButtons, - isFirstEnabled, - isLastEnabled, - rangeDisplay - ] - ); - return api; -}; \ No newline at end of file + return api; +};