feat: wrapup wow — animated counters, scroll-reveal, fun facts, component split, budget formatting
Some checks failed
CI / Check / Test (push) Failing after 6m25s

This commit is contained in:
2026-06-04 17:15:35 +02:00
parent ebf9a9f4a8
commit 4bd8dcbf05
8 changed files with 425 additions and 238 deletions

View File

@@ -0,0 +1,57 @@
import { useEffect, useRef, useState } from "react"
export function useCountUp(target: number, duration = 1200) {
const [value, setValue] = useState(0)
const ref = useRef<HTMLDivElement>(null)
const started = useRef(false)
useEffect(() => {
const el = ref.current
if (!el) return
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting && !started.current) {
started.current = true
const start = performance.now()
const step = (now: number) => {
const progress = Math.min((now - start) / duration, 1)
const eased = 1 - Math.pow(1 - progress, 3)
setValue(Math.round(eased * target))
if (progress < 1) requestAnimationFrame(step)
}
requestAnimationFrame(step)
}
},
{ threshold: 0.3 },
)
observer.observe(el)
return () => observer.disconnect()
}, [target, duration])
return { ref, value }
}
export function useScrollReveal() {
const ref = useRef<HTMLDivElement>(null)
const [visible, setVisible] = useState(false)
useEffect(() => {
const el = ref.current
if (!el) return
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setVisible(true)
observer.disconnect()
}
},
{ threshold: 0.1 },
)
observer.observe(el)
return () => observer.disconnect()
}, [])
return { ref, visible }
}