mirror of
https://github.com/langgenius/dify.git
synced 2026-04-21 03:07:39 +08:00
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: jyong <718720800@qq.com> Co-authored-by: Yansong Zhang <916125788@qq.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: hj24 <mambahj24@gmail.com> Co-authored-by: hj24 <huangjian@dify.ai> Co-authored-by: Joel <iamjoel007@gmail.com> Co-authored-by: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Co-authored-by: CodingOnStar <hanxujiang@dify.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: 非法操作 <hjlarry@163.com> Co-authored-by: Ayush Baluni <73417844+aayushbaluni@users.noreply.github.com> Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com> Co-authored-by: jimcody1995 <jjimcody@gmail.com> Co-authored-by: James <63717587+jamesrayammons@users.noreply.github.com> Co-authored-by: Yunlu Wen <yunlu.wen@dify.ai> Co-authored-by: Stephen Zhou <hi@hyoban.cc> Co-authored-by: Coding On Star <447357187@qq.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jerryzai <jerryzh8710@protonmail.com> Co-authored-by: NVIDIAN <speedy.hpc@hotmail.com> Co-authored-by: ai-hpc <ai-hpc@users.noreply.github.com> Co-authored-by: Asuka Minato <i@asukaminato.eu.org> Co-authored-by: Junghwan <70629228+shaun0927@users.noreply.github.com> Co-authored-by: HeYinKazune <70251095+HeYin-OS@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: yyh <yuanyouhuilyz@gmail.com> Co-authored-by: Jingyi <jingyi.qi@dify.ai> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: sxxtony <166789813+sxxtony@users.noreply.github.com>
109 lines
3.5 KiB
TypeScript
109 lines
3.5 KiB
TypeScript
import type { FC } from 'react'
|
|
import { RiCloseLine, RiZoomInLine, RiZoomOutLine } from '@remixicon/react'
|
|
import { noop } from 'es-toolkit/function'
|
|
import { t } from 'i18next'
|
|
import * as React from 'react'
|
|
import { useState } from 'react'
|
|
import { createPortal } from 'react-dom'
|
|
import { useHotkeys } from 'react-hotkeys-hook'
|
|
import Loading from '@/app/components/base/loading'
|
|
import Tooltip from '@/app/components/base/tooltip'
|
|
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
|
import { PdfHighlighter, PdfLoader } from './pdf-highlighter-adapter'
|
|
|
|
type PdfPreviewProps = {
|
|
url: string
|
|
onCancel: () => void
|
|
}
|
|
|
|
const PdfPreview: FC<PdfPreviewProps> = ({
|
|
url,
|
|
onCancel,
|
|
}) => {
|
|
const media = useBreakpoints()
|
|
const [scale, setScale] = useState(1)
|
|
const [position, setPosition] = useState({ x: 0, y: 0 })
|
|
const isMobile = media === MediaType.mobile
|
|
|
|
const zoomIn = () => {
|
|
setScale(prevScale => Math.min(prevScale * 1.2, 15))
|
|
setPosition({ x: position.x - 50, y: position.y - 50 })
|
|
}
|
|
|
|
const zoomOut = () => {
|
|
setScale((prevScale) => {
|
|
const newScale = Math.max(prevScale / 1.2, 0.5)
|
|
if (newScale === 1)
|
|
setPosition({ x: 0, y: 0 })
|
|
else
|
|
setPosition({ x: position.x + 50, y: position.y + 50 })
|
|
|
|
return newScale
|
|
})
|
|
}
|
|
|
|
useHotkeys('esc', onCancel)
|
|
useHotkeys('up', zoomIn)
|
|
useHotkeys('down', zoomOut)
|
|
|
|
return createPortal(
|
|
<div
|
|
className={`fixed inset-0 z-1000 flex items-center justify-center bg-black/80 ${!isMobile && 'p-8'}`}
|
|
onClick={e => e.stopPropagation()}
|
|
tabIndex={-1}
|
|
>
|
|
<div
|
|
className="h-[95vh] max-h-full w-screen max-w-full overflow-hidden"
|
|
style={{ transform: `scale(${scale})`, transformOrigin: 'center', scrollbarWidth: 'none', msOverflowStyle: 'none' }}
|
|
>
|
|
<PdfLoader
|
|
workerSrc="/pdf.worker.min.mjs"
|
|
url={url}
|
|
beforeLoad={<div className="flex h-64 items-center justify-center"><Loading type="app" /></div>}
|
|
>
|
|
{(pdfDocument) => {
|
|
return (
|
|
<PdfHighlighter
|
|
pdfDocument={pdfDocument}
|
|
enableAreaSelection={event => event.altKey}
|
|
scrollRef={noop}
|
|
onScrollChange={noop}
|
|
onSelectionFinished={() => null}
|
|
highlightTransform={() => { return <div /> }}
|
|
highlights={[]}
|
|
/>
|
|
)
|
|
}}
|
|
</PdfLoader>
|
|
</div>
|
|
<Tooltip popupContent={t('operation.zoomOut', { ns: 'common' })}>
|
|
<div
|
|
className="absolute top-6 right-24 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg"
|
|
onClick={zoomOut}
|
|
>
|
|
<RiZoomOutLine className="h-4 w-4 text-gray-500" />
|
|
</div>
|
|
</Tooltip>
|
|
<Tooltip popupContent={t('operation.zoomIn', { ns: 'common' })}>
|
|
<div
|
|
className="absolute top-6 right-16 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg"
|
|
onClick={zoomIn}
|
|
>
|
|
<RiZoomInLine className="h-4 w-4 text-gray-500" />
|
|
</div>
|
|
</Tooltip>
|
|
<Tooltip popupContent={t('operation.cancel', { ns: 'common' })}>
|
|
<div
|
|
className="absolute top-6 right-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/8 backdrop-blur-[2px]"
|
|
onClick={onCancel}
|
|
>
|
|
<RiCloseLine className="h-4 w-4 text-gray-500" />
|
|
</div>
|
|
</Tooltip>
|
|
</div>,
|
|
document.body,
|
|
)
|
|
}
|
|
|
|
export default PdfPreview
|