- F1: gate the card on rows-WITH-text (`thread.some(row => row.text.length > 0)`)
instead of thread length. A text-less root whose only reply is also text-less
would otherwise open an empty <Paper> (the render already filters empty rows).
New test locks it (parent + reply both empty → no card).
- F2: ESTIMATED_CARD_HEIGHT 200 -> 300 (= CARD_MAX_HEIGHT) so the flip-above
decision reserves the real worst-case height and a tall thread near the
viewport bottom flips up instead of overflowing off-screen.
vitest 19/19, tsc 0, eslint 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per maintainer feedback: show the comment author and the whole thread (parent
+ replies), but as simple "Author: text" lines — no avatars, timestamps, or
thread chrome ("it's already clear they're comments on one entry, one after
another"). Also lengthen the open delay so the card doesn't pop up on a
passing glance.
- Render each comment in the thread as a plain line: bold "Name:" + text,
parent first then replies (createdAt asc). Empty-text comments are skipped.
- OPEN_DELAY_MS 120 -> 350.
- Drop the avatar/relative-time/divider UI (and the CustomAvatar/timeAgo
imports). buildThread (root + direct replies) is unchanged — the comment
model is flat, so direct children of the root are the full thread.
Tests updated to the "Author: text" shape (textContent-based, incl. ordering).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lock the feature's central invariant — the tooltip must never intercept the
comment-mark's click (which opens the side panel). pointer-events:none is the
single property guaranteeing that, and it was unasserted: a regression dropping
it from the style object would let a lingering card swallow the click with no
test failing. Assert it in the "shows after delay" test.
Adds CommentHoverPreview, mounted in page-editor next to <EditorContent>:
hovering a `.comment-mark[data-comment-id]` span shows a small floating card
(createPortal, position:fixed, pointer-events:none so it never intercepts the
mark's click) with the parent comment's plain text. Uses useCommentsQuery
(shares the ["comments", pageId] cache with the side panel — no extra
request). Skips unknown/not-yet-loaded, resolved (data-resolved attr or
resolvedAt/resolvedById), and empty-text comments. A ~120ms open delay avoids
flicker; hides on mouseout / mousedown / scroll(capture) / resize / page
change. commentContentToText flattens the comment's ProseMirror doc
(stringified or parsed) to plain text, preserving hardBreaks as newlines and
never throwing. Main editor only (read-only / shares / history out of scope).
closes#268
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>