Files
moalem-shop/src/components/ui/Pagination.tsx
T
2026-09-02 17:03:23 +03:30

62 lines
2.1 KiB
TypeScript

import Link from "next/link";
import { toFaDigits } from "@/lib/format";
import { ChevronLeft, ChevronRight } from "../icons";
// Simple numbered pager. `buildHref` turns a page number into the URL for
// that page — callers own how query params are preserved (search, filters).
export default function Pagination({
page,
pageSize,
total,
buildHref,
}: {
page: number;
pageSize: number;
total: number;
buildHref: (page: number) => string;
}) {
const pageCount = Math.max(1, Math.ceil(total / pageSize));
if (pageCount <= 1) return null;
// A short window around the current page, plus first/last, keeps the
// control usable even with a few hundred pages.
const pages = new Set<number>([1, pageCount, page - 1, page, page + 1].filter((p) => p >= 1 && p <= pageCount));
const sorted = [...pages].sort((a, b) => a - b);
const linkClass = (active: boolean) =>
`flex h-9 min-w-9 items-center justify-center rounded-lg px-2 text-[13px] transition ${
active ? "bg-brand text-white" : "border border-line text-ink-soft hover:border-brand hover:text-brand"
}`;
return (
<nav className="mt-8 flex items-center justify-center gap-1.5" aria-label="صفحه‌بندی">
<Link
href={buildHref(Math.max(1, page - 1))}
aria-disabled={page <= 1}
className={`${linkClass(false)} ${page <= 1 ? "pointer-events-none opacity-40" : ""}`}
aria-label="صفحه قبل"
>
<ChevronRight className="size-4" />
</Link>
{sorted.map((p, i) => (
<span key={p} className="flex items-center gap-1.5">
{i > 0 && p - sorted[i - 1] > 1 && <span className="px-1 text-body">…</span>}
<Link href={buildHref(p)} className={linkClass(p === page)}>
{toFaDigits(p)}
</Link>
</span>
))}
<Link
href={buildHref(Math.min(pageCount, page + 1))}
aria-disabled={page >= pageCount}
className={`${linkClass(false)} ${page >= pageCount ? "pointer-events-none opacity-40" : ""}`}
aria-label="صفحه بعد"
>
<ChevronLeft className="size-4" />
</Link>
</nav>
);
}