diff --git a/sponsor.html b/sponsor.html index 01b4994..a261ad7 100644 --- a/sponsor.html +++ b/sponsor.html @@ -12,28 +12,69 @@ @@ -151,17 +411,36 @@ diff --git a/sponsor_script.js b/sponsor_script.js index 600f86d..97375d5 100644 --- a/sponsor_script.js +++ b/sponsor_script.js @@ -1,7 +1,38 @@ +let allSponsors = []; +let grandTotal = 0; +let filterState = { search: '', project: 'all' }; + document.addEventListener('DOMContentLoaded', () => { fetchSponsorsData(); + setupListeners(); }); +function setupListeners() { + const searchInput = document.getElementById('sponsor-search'); + const filterContainer = document.getElementById('project-filters'); + + if (searchInput) { + searchInput.addEventListener('input', (e) => { + filterState.search = e.target.value.toLowerCase().trim(); + applyFilters(); + }); + } + + if (filterContainer) { + filterContainer.addEventListener('click', (e) => { + if (e.target.classList.contains('filter-tag')) { + // Update active class + document.querySelectorAll('.filter-tag').forEach(btn => btn.classList.remove('active')); + e.target.classList.add('active'); + + // Update filter state + filterState.project = e.target.dataset.project; + applyFilters(); + } + }); + } +} + async function fetchSponsorsData() { try { const response = await fetch('sponsors.txt'); @@ -13,7 +44,8 @@ async function fetchSponsorsData() { const sponsors = []; const userTotals = {}; - let grandTotal = 0; + const projects = new Set(); + grandTotal = 0; lines.forEach(line => { const parts = line.split(','); @@ -27,6 +59,7 @@ async function fetchSponsorsData() { if (!isNaN(amount)) { sponsors.push({ name, project, amount, date }); grandTotal += amount; + projects.add(project); if (userTotals[name]) { userTotals[name] += amount; @@ -37,36 +70,117 @@ async function fetchSponsorsData() { } }); - // Update Total - const totalDisplay = document.getElementById('total-amount-display'); - if (totalDisplay) { - totalDisplay.innerText = `累计获得赞助: ¥${grandTotal.toFixed(2)}`; - } + allSponsors = [...sponsors].reverse(); // Start with newest - // Recent Donations Logic - // Original list is chronological (oldest to newest), reverse it for newest first - const recentSponsors = [...sponsors].reverse(); - renderDonationGrid(recentSponsors); + // Animate Total + animateValue(grandTotal); + + // Render everything + renderFilters(Array.from(projects)); + applyFilters(); // Renders the grid initially } catch (error) { console.error('Error loading sponsors:', error); const grid = document.getElementById('donation-list'); - if(grid) grid.innerHTML = '

加载数据失败

'; + if(grid) grid.innerHTML = '
加载数据失败,请刷新重试
'; } } -function renderDonationGrid(sponsors) { - const container = document.getElementById('donation-list'); +function animateValue(end) { + const obj = document.getElementById('total-amount-display'); + if (!obj) return; + + // Simple count up + let startTimestamp = null; + const duration = 2000; + const start = 0; + + const step = (timestamp) => { + if (!startTimestamp) startTimestamp = timestamp; + const progress = Math.min((timestamp - startTimestamp) / duration, 1); + // Easing out Quart + const easeProgress = 1 - Math.pow(1 - progress, 4); + + const current = Math.floor(easeProgress * (end - start) + start); + + obj.innerHTML = `¥${current.toLocaleString('en-US')}`; + + if (progress < 1) { + window.requestAnimationFrame(step); + } else { + obj.innerHTML = `¥${end.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`; + } + }; + window.requestAnimationFrame(step); +} + +function renderFilters(projects) { + const container = document.getElementById('project-filters'); if (!container) return; - container.innerHTML = sponsors.map(s => ` -
-
- ${s.name} - ¥${s.amount.toFixed(2)} -
-
${s.project}
-
${s.date}
-
- `).join(''); + // Remove existing project buttons, keep "All" + const existingButtons = container.querySelectorAll('button:not([data-project="all"])'); + existingButtons.forEach(btn => btn.remove()); + + // Add project buttons + projects.forEach(proj => { + if (!proj) return; + const btn = document.createElement('button'); + btn.className = 'filter-tag'; + btn.textContent = proj; + btn.dataset.project = proj; + container.appendChild(btn); + }); } + +function applyFilters() { + const { search, project } = filterState; + const grid = document.getElementById('donation-list'); + const noResults = document.getElementById('no-results'); + + if (!grid) return; + + const filtered = allSponsors.filter(item => { + const matchesProject = project === 'all' || item.project === project; + const matchesSearch = item.name.toLowerCase().includes(search); + return matchesProject && matchesSearch; + }); + + grid.innerHTML = ''; + + if (filtered.length === 0) { + if (noResults) noResults.style.display = 'block'; + return; + } + + if (noResults) noResults.style.display = 'none'; + + filtered.forEach((item, index) => { + const card = document.createElement('div'); + card.className = 'donation-card'; + // Max delay 1s to prevent long waits on huge lists + const delay = Math.min(index * 0.05, 1); + card.style.animationDelay = `${delay}s`; + + const avatarUrl = `https://minotar.net/helm/${item.name}/64.png`; + + card.innerHTML = ` +
+
+ ${item.name} +
${item.name}
+
+
¥${item.amount}
+
+ +
+
${item.project}
+
+ ${item.date} +
+
+ `; + grid.appendChild(card); + }); +} +