diff --git a/package-lock.json b/package-lock.json
index d8e7e043..a2e6bef3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,13 +21,13 @@
},
"devDependencies": {
"@mdn/browser-compat-data": "5.4.1",
- "@playwright/test": "^1.39.0",
+ "@playwright/test": "1.39.0",
"@radix-ui/react-context-menu": "2.1.5",
"@radix-ui/react-dropdown-menu": "2.0.6",
"@radix-ui/react-menubar": "1.0.4",
"@radix-ui/react-popover": "1.0.7",
"@radix-ui/react-select": "1.2.2",
- "@radix-ui/react-switch": "^1.0.3",
+ "@radix-ui/react-switch": "1.0.3",
"@radix-ui/react-tooltip": "1.0.7",
"@re-path/react-color": "2.19.4",
"@sentry/react": "7.66.0",
diff --git a/resources/public/icons/go-to-end.svg b/resources/public/icons/go-to-end.svg
new file mode 100644
index 00000000..386b8d00
--- /dev/null
+++ b/resources/public/icons/go-to-end.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/public/icons/go-to-start.svg b/resources/public/icons/go-to-start.svg
new file mode 100644
index 00000000..9dc73e38
--- /dev/null
+++ b/resources/public/icons/go-to-start.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/renderer/db.cljs b/src/renderer/db.cljs
index 2dab5505..550ea4aa 100644
--- a/src/renderer/db.cljs
+++ b/src/renderer/db.cljs
@@ -52,7 +52,6 @@
:visible? true}
:properties {:size 300
:visible? true}
- :history? false
:timeline {:visible? true}
:xml {:visible? false}
:repl-history {:visible? false}}
@@ -61,6 +60,7 @@
:fullscreen? false
:header? true}
:timeline {:time 0
+ :replay? true
:grid-snap? false
:guide-snap? true
:paused? false}})
diff --git a/src/renderer/reepl/views.cljs b/src/renderer/reepl/views.cljs
index 0b318522..7ae8e3c7 100644
--- a/src/renderer/reepl/views.cljs
+++ b/src/renderer/reepl/views.cljs
@@ -18,7 +18,7 @@
(replumb/print-doc doc)))))
(defn main-view []
- [:div.flex.flex-col {:style {:overflow "visible"}}
+ [:div.flex.flex-col.overflow-visible
[reepl/repl
:execute #(replumb/run-repl (if (= @(rf/subscribe [:repl-mode]) :cljs) %1 (str "(js/eval \"" %1 "\")")) {:warning-as-error true} %2)
:complete-word replumb/process-apropos
diff --git a/src/renderer/timeline/events.cljs b/src/renderer/timeline/events.cljs
index 34f9af1d..0e78254a 100644
--- a/src/renderer/timeline/events.cljs
+++ b/src/renderer/timeline/events.cljs
@@ -49,3 +49,8 @@
:timeline/set-guide-snap
(fn [db [_ state]]
(assoc-in db [:timeline :guide-snap?] state)))
+
+ (rf/reg-event-db
+ :timeline/toggle-replay
+ (fn [db _]
+ (update-in db [:timeline :replay?] not)))
diff --git a/src/renderer/timeline/styles.css b/src/renderer/timeline/styles.css
index 0323b589..b96d6e5c 100644
--- a/src/renderer/timeline/styles.css
+++ b/src/renderer/timeline/styles.css
@@ -1,7 +1,7 @@
.timeline-editor {
- @apply level-1 w-full !important;
- height: 200px !important;
+ @apply level-1 w-full min-h-0 !important;
font-family: inherit !important;
+ color: var(--font-color-muted) !important;
}
.timeline-editor-action {
@@ -20,7 +20,15 @@
fill: var(--accent) !important;
}
+.timeline-editor-time-unit {
+ border-color: var(--border-color) !important;
+}
+
+.timeline-editor-time-unit-scale {
+ color: var(--font-color-muted) !important;
+}
+
.timeline-editor-edit-row {
background-image: linear-gradient(var(--level-1), var(--level-1)),
- linear-gradient(90deg, rgba(255, 255, 255, 0.08) 1px, transparent 0) !important;
+ linear-gradient(90deg, var(--border-color) 1px, transparent 0) !important;
}
diff --git a/src/renderer/timeline/subs.cljs b/src/renderer/timeline/subs.cljs
index 2126603c..7e161cf3 100644
--- a/src/renderer/timeline/subs.cljs
+++ b/src/renderer/timeline/subs.cljs
@@ -37,6 +37,12 @@
(mapv animation->timeline-row)
clj->js)))
+(rf/reg-sub
+ :timeline/end
+ :<- [:animations]
+ (fn [animations]
+ (reduce #(max (js/parseInt (-> %2 :attrs :end)) %1) 0 animations)))
+
(defn animation->effect
[{:keys [attrs] :as el}]
{:id (effect-id el)
@@ -55,10 +61,15 @@
(-> n str js/parseInt str (.padStart 2 "0")))
(rf/reg-sub
- :timeline/time-formatted
+ :timeline/time
(fn [db _]
- (let [time (-> db :timeline :time)
- min (-> time (/ 60) pad-2)
+ (-> db :timeline :time)))
+
+(rf/reg-sub
+ :timeline/time-formatted
+ :<- [:timeline/time]
+ (fn [time]
+ (let [min (-> time (/ 60) pad-2)
sec (-> time (rem 60) pad-2)
ms (-> time (rem 1) (* 100) pad-2 (str/replace "0." ""))]
(str min ":" sec ":" ms))))
@@ -77,3 +88,8 @@
:timeline/guide-snap?
(fn [db _]
(-> db :timeline :guide-snap?)))
+
+(rf/reg-sub
+ :timeline/replay?
+ (fn [db _]
+ (-> db :timeline :replay?)))
diff --git a/src/renderer/timeline/views.cljs b/src/renderer/timeline/views.cljs
index 6ae55635..9419a7db 100644
--- a/src/renderer/timeline/views.cljs
+++ b/src/renderer/timeline/views.cljs
@@ -7,18 +7,11 @@
[reagent.core :as ra]
[renderer.components :as comp]))
-(defn toolbar
- [editor-ref]
- (let [time @(rf/subscribe [:timeline/time-formatted])
- paused? @(rf/subscribe [:timeline/paused?])
- grid-snap? @(rf/subscribe [:timeline/grid-snap?])
+(defn snap-controls
+ []
+ (let [grid-snap? @(rf/subscribe [:timeline/grid-snap?])
guide-snap? @(rf/subscribe [:timeline/guide-snap?])]
- [:div.toolbar.level-1
- (if paused?
- [comp/icon-button "play" {:on-click #(.play (.-current editor-ref))}]
- [comp/icon-button "pause" {:on-click #(.pause (.-current editor-ref))}])
- [:span.p-2.font-mono time]
- [:span.v-divider]
+ [:<>
[:span.inline-flex.items-center
[:label
{:for "grid-snap"
@@ -36,7 +29,7 @@
{:for "guide-snap"
:style {:background "transparent"
:height "auto"}}
- "Line snap"]
+ "Guide snap"]
[:> Switch/Root
{:class "switch-root"
:id "guide-snap"
@@ -44,6 +37,41 @@
:on-checked-change #(rf/dispatch [:timeline/set-guide-snap %])}
[:> Switch/Thumb {:class "switch-thumb"}]]]]))
+(defn toolbar
+ [editor-ref]
+ (let [time @(rf/subscribe [:timeline/time])
+ time-formatted @(rf/subscribe [:timeline/time-formatted])
+ paused? @(rf/subscribe [:timeline/paused?])
+ replay? @(rf/subscribe [:timeline/replay?])
+ end @(rf/subscribe [:timeline/end])
+ timeline? @(rf/subscribe [:panel/visible? :timeline])]
+ [:div.toolbar.level-1.mb-px
+ [:div.flex-1.flex
+ [comp/icon-button "go-to-start" {:on-click #(.setTime (.-current editor-ref) 0)
+ :disabled (zero? time)}]
+ (if paused?
+ [comp/icon-button "play" {:on-click #(.play (.-current editor-ref) #js {:autoEnd true})}]
+ [comp/icon-button "pause" {:on-click #(.pause (.-current editor-ref))}])
+ [comp/icon-button "go-to-end" {:on-click #(.setTime (.-current editor-ref) end)
+ :disabled (>= time end)}]
+ [comp/radio-icon-button
+ {:title "Replay"
+ :active? replay?
+ :icon "refresh"
+ :action #(rf/dispatch [:timeline/toggle-replay])}]
+ [:span.p-2.font-mono time-formatted]
+ (when timeline?
+ [:<>
+ [:span.v-divider]
+ [snap-controls]])]
+ [comp/toggle-icon-button
+ {:active? (not timeline?)
+ :active-icon "chevron-up"
+ :active-text "Show timeline"
+ :inactive-icon "times"
+ :inactive-text "Hide timeline"
+ :action #(rf/dispatch [:panel/toggle :timeline])}]]))
+
(defn root
[]
(let [ref (react/createRef)]
@@ -56,6 +84,9 @@
[[e f]
[["play" #(rf/dispatch-sync [:timeline/play])] ;; Prevent navigation
["paused" #(rf/dispatch-sync [:timeline/pause])]
+ ["ended" #(when @(rf/subscribe [:timeline/replay?])
+ (.setTime (.-current ref) 0)
+ (.play (.-current ref) #js {:autoEnd true}))]
["afterSetTime" #(rf/dispatch-sync [:timeline/set-time (.-time %)])]
["setTimeByTick" #(rf/dispatch-sync [:timeline/set-time (.-time %)])]]]
(.on (.-listener (.-current ref)) e f)))
@@ -68,10 +99,12 @@
(let [data @(rf/subscribe [:timeline/rows])
effects @(rf/subscribe [:timeline/effects])
grid-snap? @(rf/subscribe [:timeline/grid-snap?])
- guide-snap? @(rf/subscribe [:timeline/guide-snap?])]
+ guide-snap? @(rf/subscribe [:timeline/guide-snap?])
+ timeline? @(rf/subscribe [:panel/visible? :timeline])]
[:div
[toolbar ref]
- [:> Timeline {:editor-data data
+ [:> Timeline {:style {:height (if timeline? "200px" 0)}
+ :editor-data data
:effects effects
:ref ref
:grid-snap grid-snap?
diff --git a/src/renderer/tools/animate_motion.cljs b/src/renderer/tools/animate_motion.cljs
index 99e99378..9865a7ea 100644
--- a/src/renderer/tools/animate_motion.cljs
+++ b/src/renderer/tools/animate_motion.cljs
@@ -9,4 +9,6 @@
[]
{:description "The SVG element let define how an element
moves along a motion path."
- :attrs []})
+ :attrs [:keyPoints
+ :path
+ :rotate]})
diff --git a/src/renderer/tools/animate_transform.cljs b/src/renderer/tools/animate_transform.cljs
index f7018129..9b239b0c 100644
--- a/src/renderer/tools/animate_transform.cljs
+++ b/src/renderer/tools/animate_transform.cljs
@@ -10,4 +10,7 @@
{:description "The animateTransform element animates a transformation
attribute on its target element, thereby allowing animations
to control translation, scaling, rotation, and/or skewing."
- :attrs []})
+ :attrs [:type
+ :from
+ :to
+ :by]})