1/** 2 * WP Frank Theme - Main JavaScript 3 * Handles: mobile menu, scroll animations, FAQ accordion, marketplace tabs, smooth scroll 4 */ 5document.addEventListener('DOMContentLoaded', function () { 6 7 // === Mobile Menu Toggle === 8 const mobileMenuBtn = document.getElementById('mobile-menu-btn'); 9 const mobileMenu = document.getElementById('mobile-menu'); 10 const mobileMenuClose = document.getElementById('mobile-menu-close'); 11 const mobileMenuOverlay = document.getElementById('mobile-menu-overlay'); 12 13 function openMobileMenu() { 14 if (mobileMenu) { 15 mobileMenu.classList.remove('translate-x-full'); 16 mobileMenu.classList.add('translate-x-0'); 17 } 18 if (mobileMenuOverlay) { 19 mobileMenuOverlay.classList.remove('hidden'); 20 mobileMenuOverlay.classList.add('block'); 21 } 22 document.body.style.overflow = 'hidden'; 23 } 24 25 function closeMobileMenu() { 26 if (mobileMenu) { 27 mobileMenu.classList.remove('translate-x-0'); 28 mobileMenu.classList.add('translate-x-full'); 29 } 30 if (mobileMenuOverlay) { 31 mobileMenuOverlay.classList.remove('block'); 32 mobileMenuOverlay.classList.add('hidden'); 33 } 34 document.body.style.overflow = ''; 35 } 36 37 if (mobileMenuBtn) mobileMenuBtn.addEventListener('click', openMobileMenu); 38 if (mobileMenuClose) mobileMenuClose.addEventListener('click', closeMobileMenu); 39 if (mobileMenuOverlay) mobileMenuOverlay.addEventListener('click', closeMobileMenu); 40 41 // === Scroll-based Navigation Shrink === 42 const nav = document.querySelector('nav.fixed'); 43 if (nav) { 44 window.addEventListener('scroll', function () { 45 if (window.scrollY > 50) { 46 nav.classList.add('shadow-md', 'bg-white/95'); 47 } else { 48 nav.classList.remove('shadow-md', 'bg-white/95'); 49 } 50 }); 51 } 52 53 // === Scroll Reveal Animation (Intersection Observer) === 54 const revealElements = document.querySelectorAll('.reveal-item'); 55 if (revealElements.length > 0) { 56 const revealObserver = new IntersectionObserver(function (entries) { 57 entries.forEach(function (entry) { 58 if (entry.isIntersecting) { 59 entry.target.classList.add('opacity-100', 'translate-y-0'); 60 entry.target.classList.remove('opacity-0', 'translate-y-8'); 61 revealObserver.unobserve(entry.target); 62 } 63 }); 64 }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); 65 66 revealElements.forEach(function (el) { 67 el.classList.add('opacity-0', 'translate-y-8'); 68 revealObserver.observe(el); 69 }); 70 } 71 72 // === FAQ Accordion === 73 const faqQuestions = document.querySelectorAll('.faq-question'); 74 faqQuestions.forEach(function (question) { 75 question.addEventListener('click', function () { 76 const answer = this.nextElementSibling; 77 const icon = this.querySelector('.faq-icon'); 78 const isActive = answer.classList.contains('active'); 79 80 // Close all 81 document.querySelectorAll('.faq-answer').forEach(function (a) { 82 a.classList.remove('active'); 83 a.style.maxHeight = null; 84 }); 85 document.querySelectorAll('.faq-icon').forEach(function (i) { 86 i.style.transform = 'rotate(0deg)'; 87 }); 88 89 // Open clicked (if it was closed) 90 if (!isActive) { 91 answer.classList.add('active'); 92 answer.style.maxHeight = answer.scrollHeight + 'px'; 93 if (icon) icon.style.transform = 'rotate(180deg)'; 94 } 95 }); 96 }); 97 98 // === Marketplace Tabs (Themes / Plugins) === 99 const tabBtns = document.querySelectorAll('[data-tab-target]'); 100 tabBtns.forEach(function (btn) { 101 btn.addEventListener('click', function () { 102 const target = this.getAttribute('data-tab-target'); 103 104 // Deactivate all tabs 105 tabBtns.forEach(function (b) { 106 b.classList.remove('bg-primary', 'text-white', 'shadow-btn-primary'); 107 b.classList.add('bg-gray-100', 'text-text-muted'); 108 }); 109 110 // Activate clicked 111 this.classList.remove('bg-gray-100', 'text-text-muted'); 112 this.classList.add('bg-primary', 'text-white', 'shadow-btn-primary'); 113 114 // Show/hide tab panels 115 document.querySelectorAll('[data-tab-panel]').forEach(function (panel) { 116 if (panel.getAttribute('data-tab-panel') === target) { 117 panel.classList.remove('hidden'); 118 } else { 119 panel.classList.add('hidden'); 120 } 121 }); 122 });
123 }); 124 125 // === Smooth Scroll for Anchor Links === 126 document.querySelectorAll('a[href^="#"]').forEach(function (anchor) { 127 anchor.addEventListener('click', function (e) { 128 const targetId = this.getAttribute('href'); 129 if (targetId === '#') return; 130 const targetEl = document.querySelector(targetId); 131 if (targetEl) { 132 e.preventDefault(); 133 const navHeight = nav ? nav.offsetHeight : 0; 134 const targetPos = targetEl.getBoundingClientRect().top + window.scrollY - navHeight - 20; 135 window.scrollTo({ top: targetPos, behavior: 'smooth' }); 136 closeMobileMenu(); 137 } 138 }); 139 }); 140 141 // === Back to Top Button === 142 const backToTop = document.getElementById('back-to-top'); 143 if (backToTop) { 144 window.addEventListener('scroll', function () { 145 if (window.scrollY > 500) { 146 backToTop.classList.remove('opacity-0', 'pointer-events-none'); 147 backToTop.classList.add('opacity-100'); 148 } else { 149 backToTop.classList.add('opacity-0', 'pointer-events-none'); 150 backToTop.classList.remove('opacity-100'); 151 } 152 }); 153 154 backToTop.addEventListener('click', function (e) { 155 e.preventDefault(); 156 window.scrollTo({ top: 0, behavior: 'smooth' }); 157 }); 158 } 159 160});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.