Files
reui-blocks/blocks/gallery22.tsx
T

238 lines
7.2 KiB
TypeScript

"use client";
import "swiper/css/effect-coverflow";
import "swiper/css/pagination";
import "swiper/css/navigation";
import "swiper/css";
import "swiper/css/effect-cards";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { FaXTwitter } from "react-icons/fa6";
import type { Swiper as SwiperType } from "swiper";
import { Autoplay, EffectCoverflow } from "swiper/modules";
import { Swiper, SwiperSlide } from "swiper/react";
import { cn } from "@/lib/utils";
const TEAM = [
{
src: "/block-media/shadcnblocks/block/lummi/person2.jpg",
alt: "پرتره سارا احمدی در فضای شهری",
name: "سارا احمدی",
role: "سرپرست طراحی",
url: "#",
},
{
src: "/block-media/shadcnblocks/block/lummi/person1.jpg",
alt: "پرتره مریم رضایی در نور طبیعی",
name: "مریم رضایی",
role: "مدیر خلاق",
url: "#",
},
{
src: "/block-media/shadcnblocks/block/lummi/person2.jpg",
alt: "پرتره نیلوفر کریمی در استودیو",
name: "نیلوفر کریمی",
role: "مدیر محصول",
url: "#",
},
{
src: "/block-media/shadcnblocks/block/lummi/person3.jpg",
alt: "پرتره امیر حسینی",
name: "امیر حسینی",
role: "سرپرست طراحی",
url: "#",
},
{
src: "/block-media/shadcnblocks/block/lummi/person1.jpg",
alt: "پرتره لیلا محمدی در نور طبیعی",
name: "لیلا محمدی",
role: "مدیر خلاق",
url: "#",
},
{
src: "/block-media/shadcnblocks/block/lummi/random11.jpg",
alt: "پرتره کامران نظری در استودیو",
name: "کامران نظری",
role: "مدیر محصول",
url: "#",
},
];
const css = `
.mySwiper22 {
position: relative;
z-index: 2;
width: 100%;
height: 350px;
}
.mySwiper22 .swiper-slide {
width: 200px;
height: 300px;
border-radius: 0;
opacity: 0.25;
transition: opacity 0.3s ease-in-out;
}
.mySwiper22 .swiper-slide-active {
opacity: 1;
z-index: 10;
}
.mySwiper22 .swiper-slide img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.mySwiper22.swiper-3d .swiper-slide-shadow-left,
.mySwiper22.swiper-3d .swiper-slide-shadow-right {
background: none;
}
`;
interface Gallery22Props {
className?: string;
}
const Gallery22 = ({ className }: Gallery22Props) => {
const [activeIndex, setActiveIndex] = useState(0);
const swiperRef = useRef<SwiperType | null>(null);
const swiperContainerRef = useRef<HTMLDivElement>(null);
const [swiperReady, setSwiperReady] = useState(false);
useEffect(() => {
const swiper = swiperRef.current;
if (!swiper || !swiperReady) {
return;
}
const updateSwiper = () => {
swiper.update();
swiper.slideToLoop(swiper.realIndex, 0);
};
updateSwiper();
const container = swiperContainerRef.current;
if (!container) {
return;
}
const resizeObserver = new ResizeObserver(updateSwiper);
resizeObserver.observe(container);
return () => {
resizeObserver.disconnect();
};
}, [swiperReady]);
return (
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
<style>{css}</style>
<div className="container">
<div
ref={swiperContainerRef}
dir="rtl"
className="relative mx-auto w-full max-w-3xl"
>
<div className="pointer-events-none absolute inset-y-0 start-0 z-20 w-16 bg-gradient-to-r from-background to-transparent sm:w-24 lg:w-42" />
<div className="pointer-events-none absolute inset-y-0 end-0 z-20 w-16 bg-gradient-to-l from-background to-transparent sm:w-24 lg:w-42" />
<div className="relative flex w-full justify-center">
<Swiper
onSwiper={(instance) => {
swiperRef.current = instance;
setSwiperReady(true);
}}
autoplay={{
delay: 1500,
disableOnInteraction: false,
}}
breakpoints={{
0: { spaceBetween: 40 },
640: { spaceBetween: 70 },
1024: { spaceBetween: 100 },
}}
effect="coverflow"
grabCursor={true}
centeredSlides={true}
loop={true}
slidesPerView="auto"
coverflowEffect={{
rotate: 0,
stretch: 0,
depth: 80,
modifier: 2.5,
}}
className="mySwiper22"
modules={[EffectCoverflow, Autoplay]}
onSlideChange={(instance) => setActiveIndex(instance.realIndex)}
>
{TEAM.map((member, index) => (
<SwiperSlide key={`${member.name}-${index}`} className="relative">
<img
className="mt-4 h-full w-full object-cover shadow-lg"
src={member.src}
alt={member.alt}
/>
<a
href={member.url}
className="absolute top-1 -left-2.5 flex size-10 items-center justify-center bg-foreground transition-all duration-300 hover:scale-90 hover:rotate-12"
>
<FaXTwitter className="size-5 text-background" />
<span className="sr-only">{member.name}</span>
</a>
</SwiperSlide>
))}
</Swiper>
</div>
<div
dir="rtl"
className="pointer-events-none absolute top-0 left-1/2 z-[1] flex h-[450px] w-[230px] -translate-x-1/2 flex-col justify-end border border-border p-4 text-right"
>
<div className="pointer-events-auto relative z-20 w-full text-right">
<h3 className="mb-2 text-xl leading-7 font-semibold tracking-tighter">
{TEAM[activeIndex].name}
</h3>
<p className="text-sm text-muted-foreground">
{TEAM[activeIndex].role}
</p>
</div>
<div className="pointer-events-auto absolute right-0 -bottom-12 z-20 flex gap-2 md:-right-20 md:bottom-0">
<button
type="button"
className="bg-muted p-2 transition-colors hover:bg-muted/80 active:scale-95"
aria-label="اسلاید قبلی"
onClick={(e) => {
e.preventDefault();
swiperRef.current?.slidePrev();
}}
>
<ChevronRight className="size-4" />
</button>
<button
type="button"
className="bg-muted p-2 transition-colors hover:bg-muted/80 active:scale-95"
aria-label="اسلاید بعدی"
onClick={(e) => {
e.preventDefault();
swiperRef.current?.slideNext();
}}
>
<ChevronLeft className="size-4" />
</button>
</div>
</div>
</div>
</div>
</section>
);
};
export { Gallery22 };