mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Add PDF file preview (#15503)
GitOrigin-RevId: d5d84da65d328222556bfa9f5b585f7e47ba14ad
This commit is contained in:
parent
ee4e1f5429
commit
d3e4f59885
3 changed files with 92 additions and 3 deletions
|
@ -0,0 +1,70 @@
|
|||
import { FC, useCallback } from 'react'
|
||||
import useIsMounted from '@/shared/hooks/use-is-mounted'
|
||||
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
||||
import { useIdeContext } from '@/shared/context/ide-context'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
|
||||
const FileViewPdf: FC<{
|
||||
fileId: string
|
||||
onLoad: () => void
|
||||
onError: () => void
|
||||
}> = ({ fileId, onLoad, onError }) => {
|
||||
const mountedRef = useIsMounted()
|
||||
|
||||
const { fileTreeManager } = useIdeContext()
|
||||
const { previewByPath } = useFileTreePathContext()
|
||||
|
||||
const handleContainer = useCallback(
|
||||
async (element: HTMLDivElement | null) => {
|
||||
if (element) {
|
||||
const { PDFJS } = await import(
|
||||
'../../pdf-preview/util/pdf-js-versions'
|
||||
).then(m => m.default as any)
|
||||
|
||||
// bail out if loading PDF.js took too long
|
||||
if (!mountedRef.current) {
|
||||
onError()
|
||||
return
|
||||
}
|
||||
|
||||
const entity = fileTreeManager.findEntityById(fileId)
|
||||
const path = fileTreeManager.getEntityPath(entity)
|
||||
const preview = previewByPath(path)
|
||||
|
||||
if (!preview) {
|
||||
onError()
|
||||
return
|
||||
}
|
||||
|
||||
const pdf = await PDFJS.getDocument(preview.url).promise
|
||||
|
||||
for (let i = 1; i <= pdf.numPages; i++) {
|
||||
const page = await pdf.getPage(i)
|
||||
const viewport = page.getViewport({ scale: 1 })
|
||||
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.classList.add('pdf-page')
|
||||
canvas.width = viewport.width
|
||||
canvas.height = viewport.height
|
||||
element.append(canvas)
|
||||
page.render({
|
||||
canvasContext: canvas.getContext('2d'),
|
||||
viewport,
|
||||
})
|
||||
}
|
||||
|
||||
onLoad()
|
||||
|
||||
return () => {
|
||||
pdf.cleanup().catch(debugConsole.error)
|
||||
pdf.destroy()
|
||||
}
|
||||
}
|
||||
},
|
||||
[fileTreeManager, mountedRef, previewByPath, fileId, onLoad, onError]
|
||||
)
|
||||
|
||||
return <div className="file-view-pdf" ref={handleContainer} />
|
||||
}
|
||||
|
||||
export default FileViewPdf
|
|
@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'
|
|||
|
||||
import FileViewHeader from './file-view-header'
|
||||
import FileViewImage from './file-view-image'
|
||||
import FileViewPdf from './file-view-pdf'
|
||||
import FileViewText from './file-view-text'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
|
||||
|
@ -24,8 +25,8 @@ export default function FileView({ file }) {
|
|||
editableFilenames.includes(file.name.toLowerCase())
|
||||
|
||||
const isImageFile = imageExtensions.includes(extension)
|
||||
|
||||
const isUnpreviewableFile = !isEditableTextFile && !isImageFile
|
||||
const isPdfFile = extension === 'pdf'
|
||||
const isUnpreviewableFile = !isEditableTextFile && !isImageFile && !isPdfFile
|
||||
|
||||
const handleLoad = useCallback(() => {
|
||||
setContentLoading(false)
|
||||
|
@ -52,6 +53,13 @@ export default function FileView({ file }) {
|
|||
{isEditableTextFile && (
|
||||
<FileViewText file={file} onLoad={handleLoad} onError={handleError} />
|
||||
)}
|
||||
{isPdfFile && (
|
||||
<FileViewPdf
|
||||
fileId={file.id}
|
||||
onLoad={handleLoad}
|
||||
onError={handleError}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
background-color: @gray-lightest;
|
||||
text-align: center;
|
||||
overflow: auto;
|
||||
img {
|
||||
img,
|
||||
.file-view-pdf {
|
||||
max-width: 100%;
|
||||
max-height: 90%;
|
||||
display: block;
|
||||
|
@ -14,6 +15,16 @@
|
|||
.box-shadow(0 2px 3px @gray;);
|
||||
background-color: white;
|
||||
}
|
||||
.file-view-pdf {
|
||||
overflow: auto;
|
||||
width: max-content;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.pdf-page:not(:last-of-type) {
|
||||
border-bottom: 1px solid @gray;
|
||||
}
|
||||
}
|
||||
p.no-preview {
|
||||
margin-top: @line-height-computed / 2;
|
||||
font-size: 24px;
|
||||
|
|
Loading…
Reference in a new issue