Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"/> | |
| <title>Finral - Telegram Leaderboard</title> | |
| <script src="https://telegram.org/js/telegram-web-app.js"></script> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| html, body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #16213e 100%); | |
| color: #e0e6ed; | |
| padding: 0; | |
| margin: 0; | |
| min-height: 100vh; | |
| position: relative; | |
| overflow-x: hidden; | |
| max-width: 100vw; | |
| } | |
| .header { | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); | |
| border-bottom: 2px solid #00bcd4; | |
| padding: 15px 10px 0; | |
| text-align: center; | |
| box-shadow: 0 4px 20px rgba(0, 188, 212, 0.3); | |
| position: relative; | |
| } | |
| .header::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: linear-gradient(45deg, transparent 30%, rgba(0, 188, 212, 0.1) 50%, transparent 70%); | |
| animation: shimmer 3s infinite; | |
| } | |
| @keyframes shimmer { | |
| 0% { transform: translateX(-100%); } | |
| 100% { transform: translateX(100%); } | |
| } | |
| .bot-title { | |
| font-size: 2.2rem; | |
| font-weight: 900; | |
| background: linear-gradient(45deg, #00bcd4, #87ceeb, #ffffff, #00bcd4); | |
| background-size: 300% 300%; | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-bottom: 5px; | |
| text-shadow: 0 0 30px rgba(0, 188, 212, 0.8); | |
| animation: gradientShift 4s ease-in-out infinite; | |
| letter-spacing: 1px; | |
| position: relative; | |
| z-index: 3; | |
| } | |
| .bot-title::after { | |
| content: 'β‘'; | |
| position: absolute; | |
| right: -30px; | |
| top: -5px; | |
| font-size: 1.2rem; | |
| animation: spark 2s infinite; | |
| } | |
| @keyframes gradientShift { | |
| 0%, 100% { background-position: 0% 50%; } | |
| 50% { background-position: 100% 50%; } | |
| } | |
| @keyframes spark { | |
| 0%, 100% { transform: rotate(0deg) scale(1); opacity: 0.7; } | |
| 50% { transform: rotate(15deg) scale(1.2); opacity: 1; } | |
| } | |
| .creator { | |
| font-size: 0.9rem; | |
| background: linear-gradient(45deg, #87ceeb, #00bcd4); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-bottom: 8px; | |
| font-weight: 600; | |
| letter-spacing: 0.5px; | |
| position: relative; | |
| z-index: 3; | |
| } | |
| .bot-subtitle { | |
| font-size: 0.8rem; | |
| color: rgba(135, 206, 235, 0.8); | |
| margin-bottom: 20px; | |
| font-style: italic; | |
| font-weight: 300; | |
| position: relative; | |
| z-index: 3; | |
| } | |
| .banner-container { | |
| position: relative; | |
| margin-bottom: 0; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| width: 100%; | |
| padding: 0; | |
| } | |
| #group-banner { | |
| width: 100%; | |
| height: 200px; | |
| object-fit: cover; | |
| border-radius: 0; | |
| border: 2px solid #00bcd4; | |
| border-left: none; | |
| border-right: none; | |
| box-shadow: 0 0 20px rgba(0, 188, 212, 0.3); | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .banner-overlay { | |
| position: absolute; | |
| top: 2px; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: linear-gradient( | |
| to bottom, | |
| rgba(0, 0, 0, 0.1) 0%, | |
| rgba(0, 0, 0, 0.3) 50%, | |
| rgba(26, 26, 46, 0.8) 100% | |
| ); | |
| z-index: 2; | |
| } | |
| #group-photo { | |
| position: absolute; | |
| bottom: -80px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| width: 160px; | |
| height: 160px; | |
| object-fit: cover; | |
| border-radius: 0%; | |
| border: 5px solid #00bcd4; | |
| box-shadow: | |
| 0 0 30px rgba(0, 188, 212, 0.8), | |
| 0 0 60px rgba(0, 188, 212, 0.4), | |
| 0 0 100px rgba(0, 188, 212, 0.2); | |
| background: #1a1a2e; | |
| z-index: 4; | |
| } | |
| .profile-glow { | |
| position: absolute; | |
| bottom: -80px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| width: 180px; | |
| height: 180px; | |
| border-radius: 50%; | |
| background: radial-gradient(circle, rgba(0, 188, 212, 0.4) 0%, rgba(0, 188, 212, 0.2) 50%, transparent 70%); | |
| z-index: 3; | |
| animation: profileGlow 3s ease-in-out infinite alternate; | |
| } | |
| @keyframes profileGlow { | |
| 0% { transform: translateX(-50%) scale(1); opacity: 0.6; } | |
| 100% { transform: translateX(-50%) scale(1.1); opacity: 0.9; } | |
| } | |
| .container { | |
| max-width: 800px; | |
| margin: 0 auto; | |
| padding: 90px 10px 100px; | |
| width: 100%; | |
| } | |
| .card { | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); | |
| border: 1px solid #00bcd4; | |
| border-radius: 12px; | |
| padding: 15px; | |
| margin-bottom: 15px; | |
| box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3); | |
| position: relative; | |
| overflow: hidden; | |
| width: 100%; | |
| max-width: 100%; | |
| } | |
| .card::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| height: 2px; | |
| background: linear-gradient(90deg, transparent, #00bcd4, transparent); | |
| } | |
| .section-title { | |
| font-size: 1.3rem; | |
| color: #00bcd4; | |
| margin-bottom: 12px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .section-title::before { | |
| content: ''; | |
| width: 3px; | |
| height: 18px; | |
| background: linear-gradient(45deg, #00bcd4, #87ceeb); | |
| border-radius: 2px; | |
| } | |
| .group-info { | |
| background: linear-gradient(135deg, #16213e 0%, #1a1a2e 100%); | |
| border: 1px solid #00bcd4; | |
| border-radius: 10px; | |
| padding: 12px; | |
| margin-bottom: 15px; | |
| } | |
| .group-info-grid { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 8px; | |
| margin-top: 8px; | |
| } | |
| .group-info-item { | |
| background: rgba(0, 188, 212, 0.1); | |
| border: 1px solid rgba(0, 188, 212, 0.3); | |
| border-radius: 6px; | |
| padding: 6px 8px; | |
| text-align: center; | |
| font-size: 0.8rem; | |
| } | |
| .group-info-value { | |
| font-weight: bold; | |
| color: #00bcd4; | |
| font-size: 0.9rem; | |
| } | |
| .group-info-label { | |
| font-size: 0.7rem; | |
| color: #87ceeb; | |
| margin-top: 2px; | |
| } | |
| .leaderboard-item { | |
| background: linear-gradient(135deg, #16213e 0%, #1a1a2e 100%); | |
| border: 1px solid rgba(0, 188, 212, 0.3); | |
| border-radius: 10px; | |
| padding: 10px; | |
| margin-bottom: 8px; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| min-height: 60px; | |
| } | |
| .leaderboard-item:hover { | |
| border-color: #00bcd4; | |
| box-shadow: 0 4px 12px rgba(0, 188, 212, 0.3); | |
| transform: translateY(-1px); | |
| } | |
| .leaderboard-item.current-user { | |
| border: 2px solid #00bcd4; | |
| background: linear-gradient(135deg, rgba(0, 188, 212, 0.15) 0%, rgba(135, 206, 235, 0.15) 100%); | |
| box-shadow: 0 0 15px rgba(0, 188, 212, 0.4); | |
| } | |
| .leaderboard-item.current-user::before { | |
| content: 'β '; | |
| position: absolute; | |
| top: 8px; | |
| right: 10px; | |
| color: #00bcd4; | |
| font-size: 1rem; | |
| animation: pulse 2s infinite; | |
| } | |
| .rank { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: linear-gradient(45deg, #00bcd4, #87ceeb); | |
| color: #0a0a0a; | |
| font-weight: bold; | |
| border-radius: 50%; | |
| width: 35px; | |
| height: 35px; | |
| font-size: 0.9rem; | |
| flex-shrink: 0; | |
| } | |
| .rank.top3 { | |
| background: linear-gradient(45deg, #ffd700, #ffed4a); | |
| animation: pulse 2s infinite; | |
| box-shadow: 0 0 10px rgba(255, 215, 0, 0.5); | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.05); } | |
| } | |
| .user-content { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .user-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: flex-start; | |
| margin-bottom: 6px; | |
| } | |
| .user-info-left { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .user-name { | |
| font-size: 1rem; | |
| font-weight: bold; | |
| color: #e0e6ed; | |
| margin-bottom: 2px; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .user-username { | |
| font-size: 0.8rem; | |
| color: #87ceeb; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .user-level { | |
| background: rgba(0, 188, 212, 0.2); | |
| border: 1px solid rgba(0, 188, 212, 0.4); | |
| border-radius: 12px; | |
| padding: 2px 8px; | |
| font-size: 0.7rem; | |
| font-weight: bold; | |
| color: #00bcd4; | |
| white-space: nowrap; | |
| } | |
| .user-stats { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr 1fr; | |
| gap: 6px; | |
| margin-top: 6px; | |
| } | |
| .stat-item { | |
| background: rgba(0, 188, 212, 0.08); | |
| border: 1px solid rgba(0, 188, 212, 0.2); | |
| border-radius: 6px; | |
| padding: 4px 6px; | |
| text-align: center; | |
| } | |
| .stat-value { | |
| font-weight: bold; | |
| color: #00bcd4; | |
| font-size: 0.8rem; | |
| line-height: 1; | |
| } | |
| .stat-label { | |
| font-size: 0.65rem; | |
| color: #87ceeb; | |
| margin-top: 1px; | |
| line-height: 1; | |
| } | |
| .current-user-section { | |
| position: fixed; | |
| bottom: 15px; | |
| left: 15px; | |
| right: 15px; | |
| z-index: 1000; | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); | |
| border: 2px solid #00bcd4; | |
| border-radius: 12px; | |
| padding: 12px; | |
| box-shadow: 0 -5px 25px rgba(0, 188, 212, 0.4); | |
| opacity: 0.95; | |
| transition: all 0.3s ease; | |
| backdrop-filter: blur(10px); | |
| max-height: 200px; | |
| overflow-y: auto; | |
| } | |
| .current-user-section:hover { | |
| opacity: 1; | |
| transform: translateY(-2px); | |
| box-shadow: 0 -8px 30px rgba(0, 188, 212, 0.6); | |
| } | |
| .floating-user-toggle { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| z-index: 1001; | |
| background: linear-gradient(45deg, #00bcd4, #87ceeb); | |
| border: none; | |
| border-radius: 50%; | |
| width: 55px; | |
| height: 55px; | |
| color: #0a0a0a; | |
| font-size: 1.3rem; | |
| font-weight: bold; | |
| cursor: pointer; | |
| box-shadow: 0 4px 20px rgba(0, 188, 212, 0.5); | |
| transition: all 0.3s ease; | |
| display: none; | |
| } | |
| .floating-user-toggle:hover { | |
| transform: scale(1.1); | |
| box-shadow: 0 6px 25px rgba(0, 188, 212, 0.7); | |
| } | |
| .floating-user-toggle.active { | |
| display: block; | |
| } | |
| .loading { | |
| text-align: center; | |
| color: #87ceeb; | |
| font-size: 1rem; | |
| padding: 30px; | |
| } | |
| .loading::after { | |
| content: ''; | |
| display: inline-block; | |
| width: 18px; | |
| height: 18px; | |
| border: 2px solid #87ceeb; | |
| border-top: 2px solid #00bcd4; | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin-left: 8px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .error { | |
| background: linear-gradient(135deg, #2d1b2d 0%, #4a1a2e 100%); | |
| border: 1px solid #ff6b6b; | |
| color: #ff9999; | |
| } | |
| .current-user-stats { | |
| display: grid; | |
| grid-template-columns: repeat(4, 1fr); | |
| gap: 8px; | |
| margin-top: 10px; | |
| } | |
| .scroll-to-user { | |
| background: linear-gradient(45deg, #00bcd4, #87ceeb); | |
| border: none; | |
| border-radius: 20px; | |
| padding: 8px 16px; | |
| color: #0a0a0a; | |
| font-size: 0.8rem; | |
| font-weight: bold; | |
| cursor: pointer; | |
| margin-top: 10px; | |
| transition: all 0.3s ease; | |
| } | |
| .scroll-to-user:hover { | |
| transform: translateY(-1px); | |
| box-shadow: 0 4px 12px rgba(0, 188, 212, 0.4); | |
| } | |
| /* Mobile optimizations */ | |
| @media (max-width: 480px) { | |
| .bot-title { | |
| font-size: 1.8rem; | |
| letter-spacing: 0.5px; | |
| } | |
| .bot-title::after { | |
| right: -25px; | |
| font-size: 1rem; | |
| } | |
| .creator { | |
| font-size: 0.8rem; | |
| } | |
| .bot-subtitle { | |
| font-size: 0.75rem; | |
| } | |
| #group-banner { | |
| height: 160px; | |
| } | |
| #group-photo { | |
| width: 120px; | |
| height: 120px; | |
| bottom: -60px; | |
| border-width: 4px; | |
| } | |
| .profile-glow { | |
| width: 140px; | |
| height: 140px; | |
| bottom: -60px; | |
| } | |
| .container { | |
| padding: 70px 8px 90px; | |
| } | |
| .card { | |
| padding: 12px; | |
| margin-bottom: 12px; | |
| border-radius: 10px; | |
| } | |
| .leaderboard-item { | |
| padding: 8px; | |
| margin-bottom: 6px; | |
| min-height: 55px; | |
| gap: 10px; | |
| } | |
| .rank { | |
| width: 30px; | |
| height: 30px; | |
| font-size: 0.8rem; | |
| } | |
| .user-name { | |
| font-size: 0.9rem; | |
| } | |
| .user-username { | |
| font-size: 0.75rem; | |
| } | |
| .user-level { | |
| font-size: 0.65rem; | |
| padding: 1px 6px; | |
| } | |
| .user-stats { | |
| gap: 4px; | |
| } | |
| .stat-item { | |
| padding: 3px 4px; | |
| } | |
| .stat-value { | |
| font-size: 0.75rem; | |
| } | |
| .stat-label { | |
| font-size: 0.6rem; | |
| } | |
| .current-user-section { | |
| bottom: 10px; | |
| left: 10px; | |
| right: 10px; | |
| padding: 10px; | |
| } | |
| .floating-user-toggle { | |
| width: 50px; | |
| height: 50px; | |
| font-size: 1.2rem; | |
| bottom: 15px; | |
| right: 15px; | |
| } | |
| .group-info-grid { | |
| gap: 6px; | |
| } | |
| .group-info-item { | |
| padding: 5px 6px; | |
| } | |
| .current-user-stats { | |
| gap: 6px; | |
| } | |
| } | |
| /* Extra small screens */ | |
| @media (max-width: 360px) { | |
| .bot-title { | |
| font-size: 1.6rem; | |
| } | |
| #group-banner { | |
| height: 140px; | |
| } | |
| #group-photo { | |
| width: 100px; | |
| height: 100px; | |
| bottom: -50px; | |
| border-width: 3px; | |
| } | |
| .profile-glow { | |
| width: 120px; | |
| height: 120px; | |
| bottom: -50px; | |
| } | |
| .container { | |
| padding: 60px 8px 90px; | |
| } | |
| .leaderboard-item { | |
| gap: 8px; | |
| } | |
| .rank { | |
| width: 28px; | |
| height: 28px; | |
| font-size: 0.75rem; | |
| } | |
| .user-stats { | |
| grid-template-columns: 1fr 1fr; | |
| gap: 3px; | |
| } | |
| .stat-item { | |
| padding: 2px 3px; | |
| } | |
| .stat-value { | |
| font-size: 0.7rem; | |
| } | |
| .stat-label { | |
| font-size: 0.55rem; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <div class="bot-title">FINRAL</div> | |
| <div class="creator">β¨ Crafted with Excellence by Saul β¨</div> | |
| <div class="bot-subtitle">"Leaderboard And Analytics"</div> | |
| <div class="banner-container"> | |
| <img id="group-banner" src="https://files.catbox.moe/sqh1t3.jpeg" alt="Group Banner" /> | |
| <div class="banner-overlay"></div> | |
| <div class="profile-glow"></div> | |
| <img id="group-photo" src="https://files.catbox.moe/znjnij.jpeg" alt="Group Photo" /> | |
| </div> | |
| </div> | |
| <div class="container"> | |
| <div class="card"> | |
| <div class="section-title">β Group Leaderboard</div> | |
| <div id="info" class="loading">Loading leaderboard data...</div> | |
| </div> | |
| </div> | |
| <div id="current-user-info"></div> | |
| <button id="floating-toggle" class="floating-user-toggle">π€</button> | |
| <script> | |
| // Group storage management | |
| function saveGroupToStorage(groupId, groupName) { | |
| try { | |
| const groups = JSON.parse(localStorage.getItem('telegramGroups') || '{}'); | |
| let groupKey = null; | |
| let nameKey = null; | |
| for (let i = 1; i <= 100; i++) { | |
| const key = `group${i}`; | |
| if (!groups[key]) { | |
| groupKey = key; | |
| nameKey = `${key}name`; | |
| break; | |
| } else if (groups[key] === groupId) { | |
| groupKey = key; | |
| nameKey = `${key}name`; | |
| break; | |
| } | |
| } | |
| if (groupKey) { | |
| groups[groupKey] = groupId; | |
| groups[nameKey] = groupName; | |
| localStorage.setItem('telegramGroups', JSON.stringify(groups)); | |
| console.log(`Saved ${groupId} as ${groupKey} with name ${groupName}`); | |
| } | |
| } catch (err) { | |
| console.error('Error saving group to storage:', err); | |
| } | |
| } | |
| function createUserCard(user, rank, isCurrentUser = false) { | |
| const card = document.createElement('div'); | |
| card.className = `leaderboard-item ${isCurrentUser ? 'current-user' : ''}`; | |
| if (isCurrentUser) { | |
| card.id = 'current-user-card'; | |
| } | |
| const rankClass = rank <= 3 ? 'rank top3' : 'rank'; | |
| card.innerHTML = ` | |
| <div class="${rankClass}">${rank}</div> | |
| <div class="user-content"> | |
| <div class="user-header"> | |
| <div class="user-info-left"> | |
| <div class="user-name">${user.fullName}</div> | |
| <div class="user-username">@${user.username}</div> | |
| </div> | |
| <div class="user-level">LV ${user.level}</div> | |
| </div> | |
| <div class="user-stats"> | |
| <div class="stat-item"> | |
| <div class="stat-value">${user.xp.toLocaleString()}</div> | |
| <div class="stat-label">XP</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value">${user.royalties.toLocaleString()}</div> | |
| <div class="stat-label">Royalties</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value">${user.dailyMessages}</div> | |
| <div class="stat-label">Daily</div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| return card; | |
| } | |
| function createCurrentUserSection(user, rank, totalUsers) { | |
| const section = document.createElement('div'); | |
| section.className = 'current-user-section'; | |
| section.id = 'user-stats-panel'; | |
| section.style.display = 'none'; | |
| const scrollButton = rank > 20 ? `<button class="scroll-to-user" onclick="scrollToCurrentUser()">π Find Me in List</button>` : ''; | |
| section.innerHTML = ` | |
| <div class="section-title">π€ Your Stats</div> | |
| <div class="group-info"> | |
| <div class="user-name">${user.fullName}</div> | |
| <div class="user-username">@${user.username} β’ Rank #${rank}/${totalUsers}</div> | |
| <div class="current-user-stats"> | |
| <div class="group-info-item"> | |
| <div class="group-info-value">${user.level}</div> | |
| <div class="group-info-label">Level</div> | |
| </div> | |
| <div class="group-info-item"> | |
| <div class="group-info-value">${user.xp.toLocaleString()}</div> | |
| <div class="group-info-label">XP</div> | |
| </div> | |
| <div class="group-info-item"> | |
| <div class="group-info-value">${user.royalties.toLocaleString()}</div> | |
| <div class="group-info-label">Royalties</div> | |
| </div> | |
| <div class="group-info-item"> | |
| <div class="group-info-value">${user.dailyMessages}</div> | |
| <div class="group-info-label">Daily</div> | |
| </div> | |
| </div> | |
| ${scrollButton} | |
| </div> | |
| `; | |
| return section; | |
| } | |
| function scrollToCurrentUser() { | |
| const currentUserCard = document.getElementById('current-user-card'); | |
| if (currentUserCard) { | |
| currentUserCard.scrollIntoView({ behavior: 'smooth', block: 'center' }); | |
| // Hide the panel after scrolling | |
| document.getElementById('user-stats-panel').style.display = 'none'; | |
| document.getElementById('floating-toggle').textContent = 'π€'; | |
| } | |
| } | |
| window.onload = async function () { | |
| const tg = window.Telegram.WebApp; | |
| tg.expand(); | |
| const initData = tg.initDataUnsafe; | |
| const user = initData?.user; | |
| const startParam = initData?.start_param; | |
| let infoDiv = document.getElementById("info"); | |
| if (!user) { | |
| infoDiv.innerHTML = `<div class="error">β οΈ Could not detect Telegram user data.</div>`; | |
| return; | |
| } | |
| if (!startParam) { | |
| infoDiv.innerHTML = `<div class="error">β No group info found in start_param.</div>`; | |
| return; | |
| } | |
| // Parse group info | |
| let imageCode = ""; | |
| let groupId = ""; | |
| let groupName = ""; | |
| try { | |
| const parts = startParam.split("__"); | |
| if (parts.length === 3) { | |
| const extMatch = parts[0].match(/-(jpg|jpeg|png|gif|webp)$/); | |
| if (extMatch) { | |
| const ext = extMatch[1]; | |
| imageCode = parts[0].replace(`-${ext}`, `.${ext}`); | |
| } else { | |
| imageCode = parts[0] + ".jpg"; | |
| } | |
| groupId = parts[1]; | |
| groupName = parts[2].replace(/_/g, " "); | |
| const imageUrl = `https://files.catbox.moe/${imageCode}`; | |
| document.getElementById("group-photo").src = imageUrl; | |
| saveGroupToStorage(groupId, groupName); | |
| } | |
| } catch (err) { | |
| console.error("Error parsing start_param:", err); | |
| groupId = startParam; | |
| groupName = "Unknown Group"; | |
| } | |
| try { | |
| const res = await fetch(`https://reaperxxxx-testldb.hf.space/group/${groupId}/users`); | |
| const data = await res.json(); | |
| if (!data.status || !data.users) { | |
| infoDiv.innerHTML = `<div class="error">β οΈ Failed to fetch leaderboard data.</div>`; | |
| return; | |
| } | |
| const usersArray = Object.entries(data.users).map(([id, u]) => ({ | |
| id, | |
| fullName: u.fullName, | |
| username: u.username || "N/A", | |
| level: u.level, | |
| xp: u.xp, | |
| royalties: u.royalties || 0, | |
| dailyMessages: u.dailyMessages || 0, | |
| })); | |
| // Sort users | |
| usersArray.sort((a, b) => { | |
| if (b.level !== a.level) return b.level - a.level; | |
| return b.xp - a.xp; | |
| }); | |
| const currentUser = usersArray.find(u => u.id == user.id); | |
| const currentUserRank = usersArray.findIndex(u => u.id == user.id) + 1; | |
| // Clear loading and build leaderboard | |
| infoDiv.innerHTML = ''; | |
| // Add group info | |
| const groupInfo = document.createElement('div'); | |
| groupInfo.className = 'group-info'; | |
| groupInfo.innerHTML = ` | |
| <div class="user-name">π© ${groupName}</div> | |
| <div class="user-username">π ${groupId}</div> | |
| <div class="group-info-grid"> | |
| <div class="group-info-item"> | |
| <div class="group-info-value">${usersArray.length}</div> | |
| <div class="group-info-label">Members</div> | |
| </div> | |
| <div class="group-info-item"> | |
| <div class="group-info-value">${currentUserRank > 0 ? `#${currentUserRank}` : 'N/A'}</div> | |
| <div class="group-info-label">Your Rank</div> | |
| </div> | |
| </div> | |
| `; | |
| infoDiv.appendChild(groupInfo); | |
| // Build leaderboard - show more users but in compact format | |
| const displayCount = Math.min(50, usersArray.length); // Show up to 50 users | |
| for (let i = 0; i < displayCount; i++) { | |
| const u = usersArray[i]; | |
| const isCurrentUser = u.id == user.id; | |
| const card = createUserCard(u, i + 1, isCurrentUser); | |
| infoDiv.appendChild(card); | |
| } | |
| // Add current user section if they exist | |
| if (currentUser) { | |
| const currentUserSection = createCurrentUserSection(currentUser, currentUserRank, usersArray.length); | |
| document.getElementById('current-user-info').appendChild(currentUserSection); | |
| const floatingToggle = document.getElementById('floating-toggle'); | |
| floatingToggle.classList.add('active'); | |
| floatingToggle.addEventListener('click', () => { | |
| const panel = document.getElementById('user-stats-panel'); | |
| if (panel.style.display === 'none') { | |
| panel.style.display = 'block'; | |
| floatingToggle.textContent = 'β'; | |
| } else { | |
| panel.style.display = 'none'; | |
| floatingToggle.textContent = 'π€'; | |
| } | |
| }); | |
| } else { | |
| // User not in leaderboard | |
| const unknownUserSection = document.createElement('div'); | |
| unknownUserSection.className = 'current-user-section'; | |
| unknownUserSection.id = 'user-stats-panel'; | |
| unknownUserSection.style.display = 'none'; | |
| unknownUserSection.innerHTML = ` | |
| <div class="section-title">π€ Your Info</div> | |
| <div class="group-info"> | |
| <div class="user-name">${user.first_name} ${user.last_name || ""}</div> | |
| <div class="user-username">@${user.username || "N/A"} β’ π ${user.id}</div> | |
| <div class="user-username">β οΈ Not yet ranked in this group</div> | |
| </div> | |
| `; | |
| document.getElementById('current-user-info').appendChild(unknownUserSection); | |
| const floatingToggle = document.getElementById('floating-toggle'); | |
| floatingToggle.classList.add('active'); | |
| floatingToggle.addEventListener('click', () => { | |
| const panel = document.getElementById('user-stats-panel'); | |
| if (panel.style.display === 'none') { | |
| panel.style.display = 'block'; | |
| floatingToggle.textContent = 'β'; | |
| } else { | |
| panel.style.display = 'none'; | |
| floatingToggle.textContent = 'π€'; | |
| } | |
| }); | |
| } | |
| } catch (err) { | |
| console.error('Error fetching leaderboard:', err); | |
| infoDiv.innerHTML = `<div class="error">β Error fetching leaderboard:<br>${err.message}</div>`; | |
| } | |
| }; | |
| // Make scrollToCurrentUser available globally | |
| window.scrollToCurrentUser = scrollToCurrentUser; | |
| </script> | |
| </body> | |
| </html> |