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] }