SPB Git

spb/rareindex

Public
1.7 KB · 38 lines tsx
1import Link from 'next/link';2import { cn } from '@/lib/format';34/** URL-driven pagination: keeps every other search param. */5export function Pagination({ page, pageSize, total, basePath, params, className }: { page: number; pageSize: number; total: number; basePath: string; params: Record<string, string | undefined>; className?: string }) {6  const pages = Math.max(1, Math.ceil(total / pageSize));7  if (pages <= 1) return null;8  const href = (p: number) => {9    const sp = new URLSearchParams();10    for (const [k, v] of Object.entries(params)) if (v) sp.set(k, v);11    if (p > 1) sp.set('page', String(p));12    else sp.delete('page');13    const qs = sp.toString();14    return qs ? `${basePath}?${qs}` : basePath;15  };16  const from = (page - 1) * pageSize + 1;17  const to = Math.min(total, page * pageSize);18  const btn = 'inline-flex h-8 items-center rounded-md border border-border px-2.5 text-xs font-medium hover:bg-inset aria-disabled:pointer-events-none aria-disabled:opacity-40';19  return (20    <nav className={cn('mt-4 flex items-center justify-between gap-3 text-xs text-muted', className)} aria-label="Pagination">21      <span className="num">22        {from.toLocaleString('en-US')}–{to.toLocaleString('en-US')} of {total.toLocaleString('en-US')}23      </span>24      <div className="flex items-center gap-1.5">25        <Link href={href(Math.max(1, page - 1))} aria-disabled={page <= 1} className={btn}>26          Previous27        </Link>28        <span className="num px-2">29          {page} / {pages}30        </span>31        <Link href={href(Math.min(pages, page + 1))} aria-disabled={page >= pages} className={btn}>32          Next33        </Link>34      </div>35    </nav>36  );37}38
Files · f9a634ec80792524177fc3e5fba5c7953d672423
Menu

Theme