The same page on every screen
The text is laid out on a page of one fixed size and the sheet scaled to the screen, so a phone breaks it exactly where a desktop does — twenty-one lines to the page on both. The type size is computed from the page and the line count rather than chosen. A PDF's full screen is the browser window, not the screen, and its button sits beside the zoom. "Recent Notes" is stamped by every write, not only by a rename. And a PDF that will not open says which of the four reasons it is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9507761bce
commit
4013e959d6
12 files changed
+295
-101
No files matched your search
@@ -261,6 +261,76 @@ try {
|
||||
"and the gap stays blank — no placeholder printed at the foot of the page"
|
||||
);
|
||||
|
||||
/* ── twenty-one lines, and the same twenty-one everywhere ──
|
||||
*
|
||||
* Two claims. First, a page holds the number of lines a ruled page holds —
|
||||
* it held eighteen on a phone, which is what started this. Second, and the
|
||||
* one that matters: the phone breaks the text in exactly the same places the
|
||||
* desktop does. It did not, because the text used to be set in screen pixels:
|
||||
* a 340-pixel sheet fitted nothing like what a 760-pixel one did, so the same
|
||||
* note had different lines on different pages depending on what you read it
|
||||
* on. The text is now laid out on a page of a fixed size and the whole sheet
|
||||
* scaled, so the only thing a narrow screen changes is how big it looks.
|
||||
*
|
||||
* Measured in page units — every length divided by the sheet's own scale —
|
||||
* because screen pixels are precisely what must not agree. */
|
||||
const pageUnits = () =>
|
||||
p.evaluate(() => {
|
||||
const scale = Number(document.querySelector("[data-text-page-scale]").dataset.textPageScale);
|
||||
const pm = document.querySelector(".ProseMirror");
|
||||
const cs = getComputedStyle(pm);
|
||||
const sheet = document.querySelector("[data-page-sheet]").getBoundingClientRect();
|
||||
const top = pm.getBoundingClientRect().top;
|
||||
const blocks = [...pm.children]
|
||||
.filter((el) => !el.classList.contains("ne-page-spacer"))
|
||||
.slice(0, 40)
|
||||
.map((el) => {
|
||||
const r = el.getBoundingClientRect();
|
||||
return { y: Math.round((r.top - top) / scale), h: Math.round(r.height / scale) };
|
||||
});
|
||||
return {
|
||||
lines:
|
||||
(sheet.height / scale - parseFloat(cs.paddingTop) - parseFloat(cs.paddingBottom)) /
|
||||
parseFloat(cs.lineHeight),
|
||||
blocks,
|
||||
};
|
||||
});
|
||||
|
||||
const onDesktop = await pageUnits();
|
||||
check(
|
||||
Math.floor(onDesktop.lines) === 21,
|
||||
"a page holds twenty-one lines",
|
||||
`${onDesktop.lines.toFixed(2)} fit`
|
||||
);
|
||||
|
||||
const phone = { width: 390, height: 844 };
|
||||
const desktop = p.viewportSize();
|
||||
await p.setViewportSize(phone);
|
||||
await p.waitForTimeout(2000);
|
||||
/* A phone shows one pane at a time, so the note may have been left behind in
|
||||
the list when the window narrowed. Open it again before measuring. */
|
||||
if ((await p.locator("[data-text-page-scale]").count()) === 0) await reopenNote(p, "Langer Text");
|
||||
await p.waitForSelector("[data-text-page-scale]", { timeout: 15000 });
|
||||
await p.waitForTimeout(3000);
|
||||
const onPhone = await pageUnits();
|
||||
check(
|
||||
Math.floor(onPhone.lines) === 21,
|
||||
"on a phone as well — the same page, not a smaller one",
|
||||
`${onPhone.lines.toFixed(2)} fit`
|
||||
);
|
||||
const moved = onDesktop.blocks
|
||||
.map((b, i) => ({ i, b, o: onPhone.blocks[i] }))
|
||||
.filter(({ b, o }) => !o || Math.abs(b.y - o.y) > 1 || Math.abs(b.h - o.h) > 1)
|
||||
.map(({ i, b, o }) => `#${i}: ${b.y}/${b.h} vs ${o ? `${o.y}/${o.h}` : "missing"}`);
|
||||
check(
|
||||
onPhone.blocks.length === onDesktop.blocks.length && moved.length === 0,
|
||||
"and every paragraph falls in the same place on both, to the page unit",
|
||||
moved.slice(0, 4).join(" | ")
|
||||
);
|
||||
await p.setViewportSize(desktop);
|
||||
await p.waitForTimeout(2000);
|
||||
if ((await p.locator(".ProseMirror").count()) === 0) await reopenNote(p, "Langer Text");
|
||||
|
||||
/* The note is still one document — pages are drawn, not stored. */
|
||||
const stored = (await api(p, "GET", "/notes")).body[0];
|
||||
const body = (await api(p, "GET", `/notes/${stored.id}`)).body.content;
|
||||
|
||||
+4
-4
@@ -271,10 +271,10 @@ try {
|
||||
await p.waitForTimeout(1500);
|
||||
|
||||
/* ── the document, and nothing else ──
|
||||
* Two things at once: the browser's own full screen, which puts the page past
|
||||
* the window frame, and an overlay over the app, which is what actually
|
||||
* removes the sidebar, the list and the title bar. The second is the half that
|
||||
* can be measured here — and the half a browser can refuse. */
|
||||
* The app laid out as an overlay over itself: the document takes the whole
|
||||
* browser window, and the sidebar, the note list and the title bar go. The
|
||||
* browser's own full screen is deliberately not asked for — this is about
|
||||
* giving the page to the document, not the screen. */
|
||||
const workspaceBox = () =>
|
||||
p.locator("[data-pdf-workspace]").evaluate((el) => {
|
||||
const r = el.getBoundingClientRect();
|
||||
|
||||
Reference in new issue
Block a user