This commit is contained in:
2026-02-16 19:34:35 +00:00
commit 9ab0940ca4
784 changed files with 41710 additions and 0 deletions
@@ -0,0 +1,122 @@
// PaginationBar.tsx
import type { UseDataControlReturn } from 'hooks/useDataControl';
import { useMemo } from 'react';
import { Button } from '@/components/ui/button';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
type PaginationBarProps<T> = {
dataManager: UseDataControlReturn<T>;
};
export const PaginationBar = <T,>(props: PaginationBarProps<T>) => {
const { currentPage, pageCount, changePage, pageSize, setPageSize } = props.dataManager;
const pageSizeOptions = useMemo(() => [5, 10, 15, 20], []);
const handlePageSizeChange = (value: string) => {
const next = Number(value);
if (!Number.isFinite(next) || next <= 0) return;
setPageSize(next);
changePage(1);
};
const buttonClass =
'h-8 w-8 p-0 hover:bg-white text-muted-foreground disabled:opacity-100 disabled:pointer-events-none';
return (
<div className="bg-muted/50 flex w-full items-center justify-between border-t p-4">
{/* LEFT */}
<div className="flex items-center gap-2 min-[500px]:gap-3 text-sm text-muted-foreground whitespace-nowrap">
<span className="hidden min-[500px]:inline">
Showing page {currentPage} of {pageCount}
</span>
<span className="min-[500px]:hidden">
p {currentPage}/{pageCount}
</span>
<span className="bg-border h-5 w-px" aria-hidden="true" />
<Select value={String(pageSize)} onValueChange={handlePageSizeChange}>
<SelectTrigger
className="
h-8
w-[80px] min-[500px]:w-[110px]
justify-between
bg-transparent
text-muted-foreground
hover:bg-white
data-[state=open]:bg-muted
"
aria-label="Rows per page"
>
<SelectValue className="text-muted-foreground">
<span className="hidden min-[500px]:inline">{pageSize} / page</span>
<span className="min-[500px]:hidden">{pageSize}/p</span>
</SelectValue>
</SelectTrigger>
<SelectContent align="start">
{pageSizeOptions.map((n) => (
<SelectItem
key={n}
value={String(n)}
className="
text-muted-foreground
data-[state=checked]:bg-muted
data-[state=checked]:text-muted-foreground
"
>
<span className="hidden min-[500px]:inline">{n} / page</span>
<span className="min-[500px]:hidden">{n}/p</span>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* RIGHT */}
<div className="flex items-center gap-0.5 min-[500px]:gap-1">
<Button
variant="outline"
size="sm"
className={buttonClass}
onClick={() => changePage(1)}
disabled={currentPage === 1}
aria-label="First"
>
«
</Button>
<Button
variant="outline"
size="sm"
className={buttonClass}
onClick={() => changePage(currentPage - 1)}
disabled={currentPage === 1}
aria-label="Prev"
>
</Button>
<Button
variant="outline"
size="sm"
className={buttonClass}
onClick={() => changePage(currentPage + 1)}
disabled={currentPage === pageCount}
aria-label="Next"
>
</Button>
<Button
variant="outline"
size="sm"
className={buttonClass}
onClick={() => changePage(pageCount)}
disabled={currentPage === pageCount}
aria-label="Last"
>
»
</Button>
</div>
</div>
);
};