argobox-portfolio/script.js

260 lines
8.1 KiB
JavaScript

/**
* Main JavaScript file for argobox.com
* Handles animations, interactions, and dynamic content
*/
document.addEventListener('DOMContentLoaded', function() {
// Initialize all website functionality
initNavigation();
initParticlesAndIcons();
initTerminalTyping();
updateYear();
});
/**
* Set up navigation functionality - mobile menu and scroll spy
*/
function initNavigation() {
const menuToggle = document.querySelector('.menu-toggle');
const navMenu = document.querySelector('.nav-menu');
const navLinks = document.querySelectorAll('.nav-link');
if (menuToggle && navMenu) {
// Toggle mobile menu
menuToggle.addEventListener('click', () => {
toggleMobileMenu();
});
// Close mobile menu when clicking outside
document.addEventListener('click', (e) => {
if (navMenu.classList.contains('show') &&
!navMenu.contains(e.target) &&
!menuToggle.contains(e.target)) {
toggleMobileMenu();
}
});
// Close mobile menu when link is clicked
navLinks.forEach(link => {
link.addEventListener('click', () => {
if (window.innerWidth <= 768 && navMenu.classList.contains('show')) {
toggleMobileMenu();
}
});
});
// Handle resize events
window.addEventListener('resize', () => {
if (window.innerWidth > 768 && navMenu.classList.contains('show')) {
navMenu.classList.remove('show');
updateMenuIcon(false);
}
});
}
// Toggle function for mobile menu
function toggleMobileMenu() {
navMenu.classList.toggle('show');
updateMenuIcon(navMenu.classList.contains('show'));
// Prevent body scrolling when menu is open
if (navMenu.classList.contains('show')) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
}
// Update menu icon based on menu state
function updateMenuIcon(isOpen) {
const icon = menuToggle.querySelector('i');
if (isOpen) {
icon.classList.remove('fa-bars');
icon.classList.add('fa-times');
} else {
icon.classList.remove('fa-times');
icon.classList.add('fa-bars');
}
}
// Scroll spy for navigation
window.addEventListener('scroll', () => {
const sections = document.querySelectorAll('section');
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop;
if (window.scrollY >= sectionTop - 100) {
current = section.getAttribute('id');
}
});
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href').substring(1) === current) {
link.classList.add('active');
}
});
});
}
/**
* Create background particles and floating tech icons
*/
function initParticlesAndIcons() {
createBackgroundParticles();
createFloatingIcons();
}
/**
* Optimize images for better mobile performance
*/
function optimizeImagesForMobile() {
if (window.innerWidth <= 768) {
// Reduce particles count on mobile for better performance
createBackgroundParticles(15); // Fewer particles
} else {
createBackgroundParticles(50); // Normal number of particles
}
}
/**
* Create animated background particles
*/
function createBackgroundParticles(count = 50) {
const particlesContainer = document.getElementById('particles-container');
if (!particlesContainer) return;
// Clear existing particles
particlesContainer.innerHTML = '';
// Create particles
for (let i = 0; i < count; i++) {
const particle = document.createElement('div');
particle.classList.add('particle');
// Random size between 2 and 6px
const size = Math.random() * 4 + 2;
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
// Random position
particle.style.left = `${Math.random() * 100}%`;
particle.style.top = `${Math.random() * 100}%`;
// Random opacity between 0.1 and 0.3
particle.style.opacity = (Math.random() * 0.2 + 0.1).toString();
// Animation properties
particle.style.animation = `float-particle ${Math.random() * 20 + 10}s linear infinite`;
particle.style.animationDelay = `${Math.random() * 10}s`;
particlesContainer.appendChild(particle);
}
}
/**
* Initialize terminal typing animation
*/
function initTerminalTyping() {
const cursor = document.querySelector('.cursor');
if (cursor) {
setInterval(() => {
cursor.style.opacity = cursor.style.opacity === '0' ? '1' : '0';
}, 600);
}
}
/**
* Update copyright year in the footer
*/
function updateYear() {
const yearElement = document.getElementById('current-year');
if (yearElement) {
yearElement.textContent = new Date().getFullYear();
}
}
/**
* Create and initialize floating icons in the hero section
*/
function createFloatingIcons() {
// Implemented if needed for mobile
}
// Initialize responsive behaviors
window.addEventListener('resize', () => {
optimizeImagesForMobile();
});
// Call once on page load
optimizeImagesForMobile();
// Contact Form Handler
const contactForm = document.getElementById('contact-form');
if (contactForm) {
contactForm.addEventListener('submit', async (e) => {
e.preventDefault();
const submitButton = contactForm.querySelector('button[type="submit"]');
const originalButtonText = submitButton.innerHTML;
try {
submitButton.disabled = true;
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
const formData = new FormData(contactForm);
const data = {
name: formData.get('name'),
email: formData.get('email'),
subject: formData.get('subject'),
message: formData.get('message')
};
const response = await fetch('/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (response.ok) {
// Show success message
const successMessage = document.createElement('div');
successMessage.className = 'alert alert-success';
successMessage.innerHTML = '<i class="fas fa-check-circle"></i> Message sent successfully! We\'ll get back to you soon.';
contactForm.insertBefore(successMessage, submitButton);
contactForm.reset();
// Remove success message after 5 seconds
setTimeout(() => {
successMessage.remove();
}, 5000);
} else {
throw new Error(result.error || 'Failed to send message');
}
} catch (error) {
console.error('Error sending email:', error);
// Show error message
const errorMessage = document.createElement('div');
errorMessage.className = 'alert alert-error';
errorMessage.innerHTML = '<i class="fas fa-exclamation-circle"></i> Failed to send message. Please try again later.';
contactForm.insertBefore(errorMessage, submitButton);
// Remove error message after 5 seconds
setTimeout(() => {
errorMessage.remove();
}, 5000);
} finally {
submitButton.disabled = false;
submitButton.innerHTML = originalButtonText;
}
});
}