Files
web/components/Lightbox/index.tsx
Bianca Widstam fc8844eb96 feat/SW-689-image-gallery-sizes (pull request #781)
Feat/SW-689 image gallery sizes

* feat(SW-689): initial gallery changes

* feat(SW-689): remove console.log

* feat(SW-689): remove unneccessary code

* feat(SW-689): change sizes

* feat(SW-689): change size

* feat(SW-689): add design for ipad for fullview

* feat(SW-689): fix import type

* feat(SW-689): fix tripAdvisor placement

* feat(SW-689): fix image gallery type

* feat(SW-689): fix check gallery length


Approved-by: Christian Andolf
Approved-by: Matilda Landström
2024-10-29 13:54:12 +00:00

116 lines
3.5 KiB
TypeScript

"use client"
import { AnimatePresence, motion } from "framer-motion"
import React, { useState } from "react"
import { Dialog, Modal, ModalOverlay } from "react-aria-components"
import FullView from "./FullView"
import Gallery from "./Gallery"
import styles from "./Lightbox.module.css"
import type { LightboxProps } from "@/types/components/lightbox/lightbox"
export default function Lightbox({
images,
children,
dialogTitle,
}: LightboxProps) {
const [isOpen, setIsOpen] = useState(false)
const [selectedImageIndex, setSelectedImageIndex] = useState(0)
const [isFullView, setIsFullView] = useState(false)
function handleOpenChange(open: boolean) {
if (!open) {
setTimeout(() => {
setIsOpen(false)
setSelectedImageIndex(0)
setIsFullView(false)
}, 300) // 300ms delay
} else {
setIsOpen(true)
}
}
function handleNext() {
setSelectedImageIndex((prevIndex) => (prevIndex + 1) % images.length)
}
function handlePrev() {
setSelectedImageIndex(
(prevIndex) => (prevIndex - 1 + images.length) % images.length
)
}
const triggerElement = React.Children.map(
children,
function mapChild(child): React.ReactNode {
if (React.isValidElement(child)) {
if (child.props.id === "lightboxTrigger") {
return React.cloneElement(child, {
onClick: () => setIsOpen(true),
} as React.HTMLAttributes<HTMLElement>)
} else if (child.props.children) {
return React.cloneElement(child, {
children: React.Children.map(child.props.children, mapChild),
} as React.HTMLAttributes<HTMLElement>)
}
}
return child
}
)
return (
<>
{triggerElement}
<ModalOverlay
isOpen={isOpen}
onOpenChange={handleOpenChange}
className={styles.overlay}
isDismissable
>
<Modal>
<AnimatePresence>
{isOpen && (
<Dialog>
<motion.div
className={`${styles.content} ${
isFullView ? styles.fullViewContent : styles.galleryContent
}`}
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1, x: "-50%", y: "-50%" }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.2 }}
>
{isFullView ? (
<FullView
image={images[selectedImageIndex]}
onClose={() => setIsFullView(false)}
onNext={handleNext}
onPrev={handlePrev}
currentIndex={selectedImageIndex}
totalImages={images.length}
/>
) : (
<Gallery
images={images}
dialogTitle={dialogTitle}
onClose={() => setIsOpen(false)}
onSelectImage={(image) => {
setSelectedImageIndex(
images.findIndex((img) => img === image)
)
}}
onImageClick={() => setIsFullView(true)}
selectedImage={images[selectedImageIndex]}
/>
)}
</motion.div>
</Dialog>
)}
</AnimatePresence>
</Modal>
</ModalOverlay>
</>
)
}