diff --git a/components/Lightbox.tsx b/components/Lightbox.tsx index 03480181..861d298c 100644 --- a/components/Lightbox.tsx +++ b/components/Lightbox.tsx @@ -3,6 +3,8 @@ import React, { useEffect, useState, useCallback } from 'react'; import Image from 'next/image'; import { createPortal } from 'react-dom'; +import { motion, AnimatePresence } from 'framer-motion'; +import { useRouter, useSearchParams, usePathname } from 'next/navigation'; interface LightboxProps { isOpen: boolean; @@ -12,6 +14,9 @@ interface LightboxProps { } export default function Lightbox({ isOpen, images, initialIndex, onClose }: LightboxProps) { + const router = useRouter(); + const searchParams = useSearchParams(); + const pathname = usePathname(); const [currentIndex, setCurrentIndex] = useState(initialIndex); const [mounted, setMounted] = useState(false); @@ -20,19 +25,53 @@ export default function Lightbox({ isOpen, images, initialIndex, onClose }: Ligh return () => setMounted(false); }, []); + const updateUrl = useCallback((index: number | null) => { + const params = new URLSearchParams(searchParams.toString()); + if (index !== null) { + params.set('photo', index.toString()); + } else { + params.delete('photo'); + } + router.replace(`${pathname}?${params.toString()}`, { scroll: false }); + }, [pathname, router, searchParams]); + const prevImage = useCallback(() => { - setCurrentIndex((prev) => (prev === 0 ? images.length - 1 : prev - 1)); - }, [images.length]); + setCurrentIndex((prev) => { + const next = prev === 0 ? images.length - 1 : prev - 1; + updateUrl(next); + return next; + }); + }, [images.length, updateUrl]); const nextImage = useCallback(() => { - setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1)); - }, [images.length]); + setCurrentIndex((prev) => { + const next = prev === images.length - 1 ? 0 : prev + 1; + updateUrl(next); + return next; + }); + }, [images.length, updateUrl]); + + useEffect(() => { + const photoParam = searchParams.get('photo'); + if (photoParam !== null) { + const index = parseInt(photoParam, 10); + if (!isNaN(index) && index >= 0 && index < images.length) { + setCurrentIndex(index); + } + } + }, [searchParams, images.length]); + + useEffect(() => { + if (isOpen) { + updateUrl(currentIndex); + } + }, [isOpen, currentIndex, updateUrl]); useEffect(() => { if (!isOpen) return; const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'Escape') onClose(); + if (e.key === 'Escape') handleClose(); if (e.key === 'ArrowLeft') prevImage(); if (e.key === 'ArrowRight') nextImage(); }; @@ -47,59 +86,119 @@ export default function Lightbox({ isOpen, images, initialIndex, onClose }: Ligh document.body.style.overflow = originalStyle; window.removeEventListener('keydown', handleKeyDown); }; - }, [isOpen, onClose, prevImage, nextImage]); + }, [isOpen, prevImage, nextImage]); - if (!isOpen || !mounted) return null; + if (!mounted) return null; + + const handleClose = () => { + updateUrl(null); + onClose(); + }; return createPortal( -