fix(web): scope timeline minimap hover target to the side gutter#3869
fix(web): scope timeline minimap hover target to the side gutter#3869xxashxx-svg wants to merge 1 commit into
Conversation
The minimap overlay is anchored to the timeline viewport's left edge with a fixed-width hover strip (left-3 w-10) and an always-interactive w-18 wrapper, while the message column is centered. Under browser zoom or a narrow pane the side gutter between them collapses, so the fixed strip lands on top of the message text: hovering body text pops the minimap preview, the copy button next to the timestamp never reveals (the row's group-hover can't fire while the overlay swallows the pointer), and text selection fights the overlay. Cap the strip's width to what actually fits between the viewport edge and the content column, measured from the already-observed viewport width; with no usable gutter the strip goes inert. The wrapper is now pointer-events-none so only the width-capped strip captures the pointer (hover reveal still works — hovering the strip puts its ancestors in :hover). Wide layouts keep the exact 40px strip they have today. Fixes pingdotgg#3702 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review Self-contained UI fix with unit tests that adjusts pointer-event handling based on viewport width. The logic is clear and well-documented, but the author is not a frequent contributor to these files, warranting a quick human review. You can customize Macroscope's approvability policy. Learn more. |
Fixes #3702
What
At non-default zoom (Cmd+Plus a few times) or at normal zoom with a wide sidebar / narrow window, the timeline minimap's hover target extends into the message text area: hovering body text triggers the minimap preview popover, the Copy button next to the timestamp can't appear, and text selection fights an invisible overlay.
Why it happens
The minimap is
absolute left-0on the full-width timeline viewport with a fixed hit strip (left-3 w-10, i.e. x = 12–52px) — and itsw-18wrapper ispointer-events-autotoo, so the interactive region is really the leftmost ~72px. Meanwhile the message column is centered (max-w-3xl), so the side gutter between the viewport edge and the text is(viewportWidth − 768) / 2. Zooming in shrinks the effective CSS viewport width, and a wide sidebar shrinks the pane — both collapse that gutter toward zero while the fixed-px overlay stays put, landing it on top of the text. The pointer hit-test (resolveTimelineMinimapIndexFromPointer) only bounds the Y axis, so nothing stops it.The Copy-button symptom is the same mechanism: the overlay swallows the pointer, so the message row's
.groupnever enters:hoverandgroup-hover:opacity-100on the action row never fires.Change
resolveTimelineMinimapHitStripWidth(viewportWidth)inMessagesTimeline.logic.ts(same shape/placement as the existingresolveTimelineMinimapHasPersistentGutter): caps the strip's width to what actually fits between the viewport edge and the content column; returns 0 when there's no usable gutter.<button>takes that measured width (wide layouts keep the exact 40px they have today) and goespointer-events-noneat width 0.w-18wrapper is nowpointer-events-none, so only the width-capped strip captures the pointer. Hover-reveal still works — hovering the strip puts its ancestors in:hover, which is what the wrapper'shover:opacity-100keys off — but it's now correctly scoped to the gutter. Keyboard navigation (focus + arrows) is unaffected.Measurement reuses the existing
ResizeObserveron the timeline viewport — no new observers or listeners.Tests
Extended the existing logic-function test with the new helper: no-gutter (768/792 → 0, inert), partial gutter (820 → 14px strip), full gutter (872/1400 → 40px, today's behavior), and degenerate inputs.
vp checkandvp run typecheckpass; the fullMessagesTimelinesuite (12 tests) passes.🤖 Generated with Claude Code
Note
Low Risk
Localized chat UI pointer-event and layout math with pure helpers and tests; no auth, data, or API changes.
Overview
Fixes timeline minimap interaction stealing pointer events from message text when zoom or a narrow pane shrinks the side gutter next to the centered column.
Adds
resolveTimelineMinimapHitStripWidthto cap the minimap hover strip to the gutter (0 when there is no room, up to 40px when there is). The existing viewportResizeObserverdrivesminimapHitStripWidthintoTimelineMinimap, which applies that width on the strip button and usespointer-events-noneon the wrapper and on the strip when width is 0.Wide layouts keep the previous 40px strip; partial gutters get a narrower target. Copy buttons, text selection, and hover on messages work again in the overlap case. Unit tests cover the new helper’s width cases.
Reviewed by Cursor Bugbot for commit f1264c1. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Scope timeline minimap hover target to the side gutter width
resolveTimelineMinimapHitStripWidthin MessagesTimeline.logic.ts to compute the available gutter width, clamped to a maximum and returning 0 when no gutter exists.TimelineMinimapcomponent now receives ahitStripWidthprop; its outer container ispointer-events-noneand the inner button only receives pointer events whenhitStripWidth > 0.Macroscope summarized f1264c1.