separate components for different media types
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Martti Malmi 2023-12-13 12:12:10 +02:00
parent 1fe6a2a50d
commit e408389cdb

View File

@ -1,7 +1,7 @@
import { ProxyImg } from "@/Element/ProxyImg";
import useImgProxy from "@/Hooks/useImgProxy";
import { IMeta } from "@snort/system";
import React, { CSSProperties, useEffect, useMemo, useRef } from "react";
import React, { CSSProperties, useEffect, useMemo, useRef, useState } from "react";
import classNames from "classnames";
import { useInView } from "react-intersection-observer";
@ -12,15 +12,59 @@ interface MediaElementProps {
onMediaClick?: (e: React.MouseEvent<HTMLImageElement>) => void;
}
export function MediaElement(props: MediaElementProps) {
const { proxy } = useImgProxy();
interface AudioElementProps {
url: string;
}
interface VideoElementProps {
url: string;
meta?: IMeta;
}
interface ImageElementProps {
url: string;
meta?: IMeta;
onMediaClick?: (e: React.MouseEvent<HTMLImageElement>) => void;
}
const AudioElement = ({ url }: AudioElementProps) => {
return <audio key={url} src={url} controls />;
};
const ImageElement = ({ url, meta, onMediaClick }: ImageElementProps) => {
const imageRef = useRef<HTMLImageElement | null>(null);
const { ref: videoContainerRef, inView } = useInView({ threshold: 1 });
const style = useMemo(() => {
const style = {} as CSSProperties;
if (meta?.height && meta.width && imageRef.current) {
const scale = imageRef.current.offsetWidth / meta.width;
style.height = `${meta.height * scale}px`;
}
return style;
}, [imageRef.current]);
return (
<div className={classNames("flex justify-center items-center -mx-4 md:mx-0 my-2", { "md:h-80": !meta })}>
<ProxyImg
key={url}
src={url}
onClick={onMediaClick}
className={classNames("max-h-[80vh]", { "md:max-h-80": !meta })}
style={style}
ref={imageRef}
/>
</div>
);
};
const VideoElement = ({ url }: VideoElementProps) => {
const { proxy } = useImgProxy();
const videoRef = useRef<HTMLVideoElement | null>(null);
const autoplay = window.innerWidth >= 768;
const { ref: videoContainerRef, inView } = useInView({ threshold: 1 });
const isMobile = window.innerWidth < 768;
const [isHovering, setIsHovering] = useState(false);
useEffect(() => {
if (!autoplay || !videoRef.current) {
if (isMobile || !videoRef.current) {
return;
}
if (inView) {
@ -30,46 +74,32 @@ export function MediaElement(props: MediaElementProps) {
}
}, [inView]);
const style = useMemo(() => {
const style = {} as CSSProperties;
if (props.meta?.height && props.meta.width && imageRef.current) {
const scale = imageRef.current.offsetWidth / props.meta.width;
style.height = `${props.meta.height * scale}px`;
}
return style;
}, [imageRef.current]);
return (
<div
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
ref={videoContainerRef}
className="flex justify-center items-center -mx-4 md:mx-0 md:h-80 my-2">
<video
ref={videoRef}
loop={true}
muted={!isMobile}
src={url}
controls={isMobile || isHovering}
poster={proxy(url)}
className="max-h-[80vh] md:max-h-80"
/>
</div>
);
};
export function MediaElement(props: MediaElementProps) {
if (props.mime.startsWith("image/")) {
return (
<div className={classNames("flex justify-center items-center -mx-4 md:mx-0 my-2", { "md:h-80": !props.meta })}>
<ProxyImg
key={props.url}
src={props.url}
onClick={props.onMediaClick}
className={classNames("max-h-[80vh]", { "md:max-h-80": !props.meta })}
style={style}
ref={imageRef}
/>
</div>
);
return <ImageElement url={props.url} meta={props.meta} onMediaClick={props.onMediaClick} />;
} else if (props.mime.startsWith("audio/")) {
return <audio key={props.url} src={props.url} controls />;
return <AudioElement url={props.url} />;
} else if (props.mime.startsWith("video/")) {
return (
<div ref={videoContainerRef} className="flex justify-center items-center -mx-4 md:mx-0 md:h-80 my-2">
<video
ref={videoRef}
loop={true}
muted={autoplay}
key={props.url}
src={props.url}
controls
poster={proxy(props.url)}
className="max-h-[80vh] md:max-h-80"
style={style}
/>
</div>
);
return <VideoElement url={props.url} />;
} else {
return (
<a