343 lines
9.9 KiB
TypeScript
343 lines
9.9 KiB
TypeScript
"use client";
|
|
import { ChevronLeft, ChevronRight, Play } from "lucide-react";
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const INSTAGRAM_ICON = {
|
|
title: "اینستاگرام",
|
|
light:
|
|
"/block-media/shadcnblocks/block/logos/instagram-icon.svg",
|
|
dark: "/block-media/shadcnblocks/block/logos/instagram-icon.svg",
|
|
} as const;
|
|
|
|
import { AspectRatio } from "@/components/ui/aspect-ratio";
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardFooter,
|
|
CardHeader,
|
|
} from "@/components/ui/card";
|
|
import type { CarouselApi } from "@/components/ui/carousel";
|
|
import {
|
|
Carousel,
|
|
CarouselContent,
|
|
CarouselItem,
|
|
} from "@/components/ui/carousel";
|
|
|
|
type Product = {
|
|
image: string;
|
|
name: string;
|
|
href: string;
|
|
};
|
|
|
|
type SocialMediaPost = {
|
|
name: string;
|
|
userAvatar: string;
|
|
username: string;
|
|
profileLink: string;
|
|
socialMediaIcon: { title: string; light: string; dark: string };
|
|
video: string;
|
|
product: Product;
|
|
};
|
|
|
|
type SocialMediaPostCardProps = SocialMediaPost;
|
|
|
|
interface SocialMediaTrending1Props {
|
|
className?: string;
|
|
posts?: SocialMediaPost[];
|
|
}
|
|
|
|
const SOCIAL_MEDIA_POSTS: SocialMediaPost[] = [
|
|
{
|
|
name: "سارا احمدی",
|
|
userAvatar:
|
|
"/block-media/shadcnblocks/block/avatar-1.webp",
|
|
profileLink: "#",
|
|
username: "@saraahmadi",
|
|
socialMediaIcon: INSTAGRAM_ICON,
|
|
video:
|
|
"/block-media/shadcnblocks/block/6875749-hd_720_1366_25fps.mp4",
|
|
product: {
|
|
image:
|
|
"/block-media/shadcnblocks/block/ecommerce/electronics/Modern-White-Headphones-1.png",
|
|
name: "هدفون بیسیم",
|
|
href: "#",
|
|
},
|
|
},
|
|
{
|
|
name: "مریم حسینی",
|
|
userAvatar:
|
|
"/block-media/shadcnblocks/block/avatar-7.webp",
|
|
profileLink: "#",
|
|
username: "@maryam.h",
|
|
socialMediaIcon: INSTAGRAM_ICON,
|
|
video:
|
|
"/block-media/shadcnblocks/block/4773195-hd_720_1280_24fps.mp4",
|
|
product: {
|
|
image:
|
|
"/block-media/shadcnblocks/block/ecommerce/electronics/klim-musalimov-IGO10LkxP_g-unsplash-2.jpg",
|
|
name: "ساعت هوشمند",
|
|
href: "#",
|
|
},
|
|
},
|
|
{
|
|
name: "علی محمدی",
|
|
userAvatar:
|
|
"/block-media/shadcnblocks/block/avatar-6.webp",
|
|
profileLink: "#",
|
|
username: "@alimohammadi",
|
|
socialMediaIcon: INSTAGRAM_ICON,
|
|
video:
|
|
"/block-media/shadcnblocks/block/9130461-hd_720_1280_30fps.mp4",
|
|
product: {
|
|
image:
|
|
"/block-media/shadcnblocks/block/ecommerce/electronics/White-Wireless-Earbuds-in-Charging-Case-1.jpeg",
|
|
name: "ایرباد بیسیم",
|
|
href: "#",
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "امیر رضایی",
|
|
userAvatar:
|
|
"/block-media/shadcnblocks/block/avatar-6.webp",
|
|
profileLink: "#",
|
|
username: "@amirrezaei",
|
|
socialMediaIcon: INSTAGRAM_ICON,
|
|
video:
|
|
"/block-media/shadcnblocks/block/8128031-hd_720_1280_25fps.mp4",
|
|
product: {
|
|
image:
|
|
"/block-media/shadcnblocks/block/ecommerce/electronics/dennis-cortes-saa-4nYJWns-unsplash-1.jpg",
|
|
name: "دسته بازی PS4",
|
|
href: "#",
|
|
},
|
|
},
|
|
{
|
|
name: "پویا جعفری",
|
|
userAvatar:
|
|
"/block-media/shadcnblocks/block/avatar-2.webp",
|
|
profileLink: "#",
|
|
username: "@poyajafari",
|
|
socialMediaIcon: INSTAGRAM_ICON,
|
|
video:
|
|
"/block-media/shadcnblocks/block/4076728-hd_720_1280_50fps.mp4",
|
|
product: {
|
|
image:
|
|
"/block-media/shadcnblocks/block/ecommerce/electronics/Laptop-on-Cozy-Blanket-1.png",
|
|
name: "لپتاپ روزمره",
|
|
href: "#",
|
|
},
|
|
},
|
|
{
|
|
name: "لیلا کریمی",
|
|
userAvatar:
|
|
"/block-media/shadcnblocks/block/avatar-1.webp",
|
|
profileLink: "#",
|
|
username: "@leila.karimi",
|
|
socialMediaIcon: INSTAGRAM_ICON,
|
|
video:
|
|
"/block-media/shadcnblocks/block/3625767-hd_720_1366_50fps.mp4",
|
|
product: {
|
|
image:
|
|
"/block-media/shadcnblocks/block/ecommerce/electronics/Sleek-Smartphone-Close-Up-1.png",
|
|
name: "گوشی هوشمند",
|
|
href: "#",
|
|
},
|
|
},
|
|
];
|
|
|
|
const SocialMediaTrending1 = ({
|
|
className,
|
|
posts = SOCIAL_MEDIA_POSTS,
|
|
}: SocialMediaTrending1Props) => {
|
|
const [api, setApi] = useState<CarouselApi>();
|
|
const [scrollProgress, setScrollProgress] = useState(0);
|
|
|
|
const handleScroll = useCallback((emblaApi: CarouselApi) => {
|
|
const progress = Math.max(0, Math.min(1, emblaApi?.scrollProgress() ?? 0));
|
|
setScrollProgress(progress);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!api) return;
|
|
|
|
api.on("scroll", handleScroll);
|
|
api.on("reInit", handleScroll);
|
|
|
|
return () => {
|
|
api.off("scroll", handleScroll);
|
|
api.off("reInit", handleScroll);
|
|
};
|
|
}, [api, handleScroll]);
|
|
|
|
return (
|
|
<section
|
|
dir="rtl"
|
|
lang="fa"
|
|
className={cn("overflow-hidden py-32", className)}
|
|
>
|
|
<div className="container">
|
|
<h2 className="mb-8 text-center font-serif text-xl leading-snug font-medium md:text-3xl">
|
|
ترندهای شبکههای اجتماعی
|
|
</h2>
|
|
<Carousel
|
|
dir="rtl"
|
|
opts={{
|
|
align: "start",
|
|
direction: "rtl",
|
|
}}
|
|
className="[&>div]:overflow-visible"
|
|
setApi={setApi}
|
|
>
|
|
<CarouselContent className="ml-0 -mr-4">
|
|
{posts.map((item, index) => (
|
|
<CarouselItem
|
|
className="basis-[75%] pl-0 pr-4 sm:basis-1/2 lg:basis-1/3 xl:basis-1/4"
|
|
key={index}
|
|
>
|
|
<SocialMediaPostCard {...item} />
|
|
</CarouselItem>
|
|
))}
|
|
</CarouselContent>
|
|
</Carousel>
|
|
<div className="mt-8 flex items-center gap-3">
|
|
<div className="flex-1">
|
|
<div className="relative h-0.5 w-full overflow-hidden bg-muted">
|
|
<div
|
|
className="h-full origin-right bg-primary"
|
|
style={{ transform: `scaleX(${scrollProgress})` }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<Button
|
|
type="button"
|
|
onClick={() => api?.scrollPrev()}
|
|
className="shrink-0 rounded-full max-sm:hidden"
|
|
size="icon-lg"
|
|
aria-label="اسلاید قبلی"
|
|
>
|
|
<ChevronRight className="size-4" />
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
onClick={() => api?.scrollNext()}
|
|
className="shrink-0 rounded-full max-sm:hidden"
|
|
size="icon-lg"
|
|
aria-label="اسلاید بعدی"
|
|
>
|
|
<ChevronLeft className="size-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
const SocialMediaPostCard = ({
|
|
userAvatar,
|
|
username,
|
|
name,
|
|
socialMediaIcon,
|
|
video,
|
|
product,
|
|
}: SocialMediaPostCardProps) => {
|
|
const videoRef = useRef<HTMLVideoElement>(null);
|
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
return (
|
|
<Card dir="rtl" lang="fa" className="h-full gap-3 p-4">
|
|
<CardHeader className="flex items-center gap-2 p-0">
|
|
<div className="shrink-0 basis-10">
|
|
<Avatar className="size-10 border">
|
|
<AvatarImage src={userAvatar} alt={name} />
|
|
<AvatarFallback>{username}</AvatarFallback>
|
|
</Avatar>
|
|
</div>
|
|
<div className="flex-1 text-start">
|
|
<div className="text-sm leading-normal font-medium">{name}</div>
|
|
<div className="text-xs leading-normal font-medium text-muted-foreground">
|
|
{username}
|
|
</div>
|
|
</div>
|
|
<div className="shrink-0 basis-4.5">
|
|
<img
|
|
className="size-4.5 dark:hidden"
|
|
alt={socialMediaIcon.title}
|
|
src={socialMediaIcon.light}
|
|
/>
|
|
<img
|
|
className="hidden size-4.5 dark:block"
|
|
alt={socialMediaIcon.title}
|
|
src={socialMediaIcon.dark}
|
|
/>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent className="p-0">
|
|
<AspectRatio ratio={0.75} className="group overflow-hidden rounded-xl">
|
|
<video
|
|
muted
|
|
playsInline
|
|
preload="metadata"
|
|
className="size-full object-cover object-center"
|
|
onPlay={() => setIsPlaying(true)}
|
|
onPause={() => setIsPlaying(false)}
|
|
onMouseEnter={() => {
|
|
videoRef.current?.play();
|
|
}}
|
|
onMouseLeave={() => {
|
|
if (!videoRef.current) return;
|
|
videoRef.current.pause();
|
|
videoRef.current.currentTime = 0;
|
|
}}
|
|
ref={videoRef}
|
|
src={video}
|
|
></video>
|
|
{!isPlaying && (
|
|
<div className="pointer-events-none absolute top-1/2 left-1/2 z-10 -translate-1/2 transition-opacity duration-500 group-hover:opacity-0">
|
|
<Button
|
|
size="icon-lg"
|
|
className="rounded-full"
|
|
aria-label="پخش ویدیو"
|
|
>
|
|
<Play />
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</AspectRatio>
|
|
</CardContent>
|
|
<CardFooter className="p-0">
|
|
<a
|
|
className="flex w-full flex-1 items-center gap-3"
|
|
href={product.href}
|
|
>
|
|
<div className="shrink-0 basis-10">
|
|
<div className="size-10 overflow-hidden rounded-full">
|
|
<img
|
|
src={product.image}
|
|
alt={product.name}
|
|
className="block size-full object-cover object-center"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 text-start">
|
|
<p className="text-sm leading-normal font-medium">{product.name}</p>
|
|
</div>
|
|
<Button
|
|
variant="outline"
|
|
className="rounded-full"
|
|
size="icon-sm"
|
|
aria-label={`مشاهده ${product.name}`}
|
|
>
|
|
<ChevronLeft className="size-4 rtl:rotate-180" />
|
|
</Button>
|
|
</a>
|
|
</CardFooter>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export { SocialMediaTrending1 };
|