114 lines
4.7 KiB
JavaScript
114 lines
4.7 KiB
JavaScript
/* ============================================================
|
|
LAYOUT.JS — shared across all layout pages
|
|
Handles: theme switching, layout switching, mobile menu,
|
|
FAQ accordion, contact form, scroll animations
|
|
============================================================ */
|
|
|
|
(function () {
|
|
|
|
const html = document.documentElement;
|
|
|
|
// ── 1. Apply saved theme immediately (before paint) ──────
|
|
const savedTheme = localStorage.getItem('demo-theme') || 'midnight';
|
|
html.setAttribute('data-theme', savedTheme);
|
|
|
|
// ── 2. Apply saved layout pill active state ──────────────
|
|
const savedLayout = localStorage.getItem('demo-layout') || 'a';
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
// ── Theme switcher ──────────────────────────────────────
|
|
const themePills = document.querySelectorAll('.theme-pill');
|
|
|
|
themePills.forEach(pill => {
|
|
if (pill.dataset.t === savedTheme) pill.classList.add('active');
|
|
pill.addEventListener('click', () => applyTheme(pill.dataset.t));
|
|
});
|
|
|
|
function applyTheme(name) {
|
|
html.setAttribute('data-theme', name);
|
|
localStorage.setItem('demo-theme', name);
|
|
themePills.forEach(p => p.classList.toggle('active', p.dataset.t === name));
|
|
}
|
|
|
|
// ── Layout switcher ─────────────────────────────────────
|
|
const layoutPills = document.querySelectorAll('.layout-pill');
|
|
const LAYOUT_PAGES = { a: 'index.html', b: 'layout-b.html', c: 'layout-c.html' };
|
|
|
|
layoutPills.forEach(pill => {
|
|
if (pill.dataset.l === savedLayout) pill.classList.add('active');
|
|
|
|
pill.addEventListener('click', () => {
|
|
const target = pill.dataset.l;
|
|
if (target === savedLayout) return; // already on this layout
|
|
localStorage.setItem('demo-layout', target);
|
|
|
|
// Fade out, navigate
|
|
document.body.style.transition = 'opacity 0.25s ease';
|
|
document.body.style.opacity = '0';
|
|
setTimeout(() => {
|
|
window.location.href = LAYOUT_PAGES[target];
|
|
}, 240);
|
|
});
|
|
});
|
|
|
|
// ── Mobile menu toggle ──────────────────────────────────
|
|
const mobileToggle = document.getElementById('mobileToggle');
|
|
const mobileMenu = document.getElementById('mobileMenu');
|
|
if (mobileToggle) {
|
|
mobileToggle.addEventListener('click', () => {
|
|
mobileMenu.classList.toggle('is-open');
|
|
});
|
|
}
|
|
|
|
// ── FAQ accordion ───────────────────────────────────────
|
|
document.querySelectorAll('.faq-question').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const item = btn.closest('.faq-item');
|
|
const isOpen = item.classList.contains('is-open');
|
|
document.querySelectorAll('.faq-item').forEach(i => i.classList.remove('is-open'));
|
|
if (!isOpen) item.classList.add('is-open');
|
|
});
|
|
});
|
|
|
|
// ── Contact form ────────────────────────────────────────
|
|
const contactForm = document.getElementById('contactForm');
|
|
const formSuccess = document.getElementById('formSuccess');
|
|
if (contactForm) {
|
|
contactForm.addEventListener('submit', e => {
|
|
e.preventDefault();
|
|
contactForm.style.display = 'none';
|
|
formSuccess.classList.add('is-visible');
|
|
});
|
|
}
|
|
|
|
// ── Scroll-triggered feature cards ──────────────────────
|
|
const featureCards = document.querySelectorAll('.feature-card');
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
entry.target.style.opacity = '1';
|
|
entry.target.style.transform = 'translateY(0)';
|
|
observer.unobserve(entry.target);
|
|
}
|
|
});
|
|
}, { threshold: 0.12 });
|
|
|
|
featureCards.forEach((card, i) => {
|
|
card.style.opacity = '0';
|
|
card.style.transform = 'translateY(24px)';
|
|
card.style.transition = `opacity 0.5s ease ${i * 0.08}s, transform 0.5s ease ${i * 0.08}s, border-color 0.3s ease, box-shadow 0.3s ease`;
|
|
observer.observe(card);
|
|
});
|
|
|
|
// ── Fade in on load ─────────────────────────────────────
|
|
document.body.style.opacity = '0';
|
|
document.body.style.transition = 'opacity 0.3s ease';
|
|
requestAnimationFrame(() => {
|
|
requestAnimationFrame(() => { document.body.style.opacity = '1'; });
|
|
});
|
|
|
|
});
|
|
|
|
})();
|