Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/assets/icons/arrow-left-gray.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/assets/icons/arrow-left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/arrow-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 117 additions & 0 deletions src/components/common/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import ArrowLeft from '@/assets/icons/arrow-left.svg';
import ArrowLeftGray from '@/assets/icons/arrow-left-gray.svg';
import ArrowRight from '@/assets/icons/arrow-right.svg';

interface Props {
totalPages: number;
currentPage: number;
setCurrentPage: React.Dispatch<React.SetStateAction<number>>;
}

export default function Pagination({
totalPages,
currentPage,
setCurrentPage,
}: Props) {
const handleClick = (page: number) => {
setCurrentPage(page);
};

const range = (start: number, end: number) => {
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
};

const renderButtons = () => {
const buttons: React.ReactNode[] = [];

if (totalPages <= 7) {
for (let page = 1; page <= totalPages; page++) {
buttons.push(
<button
key={page}
type="button"
onClick={() => handleClick(page)}
className={`flex h-10 w-10 items-center justify-center rounded text-sm ${
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
className={`flex h-10 w-10 items-center justify-center rounded text-sm ${
className={`flex size-10 items-center justify-center rounded text-body2 ${

💬 height와 width가 같은 경우 size로 쓸 수 있습니다~

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 감사합니다!! tailwind가 익숙하지 않다보니...감사합니당

currentPage === page
? 'bg-[#FF8D72] font-bold text-white'
: 'text-black hover:bg-gray-100'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ hover 스타일은 임의로 추가하신 건가요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ux적으로 저런 호버 있는 사이트들이 많아서 넣었는데 다시 보니까 그렇게 필요하지 않을 듯 합니다

}`}
disabled={currentPage === page}
>
{page}
</button>,
);
}
return buttons;
}

let start = 1;
let end = 7;

if (currentPage > 4) {
start = currentPage - 3;
end = currentPage + 3;
}

if (currentPage + 3 > totalPages) {
start = totalPages - 6;
end = totalPages;
}

const buttonRange = range(start, end);

if (totalPages > 7) {
buttons.push(
<button
key="first"
type="button"
onClick={() => handleClick(1)}
className="h-5 w-5"
>
<img
src={currentPage === 1 ? ArrowLeftGray : ArrowLeft}
alt="First Page"
/>
</button>,
);
}

buttonRange.forEach((page) => {
buttons.push(
<button
key={page}
type="button"
onClick={() => handleClick(page)}
className={`flex h-10 w-10 items-center justify-center rounded text-sm ${
currentPage === page
? 'bg-[#FF8D72] font-bold text-white'
: 'text-black hover:bg-gray-100'
}`}
>
{page}
</button>,
);
});

if (end < totalPages) {
buttons.push(
<button
key="last"
type="button"
onClick={() => handleClick(totalPages)}
className="h-5 w-5"
>
<img src={ArrowRight} alt="Last Page" />
</button>,
);
}

return buttons;
};

return (
<div className="flex items-center justify-center gap-2">
{renderButtons()}
</div>
);
}
68 changes: 68 additions & 0 deletions src/components/common/pagination/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import ArrowLeft from '../../../assets/icons/arrow-left.svg';
import ArrowLeftGray from '../../../assets/icons/arrow-left-gray.svg';
import ArrowRight from '../../../assets/icons/arrow-right.svg';

interface Props {
totalPages: number;
currentPage: number;
onChangePage: (pageNumber: number) => void;
}

export default function Pagination({
totalPages,
currentPage,
onChangePage,
}: Props) {
const groupSize = 7;
const currentGroup = Math.floor((currentPage - 1) / groupSize);
const groupStart = currentGroup * groupSize + 1;
const groupEnd = Math.min(groupStart + groupSize - 1, totalPages);

const renderPageNumbers = () => {
return Array.from(
{ length: groupEnd - groupStart + 1 },
(_, index) => groupStart + index,
).map((pageNumber) => (
<button
key={pageNumber}
type="button"
onClick={() => onChangePage(pageNumber)}
className={`w-10 h-10 rounded flex items-center justify-center text-sm ${
currentPage === pageNumber
? 'text-white font-bold'
: 'text-black hover:bg-gray-100'
}`}
style={{
backgroundColor: currentPage === pageNumber ? '#FF8D72' : '#ffffff',
}}
>
{pageNumber}
</button>
));
};

return (
<div className="flex items-center justify-center gap-4">
{/* 이전 그룹 이동 */}
{totalPages > groupSize && groupStart > 1 && (
<button type="button" onClick={() => onChangePage(groupStart - 1)}>
<img
src={groupStart - 1 === 1 ? ArrowLeftGray : ArrowLeft}
alt="이전 페이지 그룹"
className="w-5 h-5"
/>
</button>
)}

{/* 페이지 번호 */}
<div className="flex gap-1">{renderPageNumbers()}</div>

{/* 다음 그룹 이동 */}
{totalPages > groupSize && groupEnd < totalPages && (
<button type="button" onClick={() => onChangePage(groupEnd + 1)}>
<img src={ArrowRight} alt="다음 페이지 그룹" className="w-5 h-5" />
</button>
)}
</div>
);
}