75 lines
2.2 KiB
TypeScript
75 lines
2.2 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import LoadingWheel from '../LoadingWheel.tsx';
|
|
import FileBox from './FileBox.tsx';
|
|
|
|
const loadedMedia = new Set();
|
|
|
|
const AttachmentPreview = ({ url }: { url: string }) => {
|
|
const isImage = url.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/i);
|
|
const isVideo = url.match(/\.(mp4|webm|ogg|mov)$/i);
|
|
const [isLoading, setIsLoading] = useState(!loadedMedia.has(url));
|
|
useEffect(() => {
|
|
if (isImage && !loadedMedia.has(url)) {
|
|
const img = new Image();
|
|
img.onload = () => {
|
|
loadedMedia.add(url);
|
|
setIsLoading(false);
|
|
};
|
|
img.src = url;
|
|
} else if (isVideo && !loadedMedia.has(url)) {
|
|
const video = document.createElement('video');
|
|
video.onloadedmetadata = () => {
|
|
loadedMedia.add(url);
|
|
setIsLoading(false);
|
|
};
|
|
video.src = url;
|
|
}
|
|
// setIsLoading(true);
|
|
}, [url, isImage, isVideo]);
|
|
|
|
if (!isImage && !isVideo) {
|
|
return <FileBox url={url} />;
|
|
}
|
|
|
|
if (isVideo) {
|
|
return (
|
|
<div className="relative w-full">
|
|
{isLoading && (
|
|
<div className="absolute max-h-64 inset-0 flex items-center justify-center bg-gray-800 bg-opacity-50 rounded h-40">
|
|
<LoadingWheel />
|
|
</div>
|
|
)}
|
|
<video
|
|
controls
|
|
className={`w-full max-h-64 rounded transition-opacity duration-200 ${
|
|
isLoading ? 'opacity-0' : 'opacity-100'
|
|
}`}
|
|
onLoadedMetadata={() => setIsLoading(false)}
|
|
>
|
|
<source src={url} type={`video/${url.split('.').pop()}`} />
|
|
Your browser does not support the video tag.
|
|
</video>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="relative inline-block max-w-full">
|
|
{isLoading && (
|
|
<div className="absolute inset-0 flex items-center justify-center bg-gray-800 bg-opacity-50 rounded "></div>
|
|
)}
|
|
<a href={url} target="_blank" rel="noopener noreferrer">
|
|
<img
|
|
src={url}
|
|
alt="attachment"
|
|
className={`min-h-14 max-h-64 max-w-full rounded
|
|
transition-opacity duration-300 ease-in
|
|
${isLoading ? 'opacity-0' : 'opacity-100'}`}
|
|
/>
|
|
</a>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AttachmentPreview;
|