@@ -4,7 +4,58 @@ import { offsetChanged } from 'features/gallery/store/gallerySlice';
4
4
import { useCallback , useEffect , useMemo } from 'react' ;
5
5
import { useListImagesQuery } from 'services/api/endpoints/images' ;
6
6
7
- export const useGalleryPagination = ( pageButtonsPerSide : number = 2 ) => {
7
+ // Some logic copied from https://github.com/chakra-ui/zag/blob/1925b7342dc76fb06a7ec59a5a4c0063a4620422/packages/machines/pagination/src/pagination.utils.ts
8
+
9
+ export const range = ( start : number , end : number ) => {
10
+ const length = end - start + 1 ;
11
+ return Array . from ( { length } , ( _ , idx ) => idx + start ) ;
12
+ } ;
13
+
14
+ export const ELLIPSIS = 'ellipsis' as const ;
15
+
16
+ export const getRange = ( currentPage : number , totalPages : number , siblingCount : number ) => {
17
+ /**
18
+ * `2 * ctx.siblingCount + 5` explanation:
19
+ * 2 * ctx.siblingCount for left/right siblings
20
+ * 5 for 2x left/right ellipsis, 2x first/last page + 1x current page
21
+ *
22
+ * For some page counts (e.g. totalPages: 8, siblingCount: 2),
23
+ * calculated max page is higher than total pages,
24
+ * so we need to take the minimum of both.
25
+ */
26
+ const totalPageNumbers = Math . min ( 2 * siblingCount + 5 , totalPages ) ;
27
+
28
+ const firstPageIndex = 1 ;
29
+ const lastPageIndex = totalPages ;
30
+
31
+ const leftSiblingIndex = Math . max ( currentPage - siblingCount , firstPageIndex ) ;
32
+ const rightSiblingIndex = Math . min ( currentPage + siblingCount , lastPageIndex ) ;
33
+
34
+ const showLeftEllipsis = leftSiblingIndex > firstPageIndex + 1 ;
35
+ const showRightEllipsis = rightSiblingIndex < lastPageIndex - 1 ;
36
+
37
+ const itemCount = totalPageNumbers - 2 ; // 2 stands for one ellipsis and either first or last page
38
+
39
+ if ( ! showLeftEllipsis && showRightEllipsis ) {
40
+ const leftRange = range ( 1 , itemCount ) ;
41
+ return [ ...leftRange , ELLIPSIS , lastPageIndex ] ;
42
+ }
43
+
44
+ if ( showLeftEllipsis && ! showRightEllipsis ) {
45
+ const rightRange = range ( lastPageIndex - itemCount + 1 , lastPageIndex ) ;
46
+ return [ firstPageIndex , ELLIPSIS , ...rightRange ] ;
47
+ }
48
+
49
+ if ( showLeftEllipsis && showRightEllipsis ) {
50
+ const middleRange = range ( leftSiblingIndex , rightSiblingIndex ) ;
51
+ return [ firstPageIndex , ELLIPSIS , ...middleRange , ELLIPSIS , lastPageIndex ] ;
52
+ }
53
+
54
+ const fullRange = range ( firstPageIndex , lastPageIndex ) ;
55
+ return fullRange as ( number | 'ellipsis' ) [ ] ;
56
+ } ;
57
+
58
+ export const useGalleryPagination = ( ) => {
8
59
const dispatch = useAppDispatch ( ) ;
9
60
const { offset, limit } = useAppSelector ( ( s ) => s . gallery ) ;
10
61
const queryArgs = useAppSelector ( selectListImagesQueryArgs ) ;
@@ -57,24 +108,12 @@ export const useGalleryPagination = (pageButtonsPerSide: number = 2) => {
57
108
}
58
109
} , [ currentPage , pages , goToLast ] ) ;
59
110
60
- // calculate the page buttons to display - current page with 3 around it
61
111
const pageButtons = useMemo ( ( ) => {
62
- const buttons = [ ] ;
63
- const maxPageButtons = pageButtonsPerSide * 2 + 1 ;
64
- let startPage = Math . max ( currentPage - Math . floor ( maxPageButtons / 2 ) , 0 ) ;
65
- const endPage = Math . min ( startPage + maxPageButtons - 1 , pages - 1 ) ;
66
-
67
- if ( endPage - startPage < maxPageButtons - 1 ) {
68
- startPage = Math . max ( endPage - maxPageButtons + 1 , 0 ) ;
112
+ if ( pages > 7 ) {
113
+ return getRange ( currentPage + 1 , pages , 1 ) ;
69
114
}
70
-
71
- for ( let i = startPage ; i <= endPage ; i ++ ) {
72
- buttons . push ( i ) ;
73
- }
74
-
75
- return buttons ;
76
- } , [ currentPage , pageButtonsPerSide , pages ] ) ;
77
-
115
+ return range ( 1 , pages ) ;
116
+ } , [ currentPage , pages ] ) ;
78
117
const isFirstEnabled = useMemo ( ( ) => currentPage > 0 , [ currentPage ] ) ;
79
118
const isLastEnabled = useMemo ( ( ) => currentPage < pages - 1 , [ currentPage , pages ] ) ;
80
119
0 commit comments