Files
Art-gallery/client/src/components/PaintingLightbox.tsx
T
Danila KhodjaefandCursor d8385d83d6 Add painting detail navigation, influence lamps, and catalog tooling.
Expand the gallery with prev/next browsing and fullscreen detail view, golden influence lamps and chronological wall layout in 3D halls, and scripts/docs for catalog expansion, influence edges, and multi-source image fetching.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-19 16:35:33 +03:00

71 lines
1.6 KiB
TypeScript

import { useEffect } from 'react';
import { createPortal } from 'react-dom';
import './PaintingLightbox.css';
interface Props {
src: string;
alt: string;
title?: string;
subtitle?: string;
closeHint?: string;
onClose: () => void;
onDetails?: () => void;
}
export default function PaintingLightbox({
src,
alt,
title,
subtitle,
closeHint = 'Click anywhere to close',
onClose,
onDetails,
}: Props) {
useEffect(() => {
const prevOverflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
window.addEventListener('keydown', onKey);
return () => {
document.body.style.overflow = prevOverflow;
window.removeEventListener('keydown', onKey);
};
}, [onClose]);
return createPortal(
<div
className="painting-lightbox"
onClick={onClose}
role="dialog"
aria-modal="true"
aria-label={title || alt}
>
{(title || subtitle || onDetails) && (
<div className="painting-lightbox-caption">
{title && <strong>{title}</strong>}
{subtitle && <span>{subtitle}</span>}
{onDetails && (
<button
type="button"
className="painting-lightbox-details"
onClick={(e) => {
e.stopPropagation();
onDetails();
}}
>
View details
</button>
)}
</div>
)}
<img src={src} alt={alt} />
<span className="painting-lightbox-hint">{closeHint}</span>
</div>,
document.body
);
}