const root = document.documentElement; const saved = window?.localStorage?.getItem('theme'); // Umami: safe track (no-op if script blocked or not loaded) function umamiTrack(name, data) { if ( typeof window.umami !== 'undefined' && typeof window.umami.track === 'function' ) { if (data != null) window.umami.track(name, data); else window.umami.track(name); } } const sysDark = window.matchMedia('(prefers-color-scheme: dark)').matches; if (saved) { root.setAttribute('data-theme', saved); } else { if (sysDark) { root.setAttribute('data-theme', 'dark'); } else { root.setAttribute('data-theme', 'light'); } } // Theme toggle const themeToggle = document.getElementById('theme-toggle'); if (themeToggle) { themeToggle.addEventListener('click', () => { const current = root.getAttribute('data-theme') || 'light'; const next = current === 'light' ? 'dark' : 'light'; root.setAttribute('data-theme', next); try { localStorage.setItem('theme', next); } catch { /* localStorage unavailable (e.g. private browsing) */ } }); } // Umami: scroll depth (25%, 50%, 75%, 100%) – once per milestone const scrollMilestones = new Set(); function onScroll() { const doc = document.documentElement; const scrollTop = doc.scrollTop || document.body.scrollTop; const scrollHeight = (doc.scrollHeight || document.body.scrollHeight) - window.innerHeight; if (scrollHeight <= 0) return; const pct = Math.round((scrollTop / scrollHeight) * 100); for (const m of [25, 50, 75, 100]) { if (pct >= m && !scrollMilestones.has(m)) { scrollMilestones.add(m); umamiTrack('scroll-depth', { depth: String(m) }); } } } window.addEventListener('scroll', onScroll, { passive: true }); // Lightbox (structure from Lightbox.svelte; we fill content and handle open/close) const dialog = document.querySelector('dialog.lightbox'); const lbContent = dialog?.querySelector('.lb-content'); const lbCaption = dialog?.querySelector('#lb-caption, .lb-caption'); let lightboxOpener = null; function openLightbox(name, type, caption) { if (!dialog || !lbContent || !lbCaption) return; lightboxOpener = document.activeElement; document.body.style.overflow = 'hidden'; if (type === 'video') { const video = document.createElement('video'); video.src = `/assets/media/videos/${name}.mp4`; video.controls = true; video.autoplay = true; const track = document.createElement('track'); track.kind = 'captions'; track.src = `/assets/media/videos/${name}-captions.vtt`; track.default = true; video.appendChild(track); lbContent.replaceChildren(video); } else { const srcset = (bp) => type === 'image' ? `/assets/media/${bp}/${name}@1x.webp 1x, /assets/media/${bp}/${name}.webp 2x` : `/assets/media/${bp}/${name}_still@1x.webp 1x, /assets/media/${bp}/${name}_still.webp 2x`; const picture = document.createElement('picture'); const s1 = document.createElement('source'); s1.media = '(min-width:1024px)'; s1.srcset = srcset('desktop'); const s2 = document.createElement('source'); s2.media = '(min-width:768px)'; s2.srcset = srcset('tablet'); const s3 = document.createElement('source'); s3.media = '(min-width:0px)'; s3.srcset = srcset('mobile'); const img = document.createElement('img'); img.src = `/assets/media/thumbnail/${name}.webp`; img.alt = ''; picture.append(s1, s2, s3, img); lbContent.replaceChildren(picture); } lbCaption.textContent = caption || ''; umamiTrack('gallery-view', { name, type }); dialog.removeAttribute('inert'); dialog.setAttribute('aria-hidden', 'false'); dialog.showModal(); } function closeLightbox() { if (!dialog) return; if (lightboxOpener && typeof lightboxOpener.focus === 'function') { lightboxOpener.focus(); } lightboxOpener = null; document.body.style.overflow = ''; if (lbContent) lbContent.replaceChildren(); if (lbCaption) lbCaption.textContent = ''; dialog.setAttribute('aria-hidden', 'true'); dialog.setAttribute('inert', ''); dialog.close(); } if (dialog) { // Add event handlers dialog.querySelector('.lb-close').addEventListener('click', closeLightbox); dialog.querySelector('.lb-close').addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); closeLightbox(); } }); dialog.addEventListener('close', closeLightbox); dialog.addEventListener('cancel', closeLightbox); dialog.addEventListener('click', (e) => { if (e.target === dialog) closeLightbox(); }); } // Gallery items document.querySelectorAll('.gallery-item[data-name]').forEach((el) => { el.addEventListener('click', () => { const name = el.getAttribute('data-name'); const type = el.getAttribute('data-type') || 'image'; const caption = el.getAttribute('data-caption') || ''; if (name) openLightbox(name, type, caption); }); el.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); const name = el.getAttribute('data-name'); const type = el.getAttribute('data-type') || 'image'; const caption = el.getAttribute('data-caption') || ''; if (name) openLightbox(name, type, caption); } }); }); // Show video button (open lightbox with tour) const showVideoBtn = document.getElementById('show_video'); if (showVideoBtn) { const openTour = () => { const name = showVideoBtn.getAttribute('data-name') || 'tour'; const type = showVideoBtn.getAttribute('data-type') || 'video'; const caption = showVideoBtn.getAttribute('data-caption') || "Take the scenic route—explore your the home's highlights with a virtual walkthrough."; openLightbox(name, type, caption); }; showVideoBtn.addEventListener('click', openTour); showVideoBtn.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openTour(); } }); }