From de235ec0801edd5feb4d4a99485ba8e9b4066072 Mon Sep 17 00:00:00 2001 From: cozy-ito Date: Sun, 27 Apr 2025 18:15:26 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20Pagination=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icon/arrow-left.svg | 2 +- src/assets/icon/arrow-right.svg | 2 +- src/components/Pagination.tsx | 107 ++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/components/Pagination.tsx 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..b8f7982 --- /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; + /** 노출할 페이지 버튼 개수 (기본 5) – 홀수를 권장 */ + limit?: number; +} + +export default function Pagination({ + count, + itemCountPerPage, + limit = 5, +}: 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 ( + + ); +} From 01f930d2bb111618bb62faf6b0c75a3419b29386 Mon Sep 17 00:00:00 2001 From: cozy-ito Date: Sun, 27 Apr 2025 19:02:05 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=88=98=20=EB=B3=80=EA=B2=BD=20(5=20->?= =?UTF-8?q?=207)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Pagination.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Pagination.tsx b/src/components/Pagination.tsx index b8f7982..a382be1 100644 --- a/src/components/Pagination.tsx +++ b/src/components/Pagination.tsx @@ -8,14 +8,14 @@ interface PaginationProps { count: number; /** 한 페이지에 보여줄 아이템 개수 */ itemCountPerPage: number; - /** 노출할 페이지 버튼 개수 (기본 5) – 홀수를 권장 */ + /** 노출할 페이지 버튼 개수 (기본 7) – 홀수를 권장 */ limit?: number; } export default function Pagination({ count, itemCountPerPage, - limit = 5, + limit = 7, }: PaginationProps) { const [searchParams, setSearchParams] = useSearchParams();