110 lines
3.1 KiB
TypeScript
110 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const DEFAULT_GROUP_SIZE = 10;
|
|
|
|
interface PageGroupNavProps {
|
|
currentPage: number;
|
|
totalPages: number;
|
|
onPageChange: (page: number) => void;
|
|
disabled?: boolean;
|
|
groupSize?: number;
|
|
}
|
|
|
|
export function PageGroupNav({
|
|
currentPage,
|
|
totalPages,
|
|
onPageChange,
|
|
disabled = false,
|
|
groupSize = DEFAULT_GROUP_SIZE,
|
|
}: PageGroupNavProps) {
|
|
const safeTotal = Math.max(1, totalPages);
|
|
const currentGroupIndex = Math.floor((currentPage - 1) / groupSize);
|
|
const groupStartPage = currentGroupIndex * groupSize + 1;
|
|
|
|
const lastGroupIndex = Math.floor((safeTotal - 1) / groupSize);
|
|
const lastGroupStartPage = lastGroupIndex * groupSize + 1;
|
|
|
|
const isFirstGroup = currentGroupIndex === 0;
|
|
const isLastGroup = currentGroupIndex === lastGroupIndex;
|
|
|
|
const slots: (number | null)[] = [];
|
|
for (let i = 0; i < groupSize; i++) {
|
|
const page = groupStartPage + i;
|
|
slots.push(page <= safeTotal ? page : null);
|
|
}
|
|
|
|
return (
|
|
<div className="flex items-center gap-1">
|
|
{/* << 첫 단락 */}
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => onPageChange(1)}
|
|
disabled={isFirstGroup || disabled}
|
|
className="h-8 w-8 p-0 sm:h-9 sm:w-9"
|
|
>
|
|
<ChevronsLeft className="h-3 w-3 sm:h-4 sm:w-4" />
|
|
</Button>
|
|
|
|
{/* < 이전 단락 */}
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => onPageChange((currentGroupIndex - 1) * groupSize + 1)}
|
|
disabled={isFirstGroup || disabled}
|
|
className="h-8 w-8 p-0 sm:h-9 sm:w-9"
|
|
>
|
|
<ChevronLeft className="h-3 w-3 sm:h-4 sm:w-4" />
|
|
</Button>
|
|
|
|
{/* 페이지 번호 (고정 슬롯) */}
|
|
{slots.map((page, idx) =>
|
|
page !== null ? (
|
|
<Button
|
|
key={idx}
|
|
size="sm"
|
|
variant={page === currentPage ? "default" : "outline"}
|
|
onClick={() => onPageChange(page)}
|
|
disabled={disabled}
|
|
className={cn(
|
|
"h-8 w-8 p-0 text-xs sm:h-9 sm:w-9 sm:text-sm",
|
|
page === currentPage &&
|
|
"font-bold ring-2 ring-primary ring-offset-1 ring-offset-background",
|
|
)}
|
|
>
|
|
{page}
|
|
</Button>
|
|
) : (
|
|
<div key={idx} className="h-8 w-8 cursor-default sm:h-9 sm:w-9" />
|
|
),
|
|
)}
|
|
|
|
{/* > 다음 단락 */}
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => onPageChange((currentGroupIndex + 1) * groupSize + 1)}
|
|
disabled={isLastGroup || disabled}
|
|
className="h-8 w-8 p-0 sm:h-9 sm:w-9"
|
|
>
|
|
<ChevronRight className="h-3 w-3 sm:h-4 sm:w-4" />
|
|
</Button>
|
|
|
|
{/* >> 마지막 단락 */}
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => onPageChange(lastGroupStartPage)}
|
|
disabled={isLastGroup || disabled}
|
|
className="h-8 w-8 p-0 sm:h-9 sm:w-9"
|
|
>
|
|
<ChevronsRight className="h-3 w-3 sm:h-4 sm:w-4" />
|
|
</Button>
|
|
</div>
|
|
);
|
|
}
|