187 lines
5.7 KiB
TypeScript
187 lines
5.7 KiB
TypeScript
"use client";
|
|
|
|
import Autoplay from "embla-carousel-autoplay";
|
|
import { AnimatePresence, motion } from "framer-motion";
|
|
import React, { useMemo } from "react";
|
|
import { useCallback } from "react";
|
|
|
|
import {
|
|
Carousel,
|
|
type CarouselApi,
|
|
CarouselContent,
|
|
CarouselItem,
|
|
} from "@/components/ui/carousel";
|
|
import { useIsMobile } from "@/hooks/use-mobile";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface Hero228Props {
|
|
className?: string;
|
|
}
|
|
|
|
const Hero228 = ({ className }: Hero228Props) => {
|
|
const [api, setApi] = React.useState<CarouselApi>();
|
|
const [current, setCurrent] = React.useState(0);
|
|
|
|
React.useEffect(() => {
|
|
if (!api) return;
|
|
|
|
api.on("select", () => {
|
|
setCurrent(api.selectedScrollSnap());
|
|
});
|
|
}, [api]);
|
|
|
|
const isMobile = useIsMobile();
|
|
|
|
const testimonials = [
|
|
{
|
|
id: 1,
|
|
image:
|
|
"/block-media/shadcnblocks/block/lummi/person1.jpeg",
|
|
name: "جان دو",
|
|
},
|
|
{
|
|
id: 2,
|
|
image:
|
|
"/block-media/shadcnblocks/block/lummi/person2.jpeg",
|
|
name: "جین اسمیت",
|
|
},
|
|
{
|
|
id: 3,
|
|
image:
|
|
"/block-media/shadcnblocks/block/lummi/person3.jpeg",
|
|
name: "جان جانسون",
|
|
},
|
|
{
|
|
id: 4,
|
|
image:
|
|
"/block-media/shadcnblocks/block/lummi/person4.jpeg",
|
|
name: "سارا ویلیام",
|
|
},
|
|
{
|
|
id: 5,
|
|
image:
|
|
"/block-media/shadcnblocks/block/lummi/person5.jpeg",
|
|
name: "مایکل براون",
|
|
},
|
|
{
|
|
id: 6,
|
|
image:
|
|
"/block-media/shadcnblocks/block/lummi/bw3.jpeg",
|
|
name: "امیلی دیویس",
|
|
},
|
|
{
|
|
id: 7,
|
|
image:
|
|
"/block-media/shadcnblocks/block/lummi/bw11.jpeg",
|
|
name: "جیسون وایت",
|
|
},
|
|
];
|
|
|
|
const getRotation = useCallback(
|
|
(index: number) => {
|
|
if (index === current)
|
|
return "md:-rotate-45 md:translate-x-40 md:scale-75 md:relative";
|
|
if (index === current + 1) return "md:rotate-0 md:z-10 md:relative";
|
|
if (index === current + 2)
|
|
return "md:rotate-45 md:-translate-x-40 md:scale-75 md:relative";
|
|
},
|
|
[current],
|
|
);
|
|
|
|
const scrollbarBars = useMemo(
|
|
() =>
|
|
[...Array(40)].map((_, item) => (
|
|
<motion.div
|
|
key={item}
|
|
initial={{
|
|
opacity: item % 5 === 0 ? 0.2 : 0.2,
|
|
filter: "blur(1px)",
|
|
}}
|
|
animate={{
|
|
opacity: item % 5 === 0 ? 1 : 0.2,
|
|
filter: "blur(0px)",
|
|
}}
|
|
transition={{
|
|
duration: 0.2,
|
|
delay: item % 5 === 0 ? (item / 5) * 0.05 : 0,
|
|
ease: "easeOut",
|
|
}}
|
|
className={cn(
|
|
"w-[1px] bg-black",
|
|
item % 5 === 0 ? "h-[15px]" : "h-[10px]",
|
|
)}
|
|
/>
|
|
)),
|
|
[],
|
|
);
|
|
|
|
return (
|
|
<section className={cn("bg-background py-32", className)}>
|
|
<div className="container flex flex-col items-center justify-center gap-4 text-center">
|
|
<h1 className="max-w-3xl text-2xll font-medium tracking-tighter text-foreground md:px-9 md:text-2xll">
|
|
<span className="font-playfair italic">همه</span> ابزارهای لازم برای{" "}
|
|
<span className="font-playfair italic">خلاق و</span> توسعه سریع
|
|
</h1>
|
|
<p className="mt-5 max-w-xl text-muted-foreground/80">
|
|
صدها بلاک و کامپوننت آماده مبتنی بر رابط کاربری، استایلدهی مدرن و ری یو آی که مستقیماً در پروژههای شما قابل استفاده هستند.
|
|
</p>
|
|
|
|
<Carousel
|
|
className="max-w-5xl"
|
|
plugins={[
|
|
Autoplay({
|
|
delay: 1000,
|
|
stopOnInteraction: true,
|
|
}),
|
|
]}
|
|
setApi={setApi}
|
|
>
|
|
<CarouselContent>
|
|
{Array.from({
|
|
length: isMobile ? testimonials.length : testimonials.length + 2,
|
|
}).map((_, index) => (
|
|
<CarouselItem key={index} className="my-10 md:basis-1/3">
|
|
<div
|
|
className={`h-105 w-full transition-transform duration-500 ease-in-out ${getRotation(index)}`}
|
|
>
|
|
<img
|
|
src={
|
|
index == testimonials.length
|
|
? testimonials[0].image
|
|
: index == testimonials.length + 1
|
|
? testimonials[1].image
|
|
: index == testimonials.length + 2
|
|
? testimonials[2].image
|
|
: testimonials[index].image
|
|
}
|
|
className="h-full w-full object-cover"
|
|
alt="تصویر نمونه"
|
|
/>
|
|
</div>
|
|
</CarouselItem>
|
|
))}
|
|
</CarouselContent>
|
|
<div className="absolute right-0 bottom-0 flex w-full translate-y-full flex-col items-center justify-center gap-2">
|
|
<div className="flex gap-2">{scrollbarBars}</div>
|
|
<AnimatePresence mode="popLayout" initial={false}>
|
|
<motion.p
|
|
key={current}
|
|
className="w-full text-lg font-medium"
|
|
initial={{ opacity: 0, y: 20, scale: 0.9, filter: "blur(5px)" }}
|
|
animate={{ opacity: 1, y: 0, scale: 1, filter: "blur(0px)" }}
|
|
exit={{ opacity: 0, y: -20, scale: 0.9, filter: "blur(5px)" }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
{testimonials[current]?.name}
|
|
</motion.p>
|
|
</AnimatePresence>
|
|
<div className="flex gap-2">{scrollbarBars}</div>
|
|
</div>
|
|
</Carousel>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { Hero228 };
|