| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  | import type { FC } from 'react' | 
					
						
							|  |  |  | import { createPortal } from 'react-dom' | 
					
						
							|  |  |  | import 'react-pdf-highlighter/dist/style.css' | 
					
						
							|  |  |  | import { PdfHighlighter, PdfLoader } from 'react-pdf-highlighter' | 
					
						
							|  |  |  | import { t } from 'i18next' | 
					
						
							|  |  |  | import { RiCloseLine, RiZoomInLine, RiZoomOutLine } from '@remixicon/react' | 
					
						
							|  |  |  | import React, { useState } from 'react' | 
					
						
							|  |  |  | import { useHotkeys } from 'react-hotkeys-hook' | 
					
						
							|  |  |  | import Loading from '@/app/components/base/loading' | 
					
						
							|  |  |  | import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' | 
					
						
							|  |  |  | import Tooltip from '@/app/components/base/tooltip' | 
					
						
							| 
									
										
										
										
											2025-04-06 17:56:08 +08:00
										 |  |  | import { noop } from 'lodash-es' | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |       className={`fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 ${!isMobile && 'p-8'}`} | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |       onClick={e => e.stopPropagation()} | 
					
						
							|  |  |  |       tabIndex={-1} | 
					
						
							|  |  |  |     > | 
					
						
							|  |  |  |       <div | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |         className='h-[95vh] max-h-full w-[100vw] max-w-full overflow-hidden' | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |         style={{ transform: `scale(${scale})`, transformOrigin: 'center', scrollbarWidth: 'none', msOverflowStyle: 'none' }} | 
					
						
							|  |  |  |       > | 
					
						
							|  |  |  |         <PdfLoader | 
					
						
							| 
									
										
										
										
											2024-12-13 11:01:53 +08:00
										 |  |  |           workerSrc='/pdf.worker.min.mjs' | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |           url={url} | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |           beforeLoad={<div className='flex h-64 items-center justify-center'><Loading type='app' /></div>} | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |         > | 
					
						
							|  |  |  |           {(pdfDocument) => { | 
					
						
							|  |  |  |             return ( | 
					
						
							|  |  |  |               <PdfHighlighter | 
					
						
							|  |  |  |                 pdfDocument={pdfDocument} | 
					
						
							|  |  |  |                 enableAreaSelection={event => event.altKey} | 
					
						
							| 
									
										
										
										
											2025-04-06 17:56:08 +08:00
										 |  |  |                 scrollRef={noop} | 
					
						
							|  |  |  |                 onScrollChange={noop} | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |                 onSelectionFinished={() => null} | 
					
						
							|  |  |  |                 highlightTransform={() => { return <div/> }} | 
					
						
							|  |  |  |                 highlights={[]} | 
					
						
							|  |  |  |               /> | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |           }} | 
					
						
							|  |  |  |         </PdfLoader> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |       <Tooltip popupContent={t('common.operation.zoomOut')}> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |         <div className='absolute right-24 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg' | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |           onClick={zoomOut}> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |           <RiZoomOutLine className='h-4 w-4 text-gray-500'/> | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |         </div> | 
					
						
							|  |  |  |       </Tooltip> | 
					
						
							|  |  |  |       <Tooltip popupContent={t('common.operation.zoomIn')}> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |         <div className='absolute right-16 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg' | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |           onClick={zoomIn}> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |           <RiZoomInLine className='h-4 w-4 text-gray-500'/> | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |         </div> | 
					
						
							|  |  |  |       </Tooltip> | 
					
						
							|  |  |  |       <Tooltip popupContent={t('common.operation.cancel')}> | 
					
						
							|  |  |  |         <div | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |           className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/8 backdrop-blur-[2px]' | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |           onClick={onCancel}> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |           <RiCloseLine className='h-4 w-4 text-gray-500'/> | 
					
						
							| 
									
										
										
										
											2024-12-10 10:53:37 +08:00
										 |  |  |         </div> | 
					
						
							|  |  |  |       </Tooltip> | 
					
						
							|  |  |  |     </div>, | 
					
						
							|  |  |  |     document.body, | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default PdfPreview |