From 01b8a974046ed24022198ef7dab937bb4a10f970 Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Wed, 2 Sep 2026 12:38:27 +0000 Subject: [PATCH] refactor: one card builds a comment or a change in either review view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CommentCard and RevisionCard hold what the pane rows carried inline, so the margin balloon can show the same thing. The comment card gains the reply box its thread needs and moves edit / resolve / remove behind a ⋯ menu that stays in the flow — a balloon clips a floating popover, and three buttons in a row cost it two lines. --- src/lib/components/CLAUDE.md | 16 +- src/lib/components/CommentCard.svelte | 227 ++++++++++++++++++++++++ src/lib/components/CommentsPane.svelte | 112 ++---------- src/lib/components/RevisionCard.svelte | 78 ++++++++ src/lib/components/RevisionsPane.svelte | 66 +------ src/lib/i18n/locales/de.ts | 2 + src/lib/i18n/locales/en.ts | 2 + 7 files changed, 339 insertions(+), 164 deletions(-) create mode 100644 src/lib/components/CommentCard.svelte create mode 100644 src/lib/components/RevisionCard.svelte diff --git a/src/lib/components/CLAUDE.md b/src/lib/components/CLAUDE.md index 7728f38..00c2c72 100644 --- a/src/lib/components/CLAUDE.md +++ b/src/lib/components/CLAUDE.md @@ -133,10 +133,15 @@ One header and one footer (`HfDoc` = a single-paragraph TipTap doc per zone, per ## Comments (`CommentsPane.svelte`) -Word's Reviewing Pane, not its margin bubbles: the page here fills its own scroller, so a -pane beside it (`.editor-row` in `App.svelte`) keeps the sheet at its true width. It lists -`comments(editor.state.doc)` in document order — click a card to select the annotated -range, edit / resolve / remove in place. `App.svelte` owns the New-comment prompt, which +Word's Reviewing Pane, docked beside the scroller (`.editor-row` in `App.svelte`): the +list view a comment goes to instead of the margin balloon below — one control picks the +place (`storage/markup`), so no comment is in both at once. It lists `visibleComments` in +document order — click a card to select the +annotated range, answer it in the reply box, and edit / resolve / remove behind the card's +**⋯** button (`CommentCard.svelte`, shared with the balloon). That menu is **in the flow**, +not floating: the balloon clips what leaves it, so a popover would be cut off there. Only +the answer box is a command a card shows outright — it is the one used most, and three +buttons in a row cost a balloon two lines. `App.svelte` owns the New-comment prompt, which both the Review tab and the context menu (`OPEN_COMMENT_EVENT`) fire; the author comes from the document properties. The card of the comment the selection lies within (`commentIdAt`) is marked and scrolled into view, the pane half of the pairing `pm-comment-active`, @@ -147,7 +152,8 @@ is marked and scrolled into view, the pane half of the pairing `pm-comment-activ The reviewing pane both word processors list revisions in, docked beside `CommentsPane` and built the same way: one row per change **id** (a paragraph boundary splits one change into several ranges), in the author's own colour, click to select the text, accept or -reject in place through `acceptRevision`/`rejectRevision`. Opened from the Review tab. +reject in place through `acceptRevision`/`rejectRevision`. The Review tab's Show-changes +button picks between this list and the balloons; the pane is not a second view of them. The row of the change the selection lies within (`revisionIdAt`) is marked with an inset accent in the author's colour — the same colour its margin bar takes — and scrolled into view. diff --git a/src/lib/components/CommentCard.svelte b/src/lib/components/CommentCard.svelte new file mode 100644 index 0000000..69c6fca --- /dev/null +++ b/src/lib/components/CommentCard.svelte @@ -0,0 +1,227 @@ + + +
+ + +
+{#if menu} + + +{/if} + +{#if editing} + +
+ + +
+{:else} +

{c.text}

+{/if} + +{#each c.replies as r, i (i)} +
+
{r.author || author}{when(r.date)}
+

{r.text}

+
+{/each} + +{#if replying} + +
+ + +
+{:else if !editing} +
+ +
+{/if} + + diff --git a/src/lib/components/CommentsPane.svelte b/src/lib/components/CommentsPane.svelte index 28c3df8..e4d2435 100644 --- a/src/lib/components/CommentsPane.svelte +++ b/src/lib/components/CommentsPane.svelte @@ -1,12 +1,13 @@ @@ -75,33 +53,7 @@ @@ -132,7 +84,7 @@ } .title { flex: 1; font-weight: 600; } .count { color: var(--color-text-muted); } - .close, .actions button { + .close { border: 1px solid transparent; border-radius: var(--radius); background: none; @@ -141,8 +93,7 @@ font: inherit; cursor: pointer; } - .close:hover, .actions button:hover { background: var(--color-btn-hover); color: var(--color-text); } - .actions .primary { border-color: var(--color-primary); background: var(--color-primary); color: #fff; } + .close:hover { background: var(--color-btn-hover); color: var(--color-text); } .empty { padding: 12px 10px; color: var(--color-text-muted); } @@ -154,47 +105,4 @@ } li.resolved { opacity: 0.55; } li.active { background: var(--color-btn-hover); box-shadow: inset 3px 0 0 rgba(200, 140, 0, 0.9); } - - .card { - display: block; - width: 100%; - border: none; - background: none; - color: inherit; - padding: 0; - text-align: left; - font: inherit; - cursor: pointer; - } - - .meta { display: flex; justify-content: space-between; gap: 8px; color: var(--color-text-muted); } - .meta b { color: var(--color-text); } - - .quote { - margin: 3px 0; - padding-left: 6px; - border-left: 2px solid rgba(200, 140, 0, 0.7); - color: var(--color-text-muted); - /* Two lines of the annotated text is enough to recognise it. */ - display: -webkit-box; - -webkit-line-clamp: 2; - line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - } - - .body { margin: 4px 0; white-space: pre-wrap; } - - textarea { - width: 100%; - border: 1px solid var(--color-border); - border-radius: var(--radius); - background: var(--color-surface); - color: var(--color-text); - padding: 4px 6px; - font: inherit; - resize: vertical; - } - - .actions { display: flex; gap: 4px; justify-content: flex-end; } diff --git a/src/lib/components/RevisionCard.svelte b/src/lib/components/RevisionCard.svelte new file mode 100644 index 0000000..76b2505 --- /dev/null +++ b/src/lib/components/RevisionCard.svelte @@ -0,0 +1,78 @@ + + + +
+ + +
+ + diff --git a/src/lib/components/RevisionsPane.svelte b/src/lib/components/RevisionsPane.svelte index 5d83adb..36495c8 100644 --- a/src/lib/components/RevisionsPane.svelte +++ b/src/lib/components/RevisionsPane.svelte @@ -1,11 +1,13 @@ @@ -68,18 +61,7 @@ @@ -110,7 +92,7 @@ } .title { flex: 1; font-weight: 600; } .count { color: var(--color-text-muted); } - .close, .actions button { + .close { border: 1px solid transparent; border-radius: var(--radius); background: none; @@ -119,7 +101,7 @@ font: inherit; cursor: pointer; } - .close:hover, .actions button:hover { background: var(--color-btn-hover); color: var(--color-text); } + .close:hover { background: var(--color-btn-hover); color: var(--color-text); } .empty { padding: 12px 10px; color: var(--color-text-muted); } @@ -131,34 +113,4 @@ } /* The accent is the author's colour, set inline — the same one the margin bar takes. */ li.active { background: var(--color-btn-hover); } - - .card { - display: block; - width: 100%; - border: none; - background: none; - color: inherit; - padding: 0; - text-align: left; - font: inherit; - cursor: pointer; - } - - .meta { display: flex; justify-content: space-between; gap: 8px; color: var(--color-text-muted); } - .kind { color: var(--color-text-muted); } - - .quote { - margin: 3px 0; - padding-left: 6px; - border-left: 2px solid currentColor; - /* Two lines of the changed text is enough to recognise it. */ - display: -webkit-box; - -webkit-line-clamp: 2; - line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - } - .quote.struck { text-decoration: line-through; } - - .actions { display: flex; gap: 4px; justify-content: flex-end; } diff --git a/src/lib/i18n/locales/de.ts b/src/lib/i18n/locales/de.ts index 4d5833a..148ae3c 100644 --- a/src/lib/i18n/locales/de.ts +++ b/src/lib/i18n/locales/de.ts @@ -83,6 +83,8 @@ const de: Messages = { title: 'Kommentare', onPage: (n: number) => `Seite ${n}`, empty: 'Noch keine Kommentare. Text markieren und einen hinzufügen.', + more: 'Mehr', + reply: 'Antworten', edit: 'Bearbeiten', resolve: 'Erledigt', reopen: 'Wieder öffnen', diff --git a/src/lib/i18n/locales/en.ts b/src/lib/i18n/locales/en.ts index 689edb6..c1191a2 100644 --- a/src/lib/i18n/locales/en.ts +++ b/src/lib/i18n/locales/en.ts @@ -86,6 +86,8 @@ const en = { title: 'Comments', onPage: (n: number) => `Page ${n}`, empty: 'No comments yet. Select some text and add one.', + more: 'More', + reply: 'Reply', edit: 'Edit', resolve: 'Resolve', reopen: 'Reopen',