frontend initiatewith shadcn uis
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
'use client';
|
||||
|
||||
import { HugeiconsIcon } from '@hugeicons/react';
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from '@hugeicons/core-free-icons';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
|
||||
interface TablePaginationProps {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalRecords: number;
|
||||
pageSizeOptions?: number[];
|
||||
onPageChange: (page: number) => void;
|
||||
onPageSizeChange: (size: number) => void;
|
||||
}
|
||||
|
||||
function buildPageNumbers(page: number, totalPages: number): (number | '...')[] {
|
||||
if (totalPages <= 7) return Array.from({ length: totalPages }, (_, i) => i + 1);
|
||||
const pages: (number | '...')[] = [1];
|
||||
if (page > 3) pages.push('...');
|
||||
for (let i = Math.max(2, page - 1); i <= Math.min(totalPages - 1, page + 1); i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
if (page < totalPages - 2) pages.push('...');
|
||||
pages.push(totalPages);
|
||||
return pages;
|
||||
}
|
||||
|
||||
export function TablePagination({
|
||||
page,
|
||||
pageSize,
|
||||
totalRecords,
|
||||
pageSizeOptions = [10, 25, 50, 100],
|
||||
onPageChange,
|
||||
onPageSizeChange,
|
||||
}: TablePaginationProps) {
|
||||
const totalPages = Math.max(1, Math.ceil(totalRecords / pageSize));
|
||||
const from = Math.min((page - 1) * pageSize + 1, totalRecords);
|
||||
const to = Math.min(page * pageSize, totalRecords);
|
||||
const pages = buildPageNumbers(page, totalPages);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3 px-4 py-3 border-t sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<span>Rows per page:</span>
|
||||
<Select
|
||||
value={pageSize}
|
||||
onValueChange={(v) => onPageSizeChange(Number(v))}
|
||||
>
|
||||
<SelectTrigger size="sm" className="w-16">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{pageSizeOptions.map(s => (
|
||||
<SelectItem key={s} value={s}>{s}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span className="ml-2">
|
||||
{totalRecords === 0 ? '0 records' : `${from}–${to} of ${totalRecords} records`}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
onClick={() => onPageChange(page - 1)}
|
||||
disabled={page <= 1}
|
||||
>
|
||||
<HugeiconsIcon icon={ChevronLeftIcon} className="size-4" />
|
||||
</Button>
|
||||
|
||||
{pages.map((p, i) =>
|
||||
p === '...' ? (
|
||||
<span key={`ellipsis-${i}`} className="px-2 text-muted-foreground text-sm">…</span>
|
||||
) : (
|
||||
<Button
|
||||
key={p}
|
||||
variant={p === page ? 'default' : 'outline'}
|
||||
size="icon-sm"
|
||||
onClick={() => onPageChange(p as number)}
|
||||
>
|
||||
{p}
|
||||
</Button>
|
||||
)
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
onClick={() => onPageChange(page + 1)}
|
||||
disabled={page >= totalPages}
|
||||
>
|
||||
<HugeiconsIcon icon={ChevronRightIcon} className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user