Monthly Archives: julio 2020

/* =============================================== JAVASCRIPT EFECTOS INTERACTIVOS - URBANO.COM.CO Copiar en: Theme Options > Advanced > Custom JS =============================================== */ (function($) { 'use strict'; // ============================================ // 1. CONTADOR ANIMADO DE NÚMEROS // ============================================ function animateCounter(element, start, end, duration) { let startTimestamp = null; const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); const value = Math.floor(progress * (end - start) + start); element.innerHTML = value + (element.dataset.suffix || ''); if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); } // Activar contadores cuando estén visibles const observerOptions = { threshold: 0.5, rootMargin: '0px' }; const statsObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && !entry.target.classList.contains('counted')) { entry.target.classList.add('counted'); // Stats section if (entry.target.classList.contains('stat-item')) { const numberElement = entry.target.querySelector('h3'); const targetNumber = parseInt(numberElement.textContent.replace(/\D/g, '')); animateCounter(numberElement, 0, targetNumber, 2000); } // Trust bar if (entry.target.classList.contains('trust-item')) { const numberElement = entry.target.querySelector('strong'); const targetNumber = parseInt(numberElement.textContent.replace(/\D/g, '')); animateCounter(numberElement, 0, targetNumber, 1500); } // Stats en sección Propiedad Horizontal if (entry.target.classList.contains('ph-stat')) { const numberElement = entry.target.querySelector('strong'); const targetNumber = parseInt(numberElement.textContent.replace(/\D/g, '')); animateCounter(numberElement, 0, targetNumber, 1500); } } }); }, observerOptions); // Observar elementos document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.stat-item, .trust-item, .ph-stat').forEach(el => { statsObserver.observe(el); }); }); // ============================================ // 2. SCROLL REVEAL - ANIMACIÓN AL HACER SCROLL // ============================================ const revealObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('revealed'); revealObserver.unobserve(entry.target); } }); }, { threshold: 0.15, rootMargin: '0px 0px -100px 0px' }); $(document).ready(function() { // Agregar clase scroll-reveal a elementos $('.service-main-card, .project-card, .testimonial-card, .process-step, .featured_box').each(function() { $(this).addClass('scroll-reveal'); revealObserver.observe(this); }); }); // ============================================ // 3. PARALLAX SUAVE EN HERO // ============================================ $(window).on('scroll', function() { const scrolled = $(window).scrollTop(); // Parallax en hero $('.hero-section').css('transform', 'translateY(' + (scrolled * 0.5) + 'px)'); // Fade out hero al hacer scroll const heroOpacity = 1 - (scrolled / 500); $('.hero-content').css('opacity', Math.max(heroOpacity, 0)); }); // ============================================ // 4. PROGRESO DE SCROLL (Barra superior) // ============================================ $(window).on('scroll', function() { const winScroll = document.body.scrollTop || document.documentElement.scrollTop; const height = document.documentElement.scrollHeight - document.documentElement.clientHeight; const scrolled = (winScroll / height) * 100; // Actualizar variable CSS document.documentElement.style.setProperty('--scroll', scrolled + '%'); }); // ============================================ // 5. SMOOTH SCROLL PARA ANCLAS // ============================================ $('a[href^="#"]').on('click', function(e) { const target = $(this.getAttribute('href')); if(target.length) { e.preventDefault(); $('html, body').stop().animate({ scrollTop: target.offset().top - 100 }, 1000, 'easeInOutExpo'); } }); // ============================================ // 6. FORMULARIO - VALIDACIÓN MEJORADA // ============================================ $('.wpcf7-form input, .wpcf7-form textarea, .wpcf7-form select').on('focus', function() { $(this).parent().addClass('focused'); }); $('.wpcf7-form input, .wpcf7-form textarea, .wpcf7-form select').on('blur', function() { if (!$(this).val()) { $(this).parent().removeClass('focused'); } }); // Animación al enviar formulario document.addEventListener('wpcf7submit', function(event) { const form = event.target; // Éxito if (event.detail.status === 'mail_sent') { // Confetti effect (opcional) if (typeof confetti !== 'undefined') { confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); } // Scroll a mensaje de éxito setTimeout(function() { const responseOutput = $(form).find('.wpcf7-response-output'); $('html, body').animate({ scrollTop: responseOutput.offset().top - 100 }, 500); }, 100); } }); // ============================================ // 7. LAZY LOAD MEJORADO PARA IMÁGENES // ============================================ if ('loading' in HTMLImageElement.prototype) { // Navegador soporta lazy loading nativo const images = document.querySelectorAll('img[loading="lazy"]'); images.forEach(img => { img.addEventListener('load', function() { this.classList.add('loaded'); }); }); } else { // Fallback con IntersectionObserver const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.add('loaded'); imageObserver.unobserve(img); } }); }); document.querySelectorAll('img[data-src]').forEach(img => { imageObserver.observe(img); }); } // ============================================ // 8. CURSOR PERSONALIZADO (Opcional - Premium) // ============================================ const cursor = $('
'); const cursorFollower = $('
'); // Solo en desktop if ($(window).width() > 1024) { $('body').append(cursor, cursorFollower); $(document).on('mousemove', function(e) { cursor.css({ left: e.clientX, top: e.clientY }); setTimeout(function() { cursorFollower.css({ left: e.clientX, top: e.clientY }); }, 100); }); // Efecto al hacer hover en elementos clickeables $('a, button, .button').on('mouseenter', function() { cursor.addClass('active'); cursorFollower.addClass('active'); }).on('mouseleave', function() { cursor.removeClass('active'); cursorFollower.removeClass('active'); }); } // ============================================ // 9. BOTÓN WHATSAPP - MOSTRAR/OCULTAR // ============================================ $(window).on('scroll', function() { if ($(this).scrollTop() > 300) { $('.whatsapp-float, .ai-chat-button').fadeIn(300); } else { $('.whatsapp-float, .ai-chat-button').fadeOut(300); } }); // ============================================ // 10. TESTIMONIOS - AUTO ROTATE (Opcional) // ============================================ let currentTestimonial = 0; const testimonials = $('.testimonial-card'); const testimonialCount = testimonials.length; function rotateTestimonials() { testimonials.removeClass('active'); testimonials.eq(currentTestimonial).addClass('active'); currentTestimonial = (currentTestimonial + 1) % testimonialCount; } // Auto-rotate cada 5 segundos (comentar si no quieres auto-rotate) // setInterval(rotateTestimonials, 5000); // ============================================ // 11. FAQ - ACORDEÓN PERSONALIZADO // ============================================ $('.accordion-title').on('click', function() { const item = $(this).parent(); const wasActive = item.hasClass('active'); // Cerrar todos $('.accordion-item').removeClass('active'); $('.accordion-inner').slideUp(300); // Abrir el clickeado si no estaba activo if (!wasActive) { item.addClass('active'); item.find('.accordion-inner').slideDown(300); } }); // ============================================ // 12. HEADER STICKY - EFECTO CAMBIO COLOR // ============================================ $(window).on('scroll', function() { if ($(this).scrollTop() > 100) { $('header, .header-wrapper').addClass('scrolled'); } else { $('header, .header-wrapper').removeClass('scrolled'); } }); // ============================================ // 13. PRELOADER (Opcional) // ============================================ $(window).on('load', function() { $('.preloader').fadeOut(500, function() { $(this).remove(); }); }); // ============================================ // 14. MODAL POPUP PARA PROYECTOS // ============================================ $('.project-card').on('click', function(e) { if (!$(e.target).is('a')) { const projectId = $(this).data('project-id'); // Abrir modal o lightbox con detalles del proyecto // Implementar según necesidades } }); // ============================================ // 15. BOTÓN "VOLVER ARRIBA" // ============================================ const backToTop = $(''); $('body').append(backToTop); $(window).on('scroll', function() { if ($(this).scrollTop() > 500) { backToTop.addClass('visible'); } else { backToTop.removeClass('visible'); } }); backToTop.on('click', function() { $('html, body').animate({ scrollTop: 0 }, 800); }); // ============================================ // 16. COOKIE CONSENT (GDPR) // ============================================ if (!localStorage.getItem('cookieConsent')) { const cookieBanner = ` `; $('body').append(cookieBanner); $('.accept-cookies').on('click', function() { localStorage.setItem('cookieConsent', 'true'); $('.cookie-consent').fadeOut(300, function() { $(this).remove(); }); }); } // ============================================ // 17. TRACKING DE EVENTOS PARA ANALYTICS // ============================================ // Click en botones CTA $('.button, .btn-primary').on('click', function() { const buttonText = $(this).text(); if (typeof gtag !== 'undefined') { gtag('event', 'cta_click', { 'button_text': buttonText, 'button_location': $(this).closest('section').attr('class') }); } }); // Click en teléfono $('a[href^="tel:"]').on('click', function() { if (typeof gtag !== 'undefined') { gtag('event', 'phone_click', { 'phone_number': $(this).attr('href') }); } }); // Click en WhatsApp $('.whatsapp-float').on('click', function() { if (typeof gtag !== 'undefined') { gtag('event', 'whatsapp_click', { 'action': 'open_chat' }); } }); // Click en servicios $('.service-main-card a').on('click', function() { const serviceName = $(this).closest('.service-main-card').find('h3').text(); if (typeof gtag !== 'undefined') { gtag('event', 'service_view', { 'service_name': serviceName }); } }); // ============================================ // 18. DETECCIÓN DE AD BLOCKER // ============================================ function detectAdBlocker() { const testAd = document.createElement('div'); testAd.innerHTML = ' '; testAd.className = 'adsbox'; document.body.appendChild(testAd); setTimeout(function() { if (testAd.offsetHeight === 0) { console.log('AdBlocker detectado'); // Mostrar mensaje opcional } testAd.remove(); }, 100); } detectAdBlocker(); // ============================================ // 19. PERFORMANCE - LAZY LOAD VIDEOS // ============================================ const videoObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const video = entry.target; video.src = video.dataset.src; video.load(); videoObserver.unobserve(video); } }); }); document.querySelectorAll('video[data-src]').forEach(video => { videoObserver.observe(video); }); // ============================================ // 20. MOBILE MENU - MEJORAS // ============================================ // Cerrar menú al hacer click en link $('.mobile-nav a').on('click', function() { $('.mobile-nav').removeClass('active'); $('body').removeClass('mobile-nav-open'); }); // Cerrar menú al hacer scroll let lastScroll = 0; $(window).on('scroll', function() { const currentScroll = $(this).scrollTop(); if (currentScroll > lastScroll && currentScroll > 100) { $('.mobile-nav').removeClass('active'); } lastScroll = currentScroll; }); // ============================================ // 21. EASTER EGG (Opcional - Diversión) // ============================================ let konamiCode = []; const pattern = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a']; $(document).on('keydown', function(e) { konamiCode.push(e.key); konamiCode = konamiCode.slice(-10); if (konamiCode.join('') === pattern.join('')) { console.log('¡Código Konami activado!'); // Agregar efecto especial $('body').addClass('konami-mode'); setTimeout(() => $('body').removeClass('konami-mode'), 5000); } }); // ============================================ // 22. OPTIMIZACIÓN - DEBOUNCE & THROTTLE // ============================================ function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } function throttle(func, limit) { let inThrottle; return function() { const args = arguments; const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } // Aplicar a eventos de resize y scroll const handleResize = debounce(function() { console.log('Resize finalizado'); // Acciones al cambiar tamaño }, 250); const handleScroll = throttle(function() { // Acciones al hacer scroll (optimizado) }, 100); $(window).on('resize', handleResize); $(window).on('scroll', handleScroll); // ============================================ // INICIALIZACIÓN FINAL // ============================================ console.log('🚀 Urbano.com.co - Scripts cargados correctamente'); })(jQuery); // ============================================ // STYLES CSS ADICIONALES PARA JS // ============================================ /* Agregar estos estilos en el CSS también */ /* .custom-cursor { width: 10px; height: 10px; background: #E31E24; border-radius: 50%; position: fixed; pointer-events: none; z-index: 9999; transition: transform 0.15s ease; } .custom-cursor.active { transform: scale(2); } .custom-cursor-follower { width: 30px; height: 30px; border: 2px solid #E31E24; border-radius: 50%; position: fixed; pointer-events: none; z-index: 9998; transition: all 0.15s ease; } .custom-cursor-follower.active { transform: scale(1.5); } .back-to-top { position: fixed; bottom: 120px; right: 40px; width: 50px; height: 50px; background: #E31E24; color: white; border: none; border-radius: 50%; font-size: 20px; cursor: pointer; opacity: 0; visibility: hidden; transition: all 0.3s ease; z-index: 98; } .back-to-top.visible { opacity: 1; visibility: visible; } .back-to-top:hover { transform: translateY(-5px); box-shadow: 0 5px 15px rgba(227, 30, 36, 0.4); } .cookie-consent { position: fixed; bottom: 0; left: 0; right: 0; background: #1a1a1a; color: white; padding: 20px; z-index: 9999; animation: slideInUp 0.5s ease-out; } .cookie-content { max-width: 1200px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 20px; } .cookie-content p { margin: 0; flex: 1; } .accept-cookies { background: #E31E24; color: white; border: none; padding: 10px 25px; border-radius: 4px; cursor: pointer; font-weight: 600; } .accept-cookies:hover { background: #c01a1f; } @keyframes slideInUp { from { transform: translateY(100%); } to { transform: translateY(0); } } .preloader { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: white; display: flex; align-items: center; justify-content: center; z-index: 99999; } .preloader::after { content: ''; width: 50px; height: 50px; border: 5px solid #f3f3f3; border-top: 5px solid #E31E24; border-radius: 50%; animation: spin 1s linear infinite; } */