From e29428bb0f895d2eb8c7c79313b7b1b52801504f Mon Sep 17 00:00:00 2001 From: Sam Powers <35611153+sam-powers@users.noreply.github.com> Date: Tue, 7 Jul 2026 23:44:45 -0400 Subject: [PATCH 1/2] fix(editor): remove page-break guide lines that crossed through text The editor painted a horizontal line every 912px via a repeating-linear-gradient background on .ProseMirror. Because it's a background image behind the text, the line drew *through* any text sitting at the 912px boundary, which read as a rule slashing through words. Quill is a continuous-scroll editor, not paginated, so the fix is removal, not repair. - Remove the repeating-linear-gradient from .ProseMirror; keep min-height: 912px purely as a layout minimum so an empty document keeps a page-sized surface. - Rename --page-break-gap to --editor-scroll-gap (same 40px value) so no token references the deleted feature. - Update the print-media comment that referenced the guide lines. --- ...-fix-remove-page-break-guide-lines-plan.md | 97 +++++++++++++++++++ src/App.css | 20 ++-- 2 files changed, 103 insertions(+), 14 deletions(-) create mode 100644 docs/plans/2026-07-07-001-fix-remove-page-break-guide-lines-plan.md diff --git a/docs/plans/2026-07-07-001-fix-remove-page-break-guide-lines-plan.md b/docs/plans/2026-07-07-001-fix-remove-page-break-guide-lines-plan.md new file mode 100644 index 0000000..1689cc8 --- /dev/null +++ b/docs/plans/2026-07-07-001-fix-remove-page-break-guide-lines-plan.md @@ -0,0 +1,97 @@ +--- +title: 'fix: Remove page-break guide lines that cross through text' +type: fix +date: 2026-07-07 +depth: lightweight +status: ready +--- + +# fix: Remove page-break guide lines that cross through text + +## Summary + +Quill's editor paints a horizontal guide line every 912px down the page via a CSS `repeating-linear-gradient` on `.ProseMirror`. Because it's a background image behind the text (not between blocks), the line draws **through** any text that happens to sit at the 912px boundary, which looks broken. This plan removes the guide-line rendering entirely. The change is CSS-only in `src/App.css`; there is no ProseMirror node, extension, or Rust code backing the feature. + +## Problem Frame + +The "page break" attempt was implemented as a decorative background gradient rather than as real pagination (which a continuous ProseMirror editor can't do without a layout engine). The gradient has no awareness of text position, so at each 912px interval it strikes a line across whatever line of text is there. Users read it as a horizontal rule slashing through their words. The feature adds no real value — Quill is a continuous-scroll editor, not a paginated one — so the fix is removal, not repair. + +## Requirements + +- **R1.** The editor must never render a horizontal line across or between document text on screen. (Removes the visual defect.) +- **R2.** Editor layout (page card, top/inter-page spacing, min-height feel) must not visibly regress for a normal single- or multi-screen document. +- **R3.** The Export-to-PDF / print path must continue to produce a clean copy — no page-break artifacts, no new regressions. (The print block already sets `background-image: none !important`; removal must keep that path correct.) +- **R4.** No dead CSS or misleadingly-named variables left referencing the removed feature. + +## Key Technical Decisions + +- **Remove the gradient, keep the page surface.** The `.editor-page` card, its border, and the `--page-max-width` / padding system are the document's visual frame and are unrelated to the guide lines — they stay. Only the `repeating-linear-gradient` background and the now-pointless `min-height: 912px` tied to the "one page" metaphor are in question. +- **`min-height: 912px` — reduce, don't necessarily zero.** The 912px min-height gave an empty document a full-page feel. Dropping it entirely would make a blank editor collapse to a few lines. Keep a sensible min-height (retain 912px or a comparable value) purely as a layout minimum, decoupled from any page-break meaning, and update the comment so it no longer claims to mark page boundaries. +- **`--page-break-gap` variable — rename or repurpose, don't blindly delete.** It's consumed by `.editor-scroll-area` `padding` and `gap` (lines 626/629) as ordinary spacing. Deleting the variable would break that spacing. Rename it to a neutral spacing name (e.g. `--editor-scroll-gap`) so nothing references a removed feature, OR leave the value and just update naming/comments. Behavior must be unchanged. +- **Leave `.pending-comment`'s dashed border alone.** The dashed `border-bottom` at ~line 858 belongs to the comment-composer highlight, not page breaks. Out of scope — do not touch. + +## Implementation Units + +### U1. Remove the page-break gradient from `.ProseMirror` + +**Goal:** Delete the `repeating-linear-gradient` background so no horizontal line is ever painted through text (R1). + +**Files:** `src/App.css` + +**Approach:** In the `.ProseMirror` rule (~lines 647–665), remove the `background-image: repeating-linear-gradient(...)` declaration and its `/* Page break lines: dashed rule every 912px */` comment. Re-evaluate `min-height: 912px`: keep it as a plain layout minimum (updating the adjacent comment so it no longer describes "one page per 912px"), since removing it would collapse an empty editor. Do not alter font, color, or line-height declarations in the same rule. + +**Patterns to follow:** Match the surrounding CSS comment style in `src/App.css`. + +**Test scenarios:** Test expectation: none — pure presentational CSS with no behavioral surface. Verification is visual (see U3) and via the existing `format:check`/lint gates. The round-trip and component test suites already cover editor behavior and must stay green. + +**Verification:** Grep confirms no `repeating-linear-gradient` (or any page-break gradient) remains on `.ProseMirror`. In the running app, a document long enough to cross 912px shows no line through or between text. + +--- + +### U2. Retire the `--page-break-gap` naming and stale print comment + +**Goal:** Remove the last references to the deleted feature so no misleadingly-named token or comment survives (R4), with zero behavior change (R2). + +**Files:** `src/App.css` + +**Approach:** Rename `--page-break-gap` (declared ~line 169) to a neutral spacing name such as `--editor-scroll-gap`, updating both consumers in `.editor-scroll-area` (`padding` ~line 626, `gap` ~line 629) to the new name with the **same value** (40px). Update the print-media comment (~line 1895) that says "Drop … the dashed page-break guide lines" to reflect that there are no longer guide lines to drop (the `background-image: none !important` on `.ProseMirror` in the print block may stay as a harmless safety net, or be removed if it's now redundant — keep it if in doubt). + +**Dependencies:** Independent of U1, but land together (same file, same theme). + +**Test scenarios:** Test expectation: none — rename + comment edit with no behavioral change. Verification is that computed spacing is identical (same 40px) and no other rule references the old variable name. + +**Verification:** `grep -rn "page-break-gap\|page-break\|page break" src/` returns no CSS matches (comments included). Editor top/inter-page spacing is visually unchanged from before. + +--- + +### U3. Visual verification in the running app + +**Goal:** Confirm on screen that text is never crossed and layout is intact (R1, R2), and that Export-to-PDF is still clean (R3). + +**Files:** none (verification only) + +**Approach:** Run the app (`npm run tauri dev`, or `npm run dev` for a browser-only visual check), open/create a document long enough to span past 912px, and confirm: no horizontal line through or between text; the page card, spacing, and empty-doc min-height look right; toggling suggesting mode and comments still renders normally. Trigger Export to PDF (Cmd/Ctrl+P) and confirm the output has no page-break artifacts. + +**Test scenarios:** Manual visual check per the above — this is the acceptance gate for a presentational change (`/verify`-style end-to-end observation, not a unit test). + +**Verification:** Screenshot or direct observation shows clean text with the guide lines gone and no layout/PDF regression. + +--- + +## Scope Boundaries + +**In scope:** Removing the CSS guide-line gradient and cleaning up its naming/comments in `src/App.css`. + +**Out of scope / non-goals:** + +- The `.pending-comment` dashed border (~line 858) — belongs to the comment composer, unrelated. +- The `.editor-page` card, border, radius, and `--page-max-width`/padding system — that's the document frame, staying. +- Real pagination / page-numbering — Quill is a continuous-scroll editor; not attempting it. + +## Verification Strategy + +CI gates (`typecheck`, `eslint`, `prettier --check`, `vitest`, and the Rust suite) must stay green — none should be affected by a CSS-only change, but running them confirms nothing regressed. The decisive check is visual (U3): the guide lines are gone, text is uncrossed, and the PDF export is clean. + +## Compounding Note + +After the fix lands, capture a short learning (via `ce-compound` / `docs/solutions/`) recording **why the page-break attempt failed**: a `repeating-linear-gradient` background on a continuous ProseMirror editor paints lines by pixel offset with no awareness of text position, so any "page break every N px" approach will strike through text at the boundary. The general lesson — _don't fake pagination with a fixed-interval background on a reflowing text surface_ — is the reusable takeaway. diff --git a/src/App.css b/src/App.css index cea4d78..06dc582 100644 --- a/src/App.css +++ b/src/App.css @@ -166,7 +166,7 @@ --page-max-width: 816px; --page-padding-x: 96px; --page-padding-y: 72px; - --page-break-gap: 40px; + --editor-scroll-gap: 40px; font-family: var(--font-sans); font-size: var(--text-ui); @@ -623,10 +623,10 @@ body, display: flex; flex-direction: column; align-items: center; - padding: var(--page-break-gap) var(--space-xl); + padding: var(--editor-scroll-gap) var(--space-xl); padding-right: calc(var(--comment-panel-width) + var(--space-xl)); background: var(--color-bg); - gap: var(--page-break-gap); + gap: var(--editor-scroll-gap); } /* ── Page surface ───────────────────────────────────────────────── */ @@ -646,16 +646,8 @@ body, .ProseMirror { outline: none; - /* 8.5×11 at 96dpi = 1056px total; minus 2×72px padding = 912px content per page */ + /* Layout minimum so an empty document keeps a comfortable page-sized surface */ min-height: 912px; - /* Page break lines: dashed rule every 912px */ - background-image: repeating-linear-gradient( - to bottom, - transparent, - transparent calc(912px - 1px), - var(--color-border-light) calc(912px - 1px), - var(--color-border-light) 912px - ); font-family: var(--font-sans); font-size: var(--text-body); font-weight: 400; @@ -1892,8 +1884,8 @@ del.track-delete { align-items: stretch !important; } - /* Drop the screen zoom and the dashed page-break guide lines; the page is - the paper now. Full-width, no page card border or rounded corners. */ + /* Drop the screen zoom; the page is the paper now. + Full-width, no page card border or rounded corners. */ .editor-page-zoom-wrapper { zoom: 1 !important; } From f18f0f0e6ab0850972734d2c4824cad4d59ecebf Mon Sep 17 00:00:00 2001 From: Sam Powers <35611153+sam-powers@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:25:07 -0400 Subject: [PATCH 2/2] docs(solutions): compound page-break guide-line removal learning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Capture why the page-break guide lines (a repeating-linear-gradient on .ProseMirror) drew through text and had to be removed rather than repaired: a fixed-pixel-interval background on a reflowing text surface has no awareness of line-box positions, so it slices whatever line lands on the 912px boundary. - docs/solutions/ui-bugs/page-break-guide-lines-slash-through-text.md — the bug-track solution doc (problem, symptoms, why removal not repair, the CSS-only fix, prevention). - CONCEPTS.md — new project glossary, seeded with the editor-styling terms this learning grounded (continuous-scroll editor, reflowing text surface, ProseMirror surface, suggesting mode, sidecar). - CLAUDE.md — Knowledge Stores section pointing future agents at docs/solutions/ and CONCEPTS.md. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 7 + CONCEPTS.md | 26 +++ ...ge-break-guide-lines-slash-through-text.md | 158 ++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 CONCEPTS.md create mode 100644 docs/solutions/ui-bugs/page-break-guide-lines-slash-through-text.md diff --git a/CLAUDE.md b/CLAUDE.md index 062e98f..d88eab9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,6 +6,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Quill is a Tauri 2 + React 19 desktop app — a Markdown editor with track-changes and inline comments, similar to Google Docs suggesting mode. The frontend is React/TypeScript built with Vite; the backend is a thin Rust/Tauri layer that exposes file I/O and native dialogs to the frontend. +## Knowledge Stores + +Before starting work in a documented area, and when finishing a fix worth remembering, consult and grow these: + +- **`docs/solutions/`** — compounded learnings from solved problems (bug fixes and knowledge notes), each with YAML frontmatter for searchability. Check here first when debugging something that feels familiar; add an entry (via `/ce-compound`) after a non-trivial fix so the next occurrence is fast. +- **`CONCEPTS.md`** — project glossary of domain terms. Read it to ground in the vocabulary; extend it when a new term surfaces that a new engineer would need defined. + ## Commands ```bash diff --git a/CONCEPTS.md b/CONCEPTS.md new file mode 100644 index 0000000..3df64ff --- /dev/null +++ b/CONCEPTS.md @@ -0,0 +1,26 @@ +# Concepts + +A glossary of project-specific terms. Each entry is a self-contained, one-sentence +definition — enough for a new engineer to ground in the vocabulary without reading +the code. Grows as learnings surface new domain nouns. + +## Editor & styling + +- **Continuous-scroll editor** — Quill's editor is a single, uninterrupted + scrolling text surface rather than a paginated one, so text reflows freely and + there are no fixed page boundaries in the layout. + +- **Reflowing text surface** — an editable region whose line breaks and vertical + positions change whenever font size, zoom, window width, or content changes, so + nothing positioned by fixed pixel offset can be assumed to stay clear of the text. + +- **ProseMirror surface** — the underlying rich-text editing area (`.ProseMirror`) + that Tiptap renders the document into and that carries the editor's text styling. + +- **Suggesting mode** — an editing mode where changes are recorded as tracked + insertions and deletions (like Google Docs suggesting) instead of being applied + directly to the document. + +- **Sidecar** — the companion file saved alongside a document that holds its + comments, suggestions, and linked-session metadata, keeping the Markdown file + itself plain. diff --git a/docs/solutions/ui-bugs/page-break-guide-lines-slash-through-text.md b/docs/solutions/ui-bugs/page-break-guide-lines-slash-through-text.md new file mode 100644 index 0000000..44f7fab --- /dev/null +++ b/docs/solutions/ui-bugs/page-break-guide-lines-slash-through-text.md @@ -0,0 +1,158 @@ +--- +title: 'Page-break guide lines drew through reflowing editor text' +category: ui-bugs +date: 2026-07-07 +module: editor-styling +problem_type: ui_bug +component: frontend_stimulus +severity: low +symptoms: + - 'A faint horizontal rule painted every 912px slashed through any line of text sitting on the boundary' + - 'Words got cut by a horizontal line in the editor' + - 'Any change in font size, zoom, or window width reflowed text onto the 912px boundary, so the rule cut through different text' +root_cause: logic_error +resolution_type: code_fix +tags: + - css + - prosemirror + - editor + - pagination + - background-image + - reflow + - tiptap +--- + +# Page-break guide lines drew through reflowing editor text + +## Problem + +Quill's editor painted a faint horizontal "page break" rule every 912px down the +page using a CSS `repeating-linear-gradient` on `.ProseMirror`. Because the rule +was a full-bleed background image _behind_ the text (not a divider _between_ +blocks), it had no awareness of where lines of text fell — so it drew straight +through any line that happened to sit on a 912px boundary. The fix was to remove +the feature entirely: Quill is a continuous-scroll editor, not a paginated one, +so the cue added no value. + +## Symptoms + +- A faint horizontal line appeared roughly every 912px down the editor. +- Where a line of text landed on that boundary, the rule cut straight through + the words — the text looked struck out or broken. +- The defect moved: any change in font size, zoom, or window width reflowed the + text, so a _different_ line ended up on the boundary and got sliced instead. + There was no stable "safe" layout. + +## What Didn't Work + +There was no repair path, and that was the key realization. The instinct is to +"nudge" a decorative background line so it lands in the gutter between lines +rather than on a line — but a `repeating-linear-gradient` is positioned by fixed +pixel offset from the top of the element. It has zero knowledge of line-box +positions, and those positions shift with every reflow (font, zoom, width, +content). No offset, interval, or thickness makes a fixed-interval background +consistently miss the text on a surface whose text reflows. Any "page break +every N px" drawn this way will strike through text at some layout. The only +correct move was removal, not repair. _(root cause corroborated by auto memory +[claude])_ + +## Solution + +CSS-only change in `src/App.css`. Three edits, all in the same theme: + +**1. Remove the gradient from `.ProseMirror`.** Delete the `background-image` +declaration and its comment; keep `min-height` as a plain layout minimum +(comment updated so it no longer claims to mark page boundaries). + +```css +/* before */ +.ProseMirror { + /* Page break lines: dashed rule every 912px */ + background-image: repeating-linear-gradient( + to bottom, + transparent, + transparent calc(912px - 1px), + var(--color-border-light) calc(912px - 1px), + var(--color-border-light) 912px + ); + /* 8.5×11 at 96dpi = 1056px total; minus 2×72px padding = 912px content per page */ + min-height: 912px; + /* …font, color, line-height unchanged… */ +} + +/* after */ +.ProseMirror { + /* Layout minimum so an empty document keeps a comfortable page-sized surface */ + min-height: 912px; + /* …font, color, line-height unchanged… */ +} +``` + +**2. Rename the now-misleading spacing variable.** `--page-break-gap` was +consumed by `.editor-scroll-area` as ordinary spacing (padding + gap), unrelated +to the gradient. Renaming keeps the value identical and removes a token that +names a feature that no longer exists. + +```css +/* before */ /* after */ +--page-break-gap: 40px; +--editor-scroll-gap: 40px; +``` + +Both consumers in `.editor-scroll-area` (`padding` and `gap`) update to the new +name with the same `40px` value — zero behavior change. + +**3. Leave the print-block reset as a harmless net.** The print media block +already set `background-image: none !important` on `.ProseMirror`. With the +gradient gone this override now matches nothing; it was kept intentionally as a +cheap defensive net in case a background is ever reintroduced. + +Left untouched (out of scope, unrelated to page breaks): the `.editor-page` +card, `--page-max-width` and the padding system, and `.pending-comment`'s dashed +border (that belongs to the comment composer). + +## Why This Works + +Removing the gradient removes the only thing that ever painted a line across the +text, so the defect cannot recur by that mechanism. The retained `min-height: +912px` is purely a layout floor — it gives an empty document a page-sized +surface and paints nothing — so keeping it does not reintroduce any rule. The +variable rename preserves the exact spacing (`40px`) it always applied; nothing +references the removed feature anymore. + +The root cause is the reusable part: **a fixed-pixel-interval background on a +reflowing text surface has no awareness of where line boxes fall.** As soon as +font size, zoom, or window width shifts the text, some line lands on the +boundary and the rule cuts through it. Faking pagination this way is +fundamentally unsound on a continuous, reflowing surface. _(auto memory +[claude])_ + +## Prevention + +- **Before adding any repeating, tiled, or fixed-offset decorative line to an + editable text surface, ask whether the surface reflows.** If it does, a + fixed-interval background is unsafe — it will eventually intersect a line of + text. This applies to `repeating-linear-gradient`, tiled background images, + and any absolutely-positioned rule placed by pixel math rather than by + document structure. +- **Don't fake pagination on a continuous editor.** Quill is continuous-scroll, + not paginated. If real pagination is ever wanted, it needs a layout approach — + page-shaped containers with margins and shadows between breaks (which _do_ + track content flow) — not a full-bleed repeating background painted behind the + text. +- **Watch for orphaned tokens and dead resets when removing a feature.** A + removed CSS feature tends to leave behind a misleadingly-named variable + (`--page-break-gap`) still doing real work elsewhere, and a now-inert + `!important` reset. Rename the former to something neutral (don't delete it if + it's load-bearing) and either drop the latter or keep it as a documented net — + but never leave a token whose name lies about what it does. +- **This is a presentational change with no automated visual-regression suite.** + Verification is visual: open a document long enough to cross 912px and confirm + no line runs through or between text, then confirm Export-to-PDF is clean. Keep + that manual check in mind for any future editor-background work. + +## Related Issues + +- **PR #69** — `fix/remove-page-break-guide-lines`; the removal that resolved + this. No prior `docs/solutions/` entries and no related GitHub issues existed + at capture time — this is the first solution doc in the store.