mirror of
https://github.com/standardnotes/app.git
synced 2026-01-16 23:01:30 +00:00
128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
import { WebApplication } from '@/Application/WebApplication'
|
|
import { getBase64FromBlob } from '@/Utils'
|
|
import { FileItem, classNames } from '@standardnotes/snjs'
|
|
import { FunctionComponent, useCallback, useEffect, useMemo, useRef } from 'react'
|
|
import Button from '../Button/Button'
|
|
import { createObjectURLWithRef } from './CreateObjectURLWithRef'
|
|
import ImagePreview from './ImagePreview'
|
|
import { OptionalSuperEmbeddedImageProps } from './OptionalSuperEmbeddedImageProps'
|
|
import { PreviewableTextFileTypes, RequiresNativeFilePreview } from './isFilePreviewable'
|
|
import TextPreview from './TextPreview'
|
|
import { parseFileName, sanitizeFileName } from '@standardnotes/utils'
|
|
import VideoPreview from './VideoPreview'
|
|
|
|
type Props = {
|
|
application: WebApplication
|
|
file: FileItem
|
|
bytes: Uint8Array
|
|
isEmbeddedInSuper: boolean
|
|
} & OptionalSuperEmbeddedImageProps
|
|
|
|
const PreviewComponent: FunctionComponent<Props> = ({
|
|
application,
|
|
file,
|
|
bytes,
|
|
isEmbeddedInSuper,
|
|
imageZoomLevel,
|
|
setImageZoomLevel,
|
|
alignment,
|
|
changeAlignment,
|
|
}) => {
|
|
const objectUrlRef = useRef<string>()
|
|
|
|
const objectUrl = useMemo(() => {
|
|
return createObjectURLWithRef(file.mimeType, bytes, objectUrlRef)
|
|
}, [bytes, file.mimeType])
|
|
|
|
useEffect(() => {
|
|
const objectUrl = objectUrlRef.current
|
|
|
|
return () => {
|
|
if (objectUrl) {
|
|
URL.revokeObjectURL(objectUrl)
|
|
objectUrlRef.current = ''
|
|
}
|
|
}
|
|
}, [])
|
|
|
|
const isNativeMobileWeb = application.isNativeMobileWeb()
|
|
const requiresNativePreview = RequiresNativeFilePreview.includes(file.mimeType)
|
|
|
|
const openNativeFilePreview = useCallback(async () => {
|
|
if (!isNativeMobileWeb) {
|
|
throw new Error('Native file preview cannot be used on non-native platform')
|
|
}
|
|
|
|
const fileBase64 = await getBase64FromBlob(
|
|
new Blob([bytes], {
|
|
type: file.mimeType,
|
|
}),
|
|
)
|
|
|
|
const { name, ext } = parseFileName(file.name)
|
|
const sanitizedName = sanitizeFileName(name)
|
|
const filename = `${sanitizedName}.${ext}`
|
|
|
|
void application.mobileDevice.previewFile(fileBase64, filename)
|
|
}, [application, bytes, file.mimeType, file.name, isNativeMobileWeb])
|
|
|
|
if (isNativeMobileWeb && requiresNativePreview) {
|
|
return (
|
|
<div className="flex flex-grow flex-col items-center justify-center">
|
|
<div className="max-w-[30ch] text-center text-base font-bold">
|
|
This file can only be previewed in an external app
|
|
</div>
|
|
<Button className="mt-3" primary onClick={openNativeFilePreview}>
|
|
Open file preview
|
|
</Button>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (file.mimeType.startsWith('image/')) {
|
|
return (
|
|
<ImagePreview
|
|
objectUrl={objectUrl}
|
|
isEmbeddedInSuper={isEmbeddedInSuper}
|
|
imageZoomLevel={imageZoomLevel}
|
|
setImageZoomLevel={setImageZoomLevel}
|
|
alignment={alignment}
|
|
changeAlignment={changeAlignment}
|
|
/>
|
|
)
|
|
}
|
|
|
|
if (file.mimeType.startsWith('video/')) {
|
|
return (
|
|
<VideoPreview
|
|
file={file}
|
|
filesController={application.filesController}
|
|
objectUrl={objectUrl}
|
|
isEmbeddedInSuper={isEmbeddedInSuper}
|
|
/>
|
|
)
|
|
}
|
|
|
|
if (file.mimeType.startsWith('audio/')) {
|
|
return (
|
|
<div className="flex h-full w-full items-center justify-center">
|
|
<audio src={objectUrl} controls />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (PreviewableTextFileTypes.includes(file.mimeType)) {
|
|
return <TextPreview bytes={bytes} />
|
|
}
|
|
|
|
const isPDF = file.mimeType === 'application/pdf'
|
|
|
|
return (
|
|
<object
|
|
className={classNames('h-full w-full', isPDF && 'min-h-[65vh]')}
|
|
data={isPDF ? objectUrl + '#view=FitV' : objectUrl}
|
|
/>
|
|
)
|
|
}
|
|
|
|
export default PreviewComponent
|