261 lines
8.6 KiB
JavaScript
261 lines
8.6 KiB
JavaScript
/**
|
|
* Tino Andri - Quantenheilung & Selbstheilung
|
|
* JavaScript functionality
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Mobile navigation toggle
|
|
const navToggle = document.querySelector('.nav-toggle');
|
|
const navMenu = document.querySelector('.nav-menu');
|
|
|
|
if (navToggle && navMenu) {
|
|
navToggle.addEventListener('click', function() {
|
|
navToggle.classList.toggle('active');
|
|
navMenu.classList.toggle('active');
|
|
});
|
|
|
|
// Close menu when clicking a link
|
|
navMenu.querySelectorAll('a').forEach(link => {
|
|
link.addEventListener('click', () => {
|
|
navToggle.classList.remove('active');
|
|
navMenu.classList.remove('active');
|
|
});
|
|
});
|
|
}
|
|
|
|
// Smooth scroll for anchor links
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
anchor.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const target = document.querySelector(this.getAttribute('href'));
|
|
if (target) {
|
|
const headerOffset = 80;
|
|
const elementPosition = target.getBoundingClientRect().top;
|
|
const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
|
|
|
|
window.scrollTo({
|
|
top: offsetPosition,
|
|
behavior: 'smooth'
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Reveal elements on scroll
|
|
const revealElements = document.querySelectorAll('.section');
|
|
|
|
const revealOnScroll = () => {
|
|
const windowHeight = window.innerHeight;
|
|
|
|
revealElements.forEach(element => {
|
|
const elementTop = element.getBoundingClientRect().top;
|
|
const revealPoint = 150;
|
|
|
|
if (elementTop < windowHeight - revealPoint) {
|
|
element.classList.add('visible');
|
|
}
|
|
});
|
|
};
|
|
|
|
// Initial class setup
|
|
revealElements.forEach(element => {
|
|
element.classList.add('reveal');
|
|
});
|
|
|
|
// Run on load and scroll
|
|
revealOnScroll();
|
|
window.addEventListener('scroll', revealOnScroll, { passive: true });
|
|
|
|
// Navigation background change on scroll
|
|
const nav = document.querySelector('.nav');
|
|
|
|
const updateNavOnScroll = () => {
|
|
if (window.scrollY > 50) {
|
|
nav.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.1)';
|
|
} else {
|
|
nav.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.06)';
|
|
}
|
|
};
|
|
|
|
window.addEventListener('scroll', updateNavOnScroll, { passive: true });
|
|
|
|
// Form submission (placeholder - replace with actual form handling)
|
|
const contactForm = document.querySelector('.contact-form');
|
|
|
|
if (contactForm) {
|
|
contactForm.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = new FormData(this);
|
|
const data = Object.fromEntries(formData);
|
|
|
|
console.log('Form submitted:', data);
|
|
|
|
alert('Vielen Dank für deine Nachricht! Ich werde mich bald bei dir melden.');
|
|
this.reset();
|
|
});
|
|
}
|
|
|
|
// Active navigation link highlighting
|
|
const sections = document.querySelectorAll('section[id]');
|
|
|
|
const highlightNav = () => {
|
|
const scrollY = window.pageYOffset;
|
|
|
|
sections.forEach(section => {
|
|
const sectionHeight = section.offsetHeight;
|
|
const sectionTop = section.offsetTop - 100;
|
|
const sectionId = section.getAttribute('id');
|
|
const navLink = document.querySelector(`.nav-menu a[href="#${sectionId}"]`);
|
|
|
|
if (navLink) {
|
|
if (scrollY > sectionTop && scrollY <= sectionTop + sectionHeight) {
|
|
navLink.style.color = 'var(--color-primary)';
|
|
} else {
|
|
navLink.style.color = '';
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
window.addEventListener('scroll', highlightNav, { passive: true });
|
|
|
|
// =========================================================================
|
|
// Testimonial Carousel
|
|
// =========================================================================
|
|
const carousel = document.querySelector('.carousel');
|
|
|
|
if (carousel) {
|
|
const track = carousel.querySelector('.carousel-track');
|
|
const cards = track.querySelectorAll('.testimonial-card');
|
|
const prevBtn = carousel.querySelector('.carousel-prev');
|
|
const nextBtn = carousel.querySelector('.carousel-next');
|
|
const dotsContainer = carousel.querySelector('.carousel-dots');
|
|
const totalCards = cards.length;
|
|
let currentIndex = 0;
|
|
let autoAdvanceTimer = null;
|
|
|
|
// Responsive visible count
|
|
function getVisibleCount() {
|
|
if (window.innerWidth <= 640) return 1;
|
|
if (window.innerWidth <= 1024) return 2;
|
|
return 3;
|
|
}
|
|
|
|
let visibleCount = getVisibleCount();
|
|
|
|
function getMaxIndex() {
|
|
return Math.max(0, totalCards - visibleCount);
|
|
}
|
|
|
|
// Build dots
|
|
function buildDots() {
|
|
dotsContainer.innerHTML = '';
|
|
const dotCount = getMaxIndex() + 1;
|
|
for (let i = 0; i < dotCount; i++) {
|
|
const dot = document.createElement('button');
|
|
dot.classList.add('carousel-dot');
|
|
dot.setAttribute('aria-label', `Folie ${i + 1}`);
|
|
if (i === currentIndex) dot.classList.add('active');
|
|
dot.addEventListener('click', () => goTo(i));
|
|
dotsContainer.appendChild(dot);
|
|
}
|
|
}
|
|
|
|
function updateCarousel() {
|
|
const gap = 24; // matches CSS gap
|
|
const cardWidth = (track.clientWidth - gap * (visibleCount - 1)) / visibleCount;
|
|
const offset = currentIndex * (cardWidth + gap);
|
|
track.style.transform = `translateX(-${offset}px)`;
|
|
|
|
// Update dots
|
|
dotsContainer.querySelectorAll('.carousel-dot').forEach((dot, i) => {
|
|
dot.classList.toggle('active', i === currentIndex);
|
|
});
|
|
|
|
// Update button states
|
|
prevBtn.disabled = currentIndex === 0;
|
|
nextBtn.disabled = currentIndex >= getMaxIndex();
|
|
}
|
|
|
|
function goTo(index) {
|
|
currentIndex = Math.max(0, Math.min(index, getMaxIndex()));
|
|
updateCarousel();
|
|
resetAutoAdvance();
|
|
}
|
|
|
|
function goNext() {
|
|
if (currentIndex >= getMaxIndex()) {
|
|
goTo(0);
|
|
} else {
|
|
goTo(currentIndex + 1);
|
|
}
|
|
}
|
|
|
|
function goPrev() {
|
|
goTo(currentIndex - 1);
|
|
}
|
|
|
|
// Auto-advance
|
|
function startAutoAdvance() {
|
|
autoAdvanceTimer = setInterval(goNext, 6000);
|
|
}
|
|
|
|
function resetAutoAdvance() {
|
|
clearInterval(autoAdvanceTimer);
|
|
startAutoAdvance();
|
|
}
|
|
|
|
// Pause on hover
|
|
carousel.addEventListener('mouseenter', () => clearInterval(autoAdvanceTimer));
|
|
carousel.addEventListener('mouseleave', startAutoAdvance);
|
|
|
|
// Button events
|
|
prevBtn.addEventListener('click', goPrev);
|
|
nextBtn.addEventListener('click', goNext);
|
|
|
|
// Handle resize
|
|
let resizeTimeout;
|
|
window.addEventListener('resize', () => {
|
|
clearTimeout(resizeTimeout);
|
|
resizeTimeout = setTimeout(() => {
|
|
const newCount = getVisibleCount();
|
|
if (newCount !== visibleCount) {
|
|
visibleCount = newCount;
|
|
if (currentIndex > getMaxIndex()) currentIndex = getMaxIndex();
|
|
buildDots();
|
|
}
|
|
updateCarousel();
|
|
}, 150);
|
|
});
|
|
|
|
// Initialize
|
|
buildDots();
|
|
updateCarousel();
|
|
startAutoAdvance();
|
|
}
|
|
|
|
// =========================================================================
|
|
// Accordion
|
|
// =========================================================================
|
|
document.querySelectorAll('.accordion-group').forEach(group => {
|
|
const accordions = group.querySelectorAll('.accordion');
|
|
|
|
accordions.forEach(accordion => {
|
|
const header = accordion.querySelector('.accordion-header');
|
|
|
|
header.addEventListener('click', () => {
|
|
const isOpen = accordion.classList.contains('open');
|
|
|
|
// Close all in this group
|
|
accordions.forEach(a => a.classList.remove('open'));
|
|
|
|
// Toggle clicked
|
|
if (!isOpen) {
|
|
accordion.classList.add('open');
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|