diff --git a/dashboard/index.html b/dashboard/index.html index 3423238..5b1e81c 100644 --- a/dashboard/index.html +++ b/dashboard/index.html @@ -99,6 +99,43 @@

+ + +
totalPages && totalPages > 0) { + currentPage = totalPages; + } + if (currentPage < 1) currentPage = 1; + + if (totalItems === 0) { lockGrid.replaceChildren(emptyState); emptyState.textContent = lockStore.size === 0 ? 'Waiting for lock events from relays\u2026' : 'No locks match the current filters.'; + paginationControls.classList.add('hidden'); return; } - const cards = locks.map((lock) => createLockCard(lock, now)); + // Slice for pagination + const startIdx = (currentPage - 1) * itemsPerPage; + const endIdx = Math.min(startIdx + itemsPerPage, totalItems); + const pageLocks = allLocks.slice(startIdx, endIdx); + + const cards = pageLocks.map((lock) => createLockCard(lock, now)); lockGrid.replaceChildren(...cards); + + // Update Pagination Controls + if (totalItems > itemsPerPage) { + paginationControls.classList.remove('hidden'); + + // Update text + pageStartEl.textContent = startIdx + 1; + pageEndEl.textContent = endIdx; + totalItemsEl.textContent = totalItems; + + // Update buttons state + const isFirst = currentPage === 1; + const isLast = currentPage === totalPages; + + prevBtn.disabled = isFirst; + nextBtn.disabled = isLast; + mobilePrevBtn.disabled = isFirst; + mobileNextBtn.disabled = isLast; + } else { + paginationControls.classList.add('hidden'); + } } // ----------------------------------------------------------------------- @@ -729,8 +815,19 @@ // ----------------------------------------------------------------------- // Event handlers // ----------------------------------------------------------------------- - if (cadenceFilter) cadenceFilter.addEventListener('change', renderLocks); - if (statusFilter) statusFilter.addEventListener('change', renderLocks); + function setPage(p) { + currentPage = p; + renderLocks(); + } + + if (cadenceFilter) cadenceFilter.addEventListener('change', () => { currentPage = 1; renderLocks(); }); + if (statusFilter) statusFilter.addEventListener('change', () => { currentPage = 1; renderLocks(); }); + + if (prevBtn) prevBtn.addEventListener('click', () => setPage(currentPage - 1)); + if (nextBtn) nextBtn.addEventListener('click', () => setPage(currentPage + 1)); + if (mobilePrevBtn) mobilePrevBtn.addEventListener('click', () => setPage(currentPage - 1)); + if (mobileNextBtn) mobileNextBtn.addEventListener('click', () => setPage(currentPage + 1)); + if (refreshBtn) refreshBtn.addEventListener('click', () => { // Close existing connections and reconnect for (const ws of sockets) { diff --git a/src/dashboard.mjs b/src/dashboard.mjs index 247c16b..3474029 100644 --- a/src/dashboard.mjs +++ b/src/dashboard.mjs @@ -68,6 +68,7 @@ export async function cmdDashboard(port = DEFAULT_DASHBOARD_PORT) { switch (extname) { case '.html': contentType = 'text/html'; break; case '.js': contentType = 'text/javascript'; break; + case '.mjs': contentType = 'text/javascript'; break; case '.css': contentType = 'text/css'; break; case '.json': contentType = 'application/json'; break; case '.png': contentType = 'image/png'; break;