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',