Changes für lighthouse Branch

This commit is contained in:
2026-01-09 09:17:39 +01:00
parent 9938c1f9e2
commit 1c5f272f33
40 changed files with 2636 additions and 370 deletions

210
src/utils/animations.ts Normal file
View File

@@ -0,0 +1,210 @@
import { Variants } from 'framer-motion';
// Smooth easing curves
export const easing = {
smooth: [0.6, 0.01, 0.05, 0.95],
snappy: [0.25, 0.46, 0.45, 0.94],
bouncy: [0.68, -0.55, 0.265, 1.55],
elegant: [0.43, 0.13, 0.23, 0.96],
};
// Hero section animations
export const heroVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.15,
delayChildren: 0.3,
},
},
};
export const heroItemVariants: Variants = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.8,
ease: easing.elegant,
},
},
};
// Fade in up animation
export const fadeInUp: Variants = {
hidden: {
opacity: 0,
y: 60,
},
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.7,
ease: easing.elegant,
},
},
};
// Scale in animation
export const scaleIn: Variants = {
hidden: {
opacity: 0,
scale: 0.8,
},
visible: {
opacity: 1,
scale: 1,
transition: {
duration: 0.6,
ease: easing.smooth,
},
},
};
// Slide in from left
export const slideInLeft: Variants = {
hidden: {
opacity: 0,
x: -60,
},
visible: {
opacity: 1,
x: 0,
transition: {
duration: 0.7,
ease: easing.elegant,
},
},
};
// Slide in from right
export const slideInRight: Variants = {
hidden: {
opacity: 0,
x: 60,
},
visible: {
opacity: 1,
x: 0,
transition: {
duration: 0.7,
ease: easing.elegant,
},
},
};
// Stagger container
export const staggerContainer: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.12,
delayChildren: 0.1,
},
},
};
// Stagger item
export const staggerItem: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.5,
ease: easing.elegant,
},
},
};
// Button hover animation
export const buttonHover = {
scale: 1.02,
transition: {
duration: 0.2,
ease: easing.snappy,
},
};
export const buttonTap = {
scale: 0.98,
};
// Card hover animation
export const cardHover = {
y: -8,
transition: {
duration: 0.3,
ease: easing.smooth,
},
};
// Glow effect
export const glowHover = {
boxShadow: '0 0 30px rgba(51, 102, 255, 0.6)',
transition: {
duration: 0.3,
},
};
// Navigation animation
export const navVariants: Variants = {
hidden: {
y: -100,
opacity: 0,
},
visible: {
y: 0,
opacity: 1,
transition: {
duration: 0.6,
ease: easing.elegant,
},
},
};
// Page transition
export const pageTransition = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -20 },
transition: { duration: 0.4, ease: easing.elegant },
};
// Parallax scroll effect
export const parallaxScroll = (scrollY: number, factor: number = 0.5) => ({
y: scrollY * factor,
transition: { type: 'tween', ease: 'linear', duration: 0 },
});
// Scroll reveal with intersection observer
export const scrollRevealVariants: Variants = {
hidden: {
opacity: 0,
y: 50,
},
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.7,
ease: easing.elegant,
},
},
};
// Magnetic button effect (advanced)
export const magneticEffect = (x: number, y: number, strength: number = 0.3) => ({
x: x * strength,
y: y * strength,
transition: {
type: 'spring',
stiffness: 150,
damping: 15,
mass: 0.1,
},
});

View File

@@ -0,0 +1,100 @@
import { onCLS, onFCP, onLCP, onTTFB, onINP, type Metric } from 'web-vitals';
function sendToAnalytics(metric: Metric) {
// Log to console in development
if (import.meta.env.DEV) {
console.log('Web Vitals:', {
name: metric.name,
value: metric.value,
rating: metric.rating,
delta: metric.delta,
id: metric.id,
});
}
// Send to Google Analytics if available
if (typeof window !== 'undefined' && (window as any).gtag) {
(window as any).gtag('event', metric.name, {
value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value),
event_category: 'Web Vitals',
event_label: metric.id,
non_interaction: true,
});
}
// Send to custom analytics endpoint if needed
if (import.meta.env.PROD && import.meta.env.VITE_ANALYTICS_ENDPOINT) {
fetch(import.meta.env.VITE_ANALYTICS_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
metric: metric.name,
value: metric.value,
rating: metric.rating,
id: metric.id,
timestamp: Date.now(),
url: window.location.href,
userAgent: navigator.userAgent,
}),
keepalive: true,
}).catch((error) => {
console.error('Failed to send web vitals:', error);
});
}
}
export function reportWebVitals() {
// Core Web Vitals
onCLS(sendToAnalytics);
onLCP(sendToAnalytics);
onINP(sendToAnalytics); // Replaces deprecated FID
// Other important metrics
onFCP(sendToAnalytics);
onTTFB(sendToAnalytics);
}
// Performance observer for additional metrics
export function observePerformance() {
if (typeof window === 'undefined' || !('PerformanceObserver' in window)) {
return;
}
// Observe long tasks (blocking the main thread)
try {
const longTaskObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) {
console.warn('Long Task detected:', {
duration: entry.duration,
startTime: entry.startTime,
name: entry.name,
});
}
}
});
longTaskObserver.observe({ entryTypes: ['longtask'] });
} catch (e) {
// Long task API not supported
}
// Observe layout shifts
try {
const layoutShiftObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if ((entry as any).hadRecentInput) continue;
const value = (entry as any).value;
if (value > 0.1) {
console.warn('Large Layout Shift:', {
value,
startTime: entry.startTime,
sources: (entry as any).sources,
});
}
}
});
layoutShiftObserver.observe({ entryTypes: ['layout-shift'] });
} catch (e) {
// Layout shift API not supported
}
}