diff --git a/src/app/components/carousel.tsx b/src/app/components/carousel.tsx index 1052661..192c32b 100644 --- a/src/app/components/carousel.tsx +++ b/src/app/components/carousel.tsx @@ -28,7 +28,7 @@ export default function Carousel({ images, className }: Props) {
{images.map((src, index) => (
- +
))}
diff --git a/src/app/components/image-viewer.tsx b/src/app/components/image-viewer.tsx index 74aaeb1..b7f9e2d 100644 --- a/src/app/components/image-viewer.tsx +++ b/src/app/components/image-viewer.tsx @@ -1,8 +1,10 @@ "use client"; import Image from "next/image"; + import { useEffect, useState } from "react"; import { createPortal } from "react-dom"; +import useEmblaCarousel from "embla-carousel-react"; import { Icon } from "@iconify/react"; interface Props { @@ -11,12 +13,17 @@ interface Props { width: number; height: number; className?: string; + images?: string[]; } -export default function ImageViewer({ src, alt, width, height, className }: Props) { +export default function ImageViewer({ src, alt, width, height, className, images = [] }: Props) { const [isOpen, setIsOpen] = useState(false); const [isVisible, setIsVisible] = useState(false); + const [emblaRef, emblaApi] = useEmblaCarousel(); + const [selectedIndex, setSelectedIndex] = useState(0); + const [scrollSnaps, setScrollSnaps] = useState([]); + const close = () => { setIsVisible(false); setTimeout(() => { @@ -31,6 +38,21 @@ export default function ImageViewer({ src, alt, width, height, className }: Prop } }, [isOpen]); + useEffect(() => { + if (!emblaApi) return; + + // Keep order of images whilst opening on src + const index = images.indexOf(src); + if (index !== -1) { + emblaApi.scrollTo(index); + setSelectedIndex(index); + } + + // Scroll snaps + setScrollSnaps(emblaApi.scrollSnapList()); + emblaApi.on("select", () => setSelectedIndex(emblaApi.selectedScrollSnap())); + }, [emblaApi]); + return ( <> {alt} setIsOpen(true)} /> @@ -50,13 +72,81 @@ export default function ImageViewer({ src, alt, width, height, className }: Prop isVisible ? "scale-100 opacity-100" : "scale-75 opacity-0" }`} > -
+
- {alt} + +
+
+ {images.length == 0 ? ( + {alt} + ) : ( + <> + {images.map((image, index) => ( +
+ {alt} +
+ ))} + + )} +
+
+ + {images.length != 0 && ( + <> + {/* Carousel buttons */} + {/* Prev button */} +
+ +
+ {/* Next button */} +
+ +
+ + {/* Carousel snaps */} +
+ {scrollSnaps.map((_, index) => ( +
+ + )} , document.body )}