added ImageCarousel component, added icons to action buttons, modified project route
This commit is contained in:
82
frontend/islands/ImageCarousel.tsx
Normal file
82
frontend/islands/ImageCarousel.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { useState } from "preact/hooks";
|
||||
|
||||
export const ImageCarousel = function ImageCarousel(props: ImageCarouselProps) {
|
||||
const [currentImageIndex, setCurrentImageIndex] = useState(0);
|
||||
|
||||
const nextImage = (e: Event) => {
|
||||
e.stopPropagation();
|
||||
if (props.images && props.images?.length > 0) {
|
||||
const localImage = props.images;
|
||||
setCurrentImageIndex((prev) => (prev + 1) % localImage.length || 0);
|
||||
}
|
||||
};
|
||||
|
||||
const prevImage = (e: Event) => {
|
||||
e.stopPropagation();
|
||||
if (props.images && props.images.length > 0) {
|
||||
const localImage = props.images;
|
||||
setCurrentImageIndex(
|
||||
(prev) => (prev - 1 + localImage.length) % localImage.length,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="relative rounded overflow-hidden bg-gray-100 dark:bg-gray-800">
|
||||
<div class="relative w-full h-96">
|
||||
{props.images.map((image, index) => (
|
||||
<img
|
||||
key={index}
|
||||
src={image}
|
||||
alt={`screenshot ${index + 1}`}
|
||||
class={`absolute inset-0 w-full h-full object-contain transition-opacity duration-500 ${
|
||||
index === currentImageIndex ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{props.images.length > 1 && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={prevImage}
|
||||
class="absolute left-2 top-1/2 -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white rounded-full w-10 h-10 flex items-center justify-center transition-all"
|
||||
aria-label="Previous image"
|
||||
>
|
||||
←
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={nextImage}
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white rounded-full w-10 h-10 flex items-center justify-center transition-all"
|
||||
aria-label="Next image"
|
||||
>
|
||||
→
|
||||
</button>
|
||||
<div class="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2 bg-black/30 px-3 py-2 rounded-full">
|
||||
{props.images.map((_, index) => (
|
||||
<button
|
||||
key={index}
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setCurrentImageIndex(index);
|
||||
}}
|
||||
class={`w-2.5 h-2.5 rounded-full transition-all ${
|
||||
index === currentImageIndex
|
||||
? "bg-white scale-125"
|
||||
: "bg-white/50 hover:bg-white/75"
|
||||
}`}
|
||||
aria-label={`Go to image ${index + 1}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type ImageCarouselProps = {
|
||||
images: Array<string>;
|
||||
};
|
||||
Reference in New Issue
Block a user