diff --git a/src/assets/icon/arrow-left.svg b/src/assets/icon/arrow-left.svg index 3bf8631..3bbb0f7 100644 --- a/src/assets/icon/arrow-left.svg +++ b/src/assets/icon/arrow-left.svg @@ -1,3 +1,3 @@ diff --git a/src/assets/icon/arrow-right.svg b/src/assets/icon/arrow-right.svg index a609d30..3060c5a 100644 --- a/src/assets/icon/arrow-right.svg +++ b/src/assets/icon/arrow-right.svg @@ -1,3 +1,3 @@ diff --git a/src/components/Pagination.tsx b/src/components/Pagination.tsx new file mode 100644 index 0000000..a382be1 --- /dev/null +++ b/src/components/Pagination.tsx @@ -0,0 +1,107 @@ +import { useSearchParams } from "react-router-dom"; + +import { ArrowLeft, ArrowRight } from "@/assets/icon"; +import { cn } from "@/utils/cn"; + +interface PaginationProps { + /** 전체 아이템 개수 */ + count: number; + /** 한 페이지에 보여줄 아이템 개수 */ + itemCountPerPage: number; + /** 노출할 페이지 버튼 개수 (기본 7) – 홀수를 권장 */ + limit?: number; +} + +export default function Pagination({ + count, + itemCountPerPage, + limit = 7, +}: PaginationProps) { + const [searchParams, setSearchParams] = useSearchParams(); + + const currentPage = Number(searchParams.get("page")) || 1; + const totalPages = Math.max(1, Math.ceil(count / itemCountPerPage)); + + // limit 이 전체 페이지보다 크면 전체 페이지 수만큼만 사용 + const visibleCount = Math.min(limit, totalPages); + const half = Math.floor(visibleCount / 2); + + /** + * start/end 계산 – currentPage 를 중앙(slot index = half)에 배치. + * 가장 앞/뒤 구간에서는 남는 슬롯을 앞이나 뒤로 몰아넣어 빈칸이 생기지 않도록 보정합니다. + */ + let start = currentPage - half; + if (start < 1) start = 1; + let end = start + visibleCount - 1; + if (end > totalPages) { + end = totalPages; + start = Math.max(1, end - visibleCount + 1); + } + + const pages = Array.from({ length: visibleCount }, (_, i) => start + i); + + const goToPage = (page: number) => { + if (page < 1 || page > totalPages || page === currentPage) return; + const next = new URLSearchParams(searchParams); + next.set("page", String(page)); + setSearchParams(next, { replace: true }); + }; + + const isTotalPagesMoreThanLimit = totalPages > limit; + const isFirstPage = currentPage === 1; + const isLastPage = currentPage === totalPages; + + return ( +