40 lines
2.2 KiB
TypeScript
40 lines
2.2 KiB
TypeScript
import type { PageData } from "@/shared/api/pagination";
|
|
import { useId } from "react";
|
|
|
|
export type ResourcePaginationProps = {
|
|
readonly data: PageData<unknown>;
|
|
readonly onPageChange: (page: number) => void;
|
|
readonly onSizeChange: (size: number) => void;
|
|
readonly sizeOptions?: readonly number[];
|
|
};
|
|
|
|
export function ResourcePagination({ data, onPageChange, onSizeChange, sizeOptions = [20, 50] }: ResourcePaginationProps) {
|
|
const pageSizeId = useId();
|
|
|
|
return (
|
|
<nav aria-label="페이지" className="flex flex-col gap-3 rounded-lg border border-border bg-card p-4 sm:flex-row sm:items-center sm:justify-between">
|
|
<p className="break-keep text-sm font-semibold text-muted-foreground">총 {data.totalCount.toLocaleString("ko-KR")}개 · {data.page + 1}페이지</p>
|
|
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
|
<div aria-label="페이지 크기 설정" className="flex items-center gap-2" role="group">
|
|
<label className="break-keep text-sm font-semibold" htmlFor={pageSizeId}>
|
|
페이지 크기
|
|
</label>
|
|
<select className="min-h-11 rounded-md border border-input bg-card px-3 py-2 text-base" id={pageSizeId} onChange={(event) => onSizeChange(Number(event.currentTarget.value))} value={data.size}>
|
|
{sizeOptions.map((size) => (
|
|
<option key={size} value={size}>{size}개</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div aria-label="페이지 이동" className="grid grid-cols-1 gap-2 sm:flex" role="group">
|
|
<button className="min-h-11 w-full whitespace-nowrap rounded-md border border-input bg-card px-3 py-2 font-semibold hover:bg-accent disabled:opacity-60 sm:w-auto" disabled={data.page <= 0} onClick={() => onPageChange(data.page - 1)} type="button">
|
|
이전 페이지
|
|
</button>
|
|
<button className="min-h-11 w-full whitespace-nowrap rounded-md border border-input bg-card px-3 py-2 font-semibold hover:bg-accent disabled:opacity-60 sm:w-auto" disabled={!data.hasNext} onClick={() => onPageChange(data.page + 1)} type="button">
|
|
다음 페이지
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|