PageSourceSearch

https://wpfrank.com/wp-content/themes/wpfrank/js/main.js?ver=2.0.0

js wpfrank.com collected 2026-10-02 05:34:29 UTC 5,766 bytes, 160 lines download raw bytes

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.