"use client"; import React, { useEffect, useRef, useState } from "react"; import { motion, useAnimationFrame, useMotionTemplate, useMotionValue, useTransform, animate, } from "motion/react"; import { cn } from "@/lib/utils"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { Button } from "@/components/ui/button"; export function AppleCardsCarousel({ items, direction = "left", speed = "fast", pauseOnHover = true, className, }: { items: { title: string; description: string; icon: React.ReactNode; src?: string; }[]; direction?: "left" | "right"; speed?: "fast" | "normal" | "slow"; pauseOnHover?: boolean; className?: string; }) { const containerRef = useRef(null); const scrollRef = useRef(null); const [start, setStart] = useState(false); useEffect(() => { setStart(true); }, []); const baseVelocity = { fast: 50, normal: 35, slow: 20, }; const baseX = useMotionValue(0); const directionFactor = React.useRef(1); const [hovered, setHovered] = useState(false); useAnimationFrame((t, delta) => { if (hovered) return; let moveBy = directionFactor.current * baseVelocity[speed] * (delta / 1000); if (direction === "left") { directionFactor.current = -1; } else { directionFactor.current = 1; } moveBy += directionFactor.current * moveBy * 0.5; baseX.set(baseX.get() + moveBy); }); const scrollLeft = () => { if (scrollRef.current) { // Calculate responsive card width + gap const cardWidth = window.innerWidth < 640 ? 280 : window.innerWidth < 768 ? 320 : 350; const scrollAmount = cardWidth + 16; // card width + gap const newX = baseX.get() + scrollAmount; animate(baseX, newX, { duration: 0.5, ease: "easeOut" }); } }; const scrollRight = () => { if (scrollRef.current) { // Calculate responsive card width + gap const cardWidth = window.innerWidth < 640 ? 280 : window.innerWidth < 768 ? 320 : 350; const scrollAmount = cardWidth + 16; // card width + gap const newX = baseX.get() - scrollAmount; animate(baseX, newX, { duration: 0.5, ease: "easeOut" }); } }; return (
pauseOnHover && setHovered(true)} onMouseLeave={() => pauseOnHover && setHovered(false)} >
{start && items.map((item, idx) => (
{item.src && (
{item.title}
)}
{item.icon}

{item.title}

{item.description}

))} {start && items.map((item, idx) => (
{item.src && (
{item.title}
)}
{item.icon}

{item.title}

{item.description}

))}
); }