summaryrefslogtreecommitdiff
path: root/src/apps/image.tsx
blob: 12623c30d68b85fe0777441cfd7fd2c0012fc7ae (plain)
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
import { effect, Signal, useSignalEffect } from "@preact/signals"
import { Address } from "$/apps/source";
import { memo, Ref, useRef } from "preact/compat";

const filenameRegex = /.*\/(.*)$/;

export const Image = memo(function Image({ source, title, contentReady, sizingFinished }: Image.Props) {
    useSignalEffect(() => {
        const filename = decodeURIComponent(source.value.link.pathname.match(filenameRegex)?.[1] ?? source.value.link.toString());
        title.value = `${filename} - picview`;
    })

    const imgRef: Ref<HTMLImageElement> = useRef(null);

    return <img style={{ "image-rendering": (source.value.pixelated ? "crisp-edges" : undefined) }} src={source.value.link.toString()} ref={img => {
        imgRef.current = img
        const id = setInterval(() => {
            if (img && img.naturalWidth) {
                clearInterval(id)
                contentReady.value = true
                const vw = Math.max(document.documentElement.clientWidth, window.innerWidth)
                const vh = Math.max(document.documentElement.clientHeight, window.innerHeight)

                const maxImageSize = Math.min(vw, vh) * 0.4;
                const smallestImageAxis = Math.min(img.naturalHeight, img.naturalWidth);
                
                const aspectRatio = img.naturalWidth / img.naturalHeight
                if (smallestImageAxis > maxImageSize) {
                    if (img.naturalWidth > img.naturalHeight) {
                        img.style.height = `${maxImageSize / aspectRatio}px`
                        img.style.width = `${maxImageSize}px`
                    } else {
                        img.style.height = `${maxImageSize}px`
                        img.style.width = `${maxImageSize * aspectRatio}px`
                    }

                    effect(() => {
                        if (sizingFinished.value) {
                            img!.style.setProperty("height", null)
                            img!.style.setProperty("width", null)
                        }
                    })
                }
            }
        }, 50)

        return () => {
            clearInterval(id)
            imgRef.current = null
        }
    }}/>
})

namespace Image {
    export type Props = {
        source: Signal<Address>,
        title: Signal<string | undefined>,
        contentReady: Signal<boolean>,
        sizingFinished: Signal<boolean>
    }
}