Contribute rewrite Phase 3: tracked-change overlay in MarkdownPreview
Reintroduces the §8.10 inline tracked-change layer Phase 1 dropped when
Tiptap left, this time anchored to the rendered preview rather than a
writable editor. Each accepted change on the branch decorates the
preview DOM with a `<span class="tracked-insert">` at the proposed text
and a `<span class="tracked-delete">` strikethrough for the original;
hover surfaces the same ChangeTooltip DiffView uses (badge + prompt +
quote + reason), now extracted to its own file so both surfaces share
the affordance.
Design calls per the Phase 3 prompt's open list:
• Contribute pane: default-on. The pane exists for editorial review
of your own work; the overlay reinforces that.
• Discuss pane: opt-in via a new "Show tracked changes" toolbar
toggle on non-main branches. Clean prose stays the default.
• DiffView's "Review changes" toolbar is untouched — DiffView dies in
Phase 7 and overloading its toggle now creates surface to unwind.
Pre-fancy stance on the known overlay subtleties:
• Drift — if `proposed` no longer appears verbatim (later manual
edit touched it) we skip the decoration rather than mis-anchor.
• Overlap — decorate in `acted_at` ascending order; later spans win
on whatever text is still un-wrapped.
• Mermaid — text nodes inside `.mermaid-block` are skipped; a tracked
span that intersects diagram source drops silently. Flagged as a
known limitation rather than worked around.
• Code — `<pre>`/`<code>` parents skipped too; matching inside
verbatim code produced noisy false positives in fixtures.
Backend tests: 125 passed. Helper verified via Vite preview sandbox
eval across eight cases (single-paragraph match, distinct-original
strike, no-match skip, mermaid skip, two-change overlap ordering,
declined/pending ignored, whitespace-normalized cross-newline match,
code-block skip), plus computed-style proof for the new
`.markdown-preview .tracked-insert` / `.tracked-delete` rules. The
end-to-end CM6 → accept → overlay flow against a live branch wasn't
exercised (backend not running this session); the simpler unit-level
verification looked clean, but a future session with the backend up
should drive that golden path before Phase 4 piles on top.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -842,29 +842,33 @@ click-to-card binding from §8.8. The margin marker is scannable
|
||||
precise ("what changed here?"). The two answer different questions
|
||||
and both are kept.
|
||||
|
||||
The inline markup is session-local. Each accepted change is already
|
||||
a clean commit on Gitea per §8.6, so the branch's canonical state at
|
||||
any reload is the integrated text without markup. Regenerating
|
||||
markup on load by diffing against earlier commits is technically
|
||||
possible but adds a mechanism — a per-user seen-cursor for accepted
|
||||
changes, an explicit dismiss UI — to solve a problem that DiffView
|
||||
already solves durably and at higher fidelity. The editor is for
|
||||
writing; layering permanent diff overlay on top of writable text
|
||||
degrades the writing surface, so the markup clears on reload and
|
||||
DiffView is the durable artifact for inspecting accepted changes in
|
||||
context.
|
||||
The inline markup lives in the rendered preview surface, not on the
|
||||
writable editor. With the Contribute-mode split (§8.3) the raw markdown
|
||||
source is a CodeMirror buffer that can't host HTML decorations, and
|
||||
even when a writable surface could host them — as Tiptap did in earlier
|
||||
revisions — layering permanent diff overlay on top of writable text
|
||||
degraded the writing surface. The preview pane is the natural home: on
|
||||
the right side of the Contribute split it shows the editor's own work
|
||||
in-context (default-on, since the pane exists for that editorial
|
||||
review), and in Discuss mode the single preview pane gates the overlay
|
||||
behind a toolbar toggle so the default reading experience stays clean
|
||||
prose. The overlay regenerates on every render from the branch's
|
||||
`changes` table — no per-user seen-cursor, no dismiss UI; every
|
||||
accepted change on the branch is included, drift is tolerated by
|
||||
skipping spans whose `proposed` text no longer matches verbatim, and
|
||||
mermaid intersections are skipped as a known limitation. Hovering any
|
||||
marked span surfaces a tooltip with the change's type badge (`ai` or
|
||||
`manual`), the model identifier where applicable, the
|
||||
`was_edited_before_accept` flag where set, the user prompt and
|
||||
selection-quote that drove the change, and the AI's `reason`.
|
||||
|
||||
DiffView is the read-only render surface invoked via a toolbar
|
||||
toggle (§8.15). It reads from the
|
||||
`changes` table for the branch, reconstructs the markup for every
|
||||
accepted change in branch history, and renders the result in-place
|
||||
where the editor was. Hovering any marked span surfaces a tooltip
|
||||
with the change's type badge (`ai` or `manual`), the model
|
||||
identifier where applicable, the `was_edited_before_accept` flag
|
||||
where set, the user prompt and selection-quote that drove the
|
||||
change, and the AI's `reason`. The toggle is reversible; returning
|
||||
to the editor restores the live writing surface and reattaches the
|
||||
session-local baseline.
|
||||
DiffView is the legacy read-only render surface invoked via the
|
||||
Contribute-mode toolbar toggle (§8.15) — a full-editor swap-in that
|
||||
reads the same `changes` table. It is retained as an interim path while
|
||||
the preview-pane overlay matures and is slated for retirement once
|
||||
gutter markers (the §8.10 paragraph-margin layer) land in the preview
|
||||
itself; at that point both visual layers live in the same surface and
|
||||
the toolbar toggle collapses.
|
||||
|
||||
### 8.11 Manual edits and collisions with AI proposals
|
||||
|
||||
|
||||
Reference in New Issue
Block a user