/** * Main JavaScript * @package MartinsEVieira */ (function() { 'use strict'; const body = document.body; // ============= UTILITÁRIOS ============= /** * Debounce function para otimizar performance */ function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } /** * Cache de elementos do DOM */ const elements = { cookieBanner: document.getElementById('cookie-banner'), cookieAccept: document.getElementById('cookie-accept'), cookieDecline: document.getElementById('cookie-decline'), themeToggle: document.getElementById('theme-toggle'), themeToggleMobile: document.getElementById('theme-toggle-mobile'), mobileMenuToggle: document.getElementById('mobile-menu-toggle'), mobileMenuClose: document.getElementById('mobile-menu-close'), mobileNav: document.getElementById('mobile-nav'), mobileMenuOverlay: document.getElementById('mobile-menu-overlay'), header: document.querySelector('.site-header'), loadMoreBtn: document.getElementById('load-more-posts'), postsContainer: document.getElementById('posts-container'), loadingSpinner: document.getElementById('loading-spinner') }; // ============= BANNER DE COOKIES (LGPD) ============= function initCookieBanner() { if (!elements.cookieBanner) return; const cookieConsent = localStorage.getItem('cookieConsent'); if (!cookieConsent) { setTimeout(() => { elements.cookieBanner.classList.add('show'); }, 1000); } function handleCookieConsent(accepted) { localStorage.setItem('cookieConsent', accepted ? 'accepted' : 'declined'); localStorage.setItem('cookieConsentDate', new Date().toISOString()); elements.cookieBanner.classList.remove('show'); } if (elements.cookieAccept) { elements.cookieAccept.addEventListener('click', () => handleCookieConsent(true)); } if (elements.cookieDecline) { elements.cookieDecline.addEventListener('click', () => handleCookieConsent(false)); } } // ============= MODO ESCURO ============= function initDarkMode() { const toggles = [elements.themeToggle, elements.themeToggleMobile].filter(Boolean); if (toggles.length === 0) return; const currentTheme = localStorage.getItem('theme'); // Aplicar tema inicial if (currentTheme === 'light') { body.classList.remove('dark-mode'); toggles.forEach(toggle => { const icon = toggle.querySelector('i'); icon?.classList.replace('fa-sun', 'fa-moon'); }); } else { body.classList.add('dark-mode'); toggles.forEach(toggle => { const icon = toggle.querySelector('i'); icon?.classList.replace('fa-moon', 'fa-sun'); }); if (!currentTheme) { localStorage.setItem('theme', 'dark'); } } // Toggle modo escuro function toggleDarkMode(e) { e.preventDefault(); e.stopPropagation(); body.classList.toggle('dark-mode'); const isDark = body.classList.contains('dark-mode'); localStorage.setItem('theme', isDark ? 'dark' : 'light'); toggles.forEach(toggle => { const icon = toggle.querySelector('i'); if (icon) { icon.classList.replace(isDark ? 'fa-moon' : 'fa-sun', isDark ? 'fa-sun' : 'fa-moon'); } }); } toggles.forEach(toggle => { toggle.addEventListener('click', toggleDarkMode); }); } // ============= MENU MOBILE ============= function initMobileMenu() { if (!elements.mobileMenuToggle || !elements.mobileNav || !elements.mobileMenuOverlay) { return; } function openMenu() { elements.mobileMenuToggle.classList.add('active'); elements.mobileMenuToggle.setAttribute('aria-expanded', 'true'); elements.mobileNav.classList.add('active'); elements.mobileMenuOverlay.classList.add('active'); body.classList.add('menu-open'); } function closeMenu() { elements.mobileMenuToggle.classList.remove('active'); elements.mobileMenuToggle.setAttribute('aria-expanded', 'false'); elements.mobileNav.classList.remove('active'); elements.mobileMenuOverlay.classList.remove('active'); body.classList.remove('menu-open'); } function toggleMenu() { if (elements.mobileNav.classList.contains('active')) { closeMenu(); } else { openMenu(); } } // Abrir/fechar menu ao clicar no botão hamburguer elements.mobileMenuToggle.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); toggleMenu(); }); // Fechar menu ao clicar no botão X if (elements.mobileMenuClose) { elements.mobileMenuClose.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); closeMenu(); }); } // Fechar menu ao clicar no overlay elements.mobileMenuOverlay.addEventListener('click', (e) => { e.preventDefault(); closeMenu(); }); // Fechar menu ao clicar em links const mobileLinks = elements.mobileNav.querySelectorAll('a'); mobileLinks.forEach(link => { link.addEventListener('click', (e) => { // Não previne o comportamento padrão para permitir navegação // Apenas fecha o menu closeMenu(); }); }); // Fechar menu ao clicar no botão de tema mobile if (elements.themeToggleMobile) { elements.themeToggleMobile.addEventListener('click', (e) => { // Não fecha imediatamente, só após trocar tema // O evento de tema já está tratado em initDarkMode }); } // Fechar menu com tecla ESC document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && elements.mobileNav.classList.contains('active')) { closeMenu(); } }); } // ============= SMOOTH SCROLL ============= function initSmoothScroll() { document.addEventListener('click', (e) => { const anchor = e.target.closest('a[href*="#"]'); if (!anchor) return; const href = anchor.getAttribute('href'); const hashIndex = href.indexOf('#'); if (hashIndex === -1) return; const hash = href.substring(hashIndex); const targetId = hash.substring(1); const target = document.getElementById(targetId); if (target) { e.preventDefault(); target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); } // ============= HEADER SCROLL ============= function initHeaderScroll() { if (!elements.header) return; let lastScrollY = window.scrollY; let ticking = false; const updateHeader = () => { const shouldElevate = lastScrollY > 100; elements.header.style.boxShadow = shouldElevate ? '0 4px 20px rgba(0,0,0,0.15)' : '0 2px 10px rgba(0,0,0,0.1)'; ticking = false; }; const handleScroll = () => { lastScrollY = window.scrollY; if (!ticking) { window.requestAnimationFrame(updateHeader); ticking = true; } }; window.addEventListener('scroll', handleScroll, { passive: true }); } // ============= ANIMAÇÃO CARDS ============= function initCardAnimations() { const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // Usar requestAnimationFrame para animação suave requestAnimationFrame(() => { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; }); // Parar de observar após animar observer.unobserve(entry.target); } }); }, observerOptions); const cards = document.querySelectorAll('.area-card, .post-card, .post-card-archive'); cards.forEach(card => { card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; card.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; observer.observe(card); }); } // ============= EFEITO RIPPLE ============= function initRippleEffect() { document.addEventListener('click', (e) => { const card = e.target.closest('.area-card'); if (!card) return; const ripple = document.createElement('span'); ripple.classList.add('ripple-effect'); const rect = card.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; ripple.style.left = x + 'px'; ripple.style.top = y + 'px'; card.appendChild(ripple); setTimeout(() => ripple.remove(), 600); }); } // ============= CARREGAR MAIS POSTS ============= function initLoadMorePosts() { if (!elements.loadMoreBtn || !elements.postsContainer) return; elements.loadMoreBtn.addEventListener('click', async function() { const currentPage = parseInt(this.getAttribute('data-page')); const maxPages = parseInt(this.getAttribute('data-max')); const nextPage = currentPage + 1; // Mostrar spinner elements.loadMoreBtn.style.display = 'none'; elements.loadingSpinner.style.display = 'block'; const formData = new FormData(); formData.append('action', 'load_more_posts'); formData.append('page', nextPage); formData.append('nonce', ajaxData.nonce); try { const response = await fetch(ajaxData.ajaxurl, { method: 'POST', body: formData }); const data = await response.json(); if (data.success) { const tempDiv = document.createElement('div'); tempDiv.innerHTML = data.data.posts; const newPosts = tempDiv.querySelectorAll('.post-card'); newPosts.forEach((post, index) => { post.style.opacity = '0'; post.style.transform = 'translateY(20px)'; elements.postsContainer.appendChild(post); setTimeout(() => { post.style.transition = 'all 0.6s ease'; post.style.opacity = '1'; post.style.transform = 'translateY(0)'; }, index * 100); }); elements.loadMoreBtn.setAttribute('data-page', nextPage); if (nextPage >= maxPages) { elements.loadMoreBtn.style.display = 'none'; elements.loadingSpinner.style.display = 'none'; } else { elements.loadMoreBtn.style.display = 'inline-flex'; elements.loadingSpinner.style.display = 'none'; } } else { elements.loadMoreBtn.style.display = 'none'; elements.loadingSpinner.style.display = 'none'; } } catch (error) { elements.loadMoreBtn.style.display = 'inline-flex'; elements.loadingSpinner.style.display = 'none'; } }); } // ============= INICIALIZAÇÃO ============= /** * Lazy loading de imagens nativas */ function initLazyLoading() { // Verificar se o navegador suporta lazy loading nativo if ('loading' in HTMLImageElement.prototype) { const images = document.querySelectorAll('img[loading="lazy"]'); images.forEach(img => { if (img.dataset.src) { img.src = img.dataset.src; } }); } else { // Fallback: usar Intersection Observer const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; if (img.dataset.src) { img.src = img.dataset.src; img.removeAttribute('data-src'); } observer.unobserve(img); } }); }); document.querySelectorAll('img[loading="lazy"]').forEach(img => { imageObserver.observe(img); }); } } document.addEventListener('DOMContentLoaded', () => { initCookieBanner(); initDarkMode(); initMobileMenu(); initSmoothScroll(); initHeaderScroll(); initCardAnimations(); initRippleEffect(); initLoadMorePosts(); initLazyLoading(); }); })();