<div class="cell">
<section class="grid-container o-section">
<div class="grid-x grid-margin-x">
<div class="vs-container" data-href="/assets/json/videos.json">
<aside class="vs-sidebar">
<h2>Short News</h2>
<p>Kurze Video Beiträge zu aktuellen Themen</p>
</aside>
<div class="vs-filters" role="region" aria-label="Filter-Leiste">
<ul class="vs-context-menu__list">
<li class="vs-context-menu__item">
<button class="vs-filter-btn vs-context-menu__link active" data-filter="all" aria-label="Filter: Alle" aria-pressed="true">Alle Beiträge
</button>
</li>
<li class="vs-context-menu__item">
<button class="vs-filter-btn vs-context-menu__link" data-filter="459" aria-label="Filter: Gastro" aria-pressed="false">Gastro
</button>
</li>
<li class="vs-context-menu__item">
<button class="vs-filter-btn vs-context-menu__link" data-filter="458" aria-label="Filter: Hildesheim" aria-pressed="false">Hildesheim
</button>
</li>
</ul>
</div>
<div class="vs-slider-area">
<div class="vs-class-slider-grid-wrapper vs-slider-grid swiper">
<div class="swiper-wrapper">
<f:for each="{items}" as="video" iteration="i">
<div class="swiper-slide vs-slide" data-slide-index="{i.index}" data-open-modal="{i.index}">
<div class="vs-thumbnail vs-thumbnail-index-{i.index}">
<img src="{video.resolvedThumbnail}" alt="{video.title}">
<span class="vs-play-icon">â–º</span>
<div class="vs-thumb-overlay">
<div class="vs-thumb-text">
<span class="c-badge c-badge--user"><strong>HAZ+</strong></span>
<span class="vs-category" data-id="{video.category.id}">{video.category.title}</span>
<h2>{video.title}</h2>
</div>
<span>{video.shortdesc}</span>
</div>
</div>
</div>
</f:for>
</div>
<div class="swiper-button-prev vs-nav-arrow vs-nav-prev" aria-label="Vorheriges Slide"></div>
<div class="swiper-button-next vs-nav-arrow vs-nav-next" aria-label="Nächstes Slide"></div>
</div>
<div class="vs-video-modal vs-slider-grid close">
<div class="vs-modal-content">
<div class="vs-modal-video-wrapper">
<div class="vs-modal-video-inner"></div>
</div>
<div class="vs-modal-text">
<div class="vs-modal-title vs-thumb-text">
<span class="c-badge c-badge--user"><strong>HAZ+</strong></span>
<span class="vs-category">{currentCategory}</span>
<h2>{currentTitle}</h2>
</div>
<p class="vs-modal-desc">{currentDescription}</p>
<a href="" class="vs-modal-cta vs-cta-btn">Mehr erfahren</a>
<button class="vs-close-modal" aria-label="Schließen">×</button>
</div>
<button class="vs-slider-nav vs-modal-nav vs-modal-prev" aria-label="Vorheriges Video"><</button>
<button class="vs-slider-nav vs-modal-nav vs-modal-next" aria-label="Nächstes Video">></button>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
<div class="cell">
<section class="grid-container o-section">
<div class="grid-x grid-margin-x">
<div class="vs-container" data-href="/assets/json/videos.json">
<aside class="vs-sidebar">
<h2>Short News</h2>
<p>Kurze Video Beiträge zu aktuellen Themen</p>
</aside>
<div class="vs-filters" role="region" aria-label="Filter-Leiste">
<ul class="vs-context-menu__list">
<li class="vs-context-menu__item">
<button class="vs-filter-btn vs-context-menu__link active" data-filter="all" aria-label="Filter: Alle"
aria-pressed="true">Alle Beiträge
</button>
</li>
<li class="vs-context-menu__item">
<button class="vs-filter-btn vs-context-menu__link" data-filter="459" aria-label="Filter: Gastro"
aria-pressed="false">Gastro
</button>
</li>
<li class="vs-context-menu__item">
<button class="vs-filter-btn vs-context-menu__link" data-filter="458" aria-label="Filter: Hildesheim"
aria-pressed="false">Hildesheim
</button>
</li>
</ul>
</div>
<div class="vs-slider-area">
<div class="vs-class-slider-grid-wrapper vs-slider-grid swiper">
<div class="swiper-wrapper">
<f:for each="{items}" as="video" iteration="i">
<div class="swiper-slide vs-slide" data-slide-index="{i.index}" data-open-modal="{i.index}">
<div class="vs-thumbnail vs-thumbnail-index-{i.index}">
<img src="{video.resolvedThumbnail}" alt="{video.title}">
<span class="vs-play-icon">â–º</span>
<div class="vs-thumb-overlay">
<div class="vs-thumb-text">
<span class="c-badge c-badge--user"><strong>HAZ+</strong></span>
<span class="vs-category" data-id="{video.category.id}">{video.category.title}</span>
<h2>{video.title}</h2>
</div>
<span>{video.shortdesc}</span>
</div>
</div>
</div>
</f:for>
</div>
<div class="swiper-button-prev vs-nav-arrow vs-nav-prev" aria-label="Vorheriges Slide"></div>
<div class="swiper-button-next vs-nav-arrow vs-nav-next" aria-label="Nächstes Slide"></div>
</div>
<div class="vs-video-modal vs-slider-grid close">
<div class="vs-modal-content">
<div class="vs-modal-video-wrapper">
<div class="vs-modal-video-inner"></div>
</div>
<div class="vs-modal-text">
<div class="vs-modal-title vs-thumb-text">
<span class="c-badge c-badge--user"><strong>HAZ+</strong></span>
<span class="vs-category">{currentCategory}</span>
<h2>{currentTitle}</h2>
</div>
<p class="vs-modal-desc">{currentDescription}</p>
<a href="" class="vs-modal-cta vs-cta-btn">Mehr erfahren</a>
<button class="vs-close-modal" aria-label="Schließen">×</button>
</div>
<button class="vs-slider-nav vs-modal-nav vs-modal-prev" aria-label="Vorheriges Video"><</button>
<button class="vs-slider-nav vs-modal-nav vs-modal-next" aria-label="Nächstes Video">></button>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
/* No context defined for this component. */
import Swiper from 'swiper/swiper-bundle';
class Videoslider {
/**
*
* @param {HTMLElement} element
*/
constructor(element) {
this.swiperContainer = element.querySelector('.vs-class-slider-grid-wrapper.swiper');
this.swiperWrapper = this.swiperContainer.querySelector('.swiper-wrapper');
this.swiperPrev = this.swiperContainer.querySelector('.vs-nav-prev');
this.swiperNext = this.swiperContainer.querySelector('.vs-nav-next');
this.current = 0;
this.container = element;
this.container.classList.add('loading');
this.videos = [];
this.filteredVideos = [];
this.modal = element.querySelector('.vs-video-modal');
this.titleEl = this.modal.querySelector('.vs-modal-title');
this.descEl = this.modal.querySelector('.vs-modal-desc');
this.ctaEl = this.modal.querySelector('.vs-modal-cta');
this.videoWrapper = this.modal.querySelector('.vs-modal-video-wrapper');
this.videoWrapperInner = this.videoWrapper.querySelector('.vs-modal-video-inner');
this.registerModalEvents();
this.registerFilterEvents(element);
// Globale Referenz für Event-Delegation
window.videoslider = this;
}
initialize(response) {
response
// eslint-disable-next-line no-shadow
.then((response) => response.json())
// eslint-disable-next-line no-shadow
.then((response) => {
this.videos = response;
this.filteredVideos = this.videos;
this.renderSlides(this.videos);
})
.catch((error) => console.error('Fehler beim Laden der JSON-Daten:', error));
}
renderSlides(items) {
this.filteredVideos = items;
this.swiperWrapper.innerHTML = '';
items.forEach((video, index) => {
const slide = this.createSlide(video, index);
this.swiperWrapper.appendChild(slide);
});
if (!this.swiper) {
this.swiper = new Swiper(this.swiperContainer, {
slidesPerView: 'auto',
centeredSlides: true,
spaceBetween: 16,
autoHeight: true,
loop: true,
navigation: {
nextEl: '.vs-nav-next',
prevEl: '.vs-nav-prev',
},
breakpoints: {
768: {
slidesPerView: 'auto',
centeredSlides: false,
},
},
});
this.swiper.on('click', (swiper, event) => {
if (!event || typeof event.target?.closest !== 'function') return;
const slide = event.target.closest('.swiper-slide');
if (!slide || !slide.dataset.slideIndex) return;
const index = parseInt(slide.dataset.slideIndex, 10);
if (!Number.isNaN(index)) {
this.openModal(index);
}
});
} else {
this.swiper.update();
}
this.container.classList.remove('loading');
}
openModal(index) {
const video = this.filteredVideos[index];
if (!video) return;
this.current = index;
this.videoWrapperInner.innerHTML = video.videocode;
this.titleEl.innerHTML = `
<span class="c-badge c-badge--user"><strong>HAZ+</strong></span>
<span>${video.category?.title ?? ''}</span>
<h2>${video.title}</h2>
`;
this.descEl.innerHTML = video.content;
const link = video.resolvedLink || video.cta;
if (link) {
this.ctaEl.href = link;
this.ctaEl.style.display = '';
} else {
this.ctaEl.style.display = 'none';
}
// Show modal
this.modal.classList.remove('close');
this.modal.classList.add('open');
this.swiperPrev.style.display = 'none';
this.swiperNext.style.display = 'none';
}
closeModal() {
this.videoWrapperInner.innerHTML = '';
this.modal.classList.remove('open');
this.modal.classList.add('close');
this.swiperPrev.style.display = 'flex';
this.swiperNext.style.display = 'flex';
}
registerModalEvents() {
const modalPrev = this.modal.querySelector('.vs-modal-prev');
const modalNext = this.modal.querySelector('.vs-modal-next');
const modalClose = this.modal.querySelector('.vs-close-modal');
modalPrev.addEventListener('click', () => {
this.closeModal();
// eslint-disable-next-line max-len
const prevIndex = (this.current - 1 + this.filteredVideos.length) % this.filteredVideos.length;
this.openModal(prevIndex);
});
modalNext.addEventListener('click', () => {
this.closeModal();
const nextIndex = (this.current + 1) % this.filteredVideos.length;
this.openModal(nextIndex);
});
modalClose.addEventListener('click', () => {
this.closeModal();
});
}
registerFilterEvents(element) {
const filterBtns = element.querySelectorAll('.vs-filter-btn');
const allButton = element.querySelector('.vs-filter-btn[data-filter="all"]');
filterBtns.forEach((btn) => btn.addEventListener('click', () => {
if (btn.dataset.filter === 'all') {
filterBtns.forEach((b) => b.classList.remove('active'));
btn.classList.add('active');
this.renderSlides(this.videos);
return;
}
btn.classList.toggle('active');
allButton.classList.remove('active');
const act = Array.from(filterBtns)
.filter((b) => b.classList.contains('active') && b.dataset.filter !== 'all')
.map((b) => b.dataset.filter);
let slides;
if (act.length === 0) {
filterBtns[0].classList.add('active');
slides = this.videos;
} else {
slides = this.videos.filter((video) => {
if (!video.category || !video.category.id) return false;
return act.includes(String(video.category.id));
});
}
this.renderSlides(slides);
}));
}
// eslint-disable-next-line class-methods-use-this
createSlide(video, index) {
const slide = document.createElement('div');
slide.dataset.slideIndex = index;
slide.className = 'swiper-slide vs-slide';
slide.innerHTML = `
<div class="vs-thumbnail vs-thumbnail-index-${index}">
<img src="${video.resolvedThumbnail}" alt="${video.title}" style="width:100%;height:100%;object-fit:cover;">
<span class="vs-play-icon">►</span>
<div class="vs-thumb-overlay">
<div class="vs-thumb-text">
<span class="c-badge c-badge--user"><strong>HAZ+</strong></span>
<span class="vs-category" data-id="${video.category?.id ?? ''}">${video.category?.title ?? ''}</span>
<h2>${video.title}</h2>
</div>
<span>${video.shortdesc}</span>
</div>
</div>
`;
return slide;
}
}
export default Videoslider;
There are no notes for this item.