basic version by Felix
This commit is contained in:
263
js/script.js
Normal file
263
js/script.js
Normal file
@@ -0,0 +1,263 @@
|
||||
/* =====================================================
|
||||
GLOBAL STATE
|
||||
===================================================== */
|
||||
|
||||
let index = 0;
|
||||
let track;
|
||||
let dots = [];
|
||||
|
||||
|
||||
/* =====================================================
|
||||
DOM CONTENT LOADED
|
||||
===================================================== */
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
initServices();
|
||||
initNavigation();
|
||||
initNewsSlider();
|
||||
});
|
||||
|
||||
|
||||
/* =====================================================
|
||||
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; // 8 sec
|
||||
|
||||
/* -------------------------
|
||||
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++;
|
||||
|
||||
if (index >= slides.length) {
|
||||
index = 0; // LOOP BACK
|
||||
}
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
/* -------------------------
|
||||
INIT
|
||||
------------------------- */
|
||||
|
||||
updateSlider();
|
||||
startAutoSlide();
|
||||
}
|
||||
Reference in New Issue
Block a user