All files / src/components/rooms MediaLightbox.tsx

100% Statements 5/5
100% Branches 8/8
100% Functions 2/2
100% Lines 5/5

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96                                      23x 23x   23x 23x     23x                                                                                                                                          
import { type Media, getImageUrl } from "../../lib/api";
import { ChevronLeft, ChevronRight, X } from "lucide-react";
import { useDialogAccessibility } from "../../hooks";
 
type MediaLightboxProps = {
	media: Media[];
	currentIndex: number;
	onClose: () => void;
	onNext: () => void;
	onPrev: () => void;
};
 
export function MediaLightbox({
	media,
	currentIndex,
	onClose,
	onNext,
	onPrev,
}: MediaLightboxProps) {
	const { dialogRef, handleFocusTrap } = useDialogAccessibility(onClose);
	const currentMedia = media[currentIndex];
 
	const getMediaUrl = (item: Media) => {
		return getImageUrl(item.storageKey);
	};
 
	return (
		<div
			ref={dialogRef}
			role="dialog"
			aria-modal="true"
			aria-labelledby="media-lightbox-title"
			onKeyDown={handleFocusTrap}
			className="fixed inset-0 z-50 bg-overlay-darker flex items-center justify-center"
		>
			<button
				type="button"
				onClick={onClose}
				aria-label="Close"
				className="absolute top-4 right-4 text-foreground-inverse hover:text-foreground-subtle z-10"
			>
				<X className="h-8 w-8" />
			</button>
 
			{media.length > 1 && (
				<>
					<button
						type="button"
						onClick={onPrev}
						aria-label="Previous"
						className="absolute left-4 text-foreground-inverse hover:text-foreground-subtle z-10"
					>
						<ChevronLeft className="h-12 w-12" />
					</button>
					<button
						type="button"
						onClick={onNext}
						aria-label="Next"
						className="absolute right-4 text-foreground-inverse hover:text-foreground-subtle z-10"
					>
						<ChevronRight className="h-12 w-12" />
					</button>
				</>
			)}
 
			<h2 id="media-lightbox-title" className="sr-only">
				Media viewer — {currentIndex + 1} of {media.length}
			</h2>
			<div className="max-w-[90vw] max-h-[90vh]">
				{currentMedia.mediaType === "video" ? (
					<video
						src={getMediaUrl(currentMedia)}
						controls
						autoPlay
						className="max-w-full max-h-[85vh]"
					>
						<track kind="captions" label="Captions" default />
					</video>
				) : (
					<img
						src={getMediaUrl(currentMedia)}
						alt={currentMedia.caption || "Media"}
						className="max-w-full max-h-[85vh] object-contain"
					/>
				)}
				{currentMedia.caption && (
					<p className="text-foreground-inverse text-center mt-4">{currentMedia.caption}</p>
				)}
				<p className="text-foreground-subtle text-center mt-2 text-sm">
					{currentIndex + 1} / {media.length}
				</p>
			</div>
		</div>
	);
}