diff --git a/frontend/src/arthur/domain/nest.cljs b/frontend/src/arthur/domain/nest.cljs index 42c82df..598f2e6 100644 --- a/frontend/src/arthur/domain/nest.cljs +++ b/frontend/src/arthur/domain/nest.cljs @@ -144,6 +144,11 @@ [nodes id] (into #{} (filter #(some #{id} (symbol/lineage nodes %))) (keys nodes))) +(defn delete-node + "Take node `id` out of symbol `sid`, with everything hanging off it." + [clip sid id] + (clip/update-symbol clip sid update :nodes #(apply dissoc % (subtree % id)))) + (defn- transplant "Move node `id` from symbol `host`, where frame `frame` is showing, into symbol `target`, keeping where it is on screen and when. `carry` is the matrix from diff --git a/frontend/src/arthur/events/history.cljs b/frontend/src/arthur/events/history.cljs index 1ec8eb1..106b17a 100644 --- a/frontend/src/arthur/events/history.cljs +++ b/frontend/src/arthur/events/history.cljs @@ -7,6 +7,7 @@ [arthur.domain.leaf :as leaf] [arthur.events.edit :as edit] [arthur.events.playback :as pb] + [arthur.events.ui :as ui] [arthur.footage.store :as store] [re-frame.core :as rf])) @@ -66,16 +67,19 @@ (or (#{"INPUT" "TEXTAREA" "SELECT"} (.-tagName target)) (.-isContentEditable target))) (defn install-keys! - "⌘Z / Ctrl+Z undoes, with Shift redoes, and Ctrl+Y redoes. Not while typing - in a field, where the browser's own undo is the one wanted." + "⌘Z / Ctrl+Z undoes, with Shift redoes, and Ctrl+Y redoes; Delete or + Backspace deletes the selected node, which undo brings back. Not while typing + in a field, where the browser's own keys are the ones wanted." [] (.addEventListener js/window "keydown" (fn [^js e] - (when (and (or (.-metaKey e) (.-ctrlKey e)) (not (typing? (.-target e)))) + (when-not (typing? (.-target e)) (let [k (.toLowerCase (.-key e))] - (when-let [ev (cond (and (= k "z") (.-shiftKey e)) ::redo - (= k "z") ::undo - (= k "y") ::redo)] + (when-let [ev (if (or (.-metaKey e) (.-ctrlKey e)) + (cond (and (= k "z") (.-shiftKey e)) ::redo + (= k "z") ::undo + (= k "y") ::redo) + (when (#{"delete" "backspace"} k) ::ui/delete-selected))] (.preventDefault e) (rf/dispatch [ev]))))))) diff --git a/frontend/src/arthur/events/ui.cljs b/frontend/src/arthur/events/ui.cljs index e7d6d00..ca9e43c 100644 --- a/frontend/src/arthur/events/ui.cljs +++ b/frontend/src/arthur/events/ui.cljs @@ -195,6 +195,16 @@ (:refused r) (refused db (:refused r)) :else (edit/edit db (constantly (:clip r))))))) +(rf/reg-event-db + ::delete-selected + (fn [db _] + (let [[kind sid id] (get-in db [:ui :selection])] + (if (= :node kind) + (-> db + (edit/edit #(nest/delete-node % sid id)) + (assoc-in [:ui :selection] nil)) + db)))) + (rf/reg-event-db ::restack ;; Onto the edge of a row in another symbol, it goes into that symbol first: diff --git a/frontend/src/arthur/ui/timeline.cljs b/frontend/src/arthur/ui/timeline.cljs index 09e3d06..24eb3ea 100644 --- a/frontend/src/arthur/ui/timeline.cljs +++ b/frontend/src/arthur/ui/timeline.cljs @@ -259,7 +259,13 @@ (rf/dispatch [::ui/toggle-row path]))} (when expandable? (if expanded? "▾" "▸"))] [:span.name label] - (when node? [:span.kind (str "·" (name node-kind))])])) + (when node? [:span.kind (str "·" (name node-kind))]) + (when (and node? (= select selection)) + [:button.tl-delete {:title "delete, with everything in it (⌫)" + :on-click (fn [^js e] + (.stopPropagation e) + (rf/dispatch [::ui/delete-selected]))} + "×"])])) (defn- track-cell "`sliding` is the pointer's side of a bar being dragged, `{:path :x :width diff --git a/static/arthur/app.css b/static/arthur/app.css index 0081793..a92c9f4 100644 --- a/static/arthur/app.css +++ b/static/arthur/app.css @@ -618,6 +618,8 @@ button.share-button:hover, button.share-button.on { filter: brightness(1.1); } .tl-twist:hover:not(:disabled) { background: none; color: var(--fg); } .tl-twist:disabled { opacity: 0; cursor: default; } +.tl-delete { margin-left: auto; padding: 0 4px; border: 0; background: none; color: var(--dim); } +.tl-delete:hover { color: var(--fg); } .tl-ruler { position: relative;