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.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.project}
+
+ ${item.date}
+
+
+ `;
+ grid.appendChild(card);
+ });
+}
+