47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||
import { Button } from '../buttons/Button';
|
||
|
||
export interface PaginationProps {
|
||
/** 1-based current page. */
|
||
page: number;
|
||
pageSize: number;
|
||
/** Total rows across all pages. */
|
||
total: number;
|
||
onPage: (page: number) => void;
|
||
}
|
||
|
||
/** Pager: "Showing a–b of N" + Prev/Next. Renders nothing when the set fits on
|
||
* one page. Shared by the record-view tables. */
|
||
export function Pagination({ page, pageSize, total, onPage }: PaginationProps) {
|
||
if (total <= 0) return null;
|
||
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
||
const safePage = Math.min(Math.max(page, 1), totalPages);
|
||
const start = (safePage - 1) * pageSize;
|
||
|
||
const handlePageChange = (newPage: number) => {
|
||
onPage(newPage);
|
||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
};
|
||
|
||
return (
|
||
<div className="flex items-center justify-between gap-3 border-t border-border-subtle px-[18px] pt-4 pb-24">
|
||
<span className="text-xs text-faint">
|
||
Showing {start + 1}–{Math.min(start + pageSize, total)} of {total}
|
||
</span>
|
||
<div className="flex items-center gap-2">
|
||
<Button variant="secondary" size="sm" disabled={safePage <= 1} onClick={() => handlePageChange(safePage - 1)}>
|
||
<ChevronLeft size={15} />
|
||
Prev
|
||
</Button>
|
||
<span className="px-1 text-xs font-medium text-muted nums">
|
||
{safePage} / {totalPages}
|
||
</span>
|
||
<Button variant="secondary" size="sm" disabled={safePage >= totalPages} onClick={() => handlePageChange(safePage + 1)}>
|
||
Next
|
||
<ChevronRight size={15} />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|