Glossary slider: use index-based scrollIntoView instead of scrollTo (more reliable with snap)

This commit is contained in:
ask 2026-05-17 20:32:48 +05:00
parent 66e831f07f
commit 22137c6f90

View File

@ -774,8 +774,7 @@ main {
gap: 12px; gap: 12px;
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
scroll-snap-type: x mandatory; scroll-snap-type: x proximity;
scroll-behavior: smooth;
padding: 4px 4px 12px; padding: 4px 4px 12px;
width: 100%; width: 100%;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
@ -1741,42 +1740,42 @@ const SCHEDULE = [
glossaryEl.appendChild(div); glossaryEl.appendChild(div);
}); });
// Slider controls // Slider controls — index-based, uses scrollIntoView (more reliable than scrollTo with snap)
const glossPrev = document.getElementById('gloss-prev'); const glossPrev = document.getElementById('gloss-prev');
const glossNext = document.getElementById('gloss-next'); const glossNext = document.getElementById('gloss-next');
const glossCounter = document.getElementById('gloss-counter'); const glossCounter = document.getElementById('gloss-counter');
const totalCards = GLOSSARY.length; const cards = Array.from(glossaryEl.querySelectorAll('.gloss-item'));
const totalCards = cards.length;
let currentIdx = 0;
function cardStep() { function goTo(i) {
const firstCard = glossaryEl.querySelector('.gloss-item'); currentIdx = Math.max(0, Math.min(totalCards - 1, i));
if (!firstCard) return 0; cards[currentIdx].scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' });
const cs = window.getComputedStyle(glossaryEl); updateNavState();
const gap = parseFloat(cs.columnGap || cs.gap || '12');
return firstCard.getBoundingClientRect().width + gap;
} }
function currentIndex() { function updateNavState() {
const step = cardStep(); glossCounter.textContent = `${currentIdx + 1} / ${totalCards}`;
return step ? Math.round(glossaryEl.scrollLeft / step) : 0; glossPrev.disabled = currentIdx === 0;
glossNext.disabled = currentIdx === totalCards - 1;
} }
function scrollToIndex(i) { // Sync currentIdx when user scrolls manually (touch/trackpad)
const step = cardStep(); function syncFromScroll() {
const clamped = Math.max(0, Math.min(totalCards - 1, i)); const containerLeft = glossaryEl.getBoundingClientRect().left;
glossaryEl.scrollTo({ left: clamped * step, behavior: 'smooth' }); let bestIdx = 0, bestDist = Infinity;
for (let i = 0; i < cards.length; i++) {
const d = Math.abs(cards[i].getBoundingClientRect().left - containerLeft);
if (d < bestDist) { bestDist = d; bestIdx = i; }
}
if (bestIdx !== currentIdx) {
currentIdx = bestIdx;
updateNavState();
} }
function updateGlossNav() {
const idx = currentIndex();
glossCounter.textContent = `${idx + 1} / ${totalCards}`;
const maxScroll = glossaryEl.scrollWidth - glossaryEl.clientWidth;
glossPrev.disabled = glossaryEl.scrollLeft <= 2;
glossNext.disabled = glossaryEl.scrollLeft >= maxScroll - 2;
} }
glossPrev.addEventListener('click', () => scrollToIndex(currentIndex() - 1)); glossPrev.addEventListener('click', () => goTo(currentIdx - 1));
glossNext.addEventListener('click', () => scrollToIndex(currentIndex() + 1)); glossNext.addEventListener('click', () => goTo(currentIdx + 1));
glossaryEl.addEventListener('scroll', updateGlossNav, { passive: true }); glossaryEl.addEventListener('scroll', syncFromScroll, { passive: true });
window.addEventListener('resize', updateGlossNav); updateNavState();
// initial state after layout settles
requestAnimationFrame(updateGlossNav);
// Render projects // Render projects
const projectsEl = document.getElementById('projects-grid'); const projectsEl = document.getElementById('projects-grid');