aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/ui/pagination.tsx
diff options
context:
space:
mode:
authoraman333nolawz <amananudhiu@gmail.com>2026-03-02 21:49:13 +0530
committeraman333nolawz <amananudhiu@gmail.com>2026-03-02 21:49:13 +0530
commitd41eff9eccf66644c4c60f53cb516bf079937a28 (patch)
tree248a0863a3181369f943d678ec4273911d35efac /src/components/ui/pagination.tsx
Using astro-erudite for static site generation
Diffstat (limited to 'src/components/ui/pagination.tsx')
-rw-r--r--src/components/ui/pagination.tsx195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/components/ui/pagination.tsx b/src/components/ui/pagination.tsx
new file mode 100644
index 0000000..ad0d40c
--- /dev/null
+++ b/src/components/ui/pagination.tsx
@@ -0,0 +1,195 @@
+import * as React from 'react'
+import {
+ ChevronLeftIcon,
+ ChevronRightIcon,
+ MoreHorizontalIcon,
+} from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+import { Button, buttonVariants } from '@/components/ui/button'
+
+function Pagination({ className, ...props }: React.ComponentProps<'nav'>) {
+ return (
+ <nav
+ role="navigation"
+ aria-label="pagination"
+ data-slot="pagination"
+ className={cn('mx-auto flex w-full justify-center', className)}
+ {...props}
+ />
+ )
+}
+
+function PaginationContent({
+ className,
+ ...props
+}: React.ComponentProps<'ul'>) {
+ return (
+ <ul
+ data-slot="pagination-content"
+ className={cn('flex flex-row items-center gap-1', className)}
+ {...props}
+ />
+ )
+}
+
+function PaginationItem({ ...props }: React.ComponentProps<'li'>) {
+ return <li data-slot="pagination-item" {...props} />
+}
+
+type PaginationLinkProps = {
+ isActive?: boolean
+ isDisabled?: boolean
+} & Pick<React.ComponentProps<typeof Button>, 'size'> &
+ React.ComponentProps<'a'>
+
+function PaginationLink({
+ className,
+ isActive,
+ isDisabled,
+ size = 'icon',
+ ...props
+}: PaginationLinkProps) {
+ return (
+ <a
+ aria-current={isActive ? 'page' : undefined}
+ data-slot="pagination-link"
+ data-active={isActive}
+ data-disabled={isDisabled}
+ className={cn(
+ buttonVariants({
+ variant: isActive ? 'outline' : 'ghost',
+ size,
+ }),
+ isDisabled && 'pointer-events-none opacity-50',
+ className,
+ )}
+ {...props}
+ />
+ )
+}
+
+function PaginationPrevious({
+ className,
+ isDisabled,
+ ...props
+}: React.ComponentProps<typeof PaginationLink>) {
+ return (
+ <PaginationLink
+ aria-label="Go to previous page"
+ size="default"
+ className={cn('gap-1 px-2.5 sm:pl-2.5', className)}
+ isDisabled={isDisabled}
+ {...props}
+ >
+ <ChevronLeftIcon />
+ <span className="hidden sm:block">Previous</span>
+ </PaginationLink>
+ )
+}
+
+function PaginationNext({
+ className,
+ isDisabled,
+ ...props
+}: React.ComponentProps<typeof PaginationLink>) {
+ return (
+ <PaginationLink
+ aria-label="Go to next page"
+ size="default"
+ className={cn('gap-1 px-2.5 sm:pr-2.5', className)}
+ isDisabled={isDisabled}
+ {...props}
+ >
+ <span className="hidden sm:block">Next</span>
+ <ChevronRightIcon />
+ </PaginationLink>
+ )
+}
+
+function PaginationEllipsis({
+ className,
+ ...props
+}: React.ComponentProps<'span'>) {
+ return (
+ <span
+ aria-hidden
+ data-slot="pagination-ellipsis"
+ className={cn('flex size-9 items-center justify-center', className)}
+ {...props}
+ >
+ <MoreHorizontalIcon className="size-4" />
+ <span className="sr-only">More pages</span>
+ </span>
+ )
+}
+
+const PaginationComponent: React.FC<PaginationProps> = ({
+ currentPage,
+ totalPages,
+ baseUrl,
+}) => {
+ const pages = Array.from({ length: totalPages }, (_, i) => i + 1)
+
+ const getPageUrl = (page: number) => {
+ if (page === 1) return baseUrl
+ return `${baseUrl}${page}`
+ }
+
+ return (
+ <Pagination>
+ <PaginationContent className="flex-wrap">
+ <PaginationItem>
+ <PaginationPrevious
+ href={currentPage > 1 ? getPageUrl(currentPage - 1) : undefined}
+ isDisabled={currentPage === 1}
+ />
+ </PaginationItem>
+
+ {pages.map((page) => (
+ <PaginationItem key={page}>
+ <PaginationLink
+ href={getPageUrl(page)}
+ isActive={page === currentPage}
+ >
+ {page}
+ </PaginationLink>
+ </PaginationItem>
+ ))}
+
+ {totalPages > 5 && (
+ <PaginationItem>
+ <PaginationEllipsis />
+ </PaginationItem>
+ )}
+
+ <PaginationItem>
+ <PaginationNext
+ href={
+ currentPage < totalPages ? getPageUrl(currentPage + 1) : undefined
+ }
+ isDisabled={currentPage === totalPages}
+ />
+ </PaginationItem>
+ </PaginationContent>
+ </Pagination>
+ )
+}
+
+interface PaginationProps {
+ currentPage: number
+ totalPages: number
+ baseUrl: string
+}
+
+export default PaginationComponent
+
+export {
+ Pagination,
+ PaginationContent,
+ PaginationLink,
+ PaginationItem,
+ PaginationPrevious,
+ PaginationNext,
+ PaginationEllipsis,
+}