111 lines
4.2 KiB
TypeScript
111 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import Image from "next/image";
|
|
import Icon from "@/components/ui/icon";
|
|
import {
|
|
Carousel,
|
|
CarouselContent,
|
|
CarouselItem,
|
|
CarouselNext,
|
|
CarouselPrevious,
|
|
type CarouselApi,
|
|
} from "@/components/ui/carousel";
|
|
|
|
interface YachtGalleryProps {
|
|
images: string[];
|
|
badge?: string;
|
|
}
|
|
|
|
export function YachtGallery({ images, badge }: YachtGalleryProps) {
|
|
const [api, setApi] = useState<CarouselApi>();
|
|
const [current, setCurrent] = useState(0);
|
|
|
|
useEffect(() => {
|
|
if (!api) {
|
|
return;
|
|
}
|
|
|
|
setCurrent(api.selectedScrollSnap());
|
|
|
|
api.on("select", () => {
|
|
setCurrent(api.selectedScrollSnap());
|
|
});
|
|
}, [api]);
|
|
|
|
const scrollTo = (index: number) => {
|
|
api?.scrollTo(index);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* Main Image Carousel */}
|
|
<div className="relative">
|
|
<Carousel
|
|
setApi={setApi}
|
|
opts={{
|
|
align: "start",
|
|
loop: false,
|
|
}}
|
|
className="w-full"
|
|
>
|
|
<CarouselContent>
|
|
{images.map((img, index) => (
|
|
<CarouselItem key={index}>
|
|
<div className="relative w-full h-[60vh] lg:h-[592px] rounded-0 lg:rounded-[24px] overflow-hidden">
|
|
<Image
|
|
src={img}
|
|
alt={`Yacht image ${index + 1}`}
|
|
fill
|
|
className="object-cover"
|
|
priority={index === 0}
|
|
/>
|
|
</div>
|
|
</CarouselItem>
|
|
))}
|
|
</CarouselContent>
|
|
<CarouselPrevious className="left-2 lg:left-4 bg-white/80 hover:bg-white border-gray-300 w-10 h-10 lg:w-12 lg:h-12 rounded-full" />
|
|
<CarouselNext className="right-2 lg:right-4 bg-white/80 hover:bg-white border-gray-300 w-10 h-10 lg:w-12 lg:h-12 rounded-full" />
|
|
</Carousel>
|
|
{/* Badge - поверх слайдера, не скроллится */}
|
|
{badge && (
|
|
<div className="absolute bottom-4 left-4 z-20 pointer-events-none">
|
|
<div className="flex items-center justify-center bg-black/40 text-white px-3 py-1 rounded-lg text-sm gap-1">
|
|
<Icon size={16} name="restart" />
|
|
<span>{badge}</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
{/* Photo counter - поверх слайдера, не скроллится */}
|
|
<div className="absolute bottom-4 right-4 z-20 pointer-events-none">
|
|
<div className="bg-black/40 text-white px-3 py-1 rounded-lg text-sm">
|
|
{current + 1}/{images.length}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Thumbnails - скрыты на мобильных */}
|
|
<div className="hidden lg:flex gap-2 overflow-x-auto pb-2">
|
|
{images.map((img, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => scrollTo(index)}
|
|
className={`relative flex-shrink-0 w-17 h-14 rounded-lg overflow-hidden border-2 transition-all ${
|
|
current === index
|
|
? "border-[#008299] opacity-100"
|
|
: "border-transparent opacity-60 hover:opacity-100"
|
|
}`}
|
|
>
|
|
<Image
|
|
src={img}
|
|
alt={`Thumbnail ${index + 1}`}
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|