1export interface Input {
2 src: MediaFile | string;
3 alt: string;
4 displayWidthEstimate?: number | string;
5 align?: string;
6}
7
8<const/{ src, alt = "", displayWidthEstimate, align, ...rest }=input>
9<const/file=typeof src === "object" ? src : MediaFile.getByPath(src)>
10
11<if=!file>
12 <div style={ color: "red" }>ERROR: No file in database: ${src}</div>
13</if>
14<else if=extsVideo.has(file.extension.toLowerCase())>
15 <clover-video minimal noFigure ...{ file }/>
16</else>
17<else if=file.extension.toLowerCase() === ".gif">
18 <img src=`/file${escapeUri(file.path)}` ...rest>
19</else>
20<else>
21 <const/base=`/file${escapeUri(file.path)}`>
22 <const/dims=file.parseDimensions()>
23 <if=!dims || file.pending>
24 <img
25 src=base
26 style=(
27 align
28 ? { "object-position": align, width: "100%", height: "100%" }
29 : undefined
30 )
31 ...rest
32 >
33 </if>
34 <else>
35 <const/targetSizes=transcodeRules.imageSizes.filter((w) => w < dims.width)>
36 <const/sizes=(
37 displayWidthEstimate
38 ? typeof displayWidthEstimate === "number"
39 ? `${displayWidthEstimate}px`
40 : displayWidthEstimate
41 : `100vw`
42 )>
43 <picture>
44 <for|ext| of=["jxl", "webp"]>
45 <source
46 type=`image/${ext}`
47 srcset=targetSizes.map((s) => `${base}:/${s}.${ext} ${s}w`).join(",")
48 ...{ sizes }
49 >
50 </for>
51 <img
52 src=base
53 style=(
54 align
55 ? { "object-position": align, width: "100%", height: "100%" }
56 : undefined
57 )
58 ...rest
59 >
60 </picture>
61 </else>
62</else>
63
64import * as transcodeRules from "#src/file-viewer/transcode-rules.ts";
65import { extsVideo } from "#src/file-viewer/rules.ts";
66import { MediaFile } from "#src/file-viewer/models/MediaFile.ts";
67import { escapeUri } from "#src/file-viewer/format.ts";