new-personal-site/components/lib/elements/Pagination.tsx
Benjamin Toby a0a0ab8ee4 Updates
2025-07-20 10:35:54 +01:00

127 lines
4.2 KiB
TypeScript

import React, { ComponentProps, Dispatch, SetStateAction } from "react";
import _ from "lodash";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { twMerge } from "tailwind-merge";
import Row from "../layout/Row";
import Button from "../layout/Button";
import EmptyContent from "./EmptyContent";
import Span from "../layout/Span";
type Props = ComponentProps<typeof Row> & {
page?: number;
setPage?: Dispatch<SetStateAction<number>>;
count?: number;
limit?: number;
};
/**
* # Pagination Component
* @param param0
* @returns
*/
export default function Pagination({
count,
page,
setPage,
limit,
...props
}: Props) {
if (!count || !page || !limit)
return (
<EmptyContent title={`count, page, and limit are all required`} />
);
const isLimit = limit * page >= count;
const pages = Math.ceil(count / limit);
return (
<Row
{...props}
className={twMerge(
"w-full justify-between flex-nowrap",
props.className
)}
>
{pages > 1 && (
<Button
title="Next Page Button"
onClick={() => {
window.scrollTo({ top: 0, behavior: "smooth" });
setPage?.((prev) => prev - 1);
}}
variant="outlined"
size="small"
className={twMerge(
"p-1",
page == 1 ? "opacity-40 pointer-events-none" : ""
)}
>
<ChevronLeft size={20} />
</Button>
)}
<Row className={twMerge("gap-6 w-full flex-nowrap justify-center")}>
<Span size="small" variant="faded">
Page {page} / {pages}
</Span>
{pages > 1 && (
<Row
className={twMerge(
"flex-nowrap overflow-x-auto p-1 max-w-[90%]"
)}
>
{Array(pages)
.fill(0)
.map((p, index) => {
const isCurrent = page == index + 1;
return (
<Button
title={`Page ${index + 1}`}
onClick={() => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
setPage?.(index + 1);
}}
variant={
isCurrent ? "normal" : "outlined"
}
size="small"
color={isCurrent ? "primary" : "gray"}
className={twMerge(
"p-1 w-6 h-6 min-w-6"
)}
key={index}
>
{index + 1}
</Button>
);
})}
</Row>
)}
</Row>
{pages > 1 && (
<Button
title="Next Page Button"
onClick={() => {
window.scrollTo({ top: 0, behavior: "smooth" });
setPage?.((prev) => prev + 1);
}}
variant="outlined"
size="small"
className={twMerge(
"p-1",
isLimit ? "opacity-40 pointer-events-none" : ""
)}
>
<ChevronRight size={20} />
</Button>
)}
</Row>
);
}