/**
* ============================================
* KREISTAGSWAHL 2026 - INTERACTIVE COMPONENTS
* ============================================
*
* NEUE STRUKTUR:
* - Spitzenkandidaten: 3 Cards nebeneinander (kein Slider) mit Modal
* - Alle Kandidaten: Multi-Card Slider mit 1/2/3/4 Cards pro Slide (responsive)
* - Modal für alle Kandidaten-Details
*/
// ============================================
// KANDIDATEN-DATEN (werden aus JSON geladen)
// ============================================
let kandidaten = [];
let spitzenkandidaten = [];
/**
* Lädt Spitzenkandidaten-Daten aus der JSON-Datei
*/
async function loadSpitzenkandidaten() {
try {
const response = await fetch('../data/spitzenkandidaten.json');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
spitzenkandidaten = data;
console.log(`✅ ${spitzenkandidaten.length} Spitzenkandidaten erfolgreich aus JSON geladen`);
return spitzenkandidaten;
} catch (error) {
console.error('❌ Fehler beim Laden der Spitzenkandidaten:', error);
return [];
}
}
/**
* Lädt Kandidaten-Daten aus der JSON-Datei (alle 60)
*/
async function loadKandidaten() {
try {
const response = await fetch('../data/kandidaten.json');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
kandidaten = data;
// Fülle auf 60 Kandidaten auf (falls weniger in JSON vorhanden)
while (kandidaten.length < 60) {
const baseIndex = kandidaten.length % 10;
const kandidat = { ...kandidaten[baseIndex] };
const num = kandidaten.length + 1;
kandidat.name = `${kandidat.name.split(' ')[0]} ${kandidat.name.split(' ')[1]} ${num}`;
kandidat.position = `Kreistagskandidat*in, Listenplatz ${num}`;
kandidaten.push(kandidat);
}
console.log(`✅ ${kandidaten.length} Kandidaten erfolgreich aus JSON geladen`);
return kandidaten;
} catch (error) {
console.error('❌ Fehler beim Laden der Kandidaten:', error);
return [];
}
}
// ============================================
// SPITZENKANDIDATEN GRID (3 Cards nebeneinander)
// ============================================
class SpitzenkandidatenGrid {
constructor(modal) {
this.spitzenkandidaten = spitzenkandidaten;
this.gridContainer = document.querySelector('.spitzenkandidaten-grid');
this.modal = modal;
if (this.gridContainer) {
this.init();
}
}
init() {
console.log(`✅ Spitzenkandidaten-Grid wird initialisiert mit ${this.spitzenkandidaten.length} Kandidaten`);
this.createCards();
}
createCards() {
this.spitzenkandidaten.forEach((kandidat, index) => {
const card = document.createElement('div');
card.className = 'spitzenkandidat-card';
card.setAttribute('data-kandidat-id', index);
// Topics HTML
const topicsHTML = kandidat.topics
.map(topic => `${topic}`)
.join('');
card.innerHTML = `
${kandidat.name}
${kandidat.position}
${kandidat.bio.split('\n')[0]}
${topicsHTML}
`;
// Click-Event für Modal
card.style.cursor = 'pointer';
card.addEventListener('click', () => {
if (this.modal) {
this.modal.open(kandidat);
}
});
this.gridContainer.appendChild(card);
});
console.log(`📊 ${this.spitzenkandidaten.length} Spitzenkandidaten-Cards erstellt`);
}
}
// ============================================
// ALLE KANDIDATEN MULTI-CARD SLIDER
// Shows 1/2/3/4 cards per slide (responsive)
// ============================================
class AlleKandidatenSlider {
constructor(modal) {
this.kandidaten = kandidaten;
this.modal = modal;
this.currentSlide = 0;
this.totalSlides = 0;
this.cardsPerSlide = 1; // Wird responsiv angepasst
// DOM Elemente
this.sliderContent = document.querySelector('.alle-slider-content');
this.prevBtn = document.querySelector('.alle-slider-btn-prev');
this.nextBtn = document.querySelector('.alle-slider-btn-next');
this.dotsContainer = document.querySelector('.alle-slider-dots');
this.currentSlideSpan = document.querySelector('.alle-current-slide');
this.totalSlidesSpan = document.querySelector('.alle-total-slides');
if (this.sliderContent) {
this.init();
}
}
init() {
console.log(`✅ Alle-Kandidaten-Slider wird initialisiert mit ${this.kandidaten.length} Kandidaten`);
// Bestimme Cards pro Slide basierend auf Viewport
this.updateCardsPerSlide();
this.createSlides();
this.createDots();
this.attachEventListeners();
this.showSlide(0);
// Re-render bei Resize
window.addEventListener('resize', () => this.handleResize());
}
/**
* Bestimmt wie viele Cards pro Slide basierend auf Viewport-Breite
*/
updateCardsPerSlide() {
const width = window.innerWidth;
if (width >= 1024) {
this.cardsPerSlide = 4; // Desktop: 4 Cards
} else if (width >= 768) {
this.cardsPerSlide = 3; // Tablet: 3 Cards
} else if (width >= 640) {
this.cardsPerSlide = 2; // Small Tablet: 2 Cards
} else {
this.cardsPerSlide = 1; // Mobile: 1 Card
}
this.totalSlides = Math.ceil(this.kandidaten.length / this.cardsPerSlide);
console.log(`📱 Viewport: ${width}px → ${this.cardsPerSlide} Cards/Slide → ${this.totalSlides} Slides`);
}
/**
* Erstellt Slides mit mehreren Cards
*/
createSlides() {
// Lösche vorhandene Slides
this.sliderContent.innerHTML = '';
for (let i = 0; i < this.totalSlides; i++) {
const slide = document.createElement('div');
slide.className = 'alle-slide';
slide.setAttribute('data-slide', i);
// Hole Kandidaten für diesen Slide
const startIndex = i * this.cardsPerSlide;
const endIndex = Math.min(startIndex + this.cardsPerSlide, this.kandidaten.length);
const slideKandidaten = this.kandidaten.slice(startIndex, endIndex);
// Erstelle Cards für diesen Slide
slideKandidaten.forEach((kandidat, cardIndex) => {
const card = this.createCard(kandidat, startIndex + cardIndex);
slide.appendChild(card);
});
this.sliderContent.appendChild(slide);
}
console.log(`📊 ${this.totalSlides} Multi-Card Slides erstellt`);
}
/**
* Erstellt eine einzelne Kandidaten-Card
*/
createCard(kandidat, index) {
const card = document.createElement('div');
card.className = 'kandidat-card';
card.setAttribute('data-kandidat-id', index);
// Topics HTML (max 3)
const topicsHTML = kandidat.topics
.slice(0, 3)
.map(topic => `