99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import './Pagination.css';
|
|
|
|
interface PaginationProps {
|
|
page: number;
|
|
totalPages: number;
|
|
total: number;
|
|
limit: number;
|
|
onPageChange: (page: number) => void;
|
|
className?: string;
|
|
}
|
|
|
|
export function Pagination({ page, totalPages, total, limit, onPageChange, className = '' }: PaginationProps) {
|
|
const start = (page - 1) * limit + 1;
|
|
const end = Math.min(page * limit, total);
|
|
|
|
if (totalPages <= 1) {
|
|
return null;
|
|
}
|
|
|
|
const getPageNumbers = (): (number | 'ellipsis')[] => {
|
|
const pages: (number | 'ellipsis')[] = [];
|
|
const showEllipsisStart = page > 3;
|
|
const showEllipsisEnd = page < totalPages - 2;
|
|
|
|
pages.push(1);
|
|
|
|
if (showEllipsisStart) {
|
|
pages.push('ellipsis');
|
|
}
|
|
|
|
for (let i = Math.max(2, page - 1); i <= Math.min(totalPages - 1, page + 1); i++) {
|
|
if (!pages.includes(i)) {
|
|
pages.push(i);
|
|
}
|
|
}
|
|
|
|
if (showEllipsisEnd) {
|
|
pages.push('ellipsis');
|
|
}
|
|
|
|
if (totalPages > 1 && !pages.includes(totalPages)) {
|
|
pages.push(totalPages);
|
|
}
|
|
|
|
return pages;
|
|
};
|
|
|
|
return (
|
|
<div className={`pagination ${className}`.trim()}>
|
|
<span className="pagination__info">
|
|
Showing {start}-{end} of {total}
|
|
</span>
|
|
|
|
<div className="pagination__controls">
|
|
<button
|
|
type="button"
|
|
className="pagination__btn"
|
|
onClick={() => onPageChange(page - 1)}
|
|
disabled={page <= 1}
|
|
aria-label="Previous page"
|
|
>
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
<polyline points="15 18 9 12 15 6" />
|
|
</svg>
|
|
</button>
|
|
|
|
{getPageNumbers().map((pageNum, index) =>
|
|
pageNum === 'ellipsis' ? (
|
|
<span key={`ellipsis-${index}`} className="pagination__ellipsis">
|
|
...
|
|
</span>
|
|
) : (
|
|
<button
|
|
key={pageNum}
|
|
type="button"
|
|
className={`pagination__btn pagination__page ${pageNum === page ? 'pagination__page--active' : ''}`}
|
|
onClick={() => onPageChange(pageNum)}
|
|
>
|
|
{pageNum}
|
|
</button>
|
|
)
|
|
)}
|
|
|
|
<button
|
|
type="button"
|
|
className="pagination__btn"
|
|
onClick={() => onPageChange(page + 1)}
|
|
disabled={page >= totalPages}
|
|
aria-label="Next page"
|
|
>
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
<polyline points="9 18 15 12 9 6" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|