sozsoft-platform/ui/src/views/intranet/widgets/ImageLightbox.tsx
2026-06-26 22:02:53 +03:00

104 lines
3.5 KiB
TypeScript

import { createPortal } from 'react-dom'
import { motion, AnimatePresence } from 'framer-motion'
import { FaChevronLeft, FaChevronRight, FaTimes } from 'react-icons/fa'
import { Button } from '@/components/ui'
import type { MouseEvent } from 'react'
interface ImageLightboxProps {
images: string[]
activeIndex: number
isOpen: boolean
altPrefix: string
getSrc: (img: string) => string
onClose: () => void
onChangeIndex: (index: number) => void
}
const ImageLightbox = ({
images,
activeIndex,
isOpen,
altPrefix,
getSrc,
onClose,
onChangeIndex,
}: ImageLightboxProps) => {
const changeBy = (delta: number) => (event: MouseEvent) => {
event.stopPropagation()
onChangeIndex((activeIndex + delta + images.length) % images.length)
}
return createPortal(
<AnimatePresence>
{isOpen && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/95 z-[1100]"
onClick={onClose}
/>
<div className="fixed inset-0 z-[1110] flex items-center justify-center">
<Button
onClick={onClose}
variant="plain"
shape="circle"
icon={<FaTimes className="h-8 w-8" />}
className="absolute top-4 right-4 z-10 !h-12 !w-12 !px-0 text-white transition-colors hover:text-gray-300"
/>
{images.length > 1 && (
<>
<Button
onClick={changeBy(-1)}
variant="plain"
shape="circle"
icon={<FaChevronLeft className="h-6 w-6" />}
className="absolute left-4 top-1/2 z-10 !h-12 !w-12 -translate-y-1/2 !px-0 bg-black/50 text-white transition-colors hover:!bg-black/70"
/>
<Button
onClick={changeBy(1)}
variant="plain"
shape="circle"
icon={<FaChevronRight className="h-6 w-6" />}
className="absolute right-4 top-1/2 z-10 !h-12 !w-12 -translate-y-1/2 !px-0 bg-black/50 text-white transition-colors hover:!bg-black/70"
/>
</>
)}
<motion.img
key={activeIndex}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0 }}
src={getSrc(images[activeIndex])}
alt={`${altPrefix} ${activeIndex + 1}`}
className="max-w-[90vw] max-h-[90vh] object-contain rounded-lg"
onClick={(event) => event.stopPropagation()}
/>
{images.length > 1 && (
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2">
{images.map((_, index) => (
<Button
key={index}
onClick={(event) => {
event.stopPropagation()
onChangeIndex(index)
}}
variant="plain"
shape="circle"
className={`!h-2.5 !w-2.5 !min-w-2.5 !px-0 transition-all ${
index === activeIndex ? 'bg-white' : 'bg-white/40 hover:bg-white/70'
}`}
/>
))}
</div>
)}
</div>
</>
)}
</AnimatePresence>,
document.body,
)
}
export default ImageLightbox