Files
voiceon-character-admin/src/shared/ui/resource-pagination.tsx

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>
);
}