class ThemeManager { constructor() { this.currentTheme = localStorage.getItem('theme') || 'dark'; this.themeToggle = document.getElementById('theme-toggle'); this.themeIcon = document.getElementById('theme-icon'); this.init(); } init() { this.applyTheme(this.currentTheme); this.bindEvents(); } bindEvents() { if (this.themeToggle) { this.themeToggle.addEventListener('click', () => { this.toggleTheme(); }); } } toggleTheme() { this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark'; this.applyTheme(this.currentTheme); localStorage.setItem('theme', this.currentTheme); } applyTheme(theme) { document.documentElement.setAttribute('data-theme', theme); this.updateThemeIcon(theme); // Trigger theme change event for other components document.dispatchEvent(new CustomEvent('themeChanged', { detail: { theme } })); } updateThemeIcon(theme) { if (!this.themeIcon) return; if (theme === 'light') { // Moon icon for light theme (to switch to dark) this.themeIcon.innerHTML = ` `; } else { // Sun icon for dark theme (to switch to light) this.themeIcon.innerHTML = ` `; } } } // Login System Functions function showLoginModal() { const modal = document.getElementById('login-modal'); modal.classList.add('active'); } function hideLoginModal() { const modal = document.getElementById('login-modal'); modal.classList.remove('active'); } function showResetModal() { const modal = document.getElementById('reset-modal'); modal.classList.add('active'); } function hideResetModal() { const modal = document.getElementById('reset-modal'); modal.classList.remove('active'); } function sendResetCode() { const nickname = document.getElementById("login-nickname").value.trim(); if (!nickname) { showNotification("Введите игровой ник для восстановления.", 'error'); return; } fetch("/api/send_reset_code.php?nickname=" + encodeURIComponent(nickname)) .then(res => res.json()) .then(data => { if (data.success) { document.getElementById("reset-nickname").value = nickname; hideLoginModal(); showResetModal(); showNotification("Код отправлен в Telegram!", 'success'); } else { showNotification(data.message || "Ошибка при отправке кода.", 'error'); } }) .catch(() => showNotification("Сервер недоступен.", 'error')); } function login(nickname, password, remember) { // Validate inputs if (!nickname || !password) { showNotification('Пожалуйста, заполните все поля', 'error'); return; } // Create form data const formData = new FormData(); formData.append('action', 'login'); formData.append('nickname', nickname); formData.append('password', password); formData.append('remember', remember ? '1' : '0'); // Show loading notification showNotification('Выполняется вход...', 'info'); // Send request to server with improved error handling fetch('family-handler.php', { method: 'POST', body: formData }) .then(response => { if (!response.ok) { throw new Error('Ошибка сервера: ' + response.status + ' ' + response.statusText); } return response.json(); }) .then(data => { if (data.success) { hideLoginModal(); showNotification('Вы успешно вошли в систему!', 'success'); // Save user data if (remember) { localStorage.setItem('user', JSON.stringify({ nickname: data.nickname, token: data.token })); } else { sessionStorage.setItem('user', JSON.stringify({ nickname: data.nickname, token: data.token })); } updateUserInterface(data.nickname); } else { showNotification(data.message || 'Ошибка при входе в систему', 'error'); } }) .catch(error => { console.error('Error:', error); showNotification('Произошла ошибка при отправке данных: ' + error.message, 'error'); }); } function logout() { // Create form data const formData = new FormData(); formData.append('action', 'logout'); // Send request to server fetch('family-handler.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { showNotification('Вы успешно вышли из системы', 'success'); // Clear stored user data localStorage.removeItem('user'); sessionStorage.removeItem('user'); updateUserInterface(null); } else { showNotification(data.message || 'Ошибка при выходе из системы', 'error'); } }) .catch(error => { console.error('Error:', error); showNotification('Произошла ошибка при отправке данных', 'error'); }); } function updateUserInterface(nickname) { const loginButton = document.getElementById('login-button'); const userInfo = document.getElementById('user-info'); const userAvatar = document.getElementById('user-avatar'); const userName = document.getElementById('user-name'); if (nickname) { loginButton.style.display = 'none'; userInfo.style.display = 'flex'; userAvatar.textContent = nickname.charAt(0).toUpperCase(); userName.textContent = nickname; // Add click event to avatar and username userAvatar.onclick = function() { window.location.href = 'user-account.php?nickname=' + encodeURIComponent(nickname); }; userName.onclick = function() { window.location.href = 'user-account.php?nickname=' + encodeURIComponent(nickname); }; } else { loginButton.style.display = 'flex'; userInfo.style.display = 'none'; } } function checkLoggedIn() { // Check if user is logged in const user = JSON.parse(localStorage.getItem('user') || sessionStorage.getItem('user') || 'null'); if (user) { // Verify token with server const formData = new FormData(); formData.append('action', 'verify_token'); formData.append('nickname', user.nickname); formData.append('token', user.token); fetch('family-handler.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { updateUserInterface(user.nickname); } else { // Token invalid, clear stored data localStorage.removeItem('user'); sessionStorage.removeItem('user'); } }) .catch(error => { console.error('Error:', error); }); } } document.addEventListener('DOMContentLoaded', function() { const audio = document.getElementById('background-audio'); audio.volume = 0.06; // Попытка автозапуска const playPromise = audio.play(); if (playPromise !== undefined) { playPromise.catch(() => { // Если заблокировано, запускаем при клике document.addEventListener('click', function startAudio() { audio.play(); document.removeEventListener('click', startAudio); }, { once: true }); }); } const video = document.getElementById('background-video'); if (video) { // Устанавливаем громкость video.volume = 0.06; // 30% громкости, чтобы не было слишком громко // Принудительно запускаем видео со звуком const playPromise = video.play(); if (playPromise !== undefined) { playPromise.then(() => { console.log('Видео запущено со звуком'); }).catch(error => { console.log('Автовоспроизведение заблокировано, пытаемся запустить при первом клике'); // Запускаем при первом взаимодействии пользователя document.addEventListener('click', function startVideo() { video.play(); document.removeEventListener('click', startVideo); }, { once: true }); }); } } }); // Mobile menu toggle function initMobileMenu() { const mobileMenuToggle = document.querySelector('.mobile-menu-toggle'); const mobileMenu = document.querySelector('.mobile-menu'); const mobileNavLinks = document.querySelectorAll('.mobile-nav-link'); if (mobileMenuToggle && mobileMenu) { mobileMenuToggle.addEventListener('click', () => { mobileMenu.classList.toggle('active'); }); mobileNavLinks.forEach(link => { link.addEventListener('click', () => { mobileMenu.classList.remove('active'); }); }); // Close mobile menu when clicking outside document.addEventListener('click', (e) => { if (!mobileMenuToggle.contains(e.target) && !mobileMenu.contains(e.target)) { mobileMenu.classList.remove('active'); } }); } } // Screenshot slider function initScreenshotSlider() { const screenshots = document.querySelectorAll('.screenshot-item'); const dots = document.querySelectorAll('.dot'); const prevBtn = document.querySelector('.slider-arrow.prev'); const nextBtn = document.querySelector('.slider-arrow.next'); let currentSlide = 0; function showSlide(index) { screenshots.forEach((screenshot, i) => { screenshot.style.display = i === index ? 'block' : 'none'; }); dots.forEach((dot, i) => { dot.classList.toggle('active', i === index); }); } function nextSlide() { currentSlide = (currentSlide + 1) % screenshots.length; showSlide(currentSlide); } function prevSlide() { currentSlide = (currentSlide - 1 + screenshots.length) % screenshots.length; showSlide(currentSlide); } if (nextBtn && prevBtn) { nextBtn.addEventListener('click', nextSlide); prevBtn.addEventListener('click', prevSlide); } dots.forEach((dot, index) => { dot.addEventListener('click', () => { currentSlide = index; showSlide(currentSlide); }); }); // Auto-slide setInterval(nextSlide, 5000); // Initialize showSlide(0); } // Countdown timer function initCountdown() { const targetDate = new Date('2025-06-01T23:59:59').getTime(); function updateCountdown() { const now = new Date().getTime(); const distance = targetDate - now; if (distance < 0) { document.getElementById('countdown-days').textContent = '00'; document.getElementById('countdown-hours').textContent = '00'; document.getElementById('countdown-minutes').textContent = '00'; document.getElementById('countdown-seconds').textContent = '00'; return; } const days = Math.floor(distance / (1000 * 60 * 60 * 24)); const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((distance % (1000 * 60)) / 1000); document.getElementById('countdown-days').textContent = days.toString().padStart(2, '0'); document.getElementById('countdown-hours').textContent = hours.toString().padStart(2, '0'); document.getElementById('countdown-minutes').textContent = minutes.toString().padStart(2, '0'); document.getElementById('countdown-seconds').textContent = seconds.toString().padStart(2, '0'); } updateCountdown(); setInterval(updateCountdown, 1000); } // Notification system function showNotification(message, type = 'success') { // Remove existing notifications const existingNotifications = document.querySelectorAll('.glass-notification'); existingNotifications.forEach(notification => notification.remove()); const notification = document.createElement('div'); notification.className = `glass-notification ${type}`; const iconSvg = type === 'success' ? '' : ''; notification.innerHTML = `
${iconSvg}
${message}
`; document.body.appendChild(notification); // Show notification setTimeout(() => { notification.classList.add('active'); }, 100); // Auto-hide after 3 seconds setTimeout(() => { notification.classList.remove('active'); setTimeout(() => { notification.remove(); }, 300); }, 3000); // Close button const closeBtn = notification.querySelector('.notification-close'); closeBtn.addEventListener('click', () => { notification.classList.remove('active'); setTimeout(() => { notification.remove(); }, 300); }); } // Registration Form Handler class RegistrationForm { constructor() { this.form = document.getElementById('pre-register'); this.registerBtn = document.getElementById('register-button'); this.sliderThumb = document.getElementById('slider-thumb'); this.sliderTrack = document.getElementById('slider-track'); this.sliderProgress = document.getElementById('slider-progress'); this.sliderText = document.getElementById('slider-text'); this.isSliderVerified = false; this.isDragging = false; this.currentCaptcha = null; this.init(); } init() { this.setupCaptcha(); this.setupSlider(); this.setupFormValidation(); this.setupFormSubmission(); } setupCaptcha() { const captchaQuestions = [ { question: 'Сколько будет 5 + 3?', answer: '8' }, { question: 'Сколько будет 7 - 2?', answer: '5' }, { question: 'Сколько будет 4 × 2?', answer: '8' }, { question: 'Сколько будет 9 ÷ 3?', answer: '3' }, { question: 'Сколько будет 6 + 4?', answer: '10' }, { question: 'Сколько будет 8 - 3?', answer: '5' } ]; this.currentCaptcha = captchaQuestions[Math.floor(Math.random() * captchaQuestions.length)]; const captchaQuestion = document.getElementById('captcha-question'); if (captchaQuestion) { captchaQuestion.textContent = this.currentCaptcha.question; } } setupSlider() { if (!this.sliderThumb || !this.sliderTrack) return; // Mouse events this.sliderThumb.addEventListener('mousedown', (e) => { this.isDragging = true; this.sliderThumb.style.cursor = 'grabbing'; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (this.isDragging) { this.updateSlider(e.clientX); } }); document.addEventListener('mouseup', () => { if (this.isDragging) { this.isDragging = false; this.sliderThumb.style.cursor = 'grab'; } }); // Touch events this.sliderThumb.addEventListener('touchstart', (e) => { this.isDragging = true; e.preventDefault(); }); document.addEventListener('touchmove', (e) => { if (this.isDragging) { e.preventDefault(); this.updateSlider(e.touches[0].clientX); } }); document.addEventListener('touchend', () => { if (this.isDragging) { this.isDragging = false; } }); } updateSlider(clientX) { const trackRect = this.sliderTrack.getBoundingClientRect(); const thumbWidth = this.sliderThumb.offsetWidth; const maxX = trackRect.width - thumbWidth; const currentX = Math.max(0, Math.min(clientX - trackRect.left, maxX)); const percentage = (currentX / maxX) * 100; this.sliderThumb.style.left = currentX + 'px'; this.sliderProgress.style.width = percentage + '%'; if (percentage >= 95) { this.isSliderVerified = true; this.sliderText.textContent = 'Проверка пройдена!'; this.sliderTrack.parentElement.classList.add('verified'); this.checkFormValidity(); } } setupFormValidation() { const inputs = ['nickname', 'password', 'captcha-answer']; const termsCheckbox = document.getElementById('terms'); inputs.forEach(id => { const input = document.getElementById(id); if (input) { input.addEventListener('input', () => this.checkFormValidity()); } }); if (termsCheckbox) { termsCheckbox.addEventListener('change', () => this.checkFormValidity()); } } checkFormValidity() { const nickname = document.getElementById('nickname')?.value.trim() || ''; const password = document.getElementById('password')?.value.trim() || ''; const captchaAnswer = document.getElementById('captcha-answer')?.value.trim() || ''; const termsAccepted = document.getElementById('terms')?.checked || false; const isValid = nickname.length >= 3 && password.length >= 6 && captchaAnswer === this.currentCaptcha.answer && termsAccepted && this.isSliderVerified; if (this.registerBtn) { this.registerBtn.disabled = !isValid; } } setupFormSubmission() { if (this.registerBtn) { this.registerBtn.addEventListener('click', (e) => { e.preventDefault(); this.handleSubmission(); }); } } async handleSubmission() { const nickname = document.getElementById('nickname')?.value.trim(); const password = document.getElementById('password')?.value.trim(); const discord = document.getElementById('discord')?.value.trim(); // Show loading state this.registerBtn.innerHTML = 'Регистрация...'; this.registerBtn.disabled = true; try { // Simulate API call await new Promise(resolve => setTimeout(resolve, 2000)); // Success showNotification('Регистрация завершена успешно!', 'success'); this.resetForm(); this.updateUserCount(); } catch (error) { showNotification('Ошибка при регистрации. Попробуйте снова.', 'error'); } finally { this.registerBtn.innerHTML = 'Зарегистрироваться
'; this.registerBtn.disabled = false; } } resetForm() { if (this.form) { this.form.reset(); } // Reset slider this.isSliderVerified = false; if (this.sliderThumb) this.sliderThumb.style.left = '0px'; if (this.sliderProgress) this.sliderProgress.style.width = '0%'; if (this.sliderText) this.sliderText.textContent = 'Перетащите ползунок вправо'; if (this.sliderTrack) this.sliderTrack.parentElement.classList.remove('verified'); // Reset captcha this.setupCaptcha(); } updateUserCount() { const userCountElement = document.getElementById('user-count-value'); if (!userCountElement) return; const currentCount = parseInt(localStorage.getItem('userCount') || '1247'); const newCount = currentCount + 1; localStorage.setItem('userCount', newCount.toString()); // Animate count let start = currentCount; const duration = 1000; const startTime = Date.now(); function animate() { const elapsed = Date.now() - startTime; const progress = Math.min(elapsed / duration, 1); const current = Math.floor(start + (newCount - start) * progress); userCountElement.textContent = `330 игроков уже с нами`; if (progress < 1) { requestAnimationFrame(animate); } } animate(); } } // Payment Form Handler class PaymentForm { constructor() { this.form = document.getElementById('paymentForm'); this.init(); } init() { if (this.form) { this.form.addEventListener('submit', (e) => { e.preventDefault(); this.handlePayment(); }); } } handlePayment() { const amount = document.getElementById('amount')?.value; if (!amount || amount < 1) { showNotification('Введите корректную сумму', 'error'); return; } // Redirect to payment page const paymentUrl = `https://pay.cryptomus.com/pay/${amount}`; window.open(paymentUrl, '_blank'); showNotification('Переход на страницу оплаты...', 'success'); } } // Steps animation function initStepsAnimation() { const steps = document.querySelectorAll('.step-item'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('animate'); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); steps.forEach(step => { observer.observe(step); }); } // Smooth scrolling function initSmoothScrolling() { 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' }); } }); }); } // Page switcher functionality function initPageSwitcher() { const pageSwitchBtns = document.querySelectorAll('.page-switch-btn'); const mainContent = document.getElementById('main-content'); const adminPage = document.getElementById('admin-page'); pageSwitchBtns.forEach(btn => { btn.addEventListener('click', function() { const targetPage = this.getAttribute('data-page'); // Remove active class from all buttons pageSwitchBtns.forEach(b => b.classList.remove('active')); // Add active class to clicked button this.classList.add('active'); // Switch pages if (targetPage === 'main') { mainContent.style.display = 'block'; adminPage.classList.remove('active'); } else if (targetPage === 'other') { mainContent.style.display = 'none'; adminPage.classList.add('active'); // Trigger admin card animations setTimeout(() => { const adminCards = document.querySelectorAll('.admin-card'); adminCards.forEach((card, index) => { setTimeout(() => { card.style.animationDelay = (index * 0.1) + 's'; card.style.animation = 'fadeInUp 0.8s ease forwards'; }, index * 100); }); }, 100); } }); }); } // Initialize user count function initUserCount() { const userCountElement = document.getElementById('user-count-value'); if (userCountElement) { const currentCount = parseInt(localStorage.getItem('userCount') || '1247'); userCountElement.textContent = `330 игроков уже с нами`; } } // Reset password form handler document.getElementById("reset-form").addEventListener("submit", function(e) { e.preventDefault(); const nickname = document.getElementById("reset-nickname").value; const code = document.getElementById("reset-code").value.trim(); const newPassword = document.getElementById("new-password").value; const confirmPassword = document.getElementById("confirm-password").value; if (newPassword !== confirmPassword) { showNotification("Пароли не совпадают.", 'error'); return; } fetch("/api/confirm_reset.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ nickname, code, newPassword }) }) .then(res => res.json()) .then(data => { showNotification(data.message, data.success ? 'success' : 'error'); if (data.success) { hideResetModal(); } }); }); // Initialize everything when DOM is loaded document.addEventListener('DOMContentLoaded', function() { // Initialize theme manager first new ThemeManager(); // Initialize other components initMobileMenu(); initScreenshotSlider(); initCountdown(); new RegistrationForm(); new PaymentForm(); initStepsAnimation(); initSmoothScrolling(); initPageSwitcher(); initUserCount(); // Login button event listener const loginButton = document.getElementById('login-button'); if (loginButton) { loginButton.addEventListener('click', showLoginModal); } // Login form submission const loginForm = document.getElementById('login-form'); if (loginForm) { loginForm.addEventListener('submit', function(e) { e.preventDefault(); const nickname = document.getElementById('login-nickname').value; const password = document.getElementById('login-password').value; const remember = document.getElementById('remember-me').checked; login(nickname, password, remember); }); } // Close modal when clicking outside const loginModal = document.getElementById('login-modal'); if (loginModal) { loginModal.addEventListener('click', function(e) { if (e.target === loginModal) { hideLoginModal(); } }); } const resetModal = document.getElementById('reset-modal'); if (resetModal) { resetModal.addEventListener('click', function(e) { if (e.target === resetModal) { hideResetModal(); } }); } // Logout button const logoutButton = document.getElementById('logout-button'); if (logoutButton) { logoutButton.addEventListener('click', logout); } // Check if user is already logged in checkLoggedIn(); // Theme change listener for canvas updates document.addEventListener('themeChanged', (e) => { // Reinitialize sphere with new theme colors if needed const canvas = document.getElementById('sphere-canvas'); if (canvas) { const ctx = canvas.getContext('2d'); // Update particle colors based on theme // This could be enhanced to change particle colors dynamically } }); }); // Handle window resize window.addEventListener('resize', () => { // Reinitialize components that depend on window size const canvas = document.getElementById('sphere-canvas'); if (canvas) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } }); // Handle page visibility change document.addEventListener('visibilitychange', () => { if (document.hidden) { // Pause animations when page is not visible } else { // Resume animations when page becomes visible } }); // Keyboard shortcuts document.addEventListener('keydown', (e) => { // Ctrl/Cmd + Shift + T to toggle theme if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'T') { e.preventDefault(); const themeManager = new ThemeManager(); themeManager.toggleTheme(); } // Escape to close mobile menu and modals if (e.key === 'Escape') { const mobileMenu = document.querySelector('.mobile-menu'); if (mobileMenu && mobileMenu.classList.contains('active')) { mobileMenu.classList.remove('active'); } const loginModal = document.getElementById('login-modal'); if (loginModal && loginModal.classList.contains('active')) { hideLoginModal(); } const resetModal = document.getElementById('reset-modal'); if (resetModal && resetModal.classList.contains('active')) { hideResetModal(); } } }); // Performance optimization: Lazy load images function initLazyLoading() { const images = document.querySelectorAll('img[data-src]'); const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.remove('lazy'); imageObserver.unobserve(img); } }); }); images.forEach(img => imageObserver.observe(img)); } // Error handling window.addEventListener('error', (e) => { console.error('JavaScript error:', e.error); // Could send error reports to analytics service }); // Service Worker registration for PWA capabilities if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('SW registered: ', registration); }) .catch(registrationError => { console.log('SW registration failed: ', registrationError); }); }); }