38 lines
1.3 KiB
TypeScript
38 lines
1.3 KiB
TypeScript
export type PaginationItem = number | 'ellipsis'
|
|||
|
|
|
||
|
|
function range(start: number, end: number): number[] {
|
||
|
|
const length = end - start + 1
|
||
|
|
return Array.from({ length }, (_, i) => start + i)
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Windowed page list for numbered pagination: always shows the first and
|
||
|
|
* last page, the current page and its immediate siblings, collapsing any
|
||
|
|
* gap into a single 'ellipsis' marker. Returns every page when the total
|
||
|
|
* is small enough that no collapsing is needed.
|
||
|
|
*/
|
||
|
|
export function paginationRange(current: number, total: number, siblingCount = 1): PaginationItem[] {
|
||
|
|
if (total <= 0) return []
|
||
|
|
|
||
|
|
const totalVisible = siblingCount * 2 + 5 // first + last + current + 2 siblings + 2 ellipses
|
||
|
|
if (totalVisible >= total) return range(1, total)
|
||
|
|
|
||
|
|
const leftSibling = Math.max(current - siblingCount, 1)
|
||
|
|
const rightSibling = Math.min(current + siblingCount, total)
|
||
|
|
|
||
|
|
const showLeftEllipsis = leftSibling > 2
|
||
|
|
const showRightEllipsis = rightSibling < total - 1
|
||
|
|
|
||
|
|
if (!showLeftEllipsis && showRightEllipsis) {
|
||
|
|
const leftRange = range(1, 3 + siblingCount * 2)
|
||
|
|
return [...leftRange, 'ellipsis', total]
|
||
|
|
}
|
||
|
|
|
||
|
|
if (showLeftEllipsis && !showRightEllipsis) {
|
||
|
|
const rightRange = range(total - (3 + siblingCount * 2) + 1, total)
|
||
|
|
return [1, 'ellipsis', ...rightRange]
|
||
|
|
}
|
||
|
|
|
||
|
|
return [1, 'ellipsis', ...range(leftSibling, rightSibling), 'ellipsis', total]
|
||
|
|
}
|