WIP: MediaQuickview: rewritten full-screen media viewer #50

Draft
Rubicon wants to merge 4 commits from MediaQuickview into master
2 changed files with 61 additions and 7 deletions
Showing only changes of commit a720f5d9c4 - Show all commits

View file

@ -47,8 +47,6 @@
max-width: 100vw;
max-height: 100vh;
contain: strict;
display: grid;
place-items: center;
cursor: grab;

View file

@ -56,19 +56,39 @@ export function createMediaQuickview() {
return createCallback(renderIsolateMediaQuickview);
}
type VisualMediaMeta = {
width: number;
height: number;
};
function ImagePage(props: {
src: string;
alt?: string;
scale: number;
offsetX: number;
offsetY: number;
onMetadata?(metadata: VisualMediaMeta): void;
}) {
const [loaded, setLoaded] = createSignal(false);
return (
<img
onLoad={({ currentTarget }) => {
const { naturalHeight, naturalWidth } = currentTarget;
props.onMetadata?.({
width: naturalWidth,
height: naturalHeight,
});
setLoaded(true);
}}
src={props.src}
alt={props.alt}
style={{
transform: `scale(${props.scale}) translateX(${-props.offsetX}px) translateY(${-props.offsetY}px)`,
opacity: loaded() ? 1 : 0,
}}
></img>
);
@ -88,10 +108,6 @@ export type MediaQuickviewProps = {
onClose?(): void;
};
function clamp<T extends number>(value: T, min: T, max: T) {
return Math.max(Math.min(value, max), min);
}
const MediaQuickview: Component<MediaQuickviewProps> = (props) => {
let root: HTMLDialogElement;
@ -126,6 +142,11 @@ const MediaQuickview: Component<MediaQuickviewProps> = (props) => {
* positive = the top edge move towards top
*/
offsetY: number;
size?: {
width: number;
height: number;
};
}[],
);
@ -185,7 +206,7 @@ const MediaQuickview: Component<MediaQuickviewProps> = (props) => {
return;
}
const dx = movOriginX - event.clientX;
const dy = movOriginY - event.clientY ;
const dy = movOriginY - event.clientY;
setTransformations(index, ({ offsetX, offsetY }) => {
return {
@ -202,6 +223,40 @@ const MediaQuickview: Component<MediaQuickviewProps> = (props) => {
setIsMoving(false);
};
const recenter = (index: number) => {
const sz = transformations[index].size;
if (!sz) return;
const { width, height } = sz;
const xscale = Math.min(window.innerWidth / width, 1);
const yscale = Math.min(window.innerHeight / height, 1);
const finalScale = Math.min(xscale, yscale);
const nheight = height * finalScale;
const top = (window.innerHeight - nheight) / 2;
const nwidth = width * finalScale;
const left = (window.innerWidth - nwidth) / 2;
setTransformations(index, {
scale: finalScale,
offsetX: -left,
offsetY: -top,
});
};
const onMetadata = (index: number, { width, height }: VisualMediaMeta) => {
setTransformations(index, {
size: {
width,
height,
},
});
recenter(index);
};
return (
<dialog
ref={(e) => {
@ -254,6 +309,7 @@ const MediaQuickview: Component<MediaQuickviewProps> = (props) => {
<Switch>
<Match when={item().cat === "image"}>
<ImagePage
onMetadata={(m) => onMetadata(index, m)}
src={item().src}
alt={item().alt}
scale={transformationGetOrSetDefault(index).scale}