feat(12-01): PreviewModal component with react-pdf Document/Page
- 'use client' component accepting ArrayBuffer prop and onClose callback - Configures pdfjs worker independently from PdfViewer module - Imports AnnotationLayer.css and TextLayer.css - Prev/Next page navigation with disabled states - Fixed overlay (rgba black 70%) with white inner container
This commit is contained in:
@@ -0,0 +1,79 @@
|
|||||||
|
'use client';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Document, Page, pdfjs } from 'react-pdf';
|
||||||
|
import 'react-pdf/dist/Page/AnnotationLayer.css';
|
||||||
|
import 'react-pdf/dist/Page/TextLayer.css';
|
||||||
|
|
||||||
|
// Worker setup — configured independently from PdfViewer (separate module)
|
||||||
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||||
|
'pdfjs-dist/build/pdf.worker.min.mjs',
|
||||||
|
import.meta.url,
|
||||||
|
).toString();
|
||||||
|
|
||||||
|
interface PreviewModalProps {
|
||||||
|
pdfBytes: ArrayBuffer;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PreviewModal({ pdfBytes, onClose }: PreviewModalProps) {
|
||||||
|
const [numPages, setNumPages] = useState(0);
|
||||||
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'fixed',
|
||||||
|
inset: 0,
|
||||||
|
background: 'rgba(0,0,0,0.7)',
|
||||||
|
zIndex: 50,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: 'white',
|
||||||
|
maxWidth: '900px',
|
||||||
|
width: '90vw',
|
||||||
|
maxHeight: '90vh',
|
||||||
|
overflowY: 'auto',
|
||||||
|
padding: '16px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Navigation controls */}
|
||||||
|
<div className="flex items-center gap-3 text-sm mb-4">
|
||||||
|
<button
|
||||||
|
onClick={() => setPageNumber(p => Math.max(1, p - 1))}
|
||||||
|
disabled={pageNumber <= 1}
|
||||||
|
className="px-3 py-1 border rounded disabled:opacity-40 hover:bg-gray-100"
|
||||||
|
>
|
||||||
|
Prev
|
||||||
|
</button>
|
||||||
|
<span>{pageNumber} / {numPages || '?'}</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setPageNumber(p => Math.min(numPages, p + 1))}
|
||||||
|
disabled={pageNumber >= numPages}
|
||||||
|
className="px-3 py-1 border rounded disabled:opacity-40 hover:bg-gray-100"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="ml-auto px-3 py-1 border rounded hover:bg-gray-100"
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* PDF renderer */}
|
||||||
|
<Document
|
||||||
|
file={pdfBytes}
|
||||||
|
onLoadSuccess={({ numPages }) => setNumPages(numPages)}
|
||||||
|
>
|
||||||
|
<Page pageNumber={pageNumber} />
|
||||||
|
</Document>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user