| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- // Mobile Navigation Toggle
- const hamburger = document.querySelector('.hamburger');
- const navMenu = document.querySelector('.nav-menu');
- hamburger.addEventListener('click', () => {
- hamburger.classList.toggle('active');
- navMenu.classList.toggle('active');
- });
- // Close mobile menu when clicking on a link
- document.querySelectorAll('.nav-link').forEach(link => {
- link.addEventListener('click', () => {
- hamburger.classList.remove('active');
- navMenu.classList.remove('active');
- });
- });
- // 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'
- });
- }
- });
- });
- // Active navigation link on scroll
- window.addEventListener('scroll', () => {
- let current = '';
- const sections = document.querySelectorAll('section');
-
- sections.forEach(section => {
- const sectionTop = section.offsetTop;
- const sectionHeight = section.clientHeight;
- if (scrollY >= (sectionTop - 200)) {
- current = section.getAttribute('id');
- }
- });
- document.querySelectorAll('.nav-link').forEach(link => {
- link.classList.remove('active');
- if (link.getAttribute('href').slice(1) === current) {
- link.classList.add('active');
- }
- });
- });
- // Header background on scroll
- window.addEventListener('scroll', () => {
- const navbar = document.querySelector('.navbar');
- if (window.scrollY > 50) {
- navbar.style.background = 'rgba(255, 255, 255, 0.95)';
- navbar.style.backdropFilter = 'blur(10px)';
- } else {
- navbar.style.background = 'white';
- navbar.style.backdropFilter = 'none';
- }
- });
- // Form submission handling
- const contactForm = document.querySelector('.contact-form form');
- if (contactForm) {
- contactForm.addEventListener('submit', function(e) {
- e.preventDefault();
-
- // Get form data
- const formData = new FormData(this);
- const name = this.querySelector('input[type="text"]').value;
- const email = this.querySelector('input[type="email"]').value;
- const phone = this.querySelector('input[type="tel"]').value;
- const service = this.querySelector('select').value;
- const message = this.querySelector('textarea').value;
-
- // Simple validation
- if (!name || !email || !message) {
- showNotification('Por favor, completa todos los campos obligatorios.', 'error');
- return;
- }
-
- // Email validation
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
- if (!emailRegex.test(email)) {
- showNotification('Por favor, introduce un email válido.', 'error');
- return;
- }
-
- // Simulate form submission (replace with actual endpoint)
- showNotification('¡Mensaje enviado con éxito! Nos pondremos en contacto contigo pronto.', 'success');
- this.reset();
- });
- }
- // Newsletter form handling
- const newsletterForm = document.querySelector('.newsletter-form');
- if (newsletterForm) {
- newsletterForm.addEventListener('submit', function(e) {
- e.preventDefault();
- const email = this.querySelector('input[type="email"]').value;
-
- if (!email) {
- showNotification('Por favor, introduce tu email.', 'error');
- return;
- }
-
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
- if (!emailRegex.test(email)) {
- showNotification('Por favor, introduce un email válido.', 'error');
- return;
- }
-
- // Simulate newsletter subscription
- showNotification('¡Gracias por suscribirte a nuestro newsletter!', 'success');
- this.reset();
- });
- }
- // 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;
-
- // Add styles
- notification.style.cssText = `
- position: fixed;
- top: 20px;
- right: 20px;
- padding: 15px 20px;
- border-radius: 8px;
- color: white;
- font-weight: 500;
- z-index: 10000;
- transform: translateX(100%);
- transition: transform 0.3s ease;
- max-width: 300px;
- `;
-
- // Set background color based on type
- switch(type) {
- case 'success':
- notification.style.background = '#10b981';
- break;
- case 'error':
- notification.style.background = '#ef4444';
- break;
- default:
- notification.style.background = '#3b82f6';
- }
-
- // Add to page
- document.body.appendChild(notification);
-
- // Animate in
- setTimeout(() => {
- notification.style.transform = 'translateX(0)';
- }, 100);
-
- // Remove after 5 seconds
- setTimeout(() => {
- notification.style.transform = 'translateX(100%)';
- setTimeout(() => {
- notification.remove();
- }, 300);
- }, 5000);
- }
- // Intersection Observer for animations
- const observerOptions = {
- threshold: 0.1,
- rootMargin: '0px 0px -50px 0px'
- };
- const observer = new IntersectionObserver((entries) => {
- entries.forEach(entry => {
- if (entry.isIntersecting) {
- entry.target.style.opacity = '1';
- entry.target.style.transform = 'translateY(0)';
- }
- });
- }, observerOptions);
- // Observe elements for animation
- document.addEventListener('DOMContentLoaded', () => {
- const animatedElements = document.querySelectorAll('.service-card, .project-card, .testimonial-card');
-
- animatedElements.forEach(el => {
- el.style.opacity = '0';
- el.style.transform = 'translateY(30px)';
- el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
- observer.observe(el);
- });
- });
- // Lazy loading for images
- const imageObserver = new IntersectionObserver((entries) => {
- entries.forEach(entry => {
- if (entry.isIntersecting) {
- const img = entry.target;
- img.style.opacity = '0';
- img.style.transition = 'opacity 0.5s ease';
-
- img.onload = () => {
- img.style.opacity = '1';
- };
-
- // Force load if not already loaded
- if (img.complete) {
- img.style.opacity = '1';
- }
-
- imageObserver.unobserve(img);
- }
- });
- });
- // Observe all images
- document.addEventListener('DOMContentLoaded', () => {
- const images = document.querySelectorAll('img');
- images.forEach(img => imageObserver.observe(img));
- });
- // Parallax effect for hero section
- window.addEventListener('scroll', () => {
- const scrolled = window.pageYOffset;
- const hero = document.querySelector('.hero');
- if (hero) {
- hero.style.transform = `translateY(${scrolled * 0.5}px)`;
- }
- });
- // Add loading animation
- window.addEventListener('load', () => {
- document.body.style.opacity = '0';
- document.body.style.transition = 'opacity 0.5s ease';
-
- setTimeout(() => {
- document.body.style.opacity = '1';
- }, 100);
- });
- // Counter animation for statistics
- function animateCounter(element, target, duration = 2000) {
- let start = 0;
- const increment = target / (duration / 16);
-
- const timer = setInterval(() => {
- start += increment;
- if (start >= target) {
- element.textContent = target;
- clearInterval(timer);
- } else {
- element.textContent = Math.floor(start);
- }
- }, 16);
- }
- // Initialize counters when in viewport
- const counterObserver = new IntersectionObserver((entries) => {
- entries.forEach(entry => {
- if (entry.isIntersecting && !entry.target.classList.contains('counted')) {
- const target = parseInt(entry.target.textContent);
- entry.target.classList.add('counted');
- animateCounter(entry.target, target);
- }
- });
- }, { threshold: 0.5 });
- // Add hover effects to cards
- document.addEventListener('DOMContentLoaded', () => {
- const cards = document.querySelectorAll('.service-card, .project-card, .testimonial-card');
-
- cards.forEach(card => {
- card.addEventListener('mouseenter', function() {
- this.style.transform = 'translateY(-10px) scale(1.02)';
- });
-
- card.addEventListener('mouseleave', function() {
- this.style.transform = 'translateY(0) scale(1)';
- });
- });
- });
- // Add active class to current navigation item
- document.addEventListener('DOMContentLoaded', () => {
- const currentPath = window.location.hash || '#inicio';
- const activeLink = document.querySelector(`.nav-link[href="${currentPath}"]`);
- if (activeLink) {
- activeLink.classList.add('active');
- }
- });
|