react-advanced-gallery
Version:
A customizable React image gallery component with Bootstrap styling, fullscreen mode, animations, and support for various media types
92 lines (91 loc) • 8.07 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect, useRef } from 'react';
export function FullscreenViewer({ isOpen, currentImage, images, currentIndex, zoomLevel, onClose, onPrev, onNext, onFavoriteToggle, onImageRemove, onZoomIn, onZoomOut, onThumbnailClick }) {
var _a, _b, _c, _d;
const [dragPosition, setDragPosition] = useState({ x: 0, y: 0 });
const containerRef = useRef(null);
// Reset drag position when changing images or zoom level
useEffect(() => {
setDragPosition({ x: 0, y: 0 });
}, [currentIndex, zoomLevel]);
const handleDownload = () => {
if (!currentImage)
return;
const link = document.createElement('a');
link.href = currentImage.src;
link.download = currentImage.title || 'image';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
const handleFullScreen = () => {
if (!containerRef.current)
return;
if (!document.fullscreenElement) {
containerRef.current.requestFullscreen().catch(err => {
console.error(`Error attempting to enable fullscreen: ${err.message}`);
});
}
else {
document.exitFullscreen();
}
};
// Handle touch and mouse drag for panning when zoomed
const dragConstraints = zoomLevel > 1
? {
top: -((((_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) || 0) * (zoomLevel - 1) / 2),
left: -((((_b = containerRef.current) === null || _b === void 0 ? void 0 : _b.clientWidth) || 0) * (zoomLevel - 1) / 2),
right: ((((_c = containerRef.current) === null || _c === void 0 ? void 0 : _c.clientWidth) || 0) * (zoomLevel - 1) / 2),
bottom: ((((_d = containerRef.current) === null || _d === void 0 ? void 0 : _d.clientHeight) || 0) * (zoomLevel - 1) / 2)
}
: { top: 0, left: 0, right: 0, bottom: 0 };
if (!isOpen || !currentImage)
return null;
// Format the date for the metadata display
const formatDate = (dateString) => {
if (!dateString)
return '';
try {
return new Date(dateString).toLocaleDateString();
}
catch (e) {
return '';
}
};
return (_jsxs("div", { ref: containerRef, className: "rag-fullscreen", children: [_jsxs("div", { className: "rag-fullscreen-header", children: [_jsxs("div", { className: "rag-fullscreen-title", children: [_jsx("button", { className: "rag-fullscreen-btn", onClick: onClose, "aria-label": "Close fullscreen view", children: _jsx("span", { className: "rag-material-icons", children: "close" }) }), _jsx("h3", { children: currentImage.title })] }), _jsxs("div", { className: "rag-fullscreen-actions", children: [_jsx("button", { className: "rag-fullscreen-btn", onClick: () => onFavoriteToggle(currentImage), "aria-label": currentImage.isFavorite ? "Remove from favorites" : "Add to favorites", children: _jsx("span", { className: `rag-material-icons ${currentImage.isFavorite ? 'active' : ''}`, children: currentImage.isFavorite ? 'star' : 'star_border' }) }), _jsx("button", { className: "rag-fullscreen-btn", onClick: () => onImageRemove(currentImage), "aria-label": "Delete image", children: _jsx("span", { className: "rag-material-icons", children: "delete" }) }), _jsx("button", { className: "rag-fullscreen-btn", onClick: handleDownload, "aria-label": "Download image", children: _jsx("span", { className: "rag-material-icons", children: "download" }) })] })] }), _jsxs("div", { className: "rag-fullscreen-content", children: [_jsx("button", { className: "rag-fullscreen-nav-prev", onClick: onPrev, "aria-label": "Previous image", children: _jsx("span", { className: "rag-material-icons", children: "chevron_left" }) }), currentImage.type === 'video' ? (_jsx("video", { src: currentImage.src, poster: currentImage.thumbnail, controls: true, className: "rag-fullscreen-image" })) : (_jsx("img", { src: currentImage.src, alt: currentImage.alt, className: `rag-fullscreen-image ${zoomLevel > 1 ? 'zoomed' : ''}`, style: {
transform: `scale(${zoomLevel})`,
position: 'relative',
left: `${dragPosition.x}px`,
top: `${dragPosition.y}px`,
}, draggable: false, onMouseDown: (e) => {
if (zoomLevel <= 1)
return;
const startX = e.clientX;
const startY = e.clientY;
const startDragX = dragPosition.x;
const startDragY = dragPosition.y;
const onMouseMove = (e) => {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
const newX = Math.min(Math.max(startDragX + dx, -dragConstraints.right), dragConstraints.right);
const newY = Math.min(Math.max(startDragY + dy, -dragConstraints.bottom), dragConstraints.bottom);
setDragPosition({ x: newX, y: newY });
};
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
} })), _jsx("button", { className: "rag-fullscreen-nav-next", onClick: onNext, "aria-label": "Next image", children: _jsx("span", { className: "rag-material-icons", children: "chevron_right" }) }), _jsxs("div", { className: "rag-fullscreen-zoom-controls", children: [_jsx("button", { className: "rag-fullscreen-btn", onClick: onZoomOut, "aria-label": "Zoom out", disabled: zoomLevel <= 0.5, children: _jsx("span", { className: "rag-material-icons", children: "zoom_out" }) }), _jsx("button", { className: "rag-fullscreen-btn", onClick: onZoomIn, "aria-label": "Zoom in", disabled: zoomLevel >= 3, children: _jsx("span", { className: "rag-material-icons", children: "zoom_in" }) }), _jsx("button", { className: "rag-fullscreen-btn", onClick: handleFullScreen, "aria-label": "Toggle fullscreen", children: _jsx("span", { className: "rag-material-icons", children: "fullscreen" }) })] })] }), _jsxs("div", { className: "rag-fullscreen-footer", children: [_jsx("div", { className: "rag-fullscreen-thumbnails", children: images.map((image, index) => (_jsx("div", { className: `rag-fullscreen-thumbnail ${index === currentIndex ? 'active' : ''}`, onClick: () => onThumbnailClick(index), children: _jsx("img", { src: image.thumbnail, alt: `${image.alt} thumbnail`, loading: "lazy" }) }, image.id))) }), currentImage.metadata && (_jsxs("div", { className: "rag-fullscreen-metadata", children: [_jsx("p", { children: [
currentImage.metadata.camera && `Shot on ${currentImage.metadata.camera}`,
currentImage.metadata.aperture,
currentImage.metadata.shutterSpeed,
currentImage.metadata.iso && `ISO ${currentImage.metadata.iso}`,
currentImage.metadata.focalLength
].filter(Boolean).join(' • ') }), _jsx("p", { children: [
currentImage.metadata.dateTaken && `Uploaded ${formatDate(currentImage.metadata.dateTaken)}`,
currentImage.metadata.fileSize,
currentImage.metadata.dimensions
].filter(Boolean).join(' • ') })] }))] })] }));
}