You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
3.6 KiB
106 lines
3.6 KiB
import { toFa } from '@/lib/utils'
|
|
import {
|
|
Pagination,
|
|
PaginationContent,
|
|
PaginationItem,
|
|
PaginationLink,
|
|
PaginationPrevious,
|
|
PaginationNext,
|
|
PaginationEllipsis,
|
|
} from '@/components/ui/pagination'
|
|
|
|
/* ──────────────────────────────────────────────────────────────────────────
|
|
* صفحهبندی مشترک جدولهای مدیریت (تگها/ژانرها/…).
|
|
*
|
|
* server-side: total = count کل از بکاند، page صفحهٔ فعلی. تعداد صفحات از
|
|
* count/pageSize محاسبه میشود. اگر فقط یک صفحه باشد چیزی رندر نمیشود.
|
|
* ────────────────────────────────────────────────────────────────────────── */
|
|
|
|
type TablePaginationProps = {
|
|
page?: number
|
|
currentPage?: number
|
|
pageSize?: number
|
|
total?: number
|
|
totalPages?: number
|
|
onPageChange: (page: number) => void
|
|
}
|
|
|
|
/** بازهٔ صفحاتِ قابلنمایش حول صفحهٔ فعلی (حداکثر ۵ عدد). */
|
|
function pageWindow(page: number, totalPages: number): number[] {
|
|
const span = 2
|
|
let start = Math.max(1, page - span)
|
|
let end = Math.min(totalPages, page + span)
|
|
// پنجره را تا ۵ عدد پر میکنیم وقتی نزدیک ابتدا/انتها هستیم.
|
|
if (end - start < 4) {
|
|
if (start === 1) end = Math.min(totalPages, start + 4)
|
|
else if (end === totalPages) start = Math.max(1, end - 4)
|
|
}
|
|
const pages: number[] = []
|
|
for (let p = start; p <= end; p++) pages.push(p)
|
|
return pages
|
|
}
|
|
|
|
export default function TablePagination({
|
|
page,
|
|
currentPage,
|
|
pageSize = 20,
|
|
total,
|
|
totalPages: propTotalPages,
|
|
onPageChange,
|
|
}: TablePaginationProps) {
|
|
const activePage = currentPage ?? page ?? 1
|
|
const totalPages = propTotalPages ?? (total !== undefined ? Math.max(1, Math.ceil(total / pageSize)) : 1)
|
|
if (totalPages <= 1) return null
|
|
|
|
const pages = pageWindow(activePage, totalPages)
|
|
const first = pages[0]
|
|
const last = pages[pages.length - 1]
|
|
|
|
return (
|
|
<Pagination className="mx-0 w-auto">
|
|
<PaginationContent>
|
|
<PaginationItem>
|
|
<PaginationPrevious disabled={activePage <= 1} onClick={() => onPageChange(activePage - 1)} />
|
|
</PaginationItem>
|
|
|
|
{first > 1 && (
|
|
<>
|
|
<PaginationItem>
|
|
<PaginationLink onClick={() => onPageChange(1)}>{toFa(1)}</PaginationLink>
|
|
</PaginationItem>
|
|
{first > 2 && (
|
|
<PaginationItem>
|
|
<PaginationEllipsis />
|
|
</PaginationItem>
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{pages.map((p) => (
|
|
<PaginationItem key={p}>
|
|
<PaginationLink isActive={p === activePage} onClick={() => onPageChange(p)}>
|
|
{toFa(p)}
|
|
</PaginationLink>
|
|
</PaginationItem>
|
|
))}
|
|
|
|
{last < totalPages && (
|
|
<>
|
|
{last < totalPages - 1 && (
|
|
<PaginationItem>
|
|
<PaginationEllipsis />
|
|
</PaginationItem>
|
|
)}
|
|
<PaginationItem>
|
|
<PaginationLink onClick={() => onPageChange(totalPages)}>{toFa(totalPages)}</PaginationLink>
|
|
</PaginationItem>
|
|
</>
|
|
)}
|
|
|
|
<PaginationItem>
|
|
<PaginationNext disabled={activePage >= totalPages} onClick={() => onPageChange(activePage + 1)} />
|
|
</PaginationItem>
|
|
</PaginationContent>
|
|
</Pagination>
|
|
)
|
|
}
|