Files
dify/web/app/components/workflow/skill/viewer/read-only-file-preview.tsx
yyh 94c354e36d feat(web): add inline PDF preview support for skill file viewer
Enable PDF files to be previewed directly in the file content panel
instead of showing as unsupported files requiring download. Uses the
existing react-pdf-highlighter library with zoom controls and keyboard
shortcuts (up/down arrows).
2026-02-05 17:21:01 +08:00

99 lines
2.5 KiB
TypeScript

'use client'
import dynamic from 'next/dynamic'
import * as React from 'react'
import Loading from '@/app/components/base/loading'
import { useFetchTextContent } from '../hooks/use-fetch-text-content'
import { useFileTypeInfo } from '../hooks/use-file-type-info'
import { getFileLanguage } from '../utils/file-utils'
import MediaFilePreview from './media-file-preview'
import UnsupportedFileDownload from './unsupported-file-download'
const ReadOnlyCodePreview = dynamic(
() => import('./read-only-code-preview'),
{ ssr: false, loading: () => <Loading type="area" /> },
)
const ReadOnlyMarkdownPreview = dynamic(
() => import('./read-only-markdown-preview'),
{ ssr: false, loading: () => <Loading type="area" /> },
)
const SQLiteFilePreview = dynamic(
() => import('./sqlite-file-preview'),
{ ssr: false, loading: () => <Loading type="area" /> },
)
const PdfFilePreview = dynamic(
() => import('./pdf-file-preview'),
{ ssr: false, loading: () => <Loading type="area" /> },
)
type ReadOnlyFilePreviewProps = {
downloadUrl: string
fileName: string
extension?: string | null
fileSize?: number | null
}
const ReadOnlyFilePreview = ({
downloadUrl,
fileName,
extension,
fileSize,
}: ReadOnlyFilePreviewProps) => {
const fileNode = React.useMemo(
() => ({ name: fileName, extension }),
[fileName, extension],
)
const { isMarkdown, isCodeOrText, isImage, isVideo, isPdf, isSQLite, isPreviewable } = useFileTypeInfo(fileNode)
const isTextFile = isPreviewable && (isMarkdown || isCodeOrText)
const { data: textContent, isLoading: isTextLoading } = useFetchTextContent(
isTextFile ? downloadUrl : undefined,
)
if (!isPreviewable) {
return (
<UnsupportedFileDownload
name={fileName}
size={fileSize ?? undefined}
downloadUrl={downloadUrl}
/>
)
}
if (isTextFile && isTextLoading)
return <Loading type="area" />
if (isMarkdown)
return <ReadOnlyMarkdownPreview value={textContent ?? ''} />
if (isCodeOrText) {
return (
<ReadOnlyCodePreview
value={textContent ?? ''}
language={getFileLanguage(fileName)}
/>
)
}
if (isImage || isVideo)
return <MediaFilePreview type={isImage ? 'image' : 'video'} src={downloadUrl} />
if (isSQLite)
return <SQLiteFilePreview downloadUrl={downloadUrl} />
if (isPdf)
return <PdfFilePreview downloadUrl={downloadUrl} />
return (
<UnsupportedFileDownload
name={fileName}
size={fileSize ?? undefined}
downloadUrl={downloadUrl}
/>
)
}
export default React.memo(ReadOnlyFilePreview)