lightbox
All checks were successful
Build & Deploy KLZ Cables / build-and-deploy (push) Successful in 3m31s

This commit is contained in:
2026-01-27 00:21:03 +01:00
parent 3c45e5563e
commit 3cab376cd1

View File

@@ -1,7 +1,8 @@
'use client'; 'use client';
import React, { useEffect } from 'react'; import React, { useEffect, useState, useCallback } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import { createPortal } from 'react-dom';
interface LightboxProps { interface LightboxProps {
isOpen: boolean; isOpen: boolean;
@@ -11,32 +12,51 @@ interface LightboxProps {
} }
export default function Lightbox({ isOpen, images, initialIndex, onClose }: LightboxProps) { export default function Lightbox({ isOpen, images, initialIndex, onClose }: LightboxProps) {
const [currentIndex, setCurrentIndex] = React.useState(initialIndex); const [currentIndex, setCurrentIndex] = useState(initialIndex);
const [mounted, setMounted] = useState(false);
useEffect(() => { useEffect(() => {
if (isOpen) { setMounted(true);
document.body.style.overflow = 'hidden'; return () => setMounted(false);
} else { }, []);
document.body.style.overflow = 'unset';
}
return () => { const prevImage = useCallback(() => {
document.body.style.overflow = 'unset';
};
}, [isOpen]);
if (!isOpen) return null;
const prevImage = () => {
setCurrentIndex((prev) => (prev === 0 ? images.length - 1 : prev - 1)); setCurrentIndex((prev) => (prev === 0 ? images.length - 1 : prev - 1));
}; }, [images.length]);
const nextImage = () => { const nextImage = useCallback(() => {
setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1)); setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1));
}; }, [images.length]);
return ( useEffect(() => {
<div className="fixed inset-0 z-[9999] bg-black/90 flex items-center justify-center p-4 animate-in fade-in duration-300"> if (!isOpen) return;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
if (e.key === 'ArrowLeft') prevImage();
if (e.key === 'ArrowRight') nextImage();
};
// Lock scroll
const originalStyle = window.getComputedStyle(document.body).overflow;
document.body.style.overflow = 'hidden';
window.addEventListener('keydown', handleKeyDown);
return () => {
document.body.style.overflow = originalStyle;
window.removeEventListener('keydown', handleKeyDown);
};
}, [isOpen, onClose, prevImage, nextImage]);
if (!isOpen || !mounted) return null;
return createPortal(
<div
className="fixed inset-0 z-[99999] bg-black/95 backdrop-blur-sm flex items-center justify-center p-4 animate-in fade-in duration-300"
role="dialog"
aria-modal="true"
>
<button <button
onClick={onClose} onClick={onClose}
className="absolute top-6 right-6 text-white text-3xl hover:text-[#011dff] transition-colors z-[10000] rounded-full w-12 h-12 flex items-center justify-center hover:bg-white/10" className="absolute top-6 right-6 text-white text-3xl hover:text-[#011dff] transition-colors z-[10000] rounded-full w-12 h-12 flex items-center justify-center hover:bg-white/10"
@@ -74,19 +94,12 @@ export default function Lightbox({ isOpen, images, initialIndex, onClose }: Ligh
</div> </div>
</div> </div>
{/* Keyboard navigation */} {/* Backdrop click to close */}
{isOpen && ( <div
<div className="absolute inset-0 z-[9998]"
className="fixed inset-0 z-[9998]" onClick={onClose}
tabIndex={-1} />
onKeyDown={(e) => { </div>,
if (e.key === 'Escape') onClose(); document.body
if (e.key === 'ArrowLeft') prevImage();
if (e.key === 'ArrowRight') nextImage();
}}
onClick={onClose}
/>
)}
</div>
); );
} }