fix(web): lecteur PDF — pages blanches après rendu et base minimale stable

Le canvas PDF restait vide après rendu (blank-detected): la détection d'encre
reposait sur un seuil de blanc trop sensible et un fond de canvas non maîtrisé.
Le rendu passe à un fond sentinel explicite avec classification
rendered-ok/blank-detected et un seuil de pixels visibles.

Le lecteur est par ailleurs ramené à une base minimale stable: layout plein
viewport (app-main-reader), suppression des modes de lecture et des préférences
par livre, helpers de pagination/viewport extraits dans readerLayout.ts. Shell,
lecteurs CBZ/EPUB et styles alignés sur cette base.

Refs #31

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Git Agent
2026-08-24 12:52:49 +02:00
parent 7cc44871d9
commit 50a0b392e1
10 changed files with 662 additions and 714 deletions

View File

@ -6,7 +6,6 @@ import { EpubReader } from "../reader/EpubReader";
import { pageLocator, parseCbrPageLocator, parseCbzPageLocator, parsePdfPageLocator, pdfPagePercent } from "../reader/locators";
import { PdfReader } from "../reader/PdfReader";
import { ReaderShell, type ReaderControls } from "../reader/ReaderShell";
import { useReaderPreferences } from "../reader/useReaderPreferences";
import { useReaderProgress } from "../reader/useReaderProgress";
const idleControls: ReaderControls = {
@ -23,9 +22,7 @@ export function ReaderPage({ bookId }: { bookId: number }) {
const [error, setError] = useState<string>();
const [page, setPage] = useState(1);
const [readerControls, setReaderControls] = useState<ReaderControls>(idleControls);
const [controlsVisible, setControlsVisible] = useState(true);
const { progress, saving, error: progressError, save, queueSave } = useReaderProgress(bookId);
const { preferences, setMode, error: preferencesError } = useReaderPreferences(bookId);
const { progress, error: progressError, save, queueSave } = useReaderProgress(bookId);
async function loadBook() {
setLoading(true);
@ -47,7 +44,6 @@ export function ReaderPage({ bookId }: { bookId: number }) {
useEffect(() => {
setReaderControls(idleControls);
setControlsVisible(true);
}, [bookId]);
useEffect(() => {
@ -80,21 +76,15 @@ export function ReaderPage({ bookId }: { bookId: number }) {
[book?.format, queueSave, save]
);
const readerError = error ?? progressError ?? preferencesError;
const readerError = error ?? progressError;
return (
<ReaderShell
title={book?.title ?? "Ouverture du lecteur"}
status={loading ? "Chargement" : saving ? "Sauvegarde" : "Progression synchronisee"}
backHref={backHref}
progress={progress?.percent ?? 0}
error={readerError}
onRetry={error ? () => void loadBook() : undefined}
mode={preferences.mode}
onModeChange={setMode}
controls={readerControls}
controlsVisible={controlsVisible}
onToggleControls={() => setControlsVisible((visible) => !visible)}
>
{!book ? (
<div className="reader-fallback">
@ -108,7 +98,6 @@ export function ReaderPage({ bookId }: { bookId: number }) {
url={fileUrl}
page={page}
backHref={backHref}
mode={preferences.mode}
onPageCommit={savePdfPage}
onControlsChange={setReaderControls}
/>
@ -116,7 +105,6 @@ export function ReaderPage({ bookId }: { bookId: number }) {
<CbzReader
bookId={book.id}
page={page}
mode={preferences.mode}
onPageCommit={saveComicPage}
onControlsChange={setReaderControls}
/>
@ -125,7 +113,7 @@ export function ReaderPage({ bookId }: { bookId: number }) {
url={fileUrl}
locator={progress?.locator}
backHref={backHref}
mode={preferences.mode}
mode="horizontal"
onLocatorChange={saveEpubLocator}
onControlsChange={setReaderControls}
/>