From 0020d1e773d124f4e4e5c7051d76324c8a721296 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 23 Mar 2026 12:46:56 +0100 Subject: [PATCH] fix(frontend): improve PDF zoom and diff readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PDF viewer: append #zoom=page-width to iframe src so A4 letters fill the panel width instead of leaving large grey gutters - Diff view: trim unchanged context to 4 words either side of each change, replacing long runs with '…' so edits are easy to spot Co-Authored-By: Claude Sonnet 4.6 --- .../src/routes/documents/[id]/+page.svelte | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/frontend/src/routes/documents/[id]/+page.svelte b/frontend/src/routes/documents/[id]/+page.svelte index 7b2d6f0d..4cd12d7e 100644 --- a/frontend/src/routes/documents/[id]/+page.svelte +++ b/frontend/src/routes/documents/[id]/+page.svelte @@ -112,6 +112,44 @@ function personLabel(p: { firstName: string; lastName: string }): string { return `${p.firstName} ${p.lastName}`.trim(); } +const DIFF_CONTEXT_WORDS = 4; + +type DiffPart = { value: string; added?: boolean; removed?: boolean }; + +function trimContextParts(parts: DiffPart[]): DiffPart[] { + return parts.flatMap((part, i) => { + if (part.added || part.removed) return [part]; + const tokens = part.value.split(/(\s+)/).filter(Boolean); + const wordCount = tokens.filter((t) => /\S/.test(t)).length; + if (wordCount <= DIFF_CONTEXT_WORDS * 2) return [part]; + + function keepFirst(n: number): string { + let count = 0; + const out: string[] = []; + for (const t of tokens) { + out.push(t); + if (/\S/.test(t) && ++count >= n) break; + } + return out.join(''); + } + function keepLast(n: number): string { + let count = 0; + const out: string[] = []; + for (const t of [...tokens].reverse()) { + out.unshift(t); + if (/\S/.test(t) && ++count >= n) break; + } + return out.join(''); + } + + const isFirst = i === 0; + const isLast = i === parts.length - 1; + if (isFirst) return [{ value: '… ' + keepLast(DIFF_CONTEXT_WORDS) }]; + if (isLast) return [{ value: keepFirst(DIFF_CONTEXT_WORDS) + ' …' }]; + return [{ value: keepFirst(DIFF_CONTEXT_WORDS) + ' … ' + keepLast(DIFF_CONTEXT_WORDS) }]; + }); +} + function buildDiff(older: SnapshotDoc | null, newer: SnapshotDoc): DiffEntry[] { const entries: DiffEntry[] = []; @@ -119,7 +157,7 @@ function buildDiff(older: SnapshotDoc | null, newer: SnapshotDoc): DiffEntry[] { const a = older?.[field] ?? ''; const b = newer[field] ?? ''; if (a === b) continue; - const parts = diffWords(a, b); + const parts = trimContextParts(diffWords(a, b)); entries.push({ kind: 'text', field, label: fieldLabels[field](), parts }); } @@ -844,14 +882,14 @@ function versionLabel(v: VersionSummary, index: number): string { {:else if fileUrl && doc.originalFilename.toLowerCase().endsWith('.pdf')} {:else if fileUrl}
{m.doc_image_alt()}