chore: initial commit — monorepo ReadaBook (API NestJS, web PWA, Docker)
This commit is contained in:
56
apps/web/src/reader/PdfReader.tsx
Normal file
56
apps/web/src/reader/PdfReader.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import * as pdfjs from "pdfjs-dist";
|
||||
import workerUrl from "pdfjs-dist/build/pdf.worker.mjs?url";
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = workerUrl;
|
||||
|
||||
export function PdfReader({ url, page, onPageChange }: { url: string; page: number; onPageChange: (page: number, pages: number) => void }) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const [pages, setPages] = useState(1);
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
async function render() {
|
||||
try {
|
||||
const loadingTask = pdfjs.getDocument({ url, withCredentials: true });
|
||||
const document = await loadingTask.promise;
|
||||
if (cancelled) return;
|
||||
setPages(document.numPages);
|
||||
const pdfPage = await document.getPage(Math.max(1, Math.min(page, document.numPages)));
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const viewport = pdfPage.getViewport({ scale: Math.min(1.6, window.devicePixelRatio || 1) });
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
const context = canvas.getContext("2d");
|
||||
if (!context) return;
|
||||
await pdfPage.render({ canvas, canvasContext: context, viewport }).promise;
|
||||
onPageChange(Math.max(1, Math.min(page, document.numPages)), document.numPages);
|
||||
} catch (renderError) {
|
||||
setError(renderError instanceof Error ? renderError.message : "PDF indisponible");
|
||||
}
|
||||
}
|
||||
render();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [url, page, onPageChange]);
|
||||
|
||||
return (
|
||||
<div className="pdf-reader">
|
||||
{error ? <div className="reader-fallback">{error}</div> : <canvas ref={canvasRef} />}
|
||||
<div className="reader-stepper">
|
||||
<button className="ghost-button" onClick={() => onPageChange(Math.max(1, page - 1), pages)}>
|
||||
Precedent
|
||||
</button>
|
||||
<span>
|
||||
{page} / {pages}
|
||||
</span>
|
||||
<button className="ghost-button" onClick={() => onPageChange(Math.min(pages, page + 1), pages)}>
|
||||
Suivant
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user