diff --git a/CHANGELOG.md b/CHANGELOG.md index a1192b7..3222737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,20 @@ not from the output of `docker push`. --- +## Unreleased + +**Changed** +- **Narrower margins on the sheet** — the column went from about 73 characters + to about 80, leaving roughly 8% of the paper as margin either side instead of + 117px of empty page down each edge. + +**Fixed** +- **"Start writing..." was printed at the foot of every page with a break after + it.** The placeholder extension styles `[contenteditable]:empty::before`, and + the spacer holding a gap open is exactly that — empty, and not editable. + +--- + ## 2026-08-11 — Writing on paper **Images** — web `sha256:b764a9d8…`, server unchanged at `sha256:0832ee2b…` diff --git a/e2e/editor.mjs b/e2e/editor.mjs index aca1e36..d174b3f 100644 --- a/e2e/editor.mjs +++ b/e2e/editor.mjs @@ -211,6 +211,17 @@ try { (await p.locator(".ne-page-spacer").count()) > 0, "which takes holding the gap open inside the text itself" ); + /* The placeholder extension styles `[contenteditable]:empty::before`, and a + * spacer is exactly that. "Start writing..." was printed at the foot of every + * page that had a break after it. */ + check( + await p.evaluate(() => + [...document.querySelectorAll(".ne-page-spacer")].every( + (el) => getComputedStyle(el, "::before").content === "none" + ) + ), + "and the gap stays blank — no placeholder printed at the foot of the page" + ); /* The note is still one document — pages are drawn, not stored. */ const stored = (await api(p, "GET", "/notes")).body[0]; diff --git a/e2e/probe.mjs b/e2e/probe.mjs deleted file mode 100644 index 8499b4a..0000000 --- a/e2e/probe.mjs +++ /dev/null @@ -1,78 +0,0 @@ -/* Throwaway: four pages, and what that stray placeholder is. */ -import { launch, withFreshUser, createNotebook, createNote, OUT } from "./lib.mjs"; - -const browser = await launch(); -const s = await withFreshUser(browser, "probe"); -const p = s.page; -p.on("pageerror", (e) => console.log("PAGEERROR", String(e))); - -await p.setViewportSize({ width: 1680, height: 950 }); -await createNotebook(p, "Papier"); -await createNote(p); -await p.waitForTimeout(1500); -await p.locator(".ProseMirror").click(); -// Paste rather than type: typing this much loses keystrokes and says nothing -// about the layout, which is what is being looked at here. -await p.evaluate(() => { - const text = Array.from({ length: 160 }, (_, i) => `Absatz ${i + 1}: Dichtungen altern durch Wärme und Zeit.`).join("\n"); - const dt = new DataTransfer(); - dt.setData("text/plain", text); - document.querySelector(".ProseMirror").dispatchEvent( - new ClipboardEvent("paste", { clipboardData: dt, bubbles: true, cancelable: true }) - ); -}); -await p.waitForTimeout(4000); - -console.log( - JSON.stringify( - await p.evaluate(() => { - const pm = document.querySelector(".ProseMirror"); - const pmTop = pm.getBoundingClientRect().top; - const sheets = [...document.querySelectorAll("[data-page-sheet]")]; - const gaps = sheets.slice(0, -1).map((el, i) => ({ - from: el.getBoundingClientRect().bottom - pmTop, - to: sheets[i + 1].getBoundingClientRect().top - pmTop, - })); - const inGap = []; - for (const el of pm.children) { - if (el.classList.contains("ne-page-spacer")) continue; - const r = el.getBoundingClientRect(); - if (r.height === 0) continue; - const top = r.top - pmTop, - bottom = r.bottom - pmTop; - for (const g of gaps) { - if (bottom > g.from + 0.5 && top < g.to - 0.5) inGap.push((el.textContent || "").slice(0, 24)); - } - } - const placeholder = [...pm.querySelectorAll("[data-placeholder]")].map((el) => ({ - text: (el.textContent || "").slice(0, 20), - first: el === pm.firstElementChild, - top: Math.round(el.getBoundingClientRect().top - pmTop), - })); - return { - blocks: [...pm.children].filter((c) => !c.classList.contains("ne-page-spacer")).length, - height: pm.scrollHeight, - sheets: sheets.length, - spacers: [...document.querySelectorAll(".ne-page-spacer")].map((el) => el.offsetHeight), - inGap, - placeholder, - position: document.querySelector("[data-note-position]")?.textContent, - margins: (() => { - const sheet = sheets[0].getBoundingClientRect(); - const col = pm.getBoundingClientRect(); - return { - sheetW: Math.round(sheet.width), - colW: Math.round(col.width), - left: Math.round(col.left - sheet.left), - right: Math.round(sheet.right - col.right), - }; - })(), - }; - }), - null, - 1 - ) -); -await p.screenshot({ path: `${OUT}/probe.png` }); -await s.cleanup(); -await browser.close(); diff --git a/frontend/src/editor/editor.css b/frontend/src/editor/editor.css index c35605c..d790c4b 100644 --- a/frontend/src/editor/editor.css +++ b/frontend/src/editor/editor.css @@ -37,11 +37,15 @@ text used to run the full width of the pane, past 84, which is beyond the point where the eye reliably finds the start of the next line. Capped here rather than on the container so it holds on a page as well as off one. */ - max-width: 527px; - /* Centred. Pinning the column to the left edge put every line in the same - place, but on a wide window it left the whole right half of the pane as one - dead block — which is worse to look at than a column that moves. Centred, - the same leftover space reads as two margins. */ + /* Roughly 80 characters to the line, leaving about 8% of the sheet as margin + on either side — a document's margin, not a picture frame. It was 527px, + which left 117px of empty paper down each edge and made the writing look + lost on the page. Past about 84 characters the eye stops reliably finding + the start of the next line, so this is close to as wide as it should go. */ + max-width: 640px; + /* Centred on the sheet. Pinning the column to the left edge put every line in + the same place, but on a wide window it left the whole right half of the + pane as one dead block. */ margin-left: auto; margin-right: auto; outline: none; @@ -69,6 +73,13 @@ pointer-events: none; user-select: none; } +/* The placeholder extension styles `[contenteditable]:empty::before`, and a + spacer is exactly that: empty, and not editable. So "Start writing..." was + printed at the foot of every page that had a break after it. */ +.note-editor .ProseMirror > .ne-page-spacer::before, +.note-editor .ProseMirror > .ne-page-spacer::after { + content: none !important; +} .note-editor .ProseMirror p { margin: 0; } diff --git a/readme.md b/readme.md index e3e7c15..296967e 100644 --- a/readme.md +++ b/readme.md @@ -373,9 +373,12 @@ state of their own, so they can be read on their own. ## Setting a note -**A centred column, about 73 characters to the line** — measured, not guessed. +**A centred column, about 80 characters to the line** — measured, not guessed. Past roughly 84 the eye stops reliably finding the start of the next line, so the -column is capped well before the pane runs out. +column is capped a little short of that. It leaves roughly 8% of the sheet as +margin down either side: a document's margin, not a picture frame. At 73 +characters it left 117px of empty paper down each edge and the writing looked +lost on the page. It was pinned to the left margin for a while, on the reasoning that a column which floats in the middle moves as the window is resized. True, but it traded