feat: add mobile carousel view with auto-play for BentoReviews component
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { H2, P } from "@/components/Texts";
|
||||
import React from "react";
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { BentoGrid, MotionBentoGridItem } from "@/components/ui/bento-grid";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { FadeIn } from "./FadeIn";
|
||||
|
||||
const items = [
|
||||
@@ -53,6 +55,42 @@ const items = [
|
||||
];
|
||||
|
||||
export function BentoReviews() {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const [isPaused, setIsPaused] = useState(false);
|
||||
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPaused) {
|
||||
intervalRef.current = setInterval(() => {
|
||||
setActiveIndex((prevIndex) => (prevIndex + 1) % items.length);
|
||||
}, 3000);
|
||||
} else {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
};
|
||||
}, [isPaused]);
|
||||
|
||||
const handleCardTap = () => {
|
||||
setIsPaused(true);
|
||||
};
|
||||
|
||||
const handlePrev = () => {
|
||||
setActiveIndex((prevIndex) => (prevIndex - 1 + items.length) % items.length);
|
||||
setIsPaused(true);
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
setActiveIndex((prevIndex) => (prevIndex + 1) % items.length);
|
||||
setIsPaused(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="relative isolate pt-24 pb-12 bg-black text-center w-full lg:px-0 px-4">
|
||||
@@ -70,7 +108,10 @@ export function BentoReviews() {
|
||||
</div>
|
||||
</FadeIn>
|
||||
</div>
|
||||
<BentoGrid className="max-w-8xl lg:px-12 px-4pb-12 lg:grid-cols-3">
|
||||
|
||||
{/* Desktop Grid */}
|
||||
<div className="hidden lg:block">
|
||||
<BentoGrid className="max-w-8xl lg:px-12 px-4 pb-12 lg:grid-cols-3">
|
||||
{items.map((item, i) => (
|
||||
<MotionBentoGridItem
|
||||
key={i}
|
||||
@@ -88,6 +129,44 @@ export function BentoReviews() {
|
||||
))}
|
||||
</BentoGrid>
|
||||
</div>
|
||||
|
||||
{/* Mobile Carousel */}
|
||||
<div className="lg:hidden block px-4 pb-12">
|
||||
<div className="relative h-[24rem] w-full overflow-hidden">
|
||||
<div className="absolute inset-0" onTouchStart={handleCardTap} />
|
||||
<AnimatePresence initial={false}>
|
||||
<motion.div
|
||||
key={activeIndex}
|
||||
className="absolute h-full w-full"
|
||||
initial={{ x: "100%", opacity: 0 }}
|
||||
animate={{ x: 0, opacity: 1 }}
|
||||
exit={{ x: "-100%", opacity: 0 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||
>
|
||||
<MotionBentoGridItem
|
||||
className="h-full"
|
||||
title={items[activeIndex].title}
|
||||
subtitle={items[activeIndex].subtitle}
|
||||
description={items[activeIndex].description}
|
||||
video={items[activeIndex].video}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
<button
|
||||
onClick={handlePrev}
|
||||
className="absolute left-2 top-[58%] -translate-y-1/2 rounded-full bg-black/50 p-2 text-white z-10"
|
||||
>
|
||||
<ChevronLeft className="h-6 w-6" />
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="absolute right-2 top-[58%] -translate-y-1/2 rounded-full bg-black/50 p-2 text-white z-10"
|
||||
>
|
||||
<ChevronRight className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -44,7 +44,7 @@ export const BentoGridItem = React.forwardRef<HTMLDivElement, BentoGridItemProps
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-1 w-full h-full min-h-[6rem] bg-transparent overflow-hidden">
|
||||
<div className="relative w-full h-[65%] min-h-[6rem] bg-transparent overflow-hidden">
|
||||
{video ? (
|
||||
<video
|
||||
src={video}
|
||||
|
Reference in New Issue
Block a user