/** * Alpine.js Pagination Component * * Provides client-side pagination for large lists. */ document.addEventListener('alpine:init', () => { Alpine.data('paginatedList', (initialItems = [], options = {}) => ({ allItems: initialItems, filteredItems: [], currentPage: 1, perPage: options.perPage || 50, searchQuery: '', isReviewed: options.isReviewed || false, instanceId: options.instanceId || Math.random().toString(36).substring(2, 9), init() { this.filteredItems = this.allItems; }, get totalPages() { return Math.ceil(this.filteredItems.length / this.perPage); }, get paginatedItems() { const start = (this.currentPage - 1) * this.perPage; const end = start + this.perPage; return this.filteredItems.slice(start, end); }, get totalItems() { return this.filteredItems.length; }, get showingStart() { if (this.totalItems === 0) return 0; return (this.currentPage - 1) * this.perPage + 1; }, get showingEnd() { return Math.min(this.currentPage * this.perPage, this.totalItems); }, search(query) { this.searchQuery = query.toLowerCase(); if (this.searchQuery === '') { this.filteredItems = this.allItems; } else { this.filteredItems = this.allItems.filter(item => item.name.toLowerCase().includes(this.searchQuery) ); } this.currentPage = 1; }, nextPage() { if (this.currentPage < this.totalPages) { this.currentPage++; } }, prevPage() { if (this.currentPage > 1) { this.currentPage--; } }, goToPage(page) { if (page >= 1 && page <= this.totalPages) { this.currentPage = page; } }, get pageNumbers() { const pages = []; const total = this.totalPages; const current = this.currentPage; // Handle empty case if (total === 0) { return pages; } if (total <= 7) { // Show all pages if 7 or fewer for (let i = 1; i <= total; i++) { pages.push({ page: i, isEllipsis: false, key: `${this.instanceId}-page-${i}` }); } } else { // More than 7 pages - show first, last, and sliding window around current // Always show first page pages.push({ page: 1, isEllipsis: false, key: `${this.instanceId}-page-1` }); // Determine the start and end of the middle range let rangeStart, rangeEnd; if (current <= 4) { // Near the beginning: show pages 2-5 rangeStart = 2; rangeEnd = 5; } else if (current >= total - 3) { // Near the end: show last 4 pages before the last page rangeStart = total - 4; rangeEnd = total - 1; } else { // In the middle: show current page and one on each side rangeStart = current - 1; rangeEnd = current + 1; } // Add ellipsis before range if there's a gap if (rangeStart > 2) { pages.push({ page: '...', isEllipsis: true, key: `${this.instanceId}-ellipsis-start` }); } // Add pages in the range for (let i = rangeStart; i <= rangeEnd; i++) { pages.push({ page: i, isEllipsis: false, key: `${this.instanceId}-page-${i}` }); } // Add ellipsis after range if there's a gap if (rangeEnd < total - 1) { pages.push({ page: '...', isEllipsis: true, key: `${this.instanceId}-ellipsis-end` }); } // Always show last page pages.push({ page: total, isEllipsis: false, key: `${this.instanceId}-page-${total}` }); } return pages; } })); });