118 lines
3.4 KiB
TypeScript
118 lines
3.4 KiB
TypeScript
import React from 'react';
|
|
import { DownloadIcon } from '../components/icons';
|
|
import { AUDIO_EXTENSIONS, VIDEO_EXTENSIONS } from '../constants/preview';
|
|
|
|
interface MediaViewerProps {
|
|
src: string;
|
|
mimeType?: string;
|
|
filename?: string;
|
|
alt?: string;
|
|
className?: string;
|
|
style?: React.CSSProperties;
|
|
onLoad?: (event: React.SyntheticEvent<HTMLElement>) => void;
|
|
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
|
mediaRef?: React.Ref<any>;
|
|
draggable?: boolean;
|
|
}
|
|
|
|
const getFileExtension = (filename?: string | null) => {
|
|
if (!filename) {
|
|
return '';
|
|
}
|
|
const match = filename.toLowerCase().match(/\.([a-z0-9]+)$/);
|
|
return match ? match[1] : '';
|
|
};
|
|
|
|
const MediaViewer: React.FC<MediaViewerProps> = ({
|
|
src,
|
|
mimeType = '',
|
|
filename = '',
|
|
alt = 'Media preview',
|
|
className,
|
|
style,
|
|
onLoad,
|
|
onClick,
|
|
mediaRef,
|
|
draggable = false,
|
|
}) => {
|
|
const normalizedMimeType = mimeType.toLowerCase();
|
|
const fileExtension = getFileExtension(filename);
|
|
|
|
const isImage = normalizedMimeType.startsWith('image/');
|
|
const isAudio = normalizedMimeType.startsWith('audio/') || AUDIO_EXTENSIONS.has(fileExtension);
|
|
const isVideo = normalizedMimeType.startsWith('video/') || VIDEO_EXTENSIONS.has(fileExtension);
|
|
|
|
const viewerClasses = ['document-viewer__object', className].filter(Boolean).join(' ');
|
|
|
|
if (isImage) {
|
|
return (
|
|
<img
|
|
ref={mediaRef}
|
|
src={src}
|
|
alt={alt}
|
|
className={`${viewerClasses} document-viewer__object--image`}
|
|
style={style}
|
|
onLoad={onLoad}
|
|
onClick={onClick}
|
|
draggable={draggable}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (isAudio) {
|
|
return (
|
|
<audio
|
|
ref={mediaRef}
|
|
className={`${viewerClasses} document-viewer__object--audio`}
|
|
controls
|
|
preload="metadata"
|
|
src={src}
|
|
aria-label={`Audio preview of ${alt}`}
|
|
style={style}
|
|
onLoadedMetadata={onLoad}
|
|
onClick={onClick}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (isVideo) {
|
|
return (
|
|
<video
|
|
ref={mediaRef}
|
|
className={`${viewerClasses} document-viewer__object--video`}
|
|
controls
|
|
preload="metadata"
|
|
src={src}
|
|
aria-label={`Video preview of ${alt}`}
|
|
style={style}
|
|
onLoadedMetadata={onLoad}
|
|
onClick={onClick}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const displayMimeType = mimeType || 'this file type';
|
|
const displayFilename = filename || 'download';
|
|
|
|
return (
|
|
<div className="document-viewer__unsupported" style={style}>
|
|
<div className="document-viewer__unsupported-message">
|
|
Preview is not available for {displayMimeType} files.
|
|
</div>
|
|
<div className="document-viewer__unsupported-filename">{displayFilename}</div>
|
|
<a
|
|
className="button-link document-viewer__unsupported-download"
|
|
href={src}
|
|
download={displayFilename}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
<DownloadIcon />
|
|
<span>Download</span>
|
|
</a>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MediaViewer;
|