diff --git a/app/components/AnimatedCounter.tsx b/app/components/AnimatedCounter.tsx new file mode 100644 index 0000000..66f3edd --- /dev/null +++ b/app/components/AnimatedCounter.tsx @@ -0,0 +1,58 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import { useInView, useSpring, useTransform, motion } from "framer-motion"; + +interface AnimatedCounterProps { + value: number; + suffix?: string; + prefix?: string; + duration?: number; + className?: string; +} + +export default function AnimatedCounter({ + value, + suffix = "", + prefix = "", + duration = 2, + className = "", +}: AnimatedCounterProps) { + const ref = useRef(null); + const isInView = useInView(ref, { once: true, margin: "-50px" }); + const [hasAnimated, setHasAnimated] = useState(false); + + const spring = useSpring(0, { + stiffness: 50, + damping: 30, + duration: duration * 1000, + }); + + const display = useTransform(spring, (current) => { + return Math.round(current); + }); + + const [displayValue, setDisplayValue] = useState(0); + + useEffect(() => { + if (isInView && !hasAnimated) { + setHasAnimated(true); + spring.set(value); + } + }, [isInView, hasAnimated, spring, value]); + + useEffect(() => { + const unsubscribe = display.on("change", (v) => { + setDisplayValue(v); + }); + return unsubscribe; + }, [display]); + + return ( + + {prefix} + {displayValue} + {suffix} + + ); +} diff --git a/app/page.tsx b/app/page.tsx index 2b7b415..0c247a0 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -20,12 +20,13 @@ import { CheckIcon, RecycleIcon, } from "./components/Icons"; +import AnimatedCounter from "./components/AnimatedCounter"; const stats = [ - { value: "100+", label: "Years Combined Experience" }, - { value: "10", label: "States Covered" }, - { value: "2005", label: "Industry Trusted Since" }, - { value: "5", label: "Product Categories" }, + { value: 100, suffix: "+", label: "Years Combined Experience" }, + { value: 10, suffix: "", label: "States Covered" }, + { value: 2005, suffix: "", label: "Industry Trusted Since" }, + { value: 5, suffix: "", label: "Product Categories" }, ]; const productCategories = [ @@ -271,20 +272,13 @@ export default function Home() { whileHover={{ scale: 1.05 }} className="group cursor-default" > - - {stat.value} - +
+ +
{stat.label}