183 lines
5.5 KiB
TypeScript
183 lines
5.5 KiB
TypeScript
"use client"
|
|
|
|
import { type Table } from "@tanstack/react-table"
|
|
import {
|
|
Pagination,
|
|
PaginationContent,
|
|
PaginationEllipsis,
|
|
PaginationItem,
|
|
} from "@kandev/ui/pagination"
|
|
import { Button } from "@kandev/ui/button"
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@kandev/ui/select"
|
|
import {
|
|
IconChevronLeft,
|
|
IconChevronRight,
|
|
IconChevronsLeft,
|
|
IconChevronsRight,
|
|
} from "@tabler/icons-react"
|
|
|
|
interface DataTablePaginationProps<TData> {
|
|
table: Table<TData>
|
|
}
|
|
|
|
export function DataTablePagination<TData>({
|
|
table,
|
|
}: DataTablePaginationProps<TData>) {
|
|
const currentPage = table.getState().pagination.pageIndex + 1
|
|
const pageCount = table.getPageCount()
|
|
|
|
// Generate page numbers to display
|
|
const getPageNumbers = () => {
|
|
const pages: (number | 'ellipsis')[] = []
|
|
const showPages = 5 // Max pages to show
|
|
|
|
if (pageCount <= showPages) {
|
|
// Show all pages
|
|
for (let i = 1; i <= pageCount; i++) {
|
|
pages.push(i)
|
|
}
|
|
} else {
|
|
// Always show first page
|
|
pages.push(1)
|
|
|
|
if (currentPage > 3) {
|
|
pages.push('ellipsis')
|
|
}
|
|
|
|
// Pages around current
|
|
const start = Math.max(2, currentPage - 1)
|
|
const end = Math.min(pageCount - 1, currentPage + 1)
|
|
|
|
for (let i = start; i <= end; i++) {
|
|
pages.push(i)
|
|
}
|
|
|
|
if (currentPage < pageCount - 2) {
|
|
pages.push('ellipsis')
|
|
}
|
|
|
|
// Always show last page
|
|
if (pageCount > 1) {
|
|
pages.push(pageCount)
|
|
}
|
|
}
|
|
|
|
return pages
|
|
}
|
|
|
|
return (
|
|
<div className="flex items-center justify-between px-2">
|
|
<div className="flex-1 text-sm text-muted-foreground">
|
|
{table.getFilteredRowModel().rows.length > 0 && (
|
|
<>
|
|
Showing {table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1} to{" "}
|
|
{Math.min(
|
|
(table.getState().pagination.pageIndex + 1) * table.getState().pagination.pageSize,
|
|
table.getRowCount()
|
|
)}{" "}
|
|
of {table.getRowCount()} results
|
|
</>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center space-x-6 lg:space-x-8">
|
|
<div className="flex items-center space-x-2">
|
|
<p className="text-sm font-medium whitespace-nowrap">Rows per page</p>
|
|
<Select
|
|
value={`${table.getState().pagination.pageSize}`}
|
|
onValueChange={(value) => {
|
|
table.setPageSize(Number(value))
|
|
}}
|
|
>
|
|
<SelectTrigger className="h-8 w-[70px]">
|
|
<SelectValue placeholder={table.getState().pagination.pageSize} />
|
|
</SelectTrigger>
|
|
<SelectContent side="top">
|
|
{[10, 25, 50].map((pageSize) => (
|
|
<SelectItem key={pageSize} value={`${pageSize}`}>
|
|
{pageSize}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<Pagination>
|
|
<PaginationContent>
|
|
<PaginationItem>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="hidden lg:flex cursor-pointer"
|
|
onClick={() => table.setPageIndex(0)}
|
|
disabled={!table.getCanPreviousPage()}
|
|
>
|
|
<span className="sr-only">Go to first page</span>
|
|
<IconChevronsLeft className="h-4 w-4" />
|
|
</Button>
|
|
</PaginationItem>
|
|
<PaginationItem>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="cursor-pointer"
|
|
onClick={() => table.previousPage()}
|
|
disabled={!table.getCanPreviousPage()}
|
|
>
|
|
<span className="sr-only">Go to previous page</span>
|
|
<IconChevronLeft className="h-4 w-4" />
|
|
</Button>
|
|
</PaginationItem>
|
|
{getPageNumbers().map((page, idx) =>
|
|
page === 'ellipsis' ? (
|
|
<PaginationItem key={`ellipsis-${idx}`}>
|
|
<PaginationEllipsis />
|
|
</PaginationItem>
|
|
) : (
|
|
<PaginationItem key={page}>
|
|
<Button
|
|
variant={page === currentPage ? "outline" : "ghost"}
|
|
size="icon"
|
|
className="cursor-pointer"
|
|
onClick={() => table.setPageIndex(page - 1)}
|
|
>
|
|
{page}
|
|
</Button>
|
|
</PaginationItem>
|
|
)
|
|
)}
|
|
<PaginationItem>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="cursor-pointer"
|
|
onClick={() => table.nextPage()}
|
|
disabled={!table.getCanNextPage()}
|
|
>
|
|
<span className="sr-only">Go to next page</span>
|
|
<IconChevronRight className="h-4 w-4" />
|
|
</Button>
|
|
</PaginationItem>
|
|
<PaginationItem>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="hidden lg:flex cursor-pointer"
|
|
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
|
disabled={!table.getCanNextPage()}
|
|
>
|
|
<span className="sr-only">Go to last page</span>
|
|
<IconChevronsRight className="h-4 w-4" />
|
|
</Button>
|
|
</PaginationItem>
|
|
</PaginationContent>
|
|
</Pagination>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|