118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
|
import { For } from 'solid-js'
|
|||
|
import styles from '../styles/Pagination.module.css'
|
|||
|
|
|||
|
interface PaginationProps {
|
|||
|
currentPage: number
|
|||
|
totalPages: number
|
|||
|
total: number
|
|||
|
limit: number
|
|||
|
onPageChange: (page: number) => void
|
|||
|
onPerPageChange?: (limit: number) => void
|
|||
|
perPageOptions?: number[]
|
|||
|
}
|
|||
|
|
|||
|
const Pagination = (props: PaginationProps) => {
|
|||
|
const perPageOptions = props.perPageOptions || [10, 20, 50, 100]
|
|||
|
|
|||
|
// Генерируем массив страниц для отображения
|
|||
|
const pages = () => {
|
|||
|
const result: (number | string)[] = []
|
|||
|
const maxVisiblePages = 5 // Максимальное количество видимых страниц
|
|||
|
|
|||
|
// Всегда показываем первую страницу
|
|||
|
result.push(1)
|
|||
|
|
|||
|
// Вычисляем диапазон страниц вокруг текущей
|
|||
|
let startPage = Math.max(2, props.currentPage - Math.floor(maxVisiblePages / 2))
|
|||
|
const endPage = Math.min(props.totalPages - 1, startPage + maxVisiblePages - 2)
|
|||
|
|
|||
|
// Корректируем диапазон, если он выходит за границы
|
|||
|
if (endPage - startPage < maxVisiblePages - 2) {
|
|||
|
startPage = Math.max(2, endPage - maxVisiblePages + 2)
|
|||
|
}
|
|||
|
|
|||
|
// Добавляем многоточие после первой страницы, если нужно
|
|||
|
if (startPage > 2) {
|
|||
|
result.push('...')
|
|||
|
}
|
|||
|
|
|||
|
// Добавляем страницы из диапазона
|
|||
|
for (let i = startPage; i <= endPage; i++) {
|
|||
|
result.push(i)
|
|||
|
}
|
|||
|
|
|||
|
// Добавляем многоточие перед последней страницей, если нужно
|
|||
|
if (endPage < props.totalPages - 1) {
|
|||
|
result.push('...')
|
|||
|
}
|
|||
|
|
|||
|
// Всегда показываем последнюю страницу, если есть больше одной страницы
|
|||
|
if (props.totalPages > 1) {
|
|||
|
result.push(props.totalPages)
|
|||
|
}
|
|||
|
|
|||
|
return result
|
|||
|
}
|
|||
|
|
|||
|
const startIndex = () => (props.currentPage - 1) * props.limit + 1
|
|||
|
const endIndex = () => Math.min(props.currentPage * props.limit, props.total)
|
|||
|
|
|||
|
return (
|
|||
|
<div class={styles.pagination}>
|
|||
|
<div class={styles['pagination-info']}>
|
|||
|
Показано {startIndex()} - {endIndex()} из {props.total}
|
|||
|
</div>
|
|||
|
|
|||
|
<div class={styles['pagination-controls']}>
|
|||
|
<button
|
|||
|
class={styles.pageButton}
|
|||
|
onClick={() => props.onPageChange(props.currentPage - 1)}
|
|||
|
disabled={props.currentPage === 1}
|
|||
|
>
|
|||
|
←
|
|||
|
</button>
|
|||
|
|
|||
|
<For each={pages()}>
|
|||
|
{(page) => (
|
|||
|
<>
|
|||
|
{page === '...' ? (
|
|||
|
<span class={styles['pagination-ellipsis']}>...</span>
|
|||
|
) : (
|
|||
|
<button
|
|||
|
class={`${styles.pageButton} ${page === props.currentPage ? styles.currentPage : ''}`}
|
|||
|
onClick={() => props.onPageChange(Number(page))}
|
|||
|
>
|
|||
|
{page}
|
|||
|
</button>
|
|||
|
)}
|
|||
|
</>
|
|||
|
)}
|
|||
|
</For>
|
|||
|
|
|||
|
<button
|
|||
|
class={styles.pageButton}
|
|||
|
onClick={() => props.onPageChange(props.currentPage + 1)}
|
|||
|
disabled={props.currentPage === props.totalPages}
|
|||
|
>
|
|||
|
→
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
|
|||
|
{props.onPerPageChange && (
|
|||
|
<div class={styles['pagination-per-page']}>
|
|||
|
На странице:
|
|||
|
<select
|
|||
|
class={styles.perPageSelect}
|
|||
|
value={props.limit}
|
|||
|
onChange={(e) => props.onPerPageChange!(Number(e.target.value))}
|
|||
|
>
|
|||
|
<For each={perPageOptions}>{(option) => <option value={option}>{option}</option>}</For>
|
|||
|
</select>
|
|||
|
</div>
|
|||
|
)}
|
|||
|
</div>
|
|||
|
)
|
|||
|
}
|
|||
|
|
|||
|
export default Pagination
|