Add device visibility and responsive navigation for 1.10.0
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s

This commit is contained in:
kantarci committed 2026-09-14 14:46:55 +02:00
1 parent eea6747d9e
commit 37c2942d1d
18 files changed
+493 -26

No files matched your search

+12 -5
View File
@@ -11,6 +11,7 @@ export function initSliders(doc = document) {
const seconds = Number(slider.dataset.autoplay || 0);
let playing = seconds >= 3 && !preference.matches, hover = false, visible = false, timer;
const controls = doc.createElement('div'); controls.className = 'slider-controls';
for (const name of slider.classList) if (name.startsWith('visibility-')) controls.classList.add(name);
controls.setAttribute('role', 'group'); controls.setAttribute('aria-label', 'Slider bedienen');
const button = (text, label, action) => {
const node = doc.createElement('button'); node.type = 'button'; node.textContent = text;
@@ -19,18 +20,22 @@ export function initSliders(doc = document) {
controls.append(node); return node;
};
const left = slide => slide.getBoundingClientRect().left - slider.getBoundingClientRect().left + slider.scrollLeft;
const available = () => slides.map((slide, i) => slide.getClientRects().length ? i : -1).filter(i => i >= 0);
const active = () => {
let index = 0, distance = Infinity;
slides.forEach((slide, i) => { const delta = Math.abs(left(slide) - slider.scrollLeft); if (delta < distance) { distance = delta; index = i; } });
available().forEach(i => { const delta = Math.abs(left(slides[i]) - slider.scrollLeft); if (delta < distance) { distance = delta; index = i; } });
return index;
};
const go = index => {
if (!available().includes(index)) return;
slider.scrollTo({ left: Math.max(0, Math.min(slider.scrollWidth - slider.clientWidth, left(slides[index]))), behavior: preference.matches ? 'instant' : 'smooth' });
};
const step = direction => {
const visible = available(), position = visible.indexOf(active());
if (!visible.length) return;
const last = slider.scrollLeft + slider.clientWidth >= slider.scrollWidth - 2;
const first = slider.scrollLeft <= 2;
go(direction > 0 ? (last ? 0 : Math.min(slides.length - 1, active() + 1)) : (first ? slides.length - 1 : Math.max(0, active() - 1)));
go(direction > 0 ? (last ? visible[0] : visible[Math.min(visible.length - 1, position + 1)]) : (first ? visible.at(-1) : visible[Math.max(0, position - 1)]));
};
const manual = action => { playing = false; clearTimeout(timer); update(); action(); };
const previous = button('←', 'Vorherige Folie', () => manual(() => step(-1)));
@@ -45,10 +50,11 @@ export function initSliders(doc = document) {
}
const play = seconds >= 3 ? button('', 'Automatische Wiedergabe pausieren', () => { playing = !playing; update(); schedule(); }) : null;
const update = () => {
const fits = slider.scrollWidth <= slider.clientWidth + 2;
const visible = available();
const fits = visible.length < 2 || slider.scrollWidth <= slider.clientWidth + 2;
controls.hidden = fits; previous.disabled = next.disabled = fits;
const index = active(); count.textContent = `${index + 1} / ${slides.length}`;
dots.forEach((dot, i) => dot.setAttribute('aria-pressed', String(i === index)));
const index = active(); count.textContent = `${Math.max(0, visible.indexOf(index) + 1)} / ${visible.length}`;
dots.forEach((dot, i) => { dot.hidden = !visible.includes(i); dot.setAttribute('aria-pressed', String(i === index)); });
if (play) {
play.textContent = playing ? 'Pause' : 'Wiedergabe';
play.setAttribute('aria-label', playing ? 'Automatische Wiedergabe pausieren' : 'Automatische Wiedergabe starten');
@@ -62,6 +68,7 @@ export function initSliders(doc = document) {
const pause = () => { playing = false; update(); clearTimeout(timer); };
slider.after(controls); slider.classList.add('slider-controlled'); update();
slider.addEventListener('scroll', update, { passive: true, signal });
view.addEventListener('resize', update, { passive: true, signal });
slider.addEventListener('pointerenter', () => { hover = true; }, { signal });
slider.addEventListener('pointerleave', () => { hover = false; schedule(); }, { signal });
for (const event of ['pointerdown', 'wheel', 'touchstart', 'focusin']) slider.addEventListener(event, pause, { passive: true, signal });