Repository navigation
v1.5.0: review workflow, correctness fixes, Word tracked changes, calmer UI - #5
Merged
Merged
Conversation
The single 7,000-line template is now a page shell plus src/styles.css and ten src/js/*.js files that build.py concatenates in file-name order into the same single inline <script>. The bundle stays one self-contained HTML file. check.mjs audits the JS sources directly and verifies de/en i18n parity by evaluating the dictionary instead of matching indentation with a regex; it also rejects empty translation strings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
- Pass isEvalSupported: false to PDF.js getDocument() (CVE-2024-4367 defense in depth on top of the CSP that already omits unsafe-eval). - Add manifest-src 'self' so default-src 'none' no longer blocks the web app manifest on docdiff.app. - README.md and SECURITY.md now quote the shipped CSP verbatim, and check.mjs fails the build if they drift again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
pages.yml deployed the committed site/ without rebuilding, so a stale bundle could ship. It now builds, runs check.mjs, and fails if the committed bundle differs. check.mjs now matches bracket and bare access to storage APIs (e.g. window['localStorage']), not only the dotted form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…kdown, print view
- Word: replace the HTML-as-.doc export with a genuine .docx generated in the
browser (minimal STORE ZIP writer with CRC-32 plus hand-written
WordprocessingML). Every difference is a real tracked change (w:ins/w:del,
author "Doc Diff", w:date), inserted/deleted paragraphs also track the
paragraph mark, so Accept all / Reject all yield exactly the new / old text.
Heading 1-3, clause and bullet styles with hanging indents, title and
metadata block, A4 page setup, footer with page X of Y, no compatibility mode.
- HTML report: self-contained read-only report with strict CSP, lang, summary
counts, linked change list with clause references, legend, full redline,
del/ins with visually hidden "removed:/added:" text, dark-mode and print CSS.
States scope ("changes only" or full) and the header/footer setting.
- Markdown: escape document text, keep whitespace outside ~~ / ** delimiters,
fall back to <del>/<ins> where CommonMark flanking rules would fail, add a
summary table with clause references.
- Print/PDF: dedicated row-aligned print view for pages, split and inline
modes with file names, date, counts, repeated column headers, page numbers
in the page margin, break-inside: avoid, greyscale-safe marks.
- Copy/.txt: shared final-text builder, header/footer lines always excluded,
internal intake markers filtered defensively.
- File names: both document names (e.g. Vertrag_v2_vs_v1_Redline.docx),
sanitized for Windows/macOS/Linux, localized suffixes.
- Export menu: real disabled/aria-disabled state until a comparison exists,
no more silent sample substitution, menu keyboard pattern (arrows,
Home/End, Escape returns focus), .docx label, all strings in de and en.
- Add scripts/test-export.mjs (node:vm, no dependencies) and run it from
scripts/check.mjs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Word diff
- Number expansion in computeCleanWordDiff only applies to groups that both
remove and add text; "Frist 14 Tage" -> "Frist 7 14 Tage" no longer drops
"14" from the old side. Every diff is checked against the invariant
(unchanged+removed == old text, unchanged+added == new text) and falls back
to the raw diff if it would ever be violated.
Headers / footers
- PDF margin lines are headers/footers only if their digit-normalised text
repeats on >= 50% (and >= 2) of the pages at a similar vertical position;
body lines near the margins are kept. Text-only candidates ("... Page 4 of
9") must repeat as well; pure page labels stay hidden.
- A header/footer whose text differs between the versions (beyond page
numbers) is never hidden: its first occurrence stays visible. The hidden
line count reflects what is actually hidden in both documents.
PDF / file intake
- Spaces between PDF.js items come from glyph geometry and hasEOL, so a font
change inside a word no longer splits it; paragraph breaks use the page's
line step; hyphenated line breaks are joined, also across pages.
- Files are sniffed by content: scanned/image-only PDFs, images, legacy .doc,
RTF, other ZIPs and non-UTF-8 binaries are rejected with a bilingual
role="alert" notice (also for drag & drop); HTML is reduced to text via an
inert DOMParser document.
- DOCX list numbers are computed from numbering.xml/styles.xml the way Word
counts them (continuation across interruptions, level restarts,
startOverride) and injected into Mammoth's output; nesting depth is kept
as block indent. When the paragraphs cannot be matched reliably, no
numbers are shown instead of invented ones.
Document model
- Page breaks, header/footer flags and list depth are encoded with control
characters that are stripped from all external input, so typed text such
as "=== [SEITE 2] ===" or "[[HF]]" is plain text. The paste dialog shows
plain text and keeps a loaded document if its text was not edited.
- Undo/redo history is cleared whenever a document is replaced (upload,
paste, swap, sample, language switch of the sample, clear).
Alignment noise
- Block similarity uses a multiset word intersection.
- Blocks are aligned on their body without list marker / heading number;
renumber-only rows are equal rows flagged markerOnly, rendered with a muted
marker change and not counted as changes.
- Identical deleted/inserted blocks are paired as moved (flag on the
deleted/inserted rows, labelled "Verschoben" / "Moved").
Also removes dead code (form-feed check, state.syncScroll, syncBtn) and adds
scripts/test-core.mjs (run by check.mjs) covering the invariant, samples,
header/footer detection, PDF line handling, renumbering and moves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Resolved conflicts with the export rework: keep the export guard without the sample fallback, and run both the export and the core test suites from check.mjs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
… accessibility Landing page (empty state): - Static, indexable landing markup in src/template.html (works without JS): headline, trust facts, two large keyboard-accessible drop slots (old / new version), "View example" and "Paste text", then "How it works", honest "can / can't" limits and a short FAQ. - Comparison-only controls (view switch, search, counts, reset, sidebar toggle, document bars, dock, phone bottom bar) are hidden until two versions are loaded. Drag wording is hidden on touch / narrow screens. - Dismissible in-memory legend after the first comparison. Comparison view: - Header counts match the sidebar filters (modified / added / removed). - Plain-language labels: Pages / Side by side / Inline, Old / New version, "New comparison"; help dialog rewritten without jargon. - Sidebar cards drop the redundant type badge and stray bullet refs. - Minimum UI text 12px, less monospace for prose labels; 24px targets, 44px on coarse pointers; phone Edit / Revert reachable by tapping. Accessibility (WCAG 2.2 AA): - setTooltip also sets accessible names; all aria-labels translated. - Filter bar uses aria-pressed; change cards are real buttons with sibling actions (no nested interactive controls). - Focusable, labelled document panes; polite live region announces the comparison result and "Change 3 of 19 ..." on J / K. - Single-key shortcuts ignore modifier combos, text fields and open dialogs and can be switched off in the help dialog. - h1 in both states, landmarks for document bars and legend, dialog initial focus, focus handoff when the landing appears / disappears. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…iew switching incremental - Run parsing, alignment and word diffs in a Web Worker built from a Blob. scripts/build.py bundles jsdiff + src/js/04-core.js + src/js/04a-align.js + src/worker/compare-worker.js into the page, so the worker shares the exact same code. Small inputs and environments without blob workers use the synchronous path. - Only the latest comparison is applied (sequence ids, busy worker is terminated); show an accessible role=status progress pill. - Align long middles by anchoring on unique identical blocks and running the DP only inside the gaps (banded DP for huge gaps). Middles up to 250k cells keep the exact global DP. - Edits, reverts, undo and redo re-diff only the changed row when possible and patch it in place. - Render panes in chunks; keep left/right row heights aligned with a ResizeObserver instead of re-measuring every row; J/K and sidebar clicks only touch the two affected rows; search is debounced and re-highlights matching rows only. - Run PDF.js in a real Blob worker instead of its main-thread fake worker. - Lighter per-clause action buttons (CSS mask icons). - Respect prefers-reduced-motion. - Add scripts/check-diff-worker.mjs (worker vs. main-thread equivalence). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Resolve conflicts with claude/focused-mayer-3stkgw and integrate: - Header counts and sidebar filters share one helper over changeRows, so renumbered (marker-only) rows are not counted anywhere. - Moved rows are labelled "Verschoben" / "Moved" in cards and announcements; the landing page now lists moved-paragraph detection under "can" instead of "can't". - Sample loading resets the edit history; new file-intake messages kept. - Header/footer clauses no longer use opacity (insertions inside them failed contrast); the pressed header/footer count pill uses a solid background. - Leave a marked slot for further secondary start actions (session). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Run prepareComparisonBlocks + alignDocumentBlocks (incl. markMovedRows) in the worker and the sync fallback; anchor on alignKey; keep moved-row notes in the chunked renderer; incremental updates re-check header/footer reconciliation and moved-row flags; load 04a-align.js in the core and export tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
The headline is now 'Dokumente einfach vergleichen.' / 'Compare documents easily.', with a struck-out word and its green replacement in the app's own diff colours. The struck-out word is aria-hidden, so screen readers read the plain sentence. README: describe what the tool does and what it does not do, state the privacy guarantees precisely (including what the CSP does not cover), and drop the comparison table and feature marketing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
docs/og-image.html is the source of site/og-image.png now, so the preview can be re-rendered when the UI changes. The image shows the new headline and a mockup that uses the current labels. The og:image URL gets a version query so link previews pick up the new image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…o it - Open session button sits in the landing's secondary actions slot. - Save session item uses data-i18n and the rebuilt export menu (keyboard, closeExportMenu); exports including print mark a clean point. - Confirm dialog follows the dialog focus pattern (title autofocus, focus returns to the trigger); stale close events no longer cancel a reopened dialog. - Guards cover the landing "remove new version" button and compare the paste dialog against the plain text it showed. - Help dialog explains that a session file contains the full text of both versions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
- Resolve conflicts with the live-region announcements; the progress pill keeps its percentage aria-hidden and reuses the announcement strings. - Keep panes of the inactive view laid out but skipped (content-visibility: hidden) instead of display: none on desktop, so switching views does not recompute ~25k elements. - Re-highlight large search result sets in short slices, nearest rows first; preserve the scroll position when panes are re-rendered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
- Merge the session save/restore work (11-session.js wraps runComparison; the async runComparison keeps returning its Promise through the wrapper). - The single-row fast path for edits/undo/redo is now only used for long documents and only for rows that stay a matched pair; a full comparison then runs in the worker and replaces the result if the alignment differs, so results always end up identical to a full comparison. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
On long documents an edit that changes the number of paragraphs (or a revert of an insertion, undo/redo of such an edit) is re-compared in the worker. Until the result arrives the old rows stay on screen, and a second edit or revert built the new text from those old rows, silently dropping the first edit. Exports in that window wrote the old rows but still marked the session clean, so the edit could be lost on close. Edits and reverts now wait until the shown rows match the current text, an editor left open while the document is replaced is discarded instead of being written into the new document, and exports/printing bring the comparison up to date synchronously. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…r noise
- Word diff: bound the Myers work per paragraph pair (maxEditLength) and fall
back to an exact prefix/suffix + replacement diff. Two rewritten 10,000-word
paragraphs took ~45 s, a 1 MB paragraph effectively never finished.
- Bare page-number shapes ("2/3", "3 von 9", "- 4 -") in documents without
pages (DOCX, pasted text) are only hidden as page numbers when they form an
increasing sequence. A changed DOCX table cell "2/3" -> "1/3" was hidden.
- Normalise text before comparing: NFC, Latin ligatures, fixed-width spaces,
soft hyphen / zero-width space / word joiner / BOM, CR and U+2028/2029
line ends. Visually identical text no longer shows as changed.
- PDF: wrapped lines starting with an amount or a date ("145.000,00 EUR",
"12.03.2026") no longer start a new paragraph; symbol-font bullets
(U+F0B7, U+F095, ...) become "•".
- Running headers of a PDF are not reported as inserted/deleted against a
version without any page structure or headers (DOCX, text).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Performance - Move the inline vendor libraries and the app script from <head> to the end of <body>, so the static landing page is parsed and painted before ~2.5 MB of script. Throttled mobile profile (150 ms RTT, 1.6 Mbit/s, 4x CPU, gzip): FCP/LCP 3.7 s -> 1.2 s; uncompressed 11.6 s -> 1.8 s. Pages and metadata - build.py renders the page per language from one template: site/index.html and DocDiff.html (German, browser auto-detect as before) and site/en/index.html (English, starts in English via data-page-lang). - Static landing text (data-i18n, data-i18n-html, data-i18n-label) is rendered at build time from src/js/01-i18n.js, so crawlers and no-JS visitors see the page language; the app still translates at runtime. - Head: precise title and description per language, canonical, hreflang de/en/x-default, og:locale, theme-color, application-name; assets use ../ from /en/. - JSON-LD (WebApplication, SoftwareSourceCode, FAQPage) generated from the same i18n strings; the FAQPage matches the visible FAQ. Content - Two FAQ entries (scanned PDFs / OCR, continuing in Word via the tracked changes export); mixed formats (PDF against Word) in the feature list. - The struck-out hero word is drawn via CSS, so the heading text reads "Dokumente einfach vergleichen." / "Compare documents easily." - Footer links get a 24px tap target; legal links in the privacy dialog are absolute so they work from /en/ and the offline file. Crawl files - site/llms.txt and site/llms-full.txt with plain facts and limits. - sitemap.xml lists / and /en/ with hreflang alternates and lastmod; robots.txt allows all crawlers, including AI crawlers. Checks - check.mjs verifies both pages: lang, canonical, hreflang, title and description length, asset paths, scripts after the landing content, rendered static text, single landing h1, JSON-LD parse and FAQ match, robots, sitemap, llms.txt links, manifest icons, same CSP. - Workflows fail when any file under site/ differs from a fresh build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Saving or cancelling an inline edit with the keyboard, reverting a change from the document or the change list, pressing Undo/Redo until the stack is empty, and choosing an export menu item all removed or disabled the focused control, so focus fell back to <body> and keyboard users had to start again from the top of the page. Focus now returns to the row's edit button (or the next item in the change list, or the document pane when row actions are hidden on narrow screens), moves to the other history button when one gets disabled, and goes back to the export button when the menu closes. Undo/Redo button states are also updated immediately, not only after a long comparison. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
- DOCX: a line break inside a paragraph (Shift+Enter) now separates words. "Hauptstraße 1" + break + "12345 Berlin" was read as "Hauptstraße 112345". - DOCX: warn when the document contains tracked changes; Mammoth compares the all-accepted version and silently drops deleted text. - DOCX: drop Mammoth's footnote/endnote back-link arrows from the text. - File intake: a slow read (large PDF) that finishes after another file was chosen for the same side, or after the side was replaced by paste, sample or clear, is discarded instead of overwriting the newer document. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…to their page Search engines render with an English browser language, so the root page switched itself to English and duplicated /en/. The hosted pages now keep their language (data-page-lang); a visitor whose browser language differs gets a one-line link to the other page. The offline DocDiff.html still follows the browser language and no longer links website-only icon and manifest files that do not exist next to it (console error under file://). document.title now follows the in-app language toggle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…codings
- Password-protected PDF, damaged/truncated PDF and damaged DOCX now show a
translated message instead of raw library errors ("No password given",
"Invalid PDF structure", "Corrupted zip: ...").
- A DOCX is recognised by its word/document.xml entry even when the file is
named .pdf; a text file that mentions "%PDF-" stays text.
- Text files that are not UTF-8 (Windows-1252 "ANSI") are read with a
warning instead of being rejected; UTF-16 without BOM is detected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…line - PDF: a paragraph broken at a page end continues when the next page starts with a capitalised word (German nouns), provided the previous text is a long paragraph of the same font size; short unpunctuated lines (headings) are not joined. - The table-cell separator " · " produced by DOCX/HTML intake no longer makes a row differ from the same row extracted from a PDF. - Bare page-number shapes in a PDF body (not marked as footer by position and repetition) follow the same sequence rule as DOCX/text: a single-page PDF table cell "2/3" -> "1/3" was hidden. Same-content DOCX vs PDF (LibreOffice export, 61 rows): 7 -> 2 change rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…nding reads
Hidden header/footer candidates of both versions are now matched as token
sequences (top/bottom band + text with page numbers normalised) in document
order, which pairs them page by page even when pages are inserted or removed.
Only matched occurrences stay hidden; every unmatched occurrence is shown and
diffed like body text. A running line changed on one page, a footer changed on
every page, or a repeated body line misdetected as a header and edited or
deleted on one page can no longer disappear. The hidden-line badge counts only
the identical lines that remain hidden.
Unchanged exceptions: pure page-number labels stay hidden, and a PDF's running
lines stay hidden against a version without pages and without any
header/footer lines (DOCX, pasted text).
Samples: the changed running header ("Fassung v1.0" -> "Gegenentwurf v2.0") is
now shown on each of its 3 pages instead of once (modified 17 -> 19, hidden
lines 10 -> 6). No change in the samples had been hidden before.
"Clear all" / clearing a side now also cancels a file that is still being read
for that side, even when the side was already empty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…ment The selected row id survived clearing a side, swapping, pasting or loading new documents, so an unrelated row of the next document was highlighted as active and J/K continued from there. It is now reset when documents are replaced and whenever the row no longer exists. An edit that empties the revised document now moves focus to the landing heading instead of leaving it on <body>. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
When neither the Clipboard API nor execCommand could copy, the export button still flashed "Copied" and the copy counted as saving the edits, so closing the tab no longer warned about unsaved changes. A failed copy now shows a translated notice, and only downloads (txt, docx, html, md) mark the session clean: a cancelled print dialog or a volatile clipboard must not silence the unsaved-changes warning. Closing the import/copy notice from the keyboard now returns focus to the control that was focused before (or the start of the view) instead of <body>. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Dependency-free regression tests for the guards that keep edits, reverts and exports from using rows that are still being re-compared, for the list of exports that count as saving, the failed-copy feedback, immediate undo/redo button updates and the reset of a stale selected row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Rebuilding the revised text after an inline edit wrote hidden header/footer lines back per page as "first line at the top, all others at the bottom". That moved running headers and footers to different positions, so the header/footer reconciliation no longer matched them: on the sample, appending one sentence to § 1 (1) turned the six hidden header/footer lines into changes (22 -> 26 changes, badge gone, old side 31 -> 34 paragraphs). The text is now rebuilt from all blocks of the revised document in their original order with only the edited paragraph replaced (or inserted after the nearest preceding block for a deleted row), so an edit changes exactly that paragraph. Single-letter shortcuts (J/K, C, H, /) now only act while focus is on the page, in a document pane or in the change list; letters typed with focus on a toolbar control, in a dialog or in any editable element never toggle filters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…e headings
- Pairing no longer requires the same heading/paragraph kind. Appending a
sentence (or a period) to "1. Scope of Services" re-derives it as a
paragraph; it is now shown as modified instead of deleted + inserted.
- The section reference ("1.", "§ 5") follows the numbering in the text, not
the derived kind, so such an edit no longer changes the clause references
below it, which had re-paired a neighbouring "(3)" clause.
- Similarity words ignore leading/trailing punctuation ("Services." =
"Services").
- Ordinary sentences are never headings: a line ending in sentence
punctuation with 6+ words, or any line with 14+ words, is body text
("§ 2 Der Auftragnehmer erbringt die Leistungen fristgerecht." was bold).
Stability check: 232 single-paragraph edits of the de/en samples (append word,
sentence, period, clause), every other row keeps its pairing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…ruler Replace the five bands of comparison chrome (header stats, document bars, legend, floating dock, centre gutter) with a single top bar: the file pair as one button with a popover, a change stepper, find in document, a View menu, Export and a More menu. Counts appear only in the change list. - Accept / reject each change (Word terminology). Rejecting restores the old wording; both mark the change as reviewed, survive undo/redo and are kept in the list. Actions are docked under the current paragraph and on the active list card; A / R / J / K work while the document or list has focus. A toast offers undo. - Overview ruler next to the scrollbar replaces the centre minimap. - Find in document highlights matches in both versions with a counter. - Two views (side by side / inline) plus a page-breaks option. - Word export: accepted changes as plain text, open ones as tracked changes. Reports show the review status. - Saved work format version 2 stores the review status; version 1 opens. - New tokens: root font size 100 %, document text 15.5-16 px, colour roles with blue only for actions; removed/added text at >= 7:1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
…ixes - Export tests: Word semantics of accepted / rejected / open changes (Accept all = current new version, Reject all = old version with the accepted changes applied), unchanged output before any review, review status in the HTML and Markdown reports. - App state tests: review status across re-comparisons and undo/redo, saved work format version 2 and version 1 compatibility. - One tab stop per action group (document action row, active list card). - Focus returns to the menu button after a dialog opened from a menu; a rejected header/footer change stays in the list when its line is hidden. - README and llms-full.txt describe the new views, review and shortcuts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
- Phones offer only the stacked view; a split request falls back to it. - Tapping the sheet backdrop closes an open menu and returns focus to its button. - The toast action keeps focus on the page when it switches views. - Review status serializes with a stable field order. - Header/footer label capitalization is consistent in English. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
- Accept, reject and edit are three quiet icon buttons (32 px, 44 px on touch) floating at the top right of the current paragraph; colour only on hover and keyboard focus. Tooltips name the shortcut (A, R, E); E is a new shortcut for editing. - List cards are navigation only: no buttons, a status glyph and muted text once reviewed. - Accepting or rejecting moves on to the next open change. The reviewed paragraph keeps a status pill with Undo; the toast is no longer shown for review actions. - First-visit hint explains the glyphs and J/K; Help describes the new placement. - No hover fill on unchanged paragraphs; the header/footer group no longer grows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
… stable layout
- Accept / reject move on to the next open change, focus its accept button and announce it
("Angenommen – weiter mit Änderung 5 von 20"); pressing A repeatedly accepts in a row.
- The same header/footer change on several pages is one list item ("auf 3 Seiten gleich
geändert"), listed after the body changes; accepting or rejecting it covers every page.
Exports still list every occurrence in document order.
- The icon group sits in a reserved right margin of the new version, so selecting a paragraph
never changes any height. Reviewed paragraphs carry a status line with Undo.
- List cards show each change in its sentence with grey context words; whole paragraphs read
"entfernt: …" / "hinzugefügt: …". Unnumbered paragraphs are "Absatz".
- Editing a reviewed paragraph says that the change is open again.
- Screen readers hear "entfernt: … (Ende entfernt)" / "hinzugefügt: …"; panes are named
"Alte Fassung: <file>"; replacing a file announces the new comparison and keeps focus.
- Separate filters for review status (Offen / Geprüft) and kind of change; the stepper and the
list title say what they count.
- Find bar inside the top bar; no toast over open menus or sheets; import errors appear under
the file slots with an error border; one file name shortening rule everywhere.
- Search hits are blue; print hides the toggles and the current-change ring and always states
the review progress; forced-colors styles for the ruler and the current change.
- Help sits in the top bar on both screens; the language button names its target language.
- Export menu: Word, print, copy, then "Weitere Formate" (HTML, Markdown, .txt); the ⋯ menu is
trimmed to new comparison, saved work, language, legal notice and GitHub.
- Copy fixes (spelled-out counts, .txt label, J/K help, scan and empty-file messages, English
quotation marks), 44 px targets and ≥ 3:1 control edges.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
… and the extension Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tvts5ekgounJpaCtwNFnng
Spacing on a 4 px grid, three radii, one hairline colour and two weights. Panes become one white surface; page breaks are a labelled hairline instead of cards. The current change is a soft tint with an ink edge instead of a black ring, changed paragraphs get a thinner, lighter amber edge, the file pair and stepper no longer look like inputs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KgQ1PFoGfZMrXQmhBk2wgG
- List header: title, review progress as text and a hairline, one filter
(all, a review status or a kind of change) instead of hint box,
segmented control and tabs.
- List cards scan like an inbox: reference, the first change in two lines,
further changes counted as "+N".
- A reviewed paragraph shows a check or cross in the right margin with an
undo button below it; the status line above the text is gone, so
reviewing no longer shifts text, and the old version shows no mark.
- Header/footer groups lose their dividers and get a smaller toggle.
- Narrow screens show only the distinguishing parts of the file names
("v1_Vorher -> v2_Nachher").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgQ1PFoGfZMrXQmhBk2wgG
In the stacked view it stays at the right edge of the document. Both panes keep the same width in either view, so switching never re-wraps their text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KgQ1PFoGfZMrXQmhBk2wgG
- Files popover: short "Replace…" / "Remove" buttons in one row (full names stay in the accessible labels); consistent spacing. - More menu: remove a duplicated separator. - Help text describes the ruler between the versions and the undo arrow. - Below 1200 px help moves into the more menu so the file names fit. - File names on wide screens are shortened later; ellipsis as a fallback. - Pane keyboard focus is a line under the caption instead of a ring around the whole pane. - Phone bottom bar: the step counter reads as a list button, not a block. - No focus tooltips on touch screens. - Menus, popover and find bar fade in (off with reduced motion). - Dark mode: primary hover keeps 7:1 text contrast. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KgQ1PFoGfZMrXQmhBk2wgG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KgQ1PFoGfZMrXQmhBk2wgG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KgQ1PFoGfZMrXQmhBk2wgG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Everything for v1.5.0. The full user-facing list is in
docs/releases/v1.5.0.md, which the release workflow uses as the release notes.Summary
.docdiffsaved work..docxwith real tracked changes, a self-contained HTML report, Markdown, and a dedicated print layout.UI polish (last round)
src/styles.css: spacing on a 4 px grid, three radii, one hairline colour, two weights, one title size.Verification
python3 scripts/build.py && node scripts/check.mjspasses (privacy and standalone invariants, i18n parity, core/export/worker/app-state tests).color-contrast-enhanced(AAA) is clean in the same states.After merge, tag
v1.5.0on the merge commit to trigger.github/workflows/release.yml.Generated by Claude Code