Files
sent-shop/components/ui/Carousel.tsx
2026-01-19 20:21:14 +01:00

83 lines
2.2 KiB
TypeScript

'use client';
import { ReactNode, useEffect, useState } from 'react';
export interface CarouselIndicatorsProps {
totalSlides: number;
activeIndex: number;
onSelect: (index: number) => void;
className?: string;
}
export function CarouselIndicators({ totalSlides, activeIndex, onSelect, className = '' }: CarouselIndicatorsProps) {
return (
<div className={`flex justify-center gap-2 z-20 ${className}`}>
{Array.from({ length: totalSlides }).map((_, index) => (
<button
key={index}
className={`w-2 h-2 rounded-full transition-colors ${
index === activeIndex ? "bg-black" : "bg-white"
}`}
onClick={() => onSelect(index)}
aria-label={`Go to slide ${index + 1}`}
/>
))}
</div>
);
}
export interface CarouselProps {
slides: ReactNode[];
autoPlay?: boolean;
interval?: number;
showIndicators?: boolean;
indicatorsClassName?: string;
className?: string;
}
export function Carousel({
slides,
autoPlay = true,
interval = 5000,
showIndicators = true,
indicatorsClassName = '',
className = ''
}: CarouselProps) {
const [activeSlide, setActiveSlide] = useState(0);
// Auto-advance carousel if autoPlay is enabled
useEffect(() => {
if (!autoPlay) return;
const timer = setInterval(() => {
setActiveSlide((prev) => (prev === slides.length - 1 ? 0 : prev + 1));
}, interval);
return () => clearInterval(timer);
}, [autoPlay, interval, slides.length]);
return (
<div className={`relative w-full h-full ${className}`}>
{/* All slides need to be absolutely positioned */}
{slides.map((slide, index) => (
<div
key={index}
className={`absolute inset-0 w-full h-full transition-opacity duration-500 ${
index === activeSlide ? "opacity-100 z-10" : "opacity-0 z-0"
}`}
>
{slide}
</div>
))}
{showIndicators && slides.length > 1 && (
<CarouselIndicators
totalSlides={slides.length}
activeIndex={activeSlide}
onSelect={setActiveSlide}
className={indicatorsClassName}
/>
)}
</div>
);
}