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>
);
}
|