lightbox
All checks were successful
Build & Deploy KLZ Cables / build-and-deploy (push) Successful in 3m31s
All checks were successful
Build & Deploy KLZ Cables / build-and-deploy (push) Successful in 3m31s
This commit is contained in:
@@ -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';
|
|
||||||
}
|
const prevImage = useCallback(() => {
|
||||||
|
setCurrentIndex((prev) => (prev === 0 ? images.length - 1 : prev - 1));
|
||||||
|
}, [images.length]);
|
||||||
|
|
||||||
|
const nextImage = useCallback(() => {
|
||||||
|
setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1));
|
||||||
|
}, [images.length]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
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 () => {
|
return () => {
|
||||||
document.body.style.overflow = 'unset';
|
document.body.style.overflow = originalStyle;
|
||||||
|
window.removeEventListener('keydown', handleKeyDown);
|
||||||
};
|
};
|
||||||
}, [isOpen]);
|
}, [isOpen, onClose, prevImage, nextImage]);
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen || !mounted) return null;
|
||||||
|
|
||||||
const prevImage = () => {
|
return createPortal(
|
||||||
setCurrentIndex((prev) => (prev === 0 ? images.length - 1 : prev - 1));
|
<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"
|
||||||
const nextImage = () => {
|
aria-modal="true"
|
||||||
setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1));
|
>
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="fixed inset-0 z-[9999] bg-black/90 flex items-center justify-center p-4 animate-in fade-in duration-300">
|
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user