92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
"use client";
|
|
|
|
type PaginationProps = {
|
|
page: number;
|
|
totalPages: number;
|
|
onPageChange: (page: number) => void;
|
|
pageSize: number;
|
|
onPageSizeChange: (pageSize: number) => void;
|
|
pageSizeOptions?: number[];
|
|
className?: string;
|
|
};
|
|
|
|
export default function Pagination({
|
|
page,
|
|
totalPages,
|
|
onPageChange,
|
|
pageSize,
|
|
onPageSizeChange,
|
|
pageSizeOptions = [20, 50, 100],
|
|
className
|
|
}: PaginationProps) {
|
|
const windowPages = Array.from({ length: totalPages }, (_, i) => i + 1).filter(
|
|
(pageNumber) =>
|
|
pageNumber === 1 ||
|
|
pageNumber === totalPages ||
|
|
Math.abs(pageNumber - page) <= 2
|
|
);
|
|
|
|
return (
|
|
<div
|
|
className={`flex flex-wrap items-center justify-between gap-2 text-sm text-slate-600 ${
|
|
className || ""
|
|
}`}
|
|
>
|
|
<span>Seite {page} von {totalPages}</span>
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<select
|
|
value={pageSize}
|
|
onChange={(event) => onPageSizeChange(Number(event.target.value))}
|
|
className="rounded-full border border-slate-200 bg-white px-2 py-1 text-xs text-slate-700"
|
|
aria-label="Einträge pro Seite"
|
|
>
|
|
{pageSizeOptions.map((option) => (
|
|
<option key={option} value={option}>
|
|
{option} pro Seite
|
|
</option>
|
|
))}
|
|
</select>
|
|
<button
|
|
type="button"
|
|
className="rounded-full border border-slate-200 px-3 py-1 text-xs text-slate-700"
|
|
onClick={() => onPageChange(Math.max(1, page - 1))}
|
|
disabled={page <= 1}
|
|
>
|
|
Zurück
|
|
</button>
|
|
<div className="flex flex-wrap items-center gap-1">
|
|
{windowPages.map((pageNumber, index) => {
|
|
const previous = windowPages[index - 1];
|
|
const gap = previous && pageNumber - previous > 1;
|
|
return (
|
|
<span key={pageNumber} className="flex items-center gap-1">
|
|
{gap && <span className="px-1 text-xs text-slate-400">…</span>}
|
|
<button
|
|
type="button"
|
|
className={`rounded-full border px-2 py-1 text-xs ${
|
|
pageNumber === page
|
|
? "border-slate-900 bg-slate-900 text-white"
|
|
: "border-slate-200 text-slate-700"
|
|
}`}
|
|
onClick={() => onPageChange(pageNumber)}
|
|
aria-current={pageNumber === page ? "page" : undefined}
|
|
>
|
|
{pageNumber}
|
|
</button>
|
|
</span>
|
|
);
|
|
})}
|
|
</div>
|
|
<button
|
|
type="button"
|
|
className="rounded-full border border-slate-200 px-3 py-1 text-xs text-slate-700"
|
|
onClick={() => onPageChange(Math.min(totalPages, page + 1))}
|
|
disabled={page >= totalPages}
|
|
>
|
|
Weiter
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|