Spaces:
Running
Running
File size: 4,919 Bytes
0f31229 8dd8f8e 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 |
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,
onPageChange,
className = ''
}: PaginatorProps) {
// 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);
const 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>
);
}
|