spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1import Link from 'next/link';2import { cn } from '@/lib/cn';3import { fmtInt } from '@/lib/format';45/** URL-driven pagination (server component). `makeHref(page)` builds the link preserving current filters. */6export function Pagination({ total, page, pages, perPage, makeHref, className }: { total: number; page: number; pages: number; perPage: number; makeHref: (page: number) => string; className?: string }) {7 if (pages <= 1) return <p className={cn('tnum text-xs text-ink-3', className)}>{fmtInt(total)} results</p>;8 const from = (page - 1) * perPage + 1;9 const to = Math.min(total, page * perPage);10 const btn = 'inline-flex h-10 min-w-10 items-center justify-center border border-rule px-3 text-sm text-ink-2 hover:bg-surface-2 hover:text-ink';11 return (12 <nav className={cn('flex flex-wrap items-center justify-between gap-3', className)} aria-label="Pagination">13 <p className="tnum text-xs text-ink-3">14 {fmtInt(from)}–{fmtInt(to)} of {fmtInt(total)}15 </p>16 <div className="flex items-center gap-1.5">17 {page > 1 ? (18 <Link href={makeHref(page - 1)} className={btn} rel="prev">19 ‹ Prev20 </Link>21 ) : (22 <span className={cn(btn, 'opacity-40')}>‹ Prev</span>23 )}24 <span className="mono px-2 text-xs text-ink-3">25 {page} / {fmtInt(pages)}26 </span>27 {page < pages ? (28 <Link href={makeHref(page + 1)} className={btn} rel="next">29 Next ›30 </Link>31 ) : (32 <span className={cn(btn, 'opacity-40')}>Next ›</span>33 )}34 </div>35 </nav>36 );37}3839/** Build a query-string href preserving existing params (page reset unless patched). */40export function withParams(base: string, current: Record<string, string | undefined>, patch: Record<string, string | number | undefined | null>): string {41 const p = new URLSearchParams();42 for (const [k, v] of Object.entries(current)) if (v !== undefined && v !== '') p.set(k, v);43 for (const [k, v] of Object.entries(patch)) {44 if (v === undefined || v === null || v === '') p.delete(k);45 else p.set(k, String(v));46 }47 if (!('page' in patch)) p.delete('page');48 const s = p.toString();49 return s ? `${base}?${s}` : base;50}51