/** * Main JavaScript file for argobox.com * Handles animations, interactions, and dynamic content */ document.addEventListener('DOMContentLoaded', function() { // Initialize all website functionality initNavigation(); initParticlesAndIcons(); initRoleAnimation(); initTerminalTyping(); initSolutionsCarousel(); initScrollReveal(); updateMetrics(); updateYear(); // Initialize form handling const contactForm = document.getElementById('contact-form'); if (contactForm) { initFormHandling(contactForm); } // Highlight navigation on scroll setupScrollSpy(); // Setup role switching with improved timing setupRoleSwitching(); // Other initializations... setupFloatingIcons(); setupParticles(); setupRevealAnimations(); initializeSlider(); // Contact form handling setupContactForm(); // Mobile menu toggle document.querySelector('.menu-toggle').addEventListener('click', function() { document.querySelector('.nav-menu').classList.toggle('active'); }); // Navbar effects on scroll window.addEventListener('scroll', function() { const navbar = document.querySelector('.navbar'); if (window.scrollY > 50) { navbar.classList.add('scrolled'); } else { navbar.classList.remove('scrolled'); } }); }); /** * Set up navigation functionality - mobile menu and scroll spy */ function initNavigation() { // Mobile menu toggle const menuToggle = document.querySelector('.menu-toggle'); const navMenu = document.querySelector('.nav-menu'); if (menuToggle && navMenu) { menuToggle.addEventListener('click', function() { navMenu.classList.toggle('active'); menuToggle.setAttribute('aria-expanded', menuToggle.getAttribute('aria-expanded') === 'true' ? 'false' : 'true'); }); } // Navigation scroll spy const sections = document.querySelectorAll('section[id]'); const navLinks = document.querySelectorAll('.nav-link'); function updateActiveNavLink() { let scrollPosition = window.scrollY + 100; sections.forEach(section => { const sectionTop = section.offsetTop; const sectionHeight = section.offsetHeight; const sectionId = section.getAttribute('id'); if (scrollPosition >= sectionTop && scrollPosition < sectionTop + sectionHeight) { navLinks.forEach(link => { link.classList.remove('active'); if (link.getAttribute('href') === `#${sectionId}`) { link.classList.add('active'); } }); } }); } // Navbar style change on scroll const navbar = document.querySelector('.navbar'); function updateNavbarStyle() { if (window.scrollY > 50) { navbar?.classList.add('scrolled'); } else { navbar?.classList.remove('scrolled'); } } window.addEventListener('scroll', () => { updateActiveNavLink(); updateNavbarStyle(); }); // Initial call to set correct states updateActiveNavLink(); updateNavbarStyle(); } /** * Create background particles and floating tech icons */ function initParticlesAndIcons() { createBackgroundParticles(); createFloatingIcons(); } /** * Create animated background particles */ function createBackgroundParticles() { const particlesContainer = document.getElementById('particles-container'); if (!particlesContainer) return; particlesContainer.innerHTML = ''; for (let i = 0; i < 40; i++) { const particle = document.createElement('div'); particle.classList.add('particle'); // Random size, opacity, and position const size = Math.random() * 4 + 1; const opacity = Math.random() * 0.3 + 0.1; particle.style.width = `${size}px`; particle.style.height = `${size}px`; particle.style.opacity = opacity; // Position randomly with some clustering toward top areas const xPos = Math.random() * 100; const yPos = Math.random() * 100; particle.style.left = `${xPos}%`; particle.style.top = `${yPos}%`; // Animation properties const duration = Math.random() * 20 + 10; particle.style.animationDuration = `${duration}s`; particle.style.animationDelay = `${Math.random() * -duration}s`; // Add particle animation particle.style.animation = `float-particle ${duration}s linear infinite`; particlesContainer.appendChild(particle); } } /** * Create floating tech icons in the background */ function createFloatingIcons() { const iconContainer = document.getElementById('floating-icons'); if (!iconContainer) return; iconContainer.innerHTML = ''; // Tech-related unicode symbols and fontawesome classes const icons = [ '⚙️', '💻', '🔒', '🔌', '🌐', '☁️', '📊', 'fa-server', 'fa-network-wired', 'fa-database', 'fa-code-branch', 'fa-cloud', 'fa-shield-alt' ]; for (let i = 0; i < 12; i++) { const icon = document.createElement('div'); icon.classList.add('floating-icon'); const iconType = icons[Math.floor(Math.random() * icons.length)]; // Handle both unicode and font awesome if (iconType.startsWith('fa-')) { const faIcon = document.createElement('i'); faIcon.className = `fas ${iconType}`; icon.appendChild(faIcon); } else { icon.textContent = iconType; } // Random size and position const size = Math.random() * 24 + 16; icon.style.fontSize = `${size}px`; // Position icon.style.left = `${Math.random() * 100}%`; icon.style.bottom = `-50px`; // Animation icon.style.animationDuration = `${Math.random() * 30 + 20}s`; icon.style.animationDelay = `${Math.random() * 10}s`; iconContainer.appendChild(icon); } } /** * Initialize role rotation in the hero section */ function initRoleAnimation() { const roles = document.querySelectorAll('.role'); const description = document.getElementById('role-description'); let currentIndex = 0; function updateRole() { roles.forEach(role => role.classList.remove('active')); roles[currentIndex].classList.add('active'); description.textContent = roles[currentIndex].getAttribute('data-description'); description.style.opacity = '0'; setTimeout(() => { description.style.opacity = '1'; }, 100); currentIndex = (currentIndex + 1) % roles.length; } updateRole(); // Set initial state setInterval(updateRole, 5000); // Switch roles every 5 seconds } /** * Initialize terminal typing animation in the hero section */ function initTerminalTyping() { const terminalText = document.getElementById('terminal-text'); if (!terminalText) return; const terminalMessages = [ "> Ready for deployment...", "> Reducing operational costs by 30%", "> Improving system reliability to 99.9%", "> Accelerating digital transformation", "> Enhancing security compliance", "> Streamlining IT workflows", "> Optimizing infrastructure performance", "> Implementing best practices", "> Supporting business objectives" ]; let currentMessage = 0; function typeMessage(message, index = 0) { if (index < message.length) { terminalText.textContent = message.substring(0, index + 1); setTimeout(() => typeMessage(message, index + 1), 50 + Math.random() * 50); } else { // Wait before clearing and typing next message setTimeout(clearAndTypeNext, 3000); } } function clearAndTypeNext() { // Clear the current text with a backspace effect const currentText = terminalText.textContent; function backspace(length = currentText.length) { if (length > 0) { terminalText.textContent = currentText.substring(0, length - 1); setTimeout(() => backspace(length - 1), 20); } else { // Move to next message currentMessage = (currentMessage + 1) % terminalMessages.length; setTimeout(() => typeMessage(terminalMessages[currentMessage]), 500); } } backspace(); } // Start the typing animation with the first message typeMessage(terminalMessages[0]); } /** * Initialize the solutions carousel */ function initSolutionsCarousel() { const slides = document.querySelectorAll('.solution-slide'); const dots = document.querySelectorAll('.slider-dot'); if (slides.length === 0 || dots.length === 0) return; let currentSlide = 0; let slideInterval; function showSlide(index) { // Hide all slides slides.forEach(slide => slide.classList.remove('active')); dots.forEach(dot => dot.classList.remove('active')); // Show selected slide slides[index].classList.add('active'); dots[index].classList.add('active'); currentSlide = index; } function nextSlide() { const next = (currentSlide + 1) % slides.length; showSlide(next); } // Add click events to dots dots.forEach((dot, index) => { dot.addEventListener('click', () => { clearInterval(slideInterval); showSlide(index); // Restart automatic rotation slideInterval = setInterval(nextSlide, 5000); }); }); // Start automatic rotation slideInterval = setInterval(nextSlide, 5000); // Show first slide initially showSlide(0); } /** * Add scroll reveal animations to elements */ function initScrollReveal() { const revealElements = document.querySelectorAll('.section-header, .service-card, .project-card, .lab-card, .timeline-item, .contact-item'); revealElements.forEach(element => { element.classList.add('reveal'); }); function checkReveal() { revealElements.forEach(element => { const elementTop = element.getBoundingClientRect().top; const elementVisible = 150; if (elementTop < window.innerHeight - elementVisible) { element.classList.add('active'); } }); } // Initial check checkReveal(); // Check on scroll window.addEventListener('scroll', checkReveal); } /** * Update metrics values periodically to simulate live data */ function updateMetrics() { const metrics = { 'CPU Usage': { min: 30, max: 60, element: null }, 'Memory': { min: 45, max: 70, element: null }, 'Storage': { min: 60, max: 75, element: null }, 'Network': { min: 15, max: 40, element: null } }; // Get all metric elements document.querySelectorAll('.metric').forEach(metric => { const nameElement = metric.querySelector('.metric-name'); if (nameElement && metrics[nameElement.textContent]) { metrics[nameElement.textContent].element = metric; } }); function updateMetricValues() { Object.keys(metrics).forEach(key => { const metric = metrics[key]; if (!metric.element) return; const valueEl = metric.element.querySelector('.metric-value'); const progressEl = metric.element.querySelector('.metric-progress'); if (valueEl && progressEl) { const newValue = Math.floor(Math.random() * (metric.max - metric.min)) + metric.min; valueEl.textContent = `${newValue}%`; progressEl.style.width = `${newValue}%`; } }); } // Update metrics every 5 seconds setInterval(updateMetricValues, 5000); } /** * Initialize contact form handling */ function initFormHandling(form) { // Prevent multiple initializations if (form.hasAttribute('data-initialized')) return; form.setAttribute('data-initialized', 'true'); form.addEventListener('submit', async function (e) { e.preventDefault(); const submitButton = form.querySelector('button[type="submit"]'); const originalButtonText = submitButton.innerHTML; submitButton.innerHTML = ' Sending...'; submitButton.disabled = true; const notification = document.getElementById('form-notification'); const notificationIcon = notification.querySelector('i'); const notificationText = notification.querySelector('.notification-text'); // Hide any existing notification with animation if (notification.style.display === 'flex') { notification.classList.add('hiding'); await new Promise(resolve => setTimeout(resolve, 300)); notification.classList.remove('hiding'); notification.style.display = 'none'; } const formData = { name: form.elements['name'].value, email: form.elements['email'].value, subject: form.elements['subject'].value, message: form.elements['message'].value }; try { const res = await fetch("/api/send-email", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(formData) }); const data = await res.json(); notification.style.display = 'flex'; if (res.ok) { notification.classList.remove('error'); notification.classList.add('success'); notificationIcon.className = 'fas fa-check-circle'; notificationText.textContent = "Message sent successfully! We'll get back to you soon."; form.reset(); } else { notification.classList.remove('success'); notification.classList.add('error'); notificationIcon.className = 'fas fa-exclamation-circle'; notificationText.textContent = data.error + (data.details ? `: ${data.details}` : ''); } } catch (error) { console.error("Form submission error:", error); notification.style.display = 'flex'; notification.classList.remove('success'); notification.classList.add('error'); notificationIcon.className = 'fas fa-exclamation-circle'; notificationText.textContent = `Error: ${error.message}`; } finally { submitButton.innerHTML = originalButtonText; submitButton.disabled = false; // Hide notification after 5 seconds with animation setTimeout(() => { notification.classList.add('hiding'); setTimeout(() => { notification.classList.remove('hiding'); notification.style.display = 'none'; }, 300); }, 5000); } }); } /** * Update copyright year in the footer */ function updateYear() { const yearElement = document.getElementById('current-year'); if (yearElement) { yearElement.textContent = new Date().getFullYear(); } } /** * Sets up scroll spy functionality to highlight nav links * as the user scrolls through different sections */ function setupScrollSpy() { const sections = document.querySelectorAll('section[id]'); const navLinks = document.querySelectorAll('.nav-link'); window.addEventListener('scroll', function() { let current = ''; sections.forEach(section => { const sectionTop = section.offsetTop - 100; const sectionHeight = section.offsetHeight; if (window.scrollY >= sectionTop && window.scrollY < sectionTop + sectionHeight) { current = section.getAttribute('id'); } }); navLinks.forEach(link => { link.classList.remove('active'); if (link.getAttribute('href') === `#${current}`) { link.classList.add('active'); } }); }); } /** * Sets up automated role switching with better timing and transitions */ function setupRoleSwitching() { const roles = document.querySelectorAll('.role'); const roleDescription = document.getElementById('role-description'); let currentRoleIndex = 0; // Initial role description if (roles.length > 0 && roleDescription) { roleDescription.textContent = roles[0].getAttribute('data-description'); roles[0].classList.add('active'); } // Switch roles every 5 seconds with fade transition setInterval(() => { // Remove active class from current role roles[currentRoleIndex].classList.remove('active'); // Move to the next role or back to the first currentRoleIndex = (currentRoleIndex + 1) % roles.length; // Add active class to new role roles[currentRoleIndex].classList.add('active'); // Update the role description with fade effect if (roleDescription) { roleDescription.style.opacity = '0'; setTimeout(() => { roleDescription.textContent = roles[currentRoleIndex].getAttribute('data-description'); roleDescription.style.opacity = '1'; }, 300); } }, 5000); } // Replace the existing setupFloatingIcons with this improved version function setupFloatingIcons() { const container = document.getElementById('floating-icons'); if (!container) return; // Clear existing icons container.innerHTML = ''; // Tech icons to display const icons = [ 'fa-server', 'fa-network-wired', 'fa-shield-alt', 'fa-cloud', 'fa-code-branch', 'fa-database', 'fa-laptop-code', 'fa-lock', 'fa-terminal' ]; // Create floating icons icons.forEach(icon => { const iconElement = document.createElement('div'); iconElement.className = 'floating-icon'; iconElement.innerHTML = ``; // Random starting position const randomX = Math.floor(Math.random() * 100); const randomY = Math.floor(Math.random() * 100); const randomDelay = Math.random() * 5; const randomDuration = 20 + Math.random() * 10; // Apply styles iconElement.style.left = `${randomX}%`; iconElement.style.top = `${randomY}%`; iconElement.style.animationDelay = `${randomDelay}s`; iconElement.style.animationDuration = `${randomDuration}s`; // Add to container container.appendChild(iconElement); }); } // More existing code...