| 1 | import { useEffect, useRef, type RefObject } from "react"; |
| 2 | import type { FilePreview } from "../lib/types"; |
| 3 | import { workspaceBasename } from "../lib/workspacePanelFormat"; |
| 4 | |
| 5 | export function WorkspaceMediaPreview({ preview }: { preview: FilePreview }) { |
| 6 | if (!preview.url) return null; |
| 7 | if (preview.kind === "image") { |
| 8 | return ( |
| 9 | <div className="workspace-media workspace-media--image"> |
| 10 | <img src={preview.url} alt={workspaceBasename(preview.path)} decoding="async" draggable={false} /> |
| 11 | </div> |
| 12 | ); |
| 13 | } |
| 14 | if (preview.kind === "pdf") { |
| 15 | return <iframe className="workspace-media workspace-media--pdf" src={preview.url} title={workspaceBasename(preview.path)} />; |
| 16 | } |
| 17 | if (preview.kind === "html") { |
| 18 | return <iframe className="workspace-media workspace-media--html" src={preview.url} title={workspaceBasename(preview.path)} sandbox="allow-scripts" />; |
| 19 | } |
| 20 | if (preview.kind === "audio") { |
| 21 | return <ReleasingMedia kind="audio" url={preview.url} />; |
| 22 | } |
| 23 | if (preview.kind === "video") { |
| 24 | return <ReleasingMedia kind="video" url={preview.url} />; |
| 25 | } |
| 26 | return null; |
| 27 | } |
| 28 | |
| 29 | export function releaseMediaElement(element: Pick<HTMLMediaElement, "pause" | "removeAttribute" | "load">): void { |
| 30 | element.pause(); |
| 31 | element.removeAttribute("src"); |
| 32 | element.load(); |
| 33 | } |
| 34 | |
| 35 | function ReleasingMedia({ kind, url }: { kind: "audio" | "video"; url: string }) { |
| 36 | const ref = useRef<HTMLMediaElement>(null); |
| 37 | useEffect(() => () => { if (ref.current) releaseMediaElement(ref.current); }, [url]); |
| 38 | const media = { src: url, controls: true, preload: "metadata" as const }; |
| 39 | return <div className={`workspace-media workspace-media--${kind}`}> |
| 40 | {kind === "audio" ? <audio ref={ref as RefObject<HTMLAudioElement>} {...media} /> : <video ref={ref as RefObject<HTMLVideoElement>} {...media} />} |
| 41 | </div>; |
| 42 | } |
| 43 |