diff --git a/Leaderboard.js b/Leaderboard.js index e69de29..67aa8ec 100644 --- a/Leaderboard.js +++ b/Leaderboard.js @@ -0,0 +1,243 @@ +// ========== PARTICLES ANIMATION ========== +const particlesContainer = document.getElementById('particles'); + +function createParticle() { + const particle = document.createElement('div'); + particle.className = 'particle'; + + + particle.style.left = Math.random() * 100 + '%'; + particle.style.top = Math.random() * 100 + '%'; + + + const size = 3 + Math.random() * 4; + particle.style.width = size + 'px'; + particle.style.height = size + 'px'; + + const duration = 3 + Math.random() * 5; + const delay = Math.random() * 2; + const moveX = (Math.random() - 0.5) * 200; + + const animationName = `float-${Date.now()}-${Math.random()}`; + const keyframes = ` + @keyframes ${animationName} { + 0% { + transform: translateY(0) translateX(0); + opacity: 0; + } + 10% { + opacity: 1; + } + 90% { + opacity: 1; + } + 100% { + transform: translateY(-100vh) translateX(${moveX}px); + opacity: 0; + } + } + `; + + const style = document.createElement('style'); + style.innerHTML = keyframes; + document.head.appendChild(style); + + particle.style.animation = `${animationName} ${duration}s ${delay}s ease-in-out forwards`; + + particlesContainer.appendChild(particle); + + setTimeout(() => { + particle.remove(); + style.remove(); + }, (duration + delay) * 1000); +} + +setInterval(createParticle, 300); + +for (let i = 0; i < 25; i++) { + setTimeout(createParticle, i * 100); +} + +// ========== LEADERBOARD DATA MANAGEMENT ========== + +// Get leaderboard data from localStorage +function getLeaderboardData() { + const data = localStorage.getItem('leaderboard2048'); + return data ? JSON.parse(data) : []; +} + +// Save leaderboard data to localStorage +function saveLeaderboardData(data) { + localStorage.setItem('leaderboard2048', JSON.stringify(data)); +} + +// Get current logged-in user +function getCurrentUser() { + return localStorage.getItem('currentUser') || null; +} + +// Add or update score for a player +function addScore(playerName, score) { + let leaderboard = getLeaderboardData(); + + // Find if player already exists + const existingIndex = leaderboard.findIndex(p => p.name === playerName); + + if (existingIndex >= 0) { + // Update only if new score is higher + if (score > leaderboard[existingIndex].score) { + leaderboard[existingIndex].score = score; + leaderboard[existingIndex].level = Math.floor(score / 100); + leaderboard[existingIndex].date = new Date().toISOString(); + } + } else { + // Add new player + leaderboard.push({ + name: playerName, + score: score, + level: Math.floor(score / 100), + date: new Date().toISOString() + }); + } + + saveLeaderboardData(leaderboard); +} + +// ========== RENDER LEADERBOARD ========== +function renderLeaderboard() { + let leaderboardData = getLeaderboardData(); + const currentUser = getCurrentUser(); + const list = document.getElementById('leaderboardList'); + const emptyState = document.getElementById('emptyState'); + + // Sort by score (highest first) + leaderboardData.sort((a, b) => b.score - a.score); + + // Update stats + const totalPlayers = leaderboardData.length; + const topScore = leaderboardData.length > 0 ? leaderboardData[0].score : 0; + + document.getElementById('totalPlayers').textContent = totalPlayers; + document.getElementById('topScore').textContent = topScore.toLocaleString(); + + // Find current user's rank + let userRank = '--'; + if (currentUser) { + const userIndex = leaderboardData.findIndex(p => p.name === currentUser); + if (userIndex >= 0) { + userRank = userIndex + 1; + } + } + document.getElementById('yourRank').textContent = userRank; + + // Check if there's data + if (leaderboardData.length === 0) { + list.style.display = 'none'; + if (emptyState) emptyState.style.display = 'block'; + return; + } + + list.style.display = 'flex'; + if (emptyState) emptyState.style.display = 'none'; + + // Render top 10 players + const top10 = leaderboardData.slice(0, 10); + + list.innerHTML = top10.map((player, index) => { + const rank = index + 1; + let rankClass = 'rank-other'; + + if (rank === 1) rankClass = 'rank-1'; + else if (rank === 2) rankClass = 'rank-2'; + else if (rank === 3) rankClass = 'rank-3'; + + const isCurrentUser = currentUser && player.name === currentUser; + const yourRankClass = isCurrentUser ? 'your-rank' : ''; + + return ` +
  • +
    ${rank}
    +
    +
    ${escapeHtml(player.name)}
    +
    Level ${player.level || Math.floor(player.score / 100)}
    +
    +
    +
    ${player.score.toLocaleString()}
    +
    Points
    +
    +
  • + `; + }).join(''); +} + +// Escape HTML to prevent XSS +function escapeHtml(text) { + const map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + return text.replace(/[&<>"']/g, m => map[m]); +} + +// ========== SAMPLE DATA (FOR TESTING) ========== +function initSampleData() { + const existingData = getLeaderboardData(); + + // Only add sample data if leaderboard is empty + if (existingData.length === 0) { + const sampleData = [ + { name: "CyberKing", score: 9850, level: 98, date: new Date().toISOString() }, + { name: "NeonMaster", score: 8200, level: 82, date: new Date().toISOString() }, + { name: "PixelHunter", score: 6950, level: 69, date: new Date().toISOString() }, + { name: "StarGazer", score: 5420, level: 54, date: new Date().toISOString() }, + { name: "CodeNinja", score: 4890, level: 48, date: new Date().toISOString() }, + { name: "ByteWarrior", score: 4320, level: 43, date: new Date().toISOString() }, + { name: "DataDragon", score: 3850, level: 38, date: new Date().toISOString() }, + { name: "SyntaxSage", score: 3120, level: 31, date: new Date().toISOString() }, + { name: "LogicLord", score: 2780, level: 27, date: new Date().toISOString() }, + { name: "BugSlayer", score: 2340, level: 23, date: new Date().toISOString() } + ]; + + saveLeaderboardData(sampleData); + console.log('Sample data initialized'); + } +} + +// ========== CLEAR LEADERBOARD (FOR TESTING) ========== +function clearLeaderboard() { + if (confirm('Are you sure you want to clear all leaderboard data?')) { + localStorage.removeItem('leaderboard2048'); + renderLeaderboard(); + console.log('Leaderboard cleared'); + } +} + +// ========== REFRESH LEADERBOARD ========== +function refreshLeaderboard() { + renderLeaderboard(); + console.log('Leaderboard refreshed'); +} + +// ========== INITIALIZE ON PAGE LOAD ========== +window.addEventListener('DOMContentLoaded', function() { + + renderLeaderboard(); + + console.log('Leaderboard initialized'); + console.log('Available functions:'); + console.log('- addScore(name, score) - Add/update a score'); + console.log('- clearLeaderboard() - Clear all data'); + console.log('- refreshLeaderboard() - Refresh display'); +}); + +// ========== EXPOSE FUNCTIONS TO WINDOW (FOR EXTERNAL USE) ========== +window.leaderboard = { + addScore: addScore, + getLeaderboardData: getLeaderboardData, + clearLeaderboard: clearLeaderboard, + refreshLeaderboard: refreshLeaderboard, + initSampleData: initSampleData +}; \ No newline at end of file