spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1import Link from 'next/link';2import { fmtInt } from '@/lib/format';3import { pageInfo, pageWindow } from '@/lib/pagination';45/**6 * Server-side pager (URL state, §295). Renders "Showing a–b of N", previous/next links with7 * rel=prev/next, and a compact page window. Pure links: works without JavaScript and is crawlable.8 */9export function Pager({10 total,11 pageSize,12 page,13 hrefFor,14 label = 'Pagination',15 noun,16 className = '',17}: {18 total: number;19 pageSize: number;20 page: number;21 /** URL for a given page (1-based). Page 1 should drop the param so canonical URLs stay clean. */22 hrefFor: (page: number) => string;23 /** aria-label for the <nav>; use a distinct label when a page has several pagers. */24 label?: string;25 /** Row noun for the summary, e.g. "evidence items". */26 noun?: string;27 className?: string;28}) {29 const info = pageInfo(page, pageSize, total);30 if (total <= 0) return null;31 const linkCls = 'ci-pager-link';32 const disabledCls = 'ci-pager-link is-disabled';33 return (34 <nav aria-label={label} className={`ci-pager mt-3 flex flex-wrap items-center justify-between gap-2 text-[13px] text-ink-2 ${className}`}>35 <p className="m-0">36 Showing <span className="ci-num">{fmtInt(info.from)}</span>–<span className="ci-num">{fmtInt(info.to)}</span> of <span className="ci-num">{fmtInt(total)}</span>37 {noun ? ` ${noun}` : ''}38 </p>39 {info.pageCount > 1 ? (40 <ul className="m-0 flex list-none items-center gap-1 p-0">41 <li>42 {info.hasPrev ? (43 <Link className={linkCls} href={hrefFor(info.page - 1)} rel="prev" aria-label={`Previous page (${info.page - 1})`}>44 ← Previous45 </Link>46 ) : (47 <span className={disabledCls} aria-disabled="true">48 ← Previous49 </span>50 )}51 </li>52 {pageWindow(info.page, info.pageCount).map((p, i) =>53 p == null ? (54 <li key={`gap-${i}`} aria-hidden className="px-1 text-ink-4">55 …56 </li>57 ) : (58 <li key={p}>59 {p === info.page ? (60 <span className="ci-pager-link is-current ci-num" aria-current="page" aria-label={`Page ${p}, current page`}>61 {p}62 </span>63 ) : (64 <Link className={`${linkCls} ci-num`} href={hrefFor(p)} aria-label={`Page ${p}`}>65 {p}66 </Link>67 )}68 </li>69 ),70 )}71 <li>72 {info.hasNext ? (73 <Link className={linkCls} href={hrefFor(info.page + 1)} rel="next" aria-label={`Next page (${info.page + 1})`}>74 Next →75 </Link>76 ) : (77 <span className={disabledCls} aria-disabled="true">78 Next →79 </span>80 )}81 </li>82 </ul>83 ) : null}84 </nav>85 );86}87