feat: per-annotation scroll-to flag gating vertical scroll on jump
Add :meta {:scroll-to bool} to annotations, toggled by a "Scroll to clips on
jump" checkbox in the annotation form. goto! now separates follow? (horizontal
recenter) from scroll-to? (vertical scroll to the clip's track); the vertical
scroll only fires for annotations that opt in, resolved from the canonical
scene group at each jump site (jump button/popover, script highlight, link
chips). Persists for free via editable-group + the backend's opaque group
merge; round-trips through json keywordize, so no migration needed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0c305e42ea
commit
602c710377
2 changed files with 39 additions and 18 deletions
|
|
@ -239,6 +239,9 @@ body { overflow: hidden; background: var(--desktop); background-size: 2px 2px;
|
|||
.pt-x:hover { text-decoration: underline; }
|
||||
|
||||
.form-hint { font-size: 11px; color: var(--mute); }
|
||||
.form-check { display: flex; align-items: center; gap: 6px; font-family: var(--chicago);
|
||||
font-size: 11px; color: var(--ink); cursor: pointer; user-select: none; }
|
||||
.form-check input { cursor: pointer; }
|
||||
.form-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; }
|
||||
.save, .cancel { padding: 6px 14px; font-size: 13px; }
|
||||
/* default button: the heavy double Mac ring */
|
||||
|
|
|
|||
|
|
@ -197,9 +197,12 @@
|
|||
:behavior "smooth"}))))))
|
||||
|
||||
(defn- goto!
|
||||
"Move the playhead to local frame `local` and seek the video to match."
|
||||
([local] (goto! local false))
|
||||
([local follow?]
|
||||
"Move the playhead to local frame `local` and seek the video to match.
|
||||
`follow?` recentres horizontally; `scroll-to?` also scrolls the tracks
|
||||
vertically to the clip under the landing frame (opt-in per annotation)."
|
||||
([local] (goto! local false false))
|
||||
([local follow?] (goto! local follow? false))
|
||||
([local follow? scroll-to?]
|
||||
(let [ctx @(rf/subscribe [::subs/context])
|
||||
segs @(rf/subscribe [::subs/segments])
|
||||
fps @(rf/subscribe [::subs/fps])
|
||||
|
|
@ -209,7 +212,7 @@
|
|||
(when @play (swap! play assoc :idx (seg-at segs local))) ; keep playback in sync
|
||||
(when follow?
|
||||
(r/after-render #(do (follow! fps zoom local true) ; smooth on jump/link
|
||||
(scroll-to-seg-track! segs local)))))))
|
||||
(when scroll-to? (scroll-to-seg-track! segs local))))))))
|
||||
|
||||
(defn video-monitor []
|
||||
[:video {:src @(rf/subscribe [::subs/clip-url]) :controls true :preload "auto"
|
||||
|
|
@ -391,9 +394,16 @@
|
|||
(scene/link-local @(rf/subscribe [::subs/scene]) @(rf/subscribe [::subs/context])
|
||||
{:ref (keyword ref) :at (js/parseInt at 10)}))
|
||||
|
||||
(defn- goto-link! [local]
|
||||
(when local
|
||||
(goto! local true)))
|
||||
(defn- ann-scroll-to?
|
||||
"Does group `a` opt into vertical scroll-to-clip when navigated to?"
|
||||
[a] (boolean (get-in a [:meta :scroll-to])))
|
||||
|
||||
(defn- ref-scroll-to? [scene ref]
|
||||
(ann-scroll-to? (get-in scene [:groups (keyword ref)])))
|
||||
|
||||
(defn- goto-link!
|
||||
([local] (goto-link! local false))
|
||||
([local scroll-to?] (when local (goto! local true scroll-to?))))
|
||||
|
||||
(defn content-display
|
||||
"Read-only render of annotation `content`: markdown blocks (headings, lists,
|
||||
|
|
@ -410,7 +420,7 @@
|
|||
(let [lf (scene/link-local scene ctx {:ref ref :at at})]
|
||||
[:span.link-chip {:class (when-not lf "broken")
|
||||
:title (when-not lf "linked clip no longer in this timeline")
|
||||
:on-click #(goto-link! lf)}
|
||||
:on-click #(goto-link! lf (ref-scroll-to? scene ref))}
|
||||
(when-not lf "△ ") label
|
||||
(when lf [:span.link-f (str " " (js/Math.round lf) "f")])])))))
|
||||
|
||||
|
|
@ -483,7 +493,8 @@
|
|||
:on-input emit :on-key-up save! :on-mouse-up save! :on-blur save!
|
||||
:on-click (fn [e] (when-let [chip (.closest (.-target e) ".link-chip")]
|
||||
(when-let [lf (link-frame (.. chip -dataset -ref) (.. chip -dataset -at))]
|
||||
(goto-link! lf))))}]))
|
||||
(goto-link! lf (ref-scroll-to? @(rf/subscribe [::subs/scene])
|
||||
(.. chip -dataset -ref))))))}]))
|
||||
|
||||
(defn- point-candidates [scene ctx q timelines?]
|
||||
(let [needle (str/lower-case q)
|
||||
|
|
@ -649,9 +660,10 @@
|
|||
than one bar) — a button that opens a popover of one target per piece, each
|
||||
labelled with the clip + frame it lands on (as the annotation editor shows it)."
|
||||
[open a scene segs]
|
||||
(let [bars (:bars a)]
|
||||
(let [bars (:bars a)
|
||||
scroll? (ref-scroll-to? scene (:id a))]
|
||||
(if (< (count bars) 2)
|
||||
[:button.jump-btn {:on-click #(goto! (:start a) true)} "↪ jump"]
|
||||
[:button.jump-btn {:on-click #(goto! (:start a) true scroll?)} "↪ jump"]
|
||||
[:span {:style {:position "relative"}}
|
||||
[:button.jump-btn {:on-click #(swap! open (fn [x] (when (not= x (:id a)) (:id a))))}
|
||||
(str "↪ jump (" (count bars) ") ▾")]
|
||||
|
|
@ -659,7 +671,7 @@
|
|||
[:div.jump-pop
|
||||
(for [[i [lo _]] (map-indexed vector bars)]
|
||||
^{:key i}
|
||||
[:button {:on-click #(do (goto! lo true) (reset! open nil))}
|
||||
[:button {:on-click #(do (goto! lo true scroll?) (reset! open nil))}
|
||||
(str "▸ " (clip-at scene segs lo))])])])))
|
||||
|
||||
(defn commentary []
|
||||
|
|
@ -746,11 +758,16 @@
|
|||
[:form.form {:on-submit (fn [e] (.preventDefault e) (save))}
|
||||
[:div.form-head (cond root? "Edit description" new? "New annotation" :else "Edit annotation")]
|
||||
(when-not root?
|
||||
[:<>
|
||||
[:div.form-row
|
||||
[:input.form-name {:placeholder "Name" :value (:name d)
|
||||
:on-change #(put (assoc d :name (.. % -target -value)))}]
|
||||
[:input.form-color {:type "color" :value (:color d)
|
||||
:on-change #(put (assoc d :color (.. % -target -value)))}]])
|
||||
:on-change #(put (assoc d :color (.. % -target -value)))}]]
|
||||
[:label.form-check {:title "When you jump to this annotation, scroll the tracks to its clips"}
|
||||
[:input {:type "checkbox" :checked (boolean (get-in d [:meta :scroll-to]))
|
||||
:on-change #(put (assoc-in d [:meta :scroll-to] (.. % -target -checked)))}]
|
||||
[:span "Scroll to clips on jump"]]])
|
||||
[:div.form-marks-label "Content"]
|
||||
^{:key gid} [content-editor gid (:content orig)]
|
||||
(if (and linking (= gid (:gid linking)))
|
||||
|
|
@ -905,7 +922,8 @@
|
|||
(let [[x0 y0 x1 y1] rect]
|
||||
[:div.script-hl {:title (:name a) :data-ann (name (:id a))
|
||||
:on-mouse-down #(.stopPropagation %)
|
||||
:on-click #(goto! (:start a) true) ; jump the timeline to this annotation
|
||||
:on-click #(goto! (:start a) true ; jump the timeline to this annotation
|
||||
(ref-scroll-to? @(rf/subscribe [::subs/scene]) (:id a)))
|
||||
:style {:left (* x0 w) :top (* y0 h)
|
||||
:width (* (- x1 x0) w) :height (* (- y1 y0) h)
|
||||
:background (str (:color a) "44") :border (str "1.5px solid " (:color a))}}]))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue