Spaces:
Running
Running
| // ===== Initialize Lucide Icons ===== | |
| lucide.createIcons(); | |
| // ===== Initialize AOS ===== | |
| AOS.init({ | |
| duration: 800, | |
| easing: 'ease-out-cubic', | |
| once: true, | |
| offset: 50, | |
| }); | |
| // ===== Mobile Menu Toggle ===== | |
| const mobileMenuBtn = document.getElementById('mobile-menu-btn'); | |
| const mobileMenu = document.getElementById('mobile-menu'); | |
| mobileMenuBtn.addEventListener('click', () => { | |
| mobileMenu.classList.toggle('hidden'); | |
| const icon = mobileMenuBtn.querySelector('[data-lucide]'); | |
| if (mobileMenu.classList.contains('hidden')) { | |
| icon.setAttribute('data-lucide', 'menu'); | |
| } else { | |
| icon.setAttribute('data-lucide', 'x'); | |
| } | |
| lucide.createIcons(); | |
| }); | |
| // Close mobile menu on link click | |
| mobileMenu.querySelectorAll('a').forEach(link => { | |
| link.addEventListener('click', () => { | |
| mobileMenu.classList.add('hidden'); | |
| mobileMenuBtn.querySelector('[data-lucide]').setAttribute('data-lucide', 'menu'); | |
| lucide.createIcons(); | |
| }); | |
| }); | |
| // ===== Navbar Scroll Effect ===== | |
| const navbar = document.getElementById('navbar'); | |
| let lastScroll = 0; | |
| window.addEventListener('scroll', () => { | |
| const currentScroll = window.pageYOffset; | |
| if (currentScroll > 50) { | |
| navbar.classList.add('shadow-2xl', 'shadow-black/50'); | |
| } else { | |
| navbar.classList.remove('shadow-2xl', 'shadow-black/50'); | |
| } | |
| lastScroll = currentScroll; | |
| }); | |
| // ===== Active Nav Link on Scroll ===== | |
| const sections = document.querySelectorAll('section[id]'); | |
| const navLinks = document.querySelectorAll('.nav-link'); | |
| window.addEventListener('scroll', () => { | |
| let current = ''; | |
| sections.forEach(section => { | |
| const sectionTop = section.offsetTop - 150; | |
| const sectionHeight = section.clientHeight; | |
| if (window.pageYOffset >= sectionTop && window.pageYOffset < sectionTop + sectionHeight) { | |
| current = section.getAttribute('id'); | |
| } | |
| }); | |
| navLinks.forEach(link => { | |
| link.classList.remove('active'); | |
| if (link.getAttribute('href') === '#' + current) { | |
| link.classList.add('active'); | |
| } | |
| }); | |
| }); | |
| // ===== Back to Top Button ===== | |
| const backToTopBtn = document.getElementById('back-to-top'); | |
| window.addEventListener('scroll', () => { | |
| if (window.pageYOffset > 500) { | |
| backToTopBtn.classList.remove('opacity-0', 'invisible'); | |
| backToTopBtn.classList.add('opacity-100', 'visible'); | |
| } else { | |
| backToTopBtn.classList.add('opacity-0', 'invisible'); | |
| backToTopBtn.classList.remove('opacity-100', 'visible'); | |
| } | |
| }); | |
| backToTopBtn.addEventListener('click', () => { | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| }); | |
| // ===== Counter Animation ===== | |
| const counters = document.querySelectorAll('[data-counter]'); | |
| const speed = 200; | |
| const formatNumber = (num) => { | |
| return num.toLocaleString('fa-IR'); | |
| }; | |
| const animateCounter = (counter) => { | |
| const target = parseInt(counter.getAttribute('data-counter')); | |
| const suffix = counter.getAttribute('data-suffix') || ''; | |
| let current = 0; | |
| const increment = target / speed; | |
| const step = () => { | |
| current += increment; | |
| if (current < target) { | |
| counter.textContent = formatNumber(Math.floor(current)) + suffix; | |
| requestAnimationFrame(step); | |
| } else { | |
| counter.textContent = formatNumber(target) + suffix; | |
| } | |
| }; | |
| step(); | |
| }; | |
| // Observer for counters | |
| const counterObserver = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| animateCounter(entry.target); | |
| counterObserver.unobserve(entry.target); | |
| } | |
| }); | |
| }, { threshold: 0.5 }); | |
| counters.forEach(counter => { | |
| counterObserver.observe(counter); | |
| }); | |
| // ===== API Tab Switching ===== | |
| const apiTabs = document.querySelectorAll('.api-tab'); | |
| const apiCodes = document.querySelectorAll('.api-code'); | |
| apiTabs.forEach(tab => { | |
| tab.addEventListener('click', () => { | |
| const targetTab = tab.getAttribute('data-tab'); | |
| // Update tab buttons | |
| apiTabs.forEach(t => { | |
| t.classList.remove('active', 'bg-brand-500', 'text-white'); | |
| t.classList.add('bg-white/5', 'text-gray-400'); | |
| }); | |
| tab.classList.add('active', 'bg-brand-500', 'text-white'); | |
| tab.classList.remove('bg-white/5', 'text-gray-400'); | |
| // Update code display | |
| apiCodes.forEach(code => { | |
| if (code.getAttribute('data-code') === targetTab) { | |
| code.classList.remove('hidden'); | |
| } else { | |
| code.classList.add('hidden'); | |
| } | |
| }); | |
| }); | |
| }); | |
| // ===== Copy Code Button ===== | |
| const copyBtn = document.getElementById('copy-btn'); | |
| copyBtn.addEventListener('click', () => { | |
| const activeCode = document.querySelector('.api-code:not(.hidden)'); | |
| if (activeCode) { | |
| const textToCopy = activeCode.textContent; | |
| navigator.clipboard.writeText(textToCopy).then(() => { | |
| const icon = copyBtn.querySelector('[data-lucide]'); | |
| const originalText = copyBtn.textContent; | |
| copyBtn.innerHTML = '<i data-lucide="check" class="w-4 h-4"></i> کپی شد!'; | |
| lucide.createIcons(); | |
| setTimeout(() => { | |
| copyBtn.innerHTML = '<i data-lucide="copy" class="w-4 h-4"></i> کپی'; | |
| lucide.createIcons(); | |
| }, 2000); | |
| }); | |
| } | |
| }); | |
| // ===== Contact Form Submission ===== | |
| const contactForm = document.getElementById('contact-form'); | |
| contactForm.addEventListener('submit', (e) => { | |
| e.preventDefault(); | |
| const btn = contactForm.querySelector('button[type="submit"]'); | |
| const originalContent = btn.innerHTML; | |
| btn.innerHTML = '<i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i> در حال отправка...'; | |
| btn.disabled = true; | |
| lucide.createIcons(); | |
| setTimeout(() => { | |
| btn.innerHTML = '<i data-lucide="check-circle" class="w-5 h-5"></i> پیام ارسال شد!'; | |
| btn.classList.add('bg-green-500'); | |
| lucide.createIcons(); | |
| setTimeout(() => { | |
| btn.innerHTML = originalContent; | |
| btn.classList.remove('bg-green-500'); | |
| btn.disabled = false; | |
| contactForm.reset(); | |
| lucide.createIcons(); | |
| }, 2500); | |
| }, 1500); | |
| }); | |
| // ===== Smooth Scroll for Anchor Links ===== | |
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { | |
| anchor.addEventListener('click', function(e) { | |
| const targetId = this.getAttribute('href'); | |
| if (targetId === '#') return; | |
| const targetElement = document.querySelector(targetId); | |
| if (targetElement) { | |
| e.preventDefault(); | |
| const offset = 80; | |
| const targetPosition = targetElement.offsetTop - offset; | |
| window.scrollTo({ | |
| top: targetPosition, | |
| behavior: 'smooth' | |
| }); | |
| } | |
| }); | |
| }); | |
| // ===== Re-initialize icons after dynamic content ===== | |
| setTimeout(() => { | |
| lucide.createIcons(); | |
| }, 100); |