70 lines
2.5 KiB
JavaScript
70 lines
2.5 KiB
JavaScript
const slides = [...document.querySelectorAll('.slide')];
|
|
const counter = document.getElementById('counter');
|
|
const progressBar = document.getElementById('progressBar');
|
|
const notesBox = document.getElementById('speakerNotes');
|
|
let index = 0;
|
|
|
|
function fitDeck() {
|
|
const vw = window.innerWidth;
|
|
const vh = window.innerHeight;
|
|
const root = document.documentElement;
|
|
|
|
// Mobile uses normal document flow, so text can shrink and content can scroll.
|
|
if (vw <= 900) {
|
|
const mobileScale = Math.max(0.64, Math.min(0.9, vw / 900));
|
|
root.style.setProperty('--slide-scale', mobileScale.toFixed(3));
|
|
root.style.removeProperty('--slide-w');
|
|
root.style.removeProperty('--slide-h');
|
|
return;
|
|
}
|
|
|
|
// Desktop/tablet: keep a 16:9 slide and fill as much height as the viewport allows.
|
|
const pad = Math.max(24, Math.min(72, Math.min(vw, vh) * 0.065));
|
|
const availableW = vw - pad;
|
|
const availableH = vh - pad;
|
|
let slideW = Math.min(availableW, availableH * (16 / 9));
|
|
let slideH = slideW * (9 / 16);
|
|
|
|
// If the width-bound calculation is too tall, bind by height instead.
|
|
if (slideH > availableH) {
|
|
slideH = availableH;
|
|
slideW = slideH * (16 / 9);
|
|
}
|
|
|
|
const scale = Math.max(0.78, Math.min(1.55, Math.min(slideW / 1200, slideH / 675)));
|
|
root.style.setProperty('--slide-w', `${Math.floor(slideW)}px`);
|
|
root.style.setProperty('--slide-h', `${Math.floor(slideH)}px`);
|
|
root.style.setProperty('--slide-scale', scale.toFixed(3));
|
|
}
|
|
|
|
function update() {
|
|
slides.forEach((slide, i) => slide.classList.toggle('active', i === index));
|
|
counter.textContent = `${index + 1} / ${slides.length}`;
|
|
progressBar.style.width = `${((index + 1) / slides.length) * 100}%`;
|
|
const note = slides[index].querySelector('.notes')?.textContent.trim() || '';
|
|
notesBox.textContent = note;
|
|
}
|
|
|
|
function go(delta) {
|
|
index = Math.min(slides.length - 1, Math.max(0, index + delta));
|
|
update();
|
|
}
|
|
|
|
document.getElementById('prev').addEventListener('click', () => go(-1));
|
|
document.getElementById('next').addEventListener('click', () => go(1));
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (['ArrowLeft', 'PageUp'].includes(e.key)) go(-1);
|
|
if (['ArrowRight', 'PageDown', ' '].includes(e.key)) go(1);
|
|
if (e.key.toLowerCase() === 'n') notesBox.classList.toggle('show');
|
|
if (e.key.toLowerCase() === 'f') {
|
|
if (!document.fullscreenElement) document.documentElement.requestFullscreen?.();
|
|
else document.exitFullscreen?.();
|
|
}
|
|
});
|
|
|
|
window.addEventListener('resize', fitDeck);
|
|
window.addEventListener('orientationchange', fitDeck);
|
|
fitDeck();
|
|
update();
|