b2in/resources/js/app.js

162 lines
5.3 KiB
JavaScript

// App JS ohne Alpine-Initialisierung. Alpine wird von Livewire verwaltet.
// Premium Scroll Animations with Intersection Observer
(function() {
'use strict';
// Warte bis DOM vollständig geladen ist
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initAnimations);
} else {
initAnimations();
}
function initAnimations() {
// Intersection Observer Konfiguration
const observerOptions = {
threshold: 0.15,
rootMargin: '0px 0px -80px 0px'
};
// Erstelle Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Füge is-visible Klasse mit kleinem Delay hinzu für sanfteren Effekt
setTimeout(() => {
entry.target.classList.add('is-visible');
}, 50);
// Observer beenden nach Animation für bessere Performance
observer.unobserve(entry.target);
}
});
}, observerOptions);
// Finde alle Elemente mit Animation-Klassen
const animatedElements = document.querySelectorAll(
'.scroll-animate, .fade-in, .slide-up, .slide-right, .slide-left, .scale-in'
);
// Beobachte jedes Element
animatedElements.forEach(el => {
observer.observe(el);
});
// Smooth Scroll für Anchor-Links
document.addEventListener('click', function(e) {
const target = e.target.closest('a[href^="#"]');
if (target && target.hash) {
const targetElement = document.querySelector(target.hash);
if (targetElement) {
e.preventDefault();
const headerOffset = 80;
const elementPosition = targetElement.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
window.scrollTo({
top: offsetPosition,
behavior: 'smooth'
});
}
}
});
// Scroll Progress Indicator
initScrollProgress();
// Premium Sticky Header
initStickyHeader();
}
function initStickyHeader() {
const header = document.getElementById('main-header');
if (!header) return;
let lastScrollTop = 0;
let scrollTimeout = null;
function handleHeaderScroll() {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
// Add/Remove scrolled class for enhanced shadow
if (scrollTop > 50) {
header.classList.add('scrolled');
} else {
header.classList.remove('scrolled');
}
// Optional: Hide header on scroll down, show on scroll up
// Uncomment if you want auto-hide behavior
/*
if (scrollTop > lastScrollTop && scrollTop > 100) {
// Scrolling down
header.classList.add('hide');
} else {
// Scrolling up
header.classList.remove('hide');
}
*/
lastScrollTop = scrollTop <= 0 ? 0 : scrollTop;
}
// Listen to scroll with throttling
let headerTicking = false;
window.addEventListener('scroll', function() {
if (!headerTicking) {
window.requestAnimationFrame(function() {
handleHeaderScroll();
headerTicking = false;
});
headerTicking = true;
}
});
// Initial check
handleHeaderScroll();
}
function initScrollProgress() {
// Erstelle Progress Bar Element
const progressBar = document.createElement('div');
progressBar.className = 'scroll-progress-bar';
document.body.appendChild(progressBar);
// Update Progress on Scroll
function updateProgress() {
const windowHeight = window.innerHeight;
const documentHeight = document.documentElement.scrollHeight;
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
// Berechne Progress (0-100%)
const scrollPercentage = (scrollTop / (documentHeight - windowHeight)) * 100;
// Update Bar Width
progressBar.style.width = `${Math.min(scrollPercentage, 100)}%`;
// Optional: Show/Hide basierend auf Scroll-Position
if (scrollTop > 100) {
progressBar.classList.add('visible');
} else {
progressBar.classList.remove('visible');
}
}
// Listen to scroll events mit Throttling für Performance
let ticking = false;
window.addEventListener('scroll', function() {
if (!ticking) {
window.requestAnimationFrame(function() {
updateProgress();
ticking = false;
});
ticking = true;
}
});
// Initial update
updateProgress();
}
})();