document.addEventListener('DOMContentLoaded', function() { // Sample data - in a real app, this would come from an API const nodes = Array.from({length: 25}, (_, i) => ({ id: `NODE-${1000 + i}`, name: `Node ${i + 1}`, uptime: Math.floor(Math.random() * 20) + 80 + Math.random(), // 80-100% performance: Math.floor(Math.random() * 20) + 80 + Math.random(), // 80-100% score: Math.floor(Math.random() * 20) + 80 + Math.random(), // 80-100 status: Math.random() > 0.1 ? 'active' : 'inactive', lastUpdated: new Date(Date.now() - Math.floor(Math.random() * 86400000)) // within 24 hours })).sort((a, b) => b.score - a.score); // Chart data const performanceChartData = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'], datasets: [ { label: 'Average Score', data: [72, 75, 78, 82, 85, 87, 89], borderColor: '#6366f1', backgroundColor: 'rgba(99, 102, 241, 0.1)', tension: 0.4, fill: true }, { label: 'Network Uptime %', data: [92, 93, 94, 95, 96, 97, 98], borderColor: '#10b981', backgroundColor: 'rgba(16, 185, 129, 0.1)', tension: 0.4, fill: true } ] }; // Initialize chart const ctx = document.getElementById('performance-chart').getContext('2d'); const performanceChart = new Chart(ctx, { type: 'line', data: performanceChartData, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', labels: { color: '#6b7280', font: { family: 'Inter' } } } }, scales: { y: { beginAtZero: false, min: 60, max: 100, grid: { color: 'rgba(209, 213, 219, 0.2)' }, ticks: { color: '#6b7280' } }, x: { grid: { display: false }, ticks: { color: '#6b7280' } } } } }); // Pagination variables let currentPage = 1; const rowsPerPage = 10; const totalPages = Math.ceil(nodes.length / rowsPerPage); // DOM elements const leaderboardBody = document.getElementById('leaderboard-body'); const prevBtn = document.getElementById('prev-btn'); const nextBtn = document.getElementById('next-btn'); const showingCount = document.getElementById('showing-count'); const totalCount = document.getElementById('total-count'); const refreshBtn = document.getElementById('refresh-btn'); // Update count display totalCount.textContent = nodes.length; // Render table rows function renderTableRows() { leaderboardBody.innerHTML = ''; const startIndex = (currentPage - 1) * rowsPerPage; const endIndex = Math.min(startIndex + rowsPerPage, nodes.length); for (let i = startIndex; i < endIndex; i++) { const node = nodes[i]; const row = document.createElement('tr'); row.className = `table-row-hover ${i % 2 === 0 ? 'bg-gray-50 dark:bg-gray-800' : 'bg-white dark:bg-gray-800'}`; row.innerHTML = ` ${i + 1}
${node.id}
${node.name}
${node.uptime.toFixed(1)}%
${node.performance.toFixed(1)}%
${node.score.toFixed(1)} `; leaderboardBody.appendChild(row); } // Update showing count showingCount.textContent = `${startIndex + 1}-${endIndex}`; // Update button states prevBtn.disabled = currentPage === 1; nextBtn.disabled = currentPage === totalPages; // Refresh feather icons feather.replace(); } // Event listeners prevBtn.addEventListener('click', () => { if (currentPage > 1) { currentPage--; renderTableRows(); } }); nextBtn.addEventListener('click', () => { if (currentPage < totalPages) { currentPage++; renderTableRows(); } }); refreshBtn.addEventListener('click', () => { // Simulate refresh refreshBtn.classList.add('animate-spin'); setTimeout(() => { refreshBtn.classList.remove('animate-spin'); // In a real app, we would fetch new data here }, 1000); }); // Initial render renderTableRows(); // Update chart colors for dark mode const darkModeObserver = new MutationObserver(() => { const isDark = document.documentElement.classList.contains('dark'); performanceChart.options.scales.y.grid.color = isDark ? 'rgba(75, 85, 99, 0.2)' : 'rgba(209, 213, 219, 0.2)'; performanceChart.options.scales.y.ticks.color = isDark ? '#9ca3af' : '#6b7280'; performanceChart.options.scales.x.ticks.color = isDark ? '#9ca3af' : '#6b7280'; performanceChart.options.plugins.legend.labels.color = isDark ? '#9ca3af' : '#6b7280'; performanceChart.update(); }); darkModeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); });