// DOM Content Loaded document.addEventListener('DOMContentLoaded', function() { // Mobile Navigation const hamburger = document.querySelector('.hamburger'); const navMenu = document.querySelector('.nav-menu'); const navLinks = document.querySelectorAll('.nav-link'); if (hamburger && navMenu) { hamburger.addEventListener('click', function() { hamburger.classList.toggle('active'); navMenu.classList.toggle('active'); // Prevent body scroll when menu is open if (navMenu.classList.contains('active')) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } }); // Keyboard navigation support hamburger.addEventListener('keydown', function(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); hamburger.click(); } }); // Close mobile menu when clicking on nav links navLinks.forEach(link => { link.addEventListener('click', function() { hamburger.classList.remove('active'); navMenu.classList.remove('active'); document.body.style.overflow = ''; }); }); // Close mobile menu when clicking outside document.addEventListener('click', function(e) { if (hamburger && navMenu && !hamburger.contains(e.target) && !navMenu.contains(e.target)) { hamburger.classList.remove('active'); navMenu.classList.remove('active'); document.body.style.overflow = ''; } }); // Close mobile menu on window resize if desktop size window.addEventListener('resize', function() { if (window.innerWidth > 768) { hamburger.classList.remove('active'); navMenu.classList.remove('active'); document.body.style.overflow = ''; } }); } // Smooth Scrolling for Navigation Links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); // Button Click Handlers const inviteButtons = [ 'inviteBtn', 'inviteBtnMobile', 'heroInviteBtn', 'ctaInviteBtn', 'footerInviteBtn', 'freePlanInviteBtn' ]; const supportButtons = [ 'supportBtn', 'heroSupportBtn', 'footerSupportBtn' ]; // Handle Invite Button Clicks inviteButtons.forEach(buttonId => { const button = document.getElementById(buttonId); if (button) { button.addEventListener('click', function() { handleInviteClick(); }); } }); // Handle Support Button Clicks supportButtons.forEach(buttonId => { const button = document.getElementById(buttonId); if (button) { button.addEventListener('click', function() { handleSupportClick(); }); } }); // Fetch and Update Stats updateStats(); // Update stats every 30 seconds setInterval(updateStats, 30000); // New nav mobile menu toggle const mobileMenuBtn = document.getElementById('mobileMenuBtn'); const mobileMenu = document.getElementById('mobileMenu'); if (mobileMenuBtn && mobileMenu) { mobileMenuBtn.addEventListener('click', () => { mobileMenu.classList.toggle('hidden'); }); } // Navbar Scroll Effect const navbar = document.querySelector('.navbar'); if (navbar) { window.addEventListener('scroll', function() { if (window.scrollY > 100) { navbar.style.background = 'rgba(13, 14, 15, 0.98)'; } else { navbar.style.background = 'rgba(13, 14, 15, 1)'; } }); } // Animate Numbers on Stats Section Intersection const statsSection = document.querySelector('#stats'); if (statsSection) { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { animateNumbers(); observer.unobserve(entry.target); } }); }, { threshold: 0.5 }); observer.observe(statsSection); } // Handle touch events for better mobile experience let touchStartY = 0; let touchEndY = 0; document.addEventListener('touchstart', function(e) { touchStartY = e.changedTouches[0].screenY; }, { passive: true }); document.addEventListener('touchend', function(e) { touchEndY = e.changedTouches[0].screenY; handleSwipe(); }, { passive: true }); function handleSwipe() { const swipeThreshold = 50; const diff = touchStartY - touchEndY; // Close mobile menu on upward swipe when menu is open if (navMenu && hamburger && navMenu.classList.contains('active') && diff > swipeThreshold) { hamburger.classList.remove('active'); navMenu.classList.remove('active'); document.body.style.overflow = ''; } } }); // Handle Invite Button Click async function handleInviteClick() { try { // Direct invite URL for Toothless SQB Bot const inviteUrl = 'https://discord.com/oauth2/authorize?client_id=1254679514466877540&permissions=2048&scope=bot%20applications.commands'; window.open(inviteUrl, '_blank'); showNotification(window.__t ? __t('js.openingDiscordInvite') : 'Opening Discord invite!', 'success'); } catch (error) { console.error('Error opening invite link:', error); showNotification(window.__t ? __t('js.errorOpeningInvite') : 'Error opening invite link. Please try again later.', 'error'); // Fallback - same URL but ensure it opens const fallbackUrl = 'https://discord.com/oauth2/authorize?client_id=1254679514466877540&permissions=2048&scope=bot%20applications.commands'; window.open(fallbackUrl, '_blank'); } } // Handle Support Button Click async function handleSupportClick() { try { showNotification(window.__t ? __t('js.gettingSupportLink') : 'Getting support server link...', 'info'); const response = await fetch('/api/support'); const data = await response.json(); if (data.supportUrl) { window.open(data.supportUrl, '_blank'); showNotification(window.__t ? __t('js.openingSupportServer') : 'Opening support server!', 'success'); } else { throw new Error('No support URL received'); } } catch (error) { console.error('Error getting support link:', error); showNotification(window.__t ? __t('js.errorGettingSupport') : 'Error getting support link. Please try again later.', 'error'); // Fallback - Real support server invite const fallbackUrl = 'https://discord.gg/BCvkK8JhPe'; window.open(fallbackUrl, '_blank'); } } // Update Stats from API async function updateStats() { try { let stats; // Check if API client is available, if not use fallback if (window.apiClient && window.apiClient.getStats) { stats = await window.apiClient.getStats(); } else { // Fallback for pages without API client const response = await fetch('/api/stats'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } stats = await response.json(); } // Update server count const serverCountEl = document.getElementById('serverCount'); if (serverCountEl && stats.servers) { serverCountEl.textContent = formatNumber(stats.servers); } // Update user count const userCountEl = document.getElementById('userCount'); if (userCountEl && stats.users) { userCountEl.textContent = formatNumber(stats.users) + '+'; } // Update command count const commandCountEl = document.getElementById('commandCount'); if (commandCountEl && stats.commands) { commandCountEl.textContent = stats.commands + '+'; } } catch (error) { // Silently ignore — stat counters are non-critical and failures flash an annoying banner } } // Format numbers with commas function formatNumber(num) { return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } // Animate numbers when stats section comes into view function animateNumbers() { const numbers = document.querySelectorAll('.stat-number'); numbers.forEach(number => { const target = parseInt(number.textContent.replace(/[^0-9]/g, '')); const duration = 2000; const start = performance.now(); function updateNumber(currentTime) { const elapsed = currentTime - start; const progress = Math.min(elapsed / duration, 1); // Easing function const easeOutQuart = 1 - Math.pow(1 - progress, 4); const current = Math.floor(target * easeOutQuart); if (number.textContent.includes('+')) { number.textContent = formatNumber(current) + '+'; } else { number.textContent = formatNumber(current); } if (progress < 1) { requestAnimationFrame(updateNumber); } } requestAnimationFrame(updateNumber); }); } // Show notification system function showNotification(message, type = 'info') { // Remove existing notifications const existingNotification = document.querySelector('.notification'); if (existingNotification) { existingNotification.remove(); } // Create notification element const notification = document.createElement('div'); notification.className = `notification notification-${type}`; notification.textContent = message; // Style the notification notification.style.cssText = ` position: fixed; top: 100px; right: 20px; background: ${type === 'success' ? '#4caf50' : type === 'error' ? '#f44336' : '#2196f3'}; color: white; padding: 15px 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10000; font-weight: 500; opacity: 0; transform: translateX(100%); transition: all 0.3s ease; `; document.body.appendChild(notification); // Animate in setTimeout(() => { notification.style.opacity = '1'; notification.style.transform = 'translateX(0)'; }, 100); // Auto remove after 3 seconds setTimeout(() => { notification.style.opacity = '0'; notification.style.transform = 'translateX(100%)'; setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 300); }, 3000); } // Easter egg - Konami code let konamiCode = []; const konamiSequence = [ 'ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'KeyB', 'KeyA' ]; function triggerKonamiEasterEgg() { var t = typeof __t === 'function' ? __t : null; // --- 1. Screen shake --- document.body.style.transition = 'none'; var shakeFrames = [ '3px 0', '-3px 1px', '2px -1px', '-2px 2px', '1px -2px', '-1px 1px', '2px 0', '0 0' ]; var si = 0; var shakeInterval = setInterval(function () { if (si >= shakeFrames.length) { clearInterval(shakeInterval); document.body.style.transform = ''; return; } document.body.style.transform = 'translate(' + shakeFrames[si] + ')'; si++; }, 40); // --- 2. Confetti burst --- var colors = ['#ff6b6b', '#ffd93d', '#6bcb77', '#4d96ff', '#ff922b', '#cc5de8', '#20c997']; var confettiCount = 80; var container = document.createElement('div'); container.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:99999;overflow:hidden;'; document.body.appendChild(container); for (var i = 0; i < confettiCount; i++) { var piece = document.createElement('div'); var size = Math.random() * 8 + 4; var color = colors[Math.floor(Math.random() * colors.length)]; var startX = 50 + (Math.random() - 0.5) * 20; var startY = 50 + (Math.random() - 0.5) * 10; var dx = (Math.random() - 0.5) * 120; var dy = -(Math.random() * 60 + 30); var rot = Math.random() * 720 - 360; var dur = Math.random() * 1.5 + 1.5; piece.style.cssText = 'position:absolute;width:' + size + 'px;height:' + (size * 0.6) + 'px;' + 'background:' + color + ';border-radius:2px;' + 'left:' + startX + '%;top:' + startY + '%;' + 'opacity:1;pointer-events:none;'; piece.animate([ { transform: 'translate(0,0) rotate(0deg)', opacity: 1 }, { transform: 'translate(' + dx + 'vw,' + dy + 'vh) rotate(' + rot + 'deg)', opacity: 0 } ], { duration: dur * 1000, easing: 'cubic-bezier(.25,.8,.25,1)', fill: 'forwards' }); container.appendChild(piece); } setTimeout(function () { container.remove(); }, 4000); // --- 3. Barrel roll --- setTimeout(function () { var style = document.createElement('style'); style.textContent = '@keyframes konamiBarrelRoll{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}'; document.head.appendChild(style); document.body.style.transformOrigin = 'center center'; document.body.style.animation = 'konamiBarrelRoll 1s ease-in-out'; document.body.addEventListener('animationend', function handler() { document.body.style.animation = ''; document.body.style.transformOrigin = ''; style.remove(); document.body.removeEventListener('animationend', handler); }); }, 350); // --- 4. Themed notification --- var msg = t ? t('js.konamiActivated') : 'Achievement Unlocked: Secret Code!'; var notif = document.createElement('div'); notif.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%) scale(0);' + 'background:linear-gradient(135deg,rgba(30,30,30,0.95),rgba(50,50,50,0.95));' + 'border:2px solid #ffd93d;color:#ffd93d;padding:20px 40px;border-radius:12px;' + 'z-index:100000;font-size:1.4rem;font-weight:700;text-align:center;' + 'box-shadow:0 0 40px rgba(255,217,61,0.3);pointer-events:none;' + 'font-family:inherit;letter-spacing:1px;text-transform:uppercase;' + 'transition:transform 0.4s cubic-bezier(.34,1.56,.64,1),opacity 0.3s ease;opacity:0;'; notif.textContent = msg; document.body.appendChild(notif); setTimeout(function () { notif.style.transform = 'translate(-50%,-50%) scale(1)'; notif.style.opacity = '1'; }, 50); setTimeout(function () { notif.style.transform = 'translate(-50%,-50%) scale(0.8)'; notif.style.opacity = '0'; setTimeout(function () { notif.remove(); }, 400); }, 3000); } document.addEventListener('keydown', function(e) { konamiCode.push(e.code); if (konamiCode.length > konamiSequence.length) { konamiCode.shift(); } if (konamiCode.join(',') === konamiSequence.join(',')) { triggerKonamiEasterEgg(); konamiCode = []; } }); // Mobile menu toggle function toggleMobileMenu() { const navMenu = document.querySelector('.nav-menu'); const hamburger = document.querySelector('.hamburger'); navMenu.classList.toggle('active'); hamburger.classList.toggle('active'); } // Languages dropdown toggle function toggleLanguagesList() { const languagesList = document.getElementById('languagesList'); const dropdownToggle = document.querySelector('.dropdown-toggle'); languagesList.classList.toggle('show'); dropdownToggle.classList.toggle('active'); } // Language switcher (ENG/RUS) function switchLanguage(lang) { const next = lang || (document.documentElement.lang === 'en' ? 'ru' : 'en'); if (next === document.documentElement.lang) return; document.cookie = 'lang=' + next + ';path=/;max-age=31536000;SameSite=Lax'; window.location.reload(); } // Language dropdown: close on outside click document.addEventListener('click', function(e) { var dd = document.getElementById('langDropdown'); if (dd && !dd.contains(e.target)) { dd.classList.remove('open'); } });