109 lines
5.0 KiB
TypeScript
109 lines
5.0 KiB
TypeScript
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
|
|
|
|
interface PaginationProps {
|
|
currentPage: number;
|
|
totalPages: number;
|
|
totalItems: number;
|
|
itemsPerPage: number;
|
|
onPageChange: (page: number) => void;
|
|
}
|
|
|
|
export default function Pagination({
|
|
currentPage,
|
|
totalPages,
|
|
totalItems,
|
|
itemsPerPage,
|
|
onPageChange
|
|
}: PaginationProps) {
|
|
const startItem = (currentPage - 1) * itemsPerPage + 1;
|
|
const endItem = Math.min(currentPage * itemsPerPage, totalItems);
|
|
|
|
const pages = [];
|
|
const maxVisiblePages = 5;
|
|
|
|
let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
|
|
let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
|
|
|
|
if (endPage - startPage < maxVisiblePages - 1) {
|
|
startPage = Math.max(1, endPage - maxVisiblePages + 1);
|
|
}
|
|
|
|
for (let i = startPage; i <= endPage; i++) {
|
|
pages.push(i);
|
|
}
|
|
|
|
return (
|
|
<div className="px-6 py-4 border-t border-zinc-200 dark:border-zinc-800 bg-zinc-50/50 dark:bg-zinc-800/50 flex flex-col sm:flex-row items-center justify-between gap-4">
|
|
<p className="text-xs text-zinc-500 dark:text-zinc-400">
|
|
Mostrando <span className="font-medium">{startItem}</span> a{' '}
|
|
<span className="font-medium">{endItem}</span> de{' '}
|
|
<span className="font-medium">{totalItems}</span> resultados
|
|
</p>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<button
|
|
onClick={() => onPageChange(currentPage - 1)}
|
|
disabled={currentPage === 1}
|
|
className="inline-flex items-center gap-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-700"
|
|
>
|
|
<ChevronLeftIcon className="w-4 h-4" />
|
|
Anterior
|
|
</button>
|
|
|
|
<div className="hidden sm:flex items-center gap-1">
|
|
{startPage > 1 && (
|
|
<>
|
|
<button
|
|
onClick={() => onPageChange(1)}
|
|
className="px-3 py-1.5 text-xs font-medium rounded-md bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors"
|
|
>
|
|
1
|
|
</button>
|
|
{startPage > 2 && (
|
|
<span className="px-2 text-zinc-400">...</span>
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{pages.map(page => (
|
|
<button
|
|
key={page}
|
|
onClick={() => onPageChange(page)}
|
|
className={`px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${page === currentPage
|
|
? 'text-white shadow-sm'
|
|
: 'bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-700'
|
|
}`}
|
|
style={page === currentPage ? { background: 'var(--gradient)' } : {}}
|
|
>
|
|
{page}
|
|
</button>
|
|
))}
|
|
|
|
{endPage < totalPages && (
|
|
<>
|
|
{endPage < totalPages - 1 && (
|
|
<span className="px-2 text-zinc-400">...</span>
|
|
)}
|
|
<button
|
|
onClick={() => onPageChange(totalPages)}
|
|
className="px-3 py-1.5 text-xs font-medium rounded-md bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors"
|
|
>
|
|
{totalPages}
|
|
</button>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
<button
|
|
onClick={() => onPageChange(currentPage + 1)}
|
|
disabled={currentPage === totalPages}
|
|
className="inline-flex items-center gap-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-700"
|
|
>
|
|
Próxima
|
|
<ChevronRightIcon className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|