fix(reader): render pages at a consistent width instead of thin stripes

Reader page sizing was height-driven — `max-height: 90vh` in single mode
and unbounded natural width in continuous mode. A long vertical page hit
the height cap first and, preserving aspect ratio, collapsed into a thin
vertical stripe; narrow and wide scans rendered at different widths.

Switch both modes to width-driven sizing via a capped `--reader-page-width`
reading column (min(100%, 700px)): every page renders at the same width
regardless of intrinsic dimensions, and tall pages extend downward and
scroll instead of shrinking. Top-align the single-mode grid and make the
prev/next chevrons sticky so they stay reachable on a long page.

Add a Playwright spec asserting equal rendered width across differently-
proportioned pages and that a tall page exceeds the viewport height. The
page-context-menu fixture served a 1x1 image that now renders as a 700x700
square taller than the viewport, making Playwright scroll it into view
before right-clicking — a synthetic scroll that trips the menu's by-design
close-on-scroll. Give that fixture a realistic landscape aspect so the page
fits the viewport, matching real user behaviour (no scroll on right-click).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-04 20:44:30 +02:00
parent 38146b4d03
commit cf8971faae
6 changed files with 185 additions and 17 deletions

View File

@@ -209,12 +209,15 @@ async function mockReader(
}
);
const png = Buffer.from(
'89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c4890000000d49444154789c63000100000005000158a3b62a0000000049454e44ae426082',
'hex'
);
// A landscape page image (wide aspect) so that, under the width-driven
// reader sizing, the rendered page is SHORTER than the viewport. A tall
// page would push its centre off-screen, and Playwright's `.click()`
// would scroll it into view first — that synthetic scroll trips the
// context menu's (by-design) close-on-scroll and flakes these tests.
// Real users right-click at the visible cursor with no such scroll.
const image = `<svg xmlns="http://www.w3.org/2000/svg" width="1400" height="400"><rect width="1400" height="400" fill="#888"/></svg>`;
await page.route('**/api/v1/files/**', (route) =>
route.fulfill({ status: 200, contentType: 'image/png', body: png })
route.fulfill({ status: 200, contentType: 'image/svg+xml', body: image })
);
}