Files
the-sunken-reach/frontend/src/components/Paginated.tsx
T
joshuaandClaude Opus 5.5 94067f1268 V1.0.1: Aldenfell campaign seed, content library, party overview
- Seed now resets the database and seeds the Aldenfell campaign from the
  campaign book: admin DM user, default weapons, locations, bestiary,
  pre-built encounters, and DM/shared notes
- Default weapon/spell/monster library, character profile fields,
  locations and dice mode (new migration)
- Party overview page, pagination, info tips, build preview calc
- Remove stale demo-login hint; notes preserve line breaks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 10:24:48 +02:00

51 lines
1.5 KiB
TypeScript

import { useMemo, useState } from 'react';
// Small generic pager shared by every list-turned-table in the app, so page
// state isn't hand-rolled per screen. Resets to page 1 whenever the
// underlying item count shrinks below the current page (e.g. after a delete
// or a filter change).
export function usePagination<T>(items: T[] | undefined, pageSize = 10) {
const [page, setPage] = useState(1);
const all = items || [];
const pageCount = Math.max(1, Math.ceil(all.length / pageSize));
const safePage = Math.min(page, pageCount);
const pageItems = useMemo(() => all.slice((safePage - 1) * pageSize, safePage * pageSize), [all, safePage, pageSize]);
return {
page: safePage,
pageCount,
pageItems,
total: all.length,
setPage,
nextPage: () => setPage((p) => Math.min(pageCount, p + 1)),
prevPage: () => setPage((p) => Math.max(1, p - 1)),
};
}
export function Pagination({
page,
pageCount,
onPrev,
onNext,
}: {
page: number;
pageCount: number;
onPrev: () => void;
onNext: () => void;
}) {
if (pageCount <= 1) return null;
return (
<div className="pagination">
<button type="button" className="btn btn-ghost" onClick={onPrev} disabled={page <= 1}>
← Prev
</button>
<span className="pagination-status">
Page {page} of {pageCount}
</span>
<button type="button" className="btn btn-ghost" onClick={onNext} disabled={page >= pageCount}>
Next →
</button>
</div>
);
}