summaryrefslogtreecommitdiff
path: root/src/components/numbered-pagination.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/numbered-pagination.tsx')
-rw-r--r--src/components/numbered-pagination.tsx131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/components/numbered-pagination.tsx b/src/components/numbered-pagination.tsx
new file mode 100644
index 0000000..cf02ef1
--- /dev/null
+++ b/src/components/numbered-pagination.tsx
@@ -0,0 +1,131 @@
+'use client';
+import { Icons } from '@/components/icons/icons';
+import { buttonVariants } from '@/components/ui/button';
+import {
+ Pagination,
+ PaginationContent,
+ PaginationItem,
+ PaginationLink,
+} from '@/components/ui/pagination';
+import { usePagination } from '@/hooks/use-pagination';
+import { cn } from '@/lib/utils';
+
+type NumberedPaginationProps = {
+ currentPage: number;
+ totalPages: number;
+ paginationItemsToDisplay?: number;
+ onPageChange: (page: number) => void;
+};
+
+function NumberedPagination({
+ currentPage,
+ totalPages,
+ paginationItemsToDisplay = 5,
+ onPageChange,
+}: NumberedPaginationProps) {
+ const { pages, showLeftEllipsis, showRightEllipsis } = usePagination({
+ currentPage,
+ totalPages,
+ paginationItemsToDisplay,
+ });
+
+ const handlePageChange = (page: number) => (e: React.MouseEvent) => {
+ e.preventDefault();
+ if (page >= 1 && page <= totalPages) {
+ onPageChange(page);
+ }
+ };
+
+ return (
+ <Pagination>
+ <PaginationContent className='-space-x-px inline-flex w-full gap-0 rtl:space-x-reverse'>
+ <PaginationItem>
+ <PaginationLink
+ className={cn(
+ buttonVariants({
+ variant: 'ghost',
+ }),
+ 'rounded-none shadow-none focus-visible:z-10 aria-disabled:pointer-events-none [&[aria-disabled]>svg]:opacity-50',
+ )}
+ href='#'
+ onClick={handlePageChange(currentPage - 1)}
+ aria-label='Go to previous page'
+ aria-disabled={currentPage === 1}
+ >
+ <Icons.chevronLeft size={16} strokeWidth={2} aria-hidden='true' />
+ </PaginationLink>
+ </PaginationItem>
+
+ <div className='inline-flex w-full justify-center '>
+ {showLeftEllipsis && (
+ <PaginationItem>
+ <PaginationLink
+ className={cn(
+ buttonVariants({
+ variant: 'ghost',
+ }),
+ 'pointer-events-none rounded-none shadow-none',
+ )}
+ >
+ ...
+ </PaginationLink>
+ </PaginationItem>
+ )}
+
+ {pages.map((page) => (
+ <PaginationItem key={page} className='w-max'>
+ <PaginationLink
+ className={cn(
+ buttonVariants({
+ variant: page === currentPage ? 'default' : 'ghost',
+ }),
+ 'rounded-none border-0 shadow-none focus-visible:z-10',
+ page === currentPage &&
+ 'min-w-full dark:bg-primary dark:hover:bg-primary/90',
+ )}
+ href='#'
+ onClick={handlePageChange(page)}
+ isActive={page === currentPage}
+ >
+ {page}
+ </PaginationLink>
+ </PaginationItem>
+ ))}
+
+ {showRightEllipsis && (
+ <PaginationItem>
+ <PaginationLink
+ className={cn(
+ buttonVariants({
+ variant: 'ghost',
+ }),
+ 'pointer-events-none rounded-none shadow-none',
+ )}
+ >
+ ...
+ </PaginationLink>
+ </PaginationItem>
+ )}
+ </div>
+ <PaginationItem>
+ <PaginationLink
+ className={cn(
+ buttonVariants({
+ variant: 'ghost',
+ }),
+ 'rounded-none shadow-none focus-visible:z-10 aria-disabled:pointer-events-none [&[aria-disabled]>svg]:opacity-50',
+ )}
+ href='#'
+ onClick={handlePageChange(currentPage + 1)}
+ aria-label='Go to next page'
+ aria-disabled={currentPage === totalPages}
+ >
+ <Icons.chevronRight size={16} strokeWidth={2} aria-hidden='true' />
+ </PaginationLink>
+ </PaginationItem>
+ </PaginationContent>
+ </Pagination>
+ );
+}
+
+export { NumberedPagination };