Spaces:
Build error
Build error
Upload components/Carousel.js with huggingface_hub
Browse files- components/Carousel.js +72 -0
components/Carousel.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { useState } from 'react';
|
| 2 |
+
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
| 3 |
+
|
| 4 |
+
export default function Carousel({ items, renderItem, title }) {
|
| 5 |
+
const [currentIndex, setCurrentIndex] = useState(0);
|
| 6 |
+
const itemsPerPage = 1;
|
| 7 |
+
const totalPages = Math.ceil(items.length / itemsPerPage);
|
| 8 |
+
|
| 9 |
+
const goToPrevious = () => {
|
| 10 |
+
setCurrentIndex((prev) => (prev === 0 ? totalPages - 1 : prev - 1));
|
| 11 |
+
};
|
| 12 |
+
|
| 13 |
+
const goToNext = () => {
|
| 14 |
+
setCurrentIndex((prev) => (prev === totalPages - 1 ? 0 : prev + 1));
|
| 15 |
+
};
|
| 16 |
+
|
| 17 |
+
return (
|
| 18 |
+
<div className="brutal-card">
|
| 19 |
+
{title && <div className="section-header">{title}</div>}
|
| 20 |
+
|
| 21 |
+
<div className="relative">
|
| 22 |
+
{/* Main carousel container */}
|
| 23 |
+
<div className="overflow-hidden">
|
| 24 |
+
<div
|
| 25 |
+
className="flex transition-transform duration-300 ease-out"
|
| 26 |
+
style={{ transform: `translateX(-${currentIndex * 100}%)` }}
|
| 27 |
+
>
|
| 28 |
+
{items.map((item, index) => (
|
| 29 |
+
<div key={index} className="w-full flex-shrink-0">
|
| 30 |
+
{renderItem(item, index)}
|
| 31 |
+
</div>
|
| 32 |
+
))}
|
| 33 |
+
</div>
|
| 34 |
+
</div>
|
| 35 |
+
|
| 36 |
+
{/* Navigation buttons */}
|
| 37 |
+
<div className="flex items-center justify-between mt-6">
|
| 38 |
+
<button
|
| 39 |
+
onClick={goToPrevious}
|
| 40 |
+
className="brutal-btn flex items-center gap-2"
|
| 41 |
+
>
|
| 42 |
+
<ChevronLeft size={18} />
|
| 43 |
+
<span className="hidden sm:inline">Prev</span>
|
| 44 |
+
</button>
|
| 45 |
+
|
| 46 |
+
{/* Dots indicator */}
|
| 47 |
+
<div className="flex gap-2">
|
| 48 |
+
{Array.from({ length: totalPages }).map((_, index) => (
|
| 49 |
+
<button
|
| 50 |
+
key={index}
|
| 51 |
+
onClick={() => setCurrentIndex(index)}
|
| 52 |
+
className={`
|
| 53 |
+
w-3 h-3 border-2 border-brutal-black transition-all
|
| 54 |
+
${currentIndex === index ? 'bg-brutal-black' : 'bg-transparent'}
|
| 55 |
+
`}
|
| 56 |
+
aria-label={`Go to slide ${index + 1}`}
|
| 57 |
+
/>
|
| 58 |
+
))}
|
| 59 |
+
</div>
|
| 60 |
+
|
| 61 |
+
<button
|
| 62 |
+
onClick={goToNext}
|
| 63 |
+
className="brutal-btn flex items-center gap-2"
|
| 64 |
+
>
|
| 65 |
+
<span className="hidden sm:inline">Next</span>
|
| 66 |
+
<ChevronRight size={18} />
|
| 67 |
+
</button>
|
| 68 |
+
</div>
|
| 69 |
+
</div>
|
| 70 |
+
</div>
|
| 71 |
+
);
|
| 72 |
+
}
|