Add renamed docs, backup, and Gitea workflow
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
// Funktion zum Aktualisieren der Body-Klassen basierend auf dem aktuellen Pfad
|
||||
function updateBodyClasses() {
|
||||
// Aktuelle URL-Pfad ohne Domain
|
||||
const path = window.location.pathname;
|
||||
|
||||
// Entferne führende und abschließende Schrägstriche
|
||||
const cleanPath = path.replace(/^\/|\/$/g, '');
|
||||
|
||||
// Entferne alle vorherigen dynamischen Klassen
|
||||
// (wir müssen eine Liste der zu entfernenden Klassen erstellen, da sich die classList während der Iteration ändert)
|
||||
const classesToRemove = [];
|
||||
for (let i = 0; i < document.body.classList.length; i++) {
|
||||
const className = document.body.classList[i];
|
||||
// Bewahre nur bestimmte MkDocs-spezifische Klassen
|
||||
if (!className.startsWith('md-') &&
|
||||
className !== 'no-js' &&
|
||||
className !== 'js') {
|
||||
classesToRemove.push(className);
|
||||
}
|
||||
}
|
||||
|
||||
// Entferne die Klassen
|
||||
classesToRemove.forEach(className => {
|
||||
document.body.classList.remove(className);
|
||||
});
|
||||
|
||||
// Wenn der Pfad leer oder eine Entwickler Github Page ist (Startseite), füge die Klasse 'home' hinzu
|
||||
if (cleanPath === '' || cleanPath === 'satware.ai') {
|
||||
document.body.classList.add('home');
|
||||
} else {
|
||||
// Teile den Pfad in Segmente auf
|
||||
const segments = cleanPath.split('/');
|
||||
|
||||
// Füge Klassen für jedes Segment hinzu
|
||||
segments.forEach(function(segment) {
|
||||
if (segment) {
|
||||
document.body.classList.add(segment);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Optional: Debug-Ausgabe in der Konsole
|
||||
console.log('Updated body classes:', document.body.className);
|
||||
}
|
||||
|
||||
// Initial beim Laden der Seite
|
||||
document.addEventListener('DOMContentLoaded', updateBodyClasses);
|
||||
|
||||
// Bei Navigation innerhalb der MkDocs-Seite
|
||||
// Wir müssen auf das MkDocs-spezifische Event hören
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Warte kurz, bis MkDocs vollständig initialisiert ist
|
||||
setTimeout(function() {
|
||||
// Finde alle internen Links
|
||||
const internalLinks = document.querySelectorAll('a[href^="/"]:not([target]), a[href^="./"]:not([target]), a[href^="../"]:not([target])');
|
||||
|
||||
// Füge Event-Listener für Klicks auf interne Links hinzu
|
||||
internalLinks.forEach(link => {
|
||||
link.addEventListener('click', function() {
|
||||
// Kurze Verzögerung, um der Navigation Zeit zu geben
|
||||
setTimeout(updateBodyClasses, 100);
|
||||
});
|
||||
});
|
||||
|
||||
// Beobachte Änderungen an der URL (History API)
|
||||
if (window.MutationObserver) {
|
||||
// Beobachte Änderungen am Titel, was oft ein Indikator für Seitenwechsel ist
|
||||
const titleObserver = new MutationObserver(updateBodyClasses);
|
||||
if (document.querySelector('title')) {
|
||||
titleObserver.observe(document.querySelector('title'), { childList: true });
|
||||
}
|
||||
|
||||
// Beobachte Änderungen am Hauptinhalt
|
||||
const contentObserver = new MutationObserver(function(mutations) {
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
|
||||
updateBodyClasses();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (document.querySelector('.md-content')) {
|
||||
contentObserver.observe(document.querySelector('.md-content'), {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Regelmäßige Überprüfung auf URL-Änderungen
|
||||
let lastPath = window.location.pathname;
|
||||
setInterval(function() {
|
||||
if (window.location.pathname !== lastPath) {
|
||||
lastPath = window.location.pathname;
|
||||
updateBodyClasses();
|
||||
}
|
||||
}, 200);
|
||||
}, 500);
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Funktion zum Formatieren der Zahlen mit Kommas und Plus-Zeichen
|
||||
function formatNumber(num, includePlus = true) {
|
||||
const formatted = num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
|
||||
return includePlus ? formatted + '+' : formatted;
|
||||
}
|
||||
|
||||
// Funktion zum Extrahieren der Zahl aus dem Text (entfernt das '+' und Kommas)
|
||||
function extractNumber(text) {
|
||||
return parseInt(text.replace(/,/g, '').replace('+', ''), 10);
|
||||
}
|
||||
|
||||
// Funktion zum Animieren der Zähler
|
||||
function animateCounter(counterElement, target) {
|
||||
// Startpunkt
|
||||
let start = 0;
|
||||
// Dauer der Animation in Millisekunden (angepasst an die Größe der Zahl)
|
||||
const duration = Math.min(2000 + Math.log10(target) * 300, 3000);
|
||||
// Zeitpunkt des Starts
|
||||
const startTime = performance.now();
|
||||
|
||||
// Funktion für die Animation
|
||||
function updateCounter(currentTime) {
|
||||
// Berechne den verstrichenen Zeitanteil (0 bis 1)
|
||||
const elapsedTime = Math.min((currentTime - startTime) / duration, 1);
|
||||
|
||||
// Easing-Funktion für eine natürlichere Animation
|
||||
const progress = easeOutQuart(elapsedTime);
|
||||
|
||||
// Berechne den aktuellen Wert
|
||||
const currentValue = Math.floor(progress * target);
|
||||
|
||||
// Aktualisiere den Zähler mit dem Plus-Zeichen
|
||||
counterElement.textContent = formatNumber(currentValue, true);
|
||||
|
||||
// Wenn die Animation noch nicht abgeschlossen ist, nächsten Frame anfordern
|
||||
if (elapsedTime < 1) {
|
||||
requestAnimationFrame(updateCounter);
|
||||
} else {
|
||||
// Stelle sicher, dass der endgültige Wert exakt dem Zielwert entspricht
|
||||
counterElement.textContent = formatNumber(target, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Easing-Funktion für eine natürlichere Animation
|
||||
function easeOutQuart(t) {
|
||||
return 1 - Math.pow(1 - t, 4);
|
||||
}
|
||||
|
||||
// Starte die Animation
|
||||
requestAnimationFrame(updateCounter);
|
||||
}
|
||||
|
||||
// Intersection Observer zum Erkennen, wann die Zähler sichtbar werden
|
||||
const observer = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
// Wenn der Zähler sichtbar wird
|
||||
if (entry.isIntersecting) {
|
||||
const counterElement = entry.target;
|
||||
// Extrahiere die Zielnummer aus dem Text
|
||||
const targetText = counterElement.textContent;
|
||||
const target = extractNumber(targetText);
|
||||
|
||||
// Setze den Anfangswert auf 0 mit Plus-Zeichen
|
||||
counterElement.textContent = '0+';
|
||||
|
||||
// Starte die Animation
|
||||
animateCounter(counterElement, target);
|
||||
|
||||
// Beobachtung beenden, damit die Animation nur einmal ausgeführt wird
|
||||
observer.unobserve(counterElement);
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.1 // 10% des Elements müssen sichtbar sein
|
||||
});
|
||||
|
||||
// Alle Zähler beobachten
|
||||
document.querySelectorAll('.satag--home-counter-number').forEach(counter => {
|
||||
observer.observe(counter);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
// Funktion zur Initialisierung der FAQ-Funktionalität
|
||||
function initFAQ() {
|
||||
// Finde alle FAQ-Fragen
|
||||
const faqQuestions = document.querySelectorAll('.custom-faq-question');
|
||||
|
||||
if (faqQuestions.length === 0) {
|
||||
console.log('Keine benutzerdefinierten FAQ-Elemente gefunden');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Benutzerdefinierte FAQ-Elemente gefunden:', faqQuestions.length);
|
||||
|
||||
// Entferne zuerst alle bestehenden Event-Listener, um Duplikate zu vermeiden
|
||||
faqQuestions.forEach(question => {
|
||||
// Klonen des Elements, um alle Event-Listener zu entfernen
|
||||
const newQuestion = question.cloneNode(true);
|
||||
question.parentNode.replaceChild(newQuestion, question);
|
||||
});
|
||||
|
||||
// Hole die aktualisierten Elemente nach dem Klonen
|
||||
const updatedFaqQuestions = document.querySelectorAll('.custom-faq-question');
|
||||
|
||||
// Füge Event-Listener zu jeder Frage hinzu
|
||||
updatedFaqQuestions.forEach(question => {
|
||||
question.addEventListener('click', function() {
|
||||
// Toggle active class auf der Frage
|
||||
this.classList.toggle('active');
|
||||
|
||||
// Toggle active class auf der Antwort
|
||||
const answer = this.nextElementSibling;
|
||||
answer.classList.toggle('active');
|
||||
|
||||
// Wenn diese Frage geöffnet wurde, schließe alle anderen
|
||||
if (this.classList.contains('active')) {
|
||||
updatedFaqQuestions.forEach(otherQuestion => {
|
||||
if (otherQuestion !== this && otherQuestion.classList.contains('active')) {
|
||||
otherQuestion.classList.remove('active');
|
||||
otherQuestion.nextElementSibling.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
// Initialisiere Slideshows innerhalb der geöffneten Antwort
|
||||
setTimeout(() => {
|
||||
if (typeof initSlideshows === 'function') {
|
||||
initSlideshows();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
console.log('Benutzerdefinierte FAQ-Funktionalität initialisiert');
|
||||
}
|
||||
|
||||
// Führe die Initialisierung beim ersten Laden der Seite aus
|
||||
document.addEventListener('DOMContentLoaded', initFAQ);
|
||||
|
||||
// Führe die Initialisierung aus, wenn der Inhalt der Seite durch MkDocs aktualisiert wird
|
||||
document.addEventListener('DOMContentSwap', initFAQ);
|
||||
|
||||
// Führe die Initialisierung aus, wenn die Seite über den Material for MkDocs-Router aktualisiert wird
|
||||
document.addEventListener('mdContentChanged', initFAQ);
|
||||
|
||||
// Führe die Initialisierung aus, wenn der Inhalt der Seite durch andere Frameworks aktualisiert wird
|
||||
// MutationObserver, um Änderungen im DOM zu überwachen
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
||||
// Prüfe, ob FAQ-Elemente hinzugefügt wurden
|
||||
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
||||
const node = mutation.addedNodes[i];
|
||||
if (node.nodeType === 1 && (node.classList?.contains('custom-faq-item') ||
|
||||
node.querySelector?.('.custom-faq-item'))) {
|
||||
// FAQ-Elemente gefunden, initialisiere die Funktionalität
|
||||
setTimeout(initFAQ, 100); // Kurze Verzögerung, um sicherzustellen, dass alles geladen ist
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Starte die Beobachtung des Dokuments
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// Zusätzlicher Event-Listener für dynamisch geladene Inhalte
|
||||
window.addEventListener('load', function() {
|
||||
// Verzögerte Initialisierung, um sicherzustellen, dass alle Inhalte geladen sind
|
||||
setTimeout(initFAQ, 500);
|
||||
});
|
||||
|
||||
// Für Material for MkDocs spezifische Ereignisse
|
||||
if (typeof document$.subscribe === 'function') {
|
||||
document$.subscribe(function() {
|
||||
// Verzögerte Initialisierung, um sicherzustellen, dass alle Inhalte geladen sind
|
||||
setTimeout(initFAQ, 100);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
// Lightbox functionality for the homepage screenshot
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Get the screenshot image
|
||||
const screenshotImg = document.querySelector('.screenshot-container img');
|
||||
|
||||
// If the image exists
|
||||
if (screenshotImg) {
|
||||
// Create lightbox elements
|
||||
const lightbox = document.createElement('div');
|
||||
lightbox.className = 'satag-lightbox';
|
||||
|
||||
const closeBtn = document.createElement('span');
|
||||
closeBtn.className = 'satag-lightbox-close';
|
||||
closeBtn.innerHTML = '×';
|
||||
|
||||
const lightboxImg = document.createElement('img');
|
||||
lightboxImg.className = 'satag-lightbox-img';
|
||||
lightboxImg.src = screenshotImg.src;
|
||||
lightboxImg.alt = screenshotImg.alt;
|
||||
|
||||
// Append elements to the lightbox
|
||||
lightbox.appendChild(closeBtn);
|
||||
lightbox.appendChild(lightboxImg);
|
||||
|
||||
// Remove any existing lightbox to avoid duplicates
|
||||
const existingLightbox = document.querySelector('.satag-lightbox');
|
||||
if (existingLightbox) {
|
||||
document.body.removeChild(existingLightbox);
|
||||
}
|
||||
|
||||
// Append lightbox to the body instead of the screenshot container
|
||||
// This allows the lightbox to be as large as the viewport, not constrained by the container
|
||||
document.body.appendChild(lightbox);
|
||||
|
||||
// Function to position the lightbox directly over the original image
|
||||
function positionLightbox() {
|
||||
// Get the position and dimensions of the original image
|
||||
const imgRect = screenshotImg.getBoundingClientRect();
|
||||
const screenshotContainer = document.querySelector('.screenshot-container');
|
||||
const containerRect = screenshotContainer.getBoundingClientRect();
|
||||
|
||||
// Get the current scroll position
|
||||
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
||||
|
||||
// Get viewport dimensions
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
|
||||
// Position the lightbox directly over the original image
|
||||
lightbox.style.position = 'fixed';
|
||||
lightbox.style.top = imgRect.top + 'px';
|
||||
lightbox.style.left = imgRect.left + 'px';
|
||||
lightbox.style.width = imgRect.width + 'px';
|
||||
lightbox.style.height = imgRect.height + 'px';
|
||||
lightbox.style.display = 'flex';
|
||||
lightbox.style.alignItems = 'center';
|
||||
lightbox.style.justifyContent = 'center';
|
||||
|
||||
// Set the lightbox image to fill the lightbox container
|
||||
lightboxImg.style.position = 'relative';
|
||||
lightboxImg.style.width = '100%';
|
||||
lightboxImg.style.height = '100%';
|
||||
lightboxImg.style.objectFit = 'contain';
|
||||
|
||||
// Position the close button in the top-right corner of the lightbox
|
||||
closeBtn.style.top = '5px';
|
||||
closeBtn.style.right = '5px';
|
||||
}
|
||||
|
||||
// Function to check if lightbox should be enabled (screen width > 768px)
|
||||
function shouldEnableLightbox() {
|
||||
return window.innerWidth > 768;
|
||||
}
|
||||
|
||||
// Update cursor style based on screen width
|
||||
function updateCursorStyle() {
|
||||
screenshotImg.style.cursor = shouldEnableLightbox() ? 'pointer' : 'default';
|
||||
}
|
||||
|
||||
// Initial cursor style update
|
||||
updateCursorStyle();
|
||||
|
||||
// Update cursor style when window is resized
|
||||
window.addEventListener('resize', updateCursorStyle);
|
||||
|
||||
// Open lightbox when clicking on the screenshot (only if screen width > 768px)
|
||||
screenshotImg.addEventListener('click', function(e) {
|
||||
e.preventDefault(); // Prevent default behavior
|
||||
|
||||
// Only activate lightbox if screen width > 768px
|
||||
if (!shouldEnableLightbox()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Position the lightbox over the original image
|
||||
positionLightbox();
|
||||
|
||||
// Display the lightbox - use flex to match our CSS
|
||||
lightbox.style.display = 'flex';
|
||||
|
||||
// Force a reflow to ensure the display change takes effect before adding the active class
|
||||
void lightbox.offsetWidth;
|
||||
|
||||
// Apply transform scale to the lightbox to make it larger
|
||||
const viewportWidth = window.innerWidth;
|
||||
if (viewportWidth <= 479) { // Mobile
|
||||
lightbox.style.transform = 'scale(1.2)';
|
||||
} else if (viewportWidth <= 959) { // Tablet
|
||||
lightbox.style.transform = 'scale(1.3)';
|
||||
} else if (viewportWidth <= 1219) { // Medium screens
|
||||
lightbox.style.transform = 'scale(1.4)';
|
||||
} else { // Large screens
|
||||
lightbox.style.transform = 'scale(1.5)';
|
||||
}
|
||||
|
||||
// Add the active class to trigger the transition
|
||||
lightbox.classList.add('active');
|
||||
});
|
||||
|
||||
// Function to handle closing with transition
|
||||
function closeLightboxWithTransition() {
|
||||
lightbox.style.opacity = '0';
|
||||
lightbox.style.transform = 'scale(1)'; // Reset scale to original size
|
||||
|
||||
// Wait for transition to complete before removing active class
|
||||
setTimeout(function() {
|
||||
lightbox.classList.remove('active');
|
||||
|
||||
// Reset display to none after the transition is complete
|
||||
lightbox.style.display = 'none';
|
||||
|
||||
// Reset all inline styles after the lightbox is hidden
|
||||
setTimeout(function() {
|
||||
// Reset opacity and transform
|
||||
lightbox.style.opacity = '';
|
||||
lightbox.style.transform = '';
|
||||
|
||||
// Reset position and size styles
|
||||
lightbox.style.position = '';
|
||||
lightbox.style.top = '';
|
||||
lightbox.style.left = '';
|
||||
lightbox.style.width = '';
|
||||
lightbox.style.height = '';
|
||||
lightbox.style.alignItems = '';
|
||||
lightbox.style.justifyContent = '';
|
||||
|
||||
// Reset image styles
|
||||
lightboxImg.style.width = '';
|
||||
lightboxImg.style.height = '';
|
||||
lightboxImg.style.objectFit = '';
|
||||
|
||||
// Reset close button styles
|
||||
closeBtn.style.top = '';
|
||||
closeBtn.style.right = '';
|
||||
}, 100);
|
||||
}, 400); // Match the transition duration from CSS
|
||||
}
|
||||
|
||||
// Close lightbox when clicking on the close button
|
||||
closeBtn.addEventListener('click', function(e) {
|
||||
e.stopPropagation(); // Prevent event from bubbling up
|
||||
closeLightboxWithTransition();
|
||||
});
|
||||
|
||||
// Close lightbox when clicking on the lightbox (outside the image)
|
||||
lightbox.addEventListener('click', function(e) {
|
||||
if (e.target === lightbox) {
|
||||
closeLightboxWithTransition();
|
||||
}
|
||||
});
|
||||
|
||||
// Close lightbox when pressing Escape key
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape' && lightbox.classList.contains('active')) {
|
||||
closeLightboxWithTransition();
|
||||
}
|
||||
});
|
||||
|
||||
// Update lightbox position when window is resized
|
||||
window.addEventListener('resize', function() {
|
||||
if (lightbox.classList.contains('active')) {
|
||||
// Reposition the lightbox based on new viewport dimensions
|
||||
positionLightbox();
|
||||
|
||||
// Apply appropriate transform scale based on viewport width
|
||||
const viewportWidth = window.innerWidth;
|
||||
if (viewportWidth <= 479) { // Mobile
|
||||
lightbox.style.transform = 'scale(1.2)';
|
||||
} else if (viewportWidth <= 959) { // Tablet
|
||||
lightbox.style.transform = 'scale(1.3)';
|
||||
} else if (viewportWidth <= 1219) { // Medium screens
|
||||
lightbox.style.transform = 'scale(1.4)';
|
||||
} else { // Large screens
|
||||
lightbox.style.transform = 'scale(1.5)';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,221 @@
|
||||
// Slideshow functionality for FAQ answers - OPTIMIZED VERSION
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initSlideshows);
|
||||
document.addEventListener('DOMContentSwap', initSlideshows);
|
||||
document.addEventListener('mdContentChanged', initSlideshows);
|
||||
|
||||
// Track initialized slideshows to prevent double-initialization
|
||||
const initializedSlideshows = new Set();
|
||||
|
||||
// Function to initialize all slideshows on the page
|
||||
function initSlideshows() {
|
||||
const slideshows = document.querySelectorAll('.faq-slideshow');
|
||||
|
||||
if (slideshows.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Slideshows found:', slideshows.length);
|
||||
|
||||
slideshows.forEach((slideshow, slideshowIndex) => {
|
||||
// Create unique ID for this slideshow
|
||||
const slideshowId = `slideshow-${slideshowIndex}`;
|
||||
|
||||
// Skip if already initialized
|
||||
if (initializedSlideshows.has(slideshowId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
slideshow.setAttribute('id', slideshowId);
|
||||
initializedSlideshows.add(slideshowId);
|
||||
|
||||
// Get slideshow elements
|
||||
const container = slideshow.querySelector('.faq-slideshow-container');
|
||||
const slides = slideshow.querySelectorAll('.faq-slide');
|
||||
const prevBtn = slideshow.querySelector('button.faq-slideshow-prev');
|
||||
const nextBtn = slideshow.querySelector('button.faq-slideshow-next');
|
||||
const dotsContainer = slideshow.querySelector('.faq-slideshow-dots');
|
||||
|
||||
console.log('Slideshow elements found:', {
|
||||
container: !!container,
|
||||
slides: slides.length,
|
||||
prevBtn: !!prevBtn,
|
||||
nextBtn: !!nextBtn,
|
||||
dotsContainer: !!dotsContainer
|
||||
});
|
||||
|
||||
if (!container || slides.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Current slide index
|
||||
let currentSlide = 0;
|
||||
|
||||
// Function to go to a specific slide
|
||||
function goToSlide(index) {
|
||||
console.log(`goToSlide called for slideshow ${slideshowId} with index ${index}`);
|
||||
|
||||
// Handle wrapping around
|
||||
if (index < 0) {
|
||||
index = slides.length - 1;
|
||||
console.log(`Wrapped to last slide: ${index}`);
|
||||
} else if (index >= slides.length) {
|
||||
index = 0;
|
||||
console.log(`Wrapped to first slide: ${index}`);
|
||||
}
|
||||
|
||||
// Update current slide index
|
||||
const previousSlide = currentSlide;
|
||||
currentSlide = index;
|
||||
console.log(`Changing slide from ${previousSlide} to ${currentSlide}`);
|
||||
|
||||
// Move the container to show the current slide (OPTIMIZED)
|
||||
const transformValue = `translateX(-${currentSlide * 100}%)`;
|
||||
console.log(`Setting transform to: ${transformValue}`);
|
||||
container.style.transform = transformValue;
|
||||
|
||||
// Update active dot (OPTIMIZED)
|
||||
if (dotsContainer) {
|
||||
const dots = dotsContainer.querySelectorAll('.faq-slideshow-dot');
|
||||
const activeDot = dotsContainer.querySelector('.faq-slideshow-dot.active');
|
||||
const newActiveDot = dots[currentSlide];
|
||||
|
||||
if (activeDot && activeDot !== newActiveDot) {
|
||||
activeDot.classList.remove('active');
|
||||
}
|
||||
if (newActiveDot && !newActiveDot.classList.contains('active')) {
|
||||
newActiveDot.classList.add('active');
|
||||
}
|
||||
|
||||
console.log(`Updated active dot to index ${currentSlide}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Create dots if they don't exist
|
||||
if (dotsContainer && dotsContainer.children.length === 0) {
|
||||
for (let i = 0; i < slides.length; i++) {
|
||||
const dot = document.createElement('div');
|
||||
dot.className = 'faq-slideshow-dot';
|
||||
if (i === 0) {
|
||||
dot.classList.add('active');
|
||||
}
|
||||
dot.addEventListener('click', () => {
|
||||
goToSlide(i);
|
||||
});
|
||||
dotsContainer.appendChild(dot);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXED: Only use addEventListener (remove onclick to prevent double execution)
|
||||
if (prevBtn) {
|
||||
console.log('Adding click event listener to prev button for slideshow', slideshowId);
|
||||
|
||||
// Remove any existing handlers
|
||||
prevBtn.onclick = null;
|
||||
|
||||
// Add single event listener
|
||||
prevBtn.addEventListener('click', (e) => {
|
||||
console.log('Prev button clicked for slideshow', slideshowId);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
goToSlide(currentSlide - 1);
|
||||
}, { once: false, passive: false });
|
||||
|
||||
prevBtn.style.cursor = 'pointer';
|
||||
}
|
||||
|
||||
if (nextBtn) {
|
||||
console.log('Adding click event listener to next button for slideshow', slideshowId);
|
||||
|
||||
// Remove any existing handlers
|
||||
nextBtn.onclick = null;
|
||||
|
||||
// Add single event listener
|
||||
nextBtn.addEventListener('click', (e) => {
|
||||
console.log('Next button clicked for slideshow', slideshowId);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
goToSlide(currentSlide + 1);
|
||||
}, { once: false, passive: false });
|
||||
|
||||
nextBtn.style.cursor = 'pointer';
|
||||
}
|
||||
|
||||
// Initialize the first slide
|
||||
goToSlide(0);
|
||||
|
||||
// Add keyboard navigation when slideshow is in focus
|
||||
slideshow.tabIndex = 0;
|
||||
slideshow.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'ArrowLeft') {
|
||||
goToSlide(currentSlide - 1);
|
||||
} else if (e.key === 'ArrowRight') {
|
||||
goToSlide(currentSlide + 1);
|
||||
}
|
||||
});
|
||||
|
||||
// Add optimized swipe support for touch devices
|
||||
let touchStartX = 0;
|
||||
let touchEndX = 0;
|
||||
|
||||
slideshow.addEventListener('touchstart', (e) => {
|
||||
touchStartX = e.changedTouches[0].screenX;
|
||||
}, { passive: true });
|
||||
|
||||
slideshow.addEventListener('touchend', (e) => {
|
||||
touchEndX = e.changedTouches[0].screenX;
|
||||
handleSwipe();
|
||||
}, { passive: true });
|
||||
|
||||
function handleSwipe() {
|
||||
const swipeThreshold = 50;
|
||||
|
||||
if (touchEndX < touchStartX - swipeThreshold) {
|
||||
goToSlide(currentSlide + 1);
|
||||
} else if (touchEndX > touchStartX + swipeThreshold) {
|
||||
goToSlide(currentSlide - 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// MutationObserver to detect when new slideshows are added to the DOM
|
||||
// FIXED: Renamed to avoid conflicts and added throttling
|
||||
const slideshowObserver = new MutationObserver((mutations) => {
|
||||
let hasRelevantMutation = false;
|
||||
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
||||
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
||||
const node = mutation.addedNodes[i];
|
||||
if (node.nodeType === 1 && (node.classList?.contains('faq-slideshow') ||
|
||||
node.querySelector?.('.faq-slideshow'))) {
|
||||
hasRelevantMutation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (hasRelevantMutation) {
|
||||
setTimeout(initSlideshows, 100);
|
||||
}
|
||||
});
|
||||
|
||||
// Start observing the document
|
||||
slideshowObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// Additional event listener for dynamically loaded content
|
||||
window.addEventListener('load', function() {
|
||||
setTimeout(initSlideshows, 500);
|
||||
});
|
||||
|
||||
// For Material for MkDocs specific events
|
||||
if (typeof document$.subscribe === 'function') {
|
||||
document$.subscribe(function() {
|
||||
setTimeout(initSlideshows, 100);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
// Testimonial-Wechsel-Funktionalität
|
||||
const testimonialImages = document.querySelectorAll('.satag--home-testimonial-image-wrapper');
|
||||
const testimonialTexts = document.querySelectorAll('.satag--home-testimonials-text');
|
||||
|
||||
// Funktion zum Wechseln des aktiven Testimonials
|
||||
function switchTestimonial(id) {
|
||||
// Entferne 'active' Klasse von allen Bildern und Texten
|
||||
testimonialImages.forEach(img => img.classList.remove('active'));
|
||||
testimonialTexts.forEach(text => text.classList.remove('active'));
|
||||
|
||||
// Füge 'active' Klasse zum ausgewählten Bild und Text hinzu
|
||||
document.querySelector(`.satag--home-testimonial-image-wrapper[data-testimonial-id="${id}"]`).classList.add('active');
|
||||
document.querySelector(`.satag--home-testimonials-text[data-testimonial-id="${id}"]`).classList.add('active');
|
||||
}
|
||||
|
||||
// Event-Listener für Klicks auf die Bilder
|
||||
testimonialImages.forEach(img => {
|
||||
img.addEventListener('click', function() {
|
||||
const id = this.getAttribute('data-testimonial-id');
|
||||
switchTestimonial(id);
|
||||
});
|
||||
});
|
||||
|
||||
// Optional: Automatischer Wechsel alle 5 Sekunden
|
||||
let currentId = 1;
|
||||
const totalTestimonials = testimonialImages.length;
|
||||
|
||||
function autoSwitchTestimonial() {
|
||||
currentId = currentId % totalTestimonials + 1;
|
||||
switchTestimonial(currentId);
|
||||
}
|
||||
|
||||
// Kommentiere die nächste Zeile aus, wenn du keinen automatischen Wechsel möchtest
|
||||
const intervalId = setInterval(autoSwitchTestimonial, 5000);
|
||||
|
||||
// Optional: Stoppe den automatischen Wechsel, wenn der Benutzer mit einem Testimonial interagiert
|
||||
testimonialImages.forEach(img => {
|
||||
img.addEventListener('click', function() {
|
||||
clearInterval(intervalId);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const scrollWrap = document.querySelector('.md-search__scrollwrap');
|
||||
|
||||
if (scrollWrap) {
|
||||
scrollWrap.setAttribute('tabindex', '0');
|
||||
|
||||
scrollWrap.addEventListener('keydown', function(e) {
|
||||
// Pfeiltasten für Scrolling
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
this.scrollTop += 30;
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
this.scrollTop -= 30;
|
||||
} else if (e.key === 'PageDown') {
|
||||
e.preventDefault();
|
||||
this.scrollTop += this.clientHeight;
|
||||
} else if (e.key === 'PageUp') {
|
||||
e.preventDefault();
|
||||
this.scrollTop -= this.clientHeight;
|
||||
} else if (e.key === 'Home') {
|
||||
e.preventDefault();
|
||||
this.scrollTop = 0;
|
||||
} else if (e.key === 'End') {
|
||||
e.preventDefault();
|
||||
this.scrollTop = this.scrollHeight;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user