import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/16/solid'; import { cn } from '../../utils'; type IPageItem = { index: number; disabled?: boolean; type: 'page' | 'placeholder'; }; interface PaginationProps { total: number; onPrev: () => void; onNext: () => void; onPageChange?: (index: number) => void; pageIndex: number; pageSize?: number; extendPageNumber?: number; } export function getShowIndices(total: number, pageIndex: number, pageSize: number, extendPageNumber: number) { const totalPage = Math.ceil(total / (pageSize || 1)); const pages = [ { index: 0, disabled: false, type: 'page', }, ...(new Array(1 + extendPageNumber * 2).fill(0).map((p, i) => ({ index: pageIndex - (extendPageNumber - i), disabled: false, type: 'page', })) as IPageItem[]), { index: totalPage - 1, disabled: false, type: 'page', }, ].filter((p) => p.index >= 0 && p.index < totalPage) as IPageItem[]; const pagesUnique: IPageItem[] = []; const indexSet: Set = new Set(); for (let p of pages) { if (!indexSet.has(p.index)) { pagesUnique.push(p); indexSet.add(p.index); } } const pageResult: IPageItem[] = pagesUnique.reduce((acc, p) => { if (acc.length === 0) { return [p]; } const last = acc[acc.length - 1]; if (p.index === last.index + 1) { return [...acc, p]; } return [...acc, { index: -1, type: 'placeholder' }, p]; }, []); return pageResult; } export default function Pagination(props: PaginationProps) { const { total, onNext, onPrev, pageIndex, onPageChange, pageSize = 100, extendPageNumber = 1 } = props; const { t } = useTranslation(); const showIndices: IPageItem[] = useMemo( () => getShowIndices(total, pageIndex, pageSize, extendPageNumber), [pageIndex, pageSize, extendPageNumber, total, pageIndex] ); const pageCount = Math.ceil(total / (pageSize || 1)); if (showIndices.length === 0) { return null; } const buttonClassName = 'inline-flex h-7 min-w-[28px] items-center justify-center rounded-md px-1.5 text-[13px] tabular-nums text-foreground/80 transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-30'; return ( ); }