refactor: scroll-to-clip via scrollIntoView on the gutter label

Replace the manual lane-h/row-h/clientHeight math (fragile, clamped oddly for
top rows) with scrollIntoView on the target track's gutter label. The label
lives in the fixed track-name column, so the browser scrolls the vertical axis
only — clean, no geometry, and structurally can't fight the horizontal follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-06-30 10:28:00 -04:00
parent 602c710377
commit a99485ff48

View file

@ -180,21 +180,18 @@
(rf/reg-fx :player/seek (fn [secs] (when (and @video-el secs) (set! (.-currentTime @video-el) secs))))
(defn- scroll-to-seg-track!
"Scroll the tracks vertically so the clip under local frame `local` is visible.
No-op when there's no vertical overflow. The annotation lanes are a pinned
header of height `lane-h`, so the clip rows live below that in scroll space."
"Vertically scroll the tracks so the clip under local frame `local` is centred.
We scroll the clip's *gutter label* into view rather than the clip itself: the
label lives in the fixed track-name column (no horizontal scroller), so the
browser only moves the vertical axis — no fight with the horizontal follow,
and no manual geometry. A no-op when the row is already on screen."
[segs local]
(when-let [el @body-scroll-el]
(let [tracks @(rf/subscribe [::subs/tracks])
row-h @(rf/subscribe [::subs/row-h])
anns @(rf/subscribe [::subs/annotations])
lane-h (max 18 (* 18 (count anns)))
track (:track (nth segs (seg-at segs local) nil))
i (first (keep-indexed (fn [idx t] (when (= (:id t) track) idx)) tracks))]
(when i
(let [target (+ lane-h (* i row-h) (/ row-h 2))]
(.scrollTo el #js {:top (max 0 (- target (/ (.-clientHeight el) 2)))
:behavior "smooth"}))))))
(when-let [row (and i (aget (.querySelectorAll el ".gutter-label") i))]
(.scrollIntoView row #js {:block "center" :behavior "smooth"})))))
(defn- goto!
"Move the playhead to local frame `local` and seek the video to match.