145 lines
4.0 KiB
TypeScript
145 lines
4.0 KiB
TypeScript
// components/Pagination.tsx
|
|
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useSearchParams } from "next/navigation";
|
|
import React from "react";
|
|
|
|
interface Meta {
|
|
current_page: number;
|
|
last_page: number;
|
|
total: number; // اضافه کردن total برای بررسی وجود داده
|
|
}
|
|
|
|
interface PaginationProps {
|
|
meta: Meta;
|
|
}
|
|
|
|
const Pagination: React.FC<PaginationProps> = ({ meta }) => {
|
|
const { current_page, last_page, total } = meta;
|
|
const searchParams = useSearchParams();
|
|
|
|
// اگر هیچ دادهای وجود نداشته باشد یا تنها یک صفحه باشد، کامپوننت را رندر نکن
|
|
if (total === 0 || last_page <= 1) {
|
|
return null;
|
|
}
|
|
|
|
const generatePageLink = (page: number): string => {
|
|
const params = new URLSearchParams(searchParams.toString());
|
|
params.set("page", page.toString());
|
|
return `/blog/categories?${params.toString()}`;
|
|
};
|
|
|
|
const renderPageNumbers = (): (JSX.Element | string)[] => {
|
|
const pages: JSX.Element[] = [];
|
|
const delta = 1; // تعداد صفحات اطراف صفحه فعلی که نمایش داده شوند
|
|
const range: number[] = [];
|
|
const rangeWithDots: (number | string)[] = [];
|
|
let previous: number | undefined;
|
|
|
|
for (let i = 1; i <= last_page; i++) {
|
|
if (
|
|
i === 1 ||
|
|
i === last_page ||
|
|
(i >= current_page - delta && i <= current_page + delta)
|
|
) {
|
|
range.push(i);
|
|
}
|
|
}
|
|
|
|
for (let i of range) {
|
|
if (previous) {
|
|
if (i - previous === 2) {
|
|
rangeWithDots.push(previous + 1);
|
|
} else if (i - previous > 2) {
|
|
rangeWithDots.push("...");
|
|
}
|
|
}
|
|
rangeWithDots.push(i);
|
|
previous = i;
|
|
}
|
|
|
|
return rangeWithDots.map((page, index) => {
|
|
if (page === "...") {
|
|
return (
|
|
<span key={`ellipsis-${index}`} className="px-3 py-1">
|
|
...
|
|
</span>
|
|
);
|
|
} else {
|
|
return (
|
|
<Link
|
|
key={page}
|
|
href={generatePageLink(Number(page))}
|
|
className={`rounded-full border px-3 py-1 ${
|
|
page === current_page
|
|
? "bg-blog-red text-white"
|
|
: "bg-[#EAEAEA] text-blog-text-default hover:bg-[#d6d6d6]"
|
|
}`}
|
|
aria-current={page === current_page ? "page" : undefined}
|
|
>
|
|
{page}
|
|
</Link>
|
|
);
|
|
}
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="mt-4 flex flex-wrap items-center justify-center gap-2">
|
|
{/* Page Numbers */}
|
|
<div className="flex gap-2">{renderPageNumbers()}</div>
|
|
|
|
<div className="flex gap-2">
|
|
{/* First Page */}
|
|
{current_page > 1 && (
|
|
<Link
|
|
href={generatePageLink(1)}
|
|
className="rounded-full border bg-[#EAEAEA] px-3 py-1 text-blog-text-default hover:bg-[#d6d6d6]"
|
|
aria-label="First Page"
|
|
>
|
|
First
|
|
</Link>
|
|
)}
|
|
|
|
{/* Previous Page */}
|
|
{current_page > 1 && (
|
|
<Link
|
|
href={generatePageLink(current_page - 1)}
|
|
className="rounded-full border bg-[#EAEAEA] px-4 py-0 text-[24px] text-blog-text-default hover:bg-[#d6d6d6]"
|
|
aria-label="Previous Page"
|
|
>
|
|
{"<"}
|
|
</Link>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex gap-2">
|
|
{/* Next Page */}
|
|
{current_page < last_page && (
|
|
<Link
|
|
href={generatePageLink(current_page + 1)}
|
|
className="rounded-full border bg-[#EAEAEA] px-4 py-0 text-[24px] text-blog-text-default hover:bg-[#d6d6d6]"
|
|
aria-label="Next Page"
|
|
>
|
|
{">"}
|
|
</Link>
|
|
)}
|
|
|
|
{/* Last Page */}
|
|
{current_page < last_page && (
|
|
<Link
|
|
href={generatePageLink(last_page)}
|
|
className="rounded-full border bg-[#EAEAEA] px-3 py-1 text-blog-text-default hover:bg-[#d6d6d6]"
|
|
aria-label="Last Page"
|
|
>
|
|
Last
|
|
</Link>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Pagination;
|