forked from bots-garden/ori
| ✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme | 1 | /** |
| 2 | * ImageView shows a workspace image (png, jpeg, gif, webp, svg, bmp, ico, | |
| 3 | * avif) at its natural size, capped to the pane width, over a checkerboard | |
| 4 | * that reveals transparency. The bytes stream from GET /api/raw, and the | |
| 5 | * natural dimensions appear once the browser has decoded the image. | |
| 6 | * | |
| 7 | * @example | |
| 8 | * <ImageView path="/work/docs/logo.png" /> | |
| 9 | */ | |
| 10 | ||
| 11 | import { useState } from "react"; | |
| 12 | import { rawFileUrl } from "../api"; | |
| 13 | ||
| 14 | export function ImageView({ path }: { path: string }) { | |
| 15 | const [size, setSize] = useState<{ width: number; height: number } | null>( | |
| 16 | null, | |
| 17 | ); | |
| 18 | const [failed, setFailed] = useState(false); | |
| 19 | ||
| 20 | if (failed) { | |
| 21 | return <p className="pane-error">the image could not be loaded</p>; | |
| 22 | } | |
| 23 | return ( | |
| 24 | <figure className="image-view"> | |
| 25 | <div className="image-view-canvas"> | |
| 26 | <img | |
| 27 | src={rawFileUrl(path)} | |
| 28 | alt={path.split("/").pop() ?? path} | |
| 29 | onLoad={(event) => { | |
| 30 | const img = event.currentTarget; | |
| 31 | setSize({ width: img.naturalWidth, height: img.naturalHeight }); | |
| 32 | }} | |
| 33 | onError={() => setFailed(true)} | |
| 34 | /> | |
| 35 | </div> | |
| 36 | <figcaption className="image-view-meta"> | |
| 37 | {size ? `${size.width} × ${size.height} px` : "loading…"} | |
| 38 | </figcaption> | |
| 39 | </figure> | |
| 40 | ); | |
| 41 | } |