Spaces:
Sleeping
Sleeping
File size: 5,070 Bytes
0f31229 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
import React from 'react';
import { Button, Container } from '@ifrc-go/ui';
import { ChevronLeftLineIcon, ChevronRightLineIcon } from '@ifrc-go/icons';
import styles from './Paginator.module.css';
interface PaginatorProps {
currentPage: number;
totalPages: number;
totalItems: number;
itemsPerPage: number;
onPageChange: (page: number) => void;
className?: string;
}
export default function Paginator({
currentPage,
totalPages,
totalItems,
itemsPerPage,
onPageChange,
className = ''
}: PaginatorProps) {
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = Math.min(startIndex + itemsPerPage, totalItems);
// Don't render if only one page
if (totalPages <= 1) {
return null;
}
// Generate page numbers to display
const getPageNumbers = () => {
const pages = [];
const maxVisiblePages = 5;
if (totalPages <= maxVisiblePages) {
// Show all pages if total is small
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
// Show smart range of pages
let start = Math.max(1, currentPage - 2);
let end = Math.min(totalPages, start + maxVisiblePages - 1);
// Adjust start if we're near the end
if (end === totalPages) {
start = Math.max(1, end - maxVisiblePages + 1);
}
for (let i = start; i <= end; i++) {
pages.push(i);
}
}
return pages;
};
const pageNumbers = getPageNumbers();
return (
<div className={`${styles.paginatorContainer} ${className}`}>
{/* Pagination controls */}
<div className={styles.paginationControls}>
{/* Previous button */}
<Container withInternalPadding className="bg-white/20 backdrop-blur-sm rounded-md p-2">
<Button
name="prev-page"
variant="tertiary"
size={1}
onClick={() => onPageChange(Math.max(1, currentPage - 1))}
disabled={currentPage === 1}
title="Previous page"
>
<ChevronLeftLineIcon className="w-4 h-4" />
<span className="hidden sm:inline">Previous</span>
</Button>
</Container>
{/* Page numbers */}
<div className="flex items-center gap-1">
{/* First page (if not visible) */}
{pageNumbers[0] > 1 && (
<>
<Container withInternalPadding className="bg-white/20 backdrop-blur-sm rounded-md p-2">
<Button
name="page-1"
variant="tertiary"
size={1}
onClick={() => onPageChange(1)}
>
1
</Button>
</Container>
{pageNumbers[0] > 2 && (
<Container withInternalPadding className="bg-white/20 backdrop-blur-sm rounded-md p-2">
<span className="px-2 text-gray-500">...</span>
</Container>
)}
</>
)}
{/* Visible page numbers */}
{pageNumbers.map(pageNum => (
<Container key={pageNum} withInternalPadding className="bg-white/20 backdrop-blur-sm rounded-md p-2">
<Button
name={`page-${pageNum}`}
variant={currentPage === pageNum ? "primary" : "tertiary"}
size={1}
onClick={() => onPageChange(pageNum)}
>
{pageNum}
</Button>
</Container>
))}
{/* Last page (if not visible) */}
{pageNumbers[pageNumbers.length - 1] < totalPages && (
<>
{pageNumbers[pageNumbers.length - 1] < totalPages - 1 && (
<Container withInternalPadding className="bg-white/20 backdrop-blur-sm rounded-md p-2">
<span className="px-2 text-gray-500">...</span>
</Container>
)}
<Container withInternalPadding className="bg-white/20 backdrop-blur-sm rounded-md p-2">
<Button
name={`page-${totalPages}`}
variant="tertiary"
size={1}
onClick={() => onPageChange(totalPages)}
>
{totalPages}
</Button>
</Container>
</>
)}
</div>
{/* Next button */}
<Container withInternalPadding className="bg-white/20 backdrop-blur-sm rounded-md p-2">
<Button
name="next-page"
variant="tertiary"
size={1}
onClick={() => onPageChange(Math.min(totalPages, currentPage + 1))}
disabled={currentPage === totalPages}
title="Next page"
>
<span className="hidden sm:inline">Next</span>
<ChevronRightLineIcon className="w-4 h-4" />
</Button>
</Container>
</div>
</div>
);
}
|