feat: button, calendar, datePicker, input, pagination, icons 추가
This commit is contained in:
121
web-app/app/shared/components/pagination/Pagination.tsx
Normal file
121
web-app/app/shared/components/pagination/Pagination.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { Button as AriaButton } from 'react-aria-components';
|
||||
|
||||
type PaginationProps = {
|
||||
totalPages: number;
|
||||
currentPage: number;
|
||||
pageCount?: number;
|
||||
onPageChange: (page: number) => void;
|
||||
};
|
||||
|
||||
// https://design-system.w3.org/components/pagination.html
|
||||
export const Pagination = ({ totalPages, currentPage, pageCount = 10, onPageChange }: PaginationProps) => {
|
||||
const start = useMemo(() => {
|
||||
return Math.floor(currentPage / pageCount) * pageCount;
|
||||
}, [currentPage, pageCount]);
|
||||
|
||||
const handlePageClick = useCallback(
|
||||
(page: number) => () => {
|
||||
if (typeof onPageChange === 'function' && page >= 0 && page < totalPages) {
|
||||
onPageChange(page);
|
||||
}
|
||||
},
|
||||
[totalPages, onPageChange],
|
||||
);
|
||||
|
||||
const pageArray = useMemo(() => {
|
||||
const arr: number[] = [];
|
||||
|
||||
// totalPage가 0이면 아무것도 안나와서 최소 1이 되도록 수정
|
||||
const _totalPages = totalPages > 0 ? totalPages : 1;
|
||||
if (Number.isNaN(start)) {
|
||||
return arr;
|
||||
}
|
||||
|
||||
for (let i = 0; i < pageCount; i++) {
|
||||
const pageNumber = start + i;
|
||||
|
||||
if (pageNumber >= _totalPages) {
|
||||
continue;
|
||||
}
|
||||
|
||||
arr.push(pageNumber);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}, [start, pageCount, totalPages]);
|
||||
|
||||
const noPrev = start === 0;
|
||||
const noNext = start + pageCount >= totalPages;
|
||||
|
||||
return (
|
||||
<nav className="text-kc-gray-99 text-sm" aria-label="pagination">
|
||||
<ul className="flex items-center justify-center list-none">
|
||||
<li className="flex">
|
||||
<AriaButton
|
||||
className="cursor-pointer data-[disabled=true]:cursor-default"
|
||||
isDisabled={noPrev}
|
||||
aria-label="첫 페이지"
|
||||
onClick={handlePageClick(0)}
|
||||
>
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="15.8571" y="15" width="1.5" height="10" fill="currentColor" />
|
||||
<path d="M24.1429 15.3571L19.1429 19.8571L24.1429 24.3571" stroke="currentColor" strokeWidth="1.5" />
|
||||
</svg>
|
||||
</AriaButton>
|
||||
</li>
|
||||
<li className="mr-2.5 flex">
|
||||
<AriaButton
|
||||
className="cursor-pointer data-[disabled=true]:cursor-default"
|
||||
isDisabled={noPrev}
|
||||
aria-label="이전 페이지"
|
||||
onClick={handlePageClick(start - 1)}
|
||||
>
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22.5 15.5L17.5 20L22.5 24.5" stroke="currentColor" strokeWidth="1.5" />
|
||||
</svg>
|
||||
</AriaButton>
|
||||
</li>
|
||||
{pageArray.map((pageNumber) => (
|
||||
<li key={pageNumber}>
|
||||
<AriaButton
|
||||
isDisabled={currentPage === pageNumber}
|
||||
className="w-10 h-10 flex items-center justify-center tabular-nums not-disabled:cursor-pointer aria-[current=page]:text-sm aria-[current=page]:text-primary aria-[current=page]:font-bold"
|
||||
onClick={handlePageClick(pageNumber)}
|
||||
aria-current={currentPage === pageNumber ? 'page' : undefined}
|
||||
>
|
||||
{pageNumber + 1}
|
||||
</AriaButton>
|
||||
</li>
|
||||
))}
|
||||
<li className="ml-2.5 flex">
|
||||
<AriaButton
|
||||
isDisabled={noNext}
|
||||
className="cursor-pointer data-[disabled=true]:cursor-default"
|
||||
// className="text-[#CCCCCC]"
|
||||
aria-label="다음 페이지"
|
||||
onClick={handlePageClick(start + pageCount)}
|
||||
>
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.5 15.5L22.5 20L17.5 24.5" stroke="currentColor" strokeWidth="1.5" />
|
||||
</svg>
|
||||
</AriaButton>
|
||||
</li>
|
||||
<li className="flex">
|
||||
<AriaButton
|
||||
isDisabled={noNext}
|
||||
className="cursor-pointer data-[disabled=true]:cursor-default"
|
||||
// className="text-[#CCCCCC]"
|
||||
aria-label="마지막 페이지"
|
||||
onClick={handlePageClick(totalPages - 1)}
|
||||
>
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.75 15.5L20.75 20L15.75 24.5" stroke="currentColor" strokeWidth="1.5" />
|
||||
<path d="M24.25 15H22.75V25H24.25V15Z" fill="currentColor" />
|
||||
</svg>
|
||||
</AriaButton>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user