feat: add hidden annotation meta for decluttering timeline
Add 'hidden' meta flag to annotations to hide them from the timeline lane while keeping them available for linking. Hidden annotations appear as small 6px colored rectangles with faint color and dither pattern overlay. Click on a hidden rectangle to unhide it. Hidden annotations' marks are not resolved/used, and they don't trigger scroll-to-clip during playback. Add 'Hide from timeline' checkbox in annotation create/edit form. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e964347e51
commit
1ea675567c
2 changed files with 34 additions and 9 deletions
|
|
@ -83,16 +83,18 @@
|
||||||
(->> (:groups scene)
|
(->> (:groups scene)
|
||||||
(keep (fn [[gid g]]
|
(keep (fn [[gid g]]
|
||||||
(when (and (= :annotation (:type g)) (= ctx (:parent g)))
|
(when (and (= :annotation (:type g)) (= ctx (:parent g)))
|
||||||
(let [src-segs (scene/resolve scene gid)
|
(let [src-segs (when-not (get-in g [:meta :hidden]) (scene/resolve scene gid))
|
||||||
bars (scene/merge-bars
|
bars (scene/merge-bars
|
||||||
(mapcat (fn [{[a b] :src}] (scene/pieces segs a b)) src-segs))
|
(mapcat (fn [{[a b] :src}] (scene/pieces segs a b)) src-segs))
|
||||||
reason (scene/broken-reason scene gid)]
|
reason (scene/broken-reason scene gid)
|
||||||
|
hidden (get-in g [:meta :hidden])]
|
||||||
{:id gid :name (:name g) :color (or (:color g) "#4e8fc2")
|
{:id gid :name (:name g) :color (or (:color g) "#4e8fc2")
|
||||||
:content (:content g) :children (count (:marks g))
|
:content (:content g) :children (count (:marks g))
|
||||||
:nested (get nested gid 0)
|
:nested (get nested gid 0)
|
||||||
:draft (boolean (:draft g))
|
:draft (boolean (:draft g))
|
||||||
:script (:script g) ; pdf highlights linked to this group
|
:script (:script g) ; pdf highlights linked to this group
|
||||||
:broken (boolean reason) :reason reason
|
:broken (boolean reason) :reason reason
|
||||||
|
:hidden (boolean hidden)
|
||||||
:start (or (ffirst bars) 0) :bars bars}))))
|
:start (or (ffirst bars) 0) :bars bars}))))
|
||||||
(sort-by (juxt :broken :start)) ; broken annotations sink to the bottom
|
(sort-by (juxt :broken :start)) ; broken annotations sink to the bottom
|
||||||
vec))))
|
vec))))
|
||||||
|
|
|
||||||
|
|
@ -377,11 +377,12 @@
|
||||||
(reset! scrolled-on-load? true)
|
(reset! scrolled-on-load? true)
|
||||||
(scroll-to-seg-track! segs playhead))
|
(scroll-to-seg-track! segs playhead))
|
||||||
;; clip-following: only while the playhead is actually inside a bar of
|
;; clip-following: only while the playhead is actually inside a bar of
|
||||||
;; an annotation that opts in (:meta :scroll-to) — scroll each of its
|
;; an annotation that opts in (:meta :scroll-to) and is not hidden —
|
||||||
;; clips into view as the playhead crosses onto a new bar (discontinuity).
|
;; scroll each of its clips into view as the playhead crosses onto a new bar (discontinuity).
|
||||||
;; Track [ann-id bar-idx] to avoid scrolling within the same bar.
|
;; Track [ann-id bar-idx] to avoid scrolling within the same bar.
|
||||||
(when-let [current-bar (some (fn [a]
|
(when-let [current-bar (some (fn [a]
|
||||||
(when (and (ann-scroll-to? (get-in scene [:groups (:id a)]))
|
(when (and (not (get-in (get-in scene [:groups (:id a)]) [:meta :hidden]))
|
||||||
|
(ann-scroll-to? (get-in scene [:groups (:id a)]))
|
||||||
(some (fn [[lo hi]] (<= lo playhead hi)) (:bars a)))
|
(some (fn [[lo hi]] (<= lo playhead hi)) (:bars a)))
|
||||||
[(:id a) (first (keep-indexed (fn [j [lo hi]]
|
[(:id a) (first (keep-indexed (fn [j [lo hi]]
|
||||||
(when (<= lo playhead hi) j))
|
(when (<= lo playhead hi) j))
|
||||||
|
|
@ -414,7 +415,8 @@
|
||||||
[:div.ann-lanes {:style {:height lane-h :width width}
|
[:div.ann-lanes {:style {:height lane-h :width width}
|
||||||
:on-mouse-down #(scrub! @content fps zoom %)}
|
:on-mouse-down #(scrub! @content fps zoom %)}
|
||||||
;; annotation bars — solid for saved, dashed for the in-progress draft
|
;; annotation bars — solid for saved, dashed for the in-progress draft
|
||||||
(for [[i a] (map-indexed vector anns)
|
;; visible annotations: full bars with labels
|
||||||
|
(for [[i a] (map-indexed vector (filter (fn [a] (not (get-in (get-in scene [:groups (:id a)]) [:meta :hidden]))) anns))
|
||||||
[j [lo hi]] (map-indexed vector (:bars a))]
|
[j [lo hi]] (map-indexed vector (:bars a))]
|
||||||
^{:key (str (:id a) "-" j)}
|
^{:key (str (:id a) "-" j)}
|
||||||
[:div.ann-bar {:title (:name a)
|
[:div.ann-bar {:title (:name a)
|
||||||
|
|
@ -430,10 +432,27 @@
|
||||||
:cursor (if (:draft a) "default" "pointer")
|
:cursor (if (:draft a) "default" "pointer")
|
||||||
:border-radius 2
|
:border-radius 2
|
||||||
:border (str (if (:draft a) "1px dashed " "1px solid ") (:color a))}}])
|
:border (str (if (:draft a) "1px dashed " "1px solid ") (:color a))}}])
|
||||||
(for [[i a] (map-indexed vector anns) :let [[lo _] (first (:bars a))] :when lo]
|
;; visible annotation labels
|
||||||
|
(for [[i a] (map-indexed vector (filter (fn [a] (not (get-in (get-in scene [:groups (:id a)]) [:meta :hidden]))) anns)) :let [[lo _] (first (:bars a))] :when lo]
|
||||||
^{:key (str "lbl-" (:id a))}
|
^{:key (str "lbl-" (:id a))}
|
||||||
[:div.ann-bar-label {:style {:top (* i 18)
|
[:div.ann-bar-label {:style {:top (* i 18)
|
||||||
:left (+ 4 (px lo fps zoom))}} (:name a)])]]]
|
:left (+ 4 (px lo fps zoom))}} (:name a)])
|
||||||
|
;; hidden annotations: tiny colored dots with dither pattern — click to unhide
|
||||||
|
(for [[i a] (map-indexed vector (filter (fn [a] (get-in (get-in scene [:groups (:id a)]) [:meta :hidden])) anns)) :let [[lo _] (first (:bars a))] :when lo]
|
||||||
|
^{:key (str "hidden-" (:id a))}
|
||||||
|
[:div.ann-hidden {:title (str (:name a) " (click to unhide)")
|
||||||
|
:on-click #(do (.stopPropagation %)
|
||||||
|
(rf/dispatch [::events/put-group (:id a)
|
||||||
|
(update (get-in scene [:groups (:id a)])
|
||||||
|
:meta dissoc :hidden)]))
|
||||||
|
:style {:top (+ 6 (* i 18)) :height 6
|
||||||
|
:left (px lo fps zoom) :width 12
|
||||||
|
:background (str (:color a) "33")
|
||||||
|
:cursor "pointer"
|
||||||
|
:border-radius 1
|
||||||
|
:border (str "1px solid " (:color a) "88")
|
||||||
|
:background-image "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2' height='2'%3E%3Crect width='2' height='2' fill='%23ffffff'/%3E%3Crect width='1' height='1' fill='%23000000'/%3E%3Crect x='1' y='1' width='1' height='1' fill='%23000000'/%3E%3C/svg%3E\")"
|
||||||
|
:background-size "2px 2px"}}])]]]
|
||||||
[:div.timeline-body-scroll {:ref (fn [n] (reset! body-scroll-el n))
|
[:div.timeline-body-scroll {:ref (fn [n] (reset! body-scroll-el n))
|
||||||
:style {:padding-top (+ lane-h 24)}}
|
:style {:padding-top (+ lane-h 24)}}
|
||||||
[:div.gutter-tracks
|
[:div.gutter-tracks
|
||||||
|
|
@ -846,7 +865,11 @@
|
||||||
[:label.form-check {:title "During playback, scroll each of this annotation's clips into view as the playhead reaches it"}
|
[:label.form-check {:title "During playback, scroll each of this annotation's clips into view as the playhead reaches it"}
|
||||||
[:input {:type "checkbox" :checked (boolean (get-in d [:meta :scroll-to]))
|
[:input {:type "checkbox" :checked (boolean (get-in d [:meta :scroll-to]))
|
||||||
:on-change #(put (assoc-in d [:meta :scroll-to] (.. % -target -checked)))}]
|
:on-change #(put (assoc-in d [:meta :scroll-to] (.. % -target -checked)))}]
|
||||||
[:span "Follow clips during playback"]]])
|
[:span "Follow clips during playback"]]
|
||||||
|
[:label.form-check {:title "Hide this annotation from the timeline lane (still usable in links)"}
|
||||||
|
[:input {:type "checkbox" :checked (boolean (get-in d [:meta :hidden]))
|
||||||
|
:on-change #(put (assoc-in d [:meta :hidden] (.. % -target -checked)))}]
|
||||||
|
[:span "Hide from timeline"]]])
|
||||||
[:div.form-marks-label "Content"]
|
[:div.form-marks-label "Content"]
|
||||||
^{:key gid} [content-editor gid (:content orig)]
|
^{:key gid} [content-editor gid (:content orig)]
|
||||||
(if (and linking (= gid (:gid linking)))
|
(if (and linking (= gid (:gid linking)))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue