Files
website-html/js/script.js
2026-03-02 11:29:15 +01:00

254 lines
6.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =====================================================
GLOBAL STATE
===================================================== */
let index = 0;
let track;
let dots = [];
let currentLang = "de";
/* =====================================================
DOM CONTENT LOADED
===================================================== */
document.addEventListener("DOMContentLoaded", () => {
const saved = localStorage.getItem("lang") || "de";
setLang(saved, false);
initServices();
initNavigation();
initNewsSlider();
});
/* =====================================================
i18n LANGUAGE SWITCHING
===================================================== */
async function setLang(lang, save = true) {
try {
const res = await fetch(`locales/${lang}.json`);
const translations = await res.json();
currentLang = lang;
document.documentElement.lang = lang;
if (save) localStorage.setItem("lang", lang);
/* Plain text nodes */
document.querySelectorAll("[data-i18n]").forEach(el => {
const key = el.getAttribute("data-i18n");
if (translations[key] !== undefined) {
el.textContent = translations[key];
}
});
/* HTML nodes (for content with <strong>, <br> etc.) */
document.querySelectorAll("[data-i18n-html]").forEach(el => {
const key = el.getAttribute("data-i18n-html");
if (translations[key] !== undefined) {
el.innerHTML = translations[key];
}
});
/* Update active button */
document.getElementById("lang-de").classList.toggle("active", lang === "de");
document.getElementById("lang-en").classList.toggle("active", lang === "en");
} catch (err) {
console.error("Language file could not be loaded:", err);
}
}
/* Attribute handling (for [src], [alt], etc.) */
document.querySelectorAll("[data-i18n-attr]").forEach(el => {
const attrMap = el.getAttribute("data-i18n-attr"); // Example: "src:logo_path,alt:logo_alt"
const mappings = attrMap.split(';');
mappings.forEach(mapping => {
const [attr, key] = mapping.split(':');
if (translations[key] !== undefined) {
el.setAttribute(attr, translations[key]);
}
});
});
/* =====================================================
SERVICES EXPAND / COLLAPSE
===================================================== */
function initServices() {
const boxes = document.querySelectorAll(".service-box");
boxes.forEach(box => {
const arrow = box.querySelector(".service-arrow");
const text = box.querySelector(".service-text");
let closeTimeout;
arrow.addEventListener("click", () => {
boxes.forEach(b => {
if (b !== box) b.classList.remove("open");
if (b.closeTimeout) clearTimeout(b.closeTimeout);
});
box.classList.toggle("open");
});
/* AUTO CLOSE */
box.addEventListener("mouseleave", () => {
if (box.classList.contains("open")) {
box.classList.add("closing");
closeTimeout = setTimeout(() => {
box.classList.remove("open");
}, 600);
box.closeTimeout = closeTimeout;
}
});
/* CANCEL CLOSE */
box.addEventListener("mouseenter", () => {
if (closeTimeout) clearTimeout(closeTimeout);
box.classList.remove("closing");
});
/* CLEANUP CLASS */
text.addEventListener("transitionend", e => {
if (e.propertyName === "max-height" && box.classList.contains("closing")) {
box.classList.remove("closing");
}
});
});
}
/* =====================================================
SCROLL TO TOP
===================================================== */
function scrollToTop() {
window.scrollTo({ top: 0, behavior: "smooth" });
}
/* =====================================================
MOBILE BURGER MENU
===================================================== */
function toggleBurger() {
document.querySelector(".nav").classList.toggle("open");
}
/* =====================================================
ACTIVE NAVIGATION SCROLL
===================================================== */
function initNavigation() {
const sections = document.querySelectorAll("section");
const navLinks = document.querySelectorAll(".nav-links a");
window.addEventListener("scroll", () => {
let current = "";
sections.forEach(section => {
const top = section.offsetTop - 120;
if (window.scrollY >= top) current = section.getAttribute("id");
});
navLinks.forEach(link => {
link.classList.remove("active");
if (link.getAttribute("href") === "#" + current) link.classList.add("active");
});
});
}
/* =====================================================
NEWS SLIDER
===================================================== */
function initNewsSlider() {
track = document.querySelector(".news-track");
const slider = document.querySelector(".news-slider");
const dotsContainer = document.querySelector(".news-dots");
const slides = document.querySelectorAll(".news-slide");
if (!track || !dotsContainer || slides.length === 0) return;
let autoSlide;
const INTERVAL = 8000;
/* CREATE DOTS */
dotsContainer.innerHTML = "";
dots = [];
slides.forEach((slide, i) => {
const dot = document.createElement("div");
dot.classList.add("news-dot");
if (i === 0) dot.classList.add("active");
dot.addEventListener("click", () => {
index = i;
updateSlider();
restartAutoSlide();
});
dotsContainer.appendChild(dot);
dots.push(dot);
});
/* UPDATE SLIDER */
function updateSlider() {
track.style.transform = `translateX(-${index * 100}%)`;
dots.forEach((dot, i) => dot.classList.toggle("active", i === index));
}
/* AUTO LOOP */
function startAutoSlide() {
autoSlide = setInterval(() => {
index = (index + 1) >= slides.length ? 0 : index + 1;
updateSlider();
}, INTERVAL);
}
function stopAutoSlide() { clearInterval(autoSlide); }
function restartAutoSlide() { stopAutoSlide(); startAutoSlide(); }
/* PAUSE ON HOVER */
const newsSection = document.querySelector("#news");
newsSection.addEventListener("mouseenter", stopAutoSlide);
newsSection.addEventListener("mouseleave", startAutoSlide);
/* TOUCH SUPPORT */
let startX = 0;
let isDragging = false;
track.addEventListener("touchstart", e => {
startX = e.touches[0].clientX;
isDragging = true;
stopAutoSlide();
});
track.addEventListener("touchmove", e => {
if (!isDragging) return;
const delta = e.touches[0].clientX - startX;
track.style.transition = "none";
track.style.transform = `translateX(calc(-${index * 100}% + ${delta}px))`;
});
track.addEventListener("touchend", e => {
isDragging = false;
track.style.transition = "transform 0.6s ease";
const delta = e.changedTouches[0].clientX - startX;
if (delta > 50 && index > 0) index--;
else if (delta < -50 && index < slides.length - 1) index++;
updateSlider();
restartAutoSlide();
});
updateSlider();
startAutoSlide();
}