Spaces:
Running
Running
| /** | |
| * Reachy Mini FAQ - Interactive Script | |
| * Handles product selection via tabs, search filtering, and FAQ interactions | |
| */ | |
| (function() { | |
| 'use strict'; | |
| // ======================================== | |
| // DOM Elements | |
| // ======================================== | |
| const productTabs = document.querySelectorAll('.product-tab'); | |
| const faqContainer = document.getElementById('faq-container'); | |
| const searchInput = document.getElementById('search-input'); | |
| const faqSections = document.getElementById('faq-sections'); | |
| const footerYear = document.getElementById('footer-year'); | |
| // ======================================== | |
| // State | |
| // ======================================== | |
| let currentProduct = 'beta'; | |
| // ======================================== | |
| // Product Data | |
| // ======================================== | |
| const productInfo = { | |
| beta: { name: 'Reachy Mini Beta', color: 'beta' }, | |
| lite: { name: 'Reachy Mini Lite', color: 'lite' }, | |
| wireless: { name: 'Reachy Mini Wireless', color: 'wireless' } | |
| }; | |
| // ======================================== | |
| // Initialize | |
| // ======================================== | |
| function init() { | |
| // Set current year in footer | |
| if (footerYear) { | |
| footerYear.textContent = new Date().getFullYear(); | |
| } | |
| // Attach event listeners | |
| attachEventListeners(); | |
| // Check for URL hash to auto-select product | |
| checkUrlHash(); | |
| } | |
| // ======================================== | |
| // Event Listeners | |
| // ======================================== | |
| function attachEventListeners() { | |
| // Product tabs | |
| productTabs.forEach(tab => { | |
| tab.addEventListener('click', () => { | |
| selectProduct(tab.dataset.product); | |
| }); | |
| }); | |
| // Search functionality | |
| if (searchInput) { | |
| searchInput.addEventListener('input', debounce(handleSearch, 200)); | |
| // Clear search on Escape | |
| searchInput.addEventListener('keydown', (e) => { | |
| if (e.key === 'Escape') { | |
| searchInput.value = ''; | |
| handleSearch(); | |
| searchInput.blur(); | |
| } | |
| }); | |
| } | |
| // Handle browser back/forward | |
| window.addEventListener('popstate', checkUrlHash); | |
| } | |
| // ======================================== | |
| // Product Selection | |
| // ======================================== | |
| function selectProduct(productId) { | |
| if (!productInfo[productId]) return; | |
| currentProduct = productId; | |
| // Update URL hash | |
| history.replaceState({ product: productId }, '', `#${productId}`); | |
| // Update active state in tabs | |
| productTabs.forEach(tab => { | |
| tab.classList.toggle('active', tab.dataset.product === productId); | |
| }); | |
| // Filter content for product (placeholder for future differentiation) | |
| filterContentForProduct(productId); | |
| } | |
| function checkUrlHash() { | |
| const hash = window.location.hash.slice(1); | |
| if (hash && productInfo[hash]) { | |
| selectProduct(hash); | |
| } else { | |
| selectProduct('beta'); | |
| } | |
| } | |
| // ======================================== | |
| // Content Filtering (for future use) | |
| // ======================================== | |
| function filterContentForProduct(productId) { | |
| // Placeholder: In the future, this function can show/hide | |
| // product-specific FAQ items based on data attributes | |
| // For now, all products show the same content | |
| const allFaqItems = faqSections.querySelectorAll('.faq-item'); | |
| allFaqItems.forEach(item => { | |
| // Example future logic: | |
| // const products = item.dataset.products?.split(',') || ['all']; | |
| // item.style.display = products.includes('all') || products.includes(productId) ? '' : 'none'; | |
| item.style.display = ''; | |
| }); | |
| } | |
| // ======================================== | |
| // Search Functionality | |
| // ======================================== | |
| function handleSearch() { | |
| const query = searchInput.value.toLowerCase().trim(); | |
| const faqItems = faqSections.querySelectorAll('.faq-item'); | |
| const sections = faqSections.querySelectorAll('.faq-section'); | |
| const subsections = faqSections.querySelectorAll('.subsection'); | |
| if (!query) { | |
| // Show all items | |
| faqItems.forEach(item => { | |
| item.style.display = ''; | |
| item.removeAttribute('open'); | |
| }); | |
| sections.forEach(section => section.style.display = ''); | |
| subsections.forEach(sub => sub.style.display = ''); | |
| return; | |
| } | |
| // Filter items | |
| faqItems.forEach(item => { | |
| const question = item.querySelector('.question')?.textContent.toLowerCase() || ''; | |
| const answer = item.querySelector('.answer')?.textContent.toLowerCase() || ''; | |
| const tags = Array.from(item.querySelectorAll('.tag')) | |
| .map(tag => tag.textContent.toLowerCase()) | |
| .join(' '); | |
| const matches = question.includes(query) || | |
| answer.includes(query) || | |
| tags.includes(query); | |
| item.style.display = matches ? '' : 'none'; | |
| // Auto-expand matching items | |
| if (matches && query.length > 2) { | |
| item.setAttribute('open', ''); | |
| } | |
| }); | |
| // Hide empty subsections | |
| subsections.forEach(sub => { | |
| const visibleItems = sub.querySelectorAll('.faq-item:not([style*="display: none"])'); | |
| sub.style.display = visibleItems.length > 0 ? '' : 'none'; | |
| }); | |
| // Hide empty sections | |
| sections.forEach(section => { | |
| const visibleItems = section.querySelectorAll('.faq-item:not([style*="display: none"])'); | |
| section.style.display = visibleItems.length > 0 ? '' : 'none'; | |
| }); | |
| } | |
| // ======================================== | |
| // Utilities | |
| // ======================================== | |
| function debounce(func, wait) { | |
| let timeout; | |
| return function executedFunction(...args) { | |
| const later = () => { | |
| clearTimeout(timeout); | |
| func(...args); | |
| }; | |
| clearTimeout(timeout); | |
| timeout = setTimeout(later, wait); | |
| }; | |
| } | |
| // ======================================== | |
| // Keyboard Navigation | |
| // ======================================== | |
| document.addEventListener('keydown', (e) => { | |
| // Press '/' to focus search | |
| if (e.key === '/' && !e.ctrlKey && !e.metaKey) { | |
| if (document.activeElement !== searchInput) { | |
| e.preventDefault(); | |
| searchInput?.focus(); | |
| } | |
| } | |
| }); | |
| // ======================================== | |
| // Initialize on DOM Ready | |
| // ======================================== | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', init); | |
| } else { | |
| init(); | |
| } | |
| })(); |