83 lines
2.2 KiB
TypeScript
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>
|
|
);
|
|
}
|