177 lines
6.3 KiB
JavaScript
177 lines
6.3 KiB
JavaScript
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();
|
||
}
|
||
});
|
||
}
|