Fix slide snap + presentation keyboard nav
- html/body height 100%, html overflow-y scroll — proper snap container - box-sizing border-box on sections (padding wasn't being included) - 2px black border-top between slides — visual divider - frame display block, body margin 0 - Keyboard: ArrowDown/PageDown/Space → next, ArrowUp/PageUp → prev, Home/End → first/last Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fc8bab570e
commit
5c1ab55af0
48
index.html
48
index.html
@ -106,13 +106,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
font-size: clamp(18px, 1.6vw, 28px); /* масштабируется под экран — для проектора 24–28px */
|
||||
font-size: clamp(18px, 1.6vw, 28px);
|
||||
scroll-snap-type: y mandatory;
|
||||
overflow-y: scroll;
|
||||
scroll-padding-top: 0;
|
||||
}
|
||||
|
||||
/* PRESENTATION MODE: каждая секция = ровно 1 экран, фиксация при скролле */
|
||||
/* PRESENTATION MODE: каждая секция = ровно 1 экран */
|
||||
.hero,
|
||||
section.section,
|
||||
.dark-section {
|
||||
@ -124,7 +129,7 @@ section.section,
|
||||
justify-content: center;
|
||||
padding-top: 4vh;
|
||||
padding-bottom: 4vh;
|
||||
overflow-y: auto; /* если контент длиннее — скролл внутри слайда */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Усиливаем типографику для большого экрана */
|
||||
@ -184,9 +189,18 @@ body {
|
||||
font-family: 'Lora', Georgia, serif !important;
|
||||
background: var(--page-bg);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.frame { gap: 0; min-height: 100dvh; }
|
||||
.frame { gap: 0; min-height: 100dvh; display: block; }
|
||||
|
||||
/* Усиливаем визуальную границу между слайдами */
|
||||
.hero, section.section, .dark-section {
|
||||
border-top: 2px solid var(--text) !important;
|
||||
position: relative;
|
||||
}
|
||||
.hero { border-top: none !important; }
|
||||
|
||||
/* Шрифты заголовков */
|
||||
.hero-title, .section-title, .dark-title,
|
||||
@ -3061,16 +3075,18 @@ const SCHEDULE = [
|
||||
targets.forEach(el => io.observe(el));
|
||||
})();
|
||||
|
||||
// Slide counter — показывает текущий слайд / всего
|
||||
// Slide counter + keyboard nav (PageDown / Arrow / Space)
|
||||
(function() {
|
||||
const counter = document.getElementById('slide-counter');
|
||||
if (!counter) return;
|
||||
const slides = Array.from(document.querySelectorAll('.hero, section.section, .dark-section'));
|
||||
const total = slides.length;
|
||||
let current = 0;
|
||||
const update = (idx) => {
|
||||
counter.textContent = `— ${idx + 1} / ${total} —`;
|
||||
current = idx;
|
||||
if (counter) counter.textContent = `— ${idx + 1} / ${total} —`;
|
||||
};
|
||||
update(0);
|
||||
|
||||
const io = new IntersectionObserver((entries) => {
|
||||
entries.forEach(e => {
|
||||
if (e.isIntersecting && e.intersectionRatio > 0.5) {
|
||||
@ -3080,6 +3096,24 @@ const SCHEDULE = [
|
||||
});
|
||||
}, { threshold: [0.5, 0.6, 0.75] });
|
||||
slides.forEach(s => io.observe(s));
|
||||
|
||||
const goTo = (idx) => {
|
||||
idx = Math.max(0, Math.min(total - 1, idx));
|
||||
slides[idx].scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (['INPUT', 'TEXTAREA'].includes(document.activeElement?.tagName)) return;
|
||||
if (e.key === 'ArrowDown' || e.key === 'PageDown' || e.key === ' ') {
|
||||
e.preventDefault(); goTo(current + 1);
|
||||
} else if (e.key === 'ArrowUp' || e.key === 'PageUp') {
|
||||
e.preventDefault(); goTo(current - 1);
|
||||
} else if (e.key === 'Home') {
|
||||
e.preventDefault(); goTo(0);
|
||||
} else if (e.key === 'End') {
|
||||
e.preventDefault(); goTo(total - 1);
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user