Ticker.tsx (1867B)
1 import { cn } from "@/lib/utils" 2 import { motion, useTime, useTransform } from "framer-motion" 3 import Image from "next/image" 4 import React, { useEffect, useState } from "react" 5 import { useRef } from "react" 6 7 export function Ticker({ className, timePeriod, reverseDirection, children }: { className?: string, timePeriod?: number, reverseDirection?: boolean, children: React.ReactNode }) { 8 const ref = useRef<HTMLDivElement>(null); 9 const [childrenWidth, setChildrenWidth] = useState(0); 10 11 useEffect(() => { 12 if (ref.current) { 13 setChildrenWidth(ref.current?.offsetWidth); 14 } 15 }, [children]); 16 17 return ( 18 <div className={cn(`w-full overflow-hidden`, className)}> 19 <motion.div 20 ref={ref} 21 className={cn("flex flex-row gap-x-4 items-center justify-start overflow-visible")} 22 animate={{ 23 x: reverseDirection ? [-childrenWidth, 0] : [0, -childrenWidth], 24 transition: { duration: timePeriod ?? 12, repeat: Infinity, ease: "linear" }, 25 }} 26 > 27 <React.Fragment key="ticker-fragment-1"> 28 {children} 29 </React.Fragment> 30 {/* Duplicate for an infinite looping effect */} 31 <React.Fragment key="ticker-fragment-2"> 32 {children} 33 </React.Fragment> 34 </motion.div> 35 </div> 36 ); 37 } 38 39 export function TickerImage({ src, className, altText }: { src: string, className?: string, altText: string }) { 40 return (<> 41 <div className={cn("relative w-48 h-48 shrink-0 rounded-xl overflow-hidden", className)}> 42 <Image 43 src={src} 44 className="object-cover" 45 fill 46 alt={altText} 47 /> 48 </div> 49 </>) 50 }