SPB Git forge

spb/cancerindex

Public
37commits 1branches 0releases
2.9 MBsize
maindefault branch
10 days agolast push
TypeScript 97.2% SQL 1.5% CSS 0.6% JavaScript 0.5%
2.4 KB · 63 lines typescript
Raw Blame History
1/** Pure pagination math shared by server components, query helpers and tests (§295 URL state). */23export interface PageInfo {4  /** 1-based current page, clamped into [1, pageCount]. */5  page: number;6  pageSize: number;7  total: number;8  pageCount: number;9  /** SQL OFFSET for the clamped page. */10  offset: number;11  /** 1-based index of the first row shown (0 when total = 0). */12  from: number;13  /** 1-based index of the last row shown (0 when total = 0). */14  to: number;15  hasPrev: boolean;16  hasNext: boolean;17}1819export function pageCount(total: number, pageSize: number): number {20  if (!Number.isFinite(total) || total <= 0) return 1;21  const size = Math.max(1, Math.floor(pageSize));22  return Math.max(1, Math.ceil(total / size));23}2425/** Clamp a requested page into the valid range for `total` rows (always ≥ 1). */26export function clampPage(page: number, total: number, pageSize: number): number {27  const n = Number.isFinite(page) ? Math.floor(page) : 1;28  return Math.min(pageCount(total, pageSize), Math.max(1, n));29}3031export function offsetFor(page: number, pageSize: number): number {32  return (Math.max(1, Math.floor(page)) - 1) * Math.max(1, Math.floor(pageSize));33}3435export function pageInfo(page: number, pageSize: number, total: number): PageInfo {36  const size = Math.max(1, Math.floor(pageSize));37  const count = pageCount(total, size);38  const p = clampPage(page, total, size);39  const from = total === 0 ? 0 : (p - 1) * size + 1;40  const to = total === 0 ? 0 : Math.min(total, p * size);41  return { page: p, pageSize: size, total, pageCount: count, offset: (p - 1) * size, from, to, hasPrev: p > 1, hasNext: p < count };42}4344/**45 * Compact list of page numbers to show as links: first, last, current ±1, with `null` gaps.46 * e.g. page 7 of 20 → [1, null, 6, 7, 8, null, 20].47 */48export function pageWindow(page: number, count: number, radius = 1): Array<number | null> {49  if (count <= 1) return [1];50  const want = new Set<number>([1, count]);51  for (let i = page - radius; i <= page + radius; i++) if (i >= 1 && i <= count) want.add(i);52  const sorted = [...want].sort((a, b) => a - b);53  const out: Array<number | null> = [];54  for (let i = 0; i < sorted.length; i++) {55    const cur = sorted[i]!;56    const prev = sorted[i - 1];57    if (prev != null && cur - prev === 2) out.push(prev + 1);58    else if (prev != null && cur - prev > 2) out.push(null);59    out.push(cur);60  }61  return out;62}63