3,200+ hardcoded color values replaced with CSS variable-backed Tailwind classes (bg-card, text-foreground, border-border, etc.). Enables light mode via CSS variable swap. Only syntax highlighting colors and intentional one-offs remain hardcoded (~15 values). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
import { ChevronLeft, ChevronRight } from 'lucide-react'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
interface PaginationProps {
|
|
page: number
|
|
totalPages: number
|
|
total: number
|
|
pageSize: number
|
|
onPageChange: (page: number) => void
|
|
}
|
|
|
|
export function Pagination({ page, totalPages, total, pageSize, onPageChange }: PaginationProps) {
|
|
const start = (page - 1) * pageSize + 1
|
|
const end = Math.min(page * pageSize, total)
|
|
|
|
const getPageNumbers = (): (number | 'ellipsis')[] => {
|
|
if (totalPages <= 7) {
|
|
return Array.from({ length: totalPages }, (_, i) => i + 1)
|
|
}
|
|
const pages: (number | 'ellipsis')[] = [1]
|
|
if (page > 3) pages.push('ellipsis')
|
|
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('ellipsis')
|
|
pages.push(totalPages)
|
|
return pages
|
|
}
|
|
|
|
if (totalPages <= 1) return null
|
|
|
|
const btnBase = cn(
|
|
'inline-flex h-8 min-w-8 items-center justify-center rounded-md text-sm font-medium',
|
|
'transition-colors disabled:opacity-50 disabled:pointer-events-none'
|
|
)
|
|
|
|
return (
|
|
<div className="flex items-center justify-between gap-4 pt-4">
|
|
<span className="text-sm text-muted-foreground">
|
|
Showing {start}-{end} of {total}
|
|
</span>
|
|
<div className="flex items-center gap-1">
|
|
<button
|
|
onClick={() => onPageChange(page - 1)}
|
|
disabled={page <= 1}
|
|
className={cn(btnBase, 'px-2 text-muted-foreground hover:bg-accent hover:text-foreground')}
|
|
>
|
|
<ChevronLeft className="h-4 w-4" />
|
|
</button>
|
|
{getPageNumbers().map((p, i) =>
|
|
p === 'ellipsis' ? (
|
|
<span key={`e${i}`} className="px-1 text-muted-foreground">...</span>
|
|
) : (
|
|
<button
|
|
key={p}
|
|
onClick={() => onPageChange(p)}
|
|
className={cn(
|
|
btnBase,
|
|
'px-2',
|
|
p === page
|
|
? 'bg-primary text-white'
|
|
: 'text-muted-foreground hover:bg-accent hover:text-foreground'
|
|
)}
|
|
>
|
|
{p}
|
|
</button>
|
|
)
|
|
)}
|
|
<button
|
|
onClick={() => onPageChange(page + 1)}
|
|
disabled={page >= totalPages}
|
|
className={cn(btnBase, 'px-2 text-muted-foreground hover:bg-accent hover:text-foreground')}
|
|
>
|
|
<ChevronRight className="h-4 w-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default Pagination
|