diff --git a/frontend/src/app/main/data/shortcuts.cljs b/frontend/src/app/main/data/shortcuts.cljs index 850380517c..e3eb7810d0 100644 --- a/frontend/src/app/main/data/shortcuts.cljs +++ b/frontend/src/app/main/data/shortcuts.cljs @@ -5,14 +5,22 @@ ;; Copyright (c) UXBOX Labs SL (ns app.main.data.shortcuts + (:refer-clojure :exclude [meta reset!]) (:require ["mousetrap" :as mousetrap] + [app.common.data :as d] + [app.common.spec :as us] [app.config :as cfg] - [app.util.logging :as log]) - (:refer-clojure :exclude [meta])) + [app.util.logging :as log] + [cljs.spec.alpha :as s] + [potok.core :as ptk])) (log/set-level! :warn) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Helpers +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (def mac-command "\u2318") (def mac-option "\u2325") (def mac-delete "\u232B") @@ -44,30 +52,8 @@ [shortcut] (c-mod (a-mod shortcut))) -(defn bind-shortcuts - ([shortcuts-config] - (bind-shortcuts - shortcuts-config - mousetrap/bind - (fn [key cb] - (fn [event] - (log/debug :msg (str "Shortcut" key)) - (.preventDefault event) - (cb event))))) - - ([shortcuts-config bind-fn cb-fn] - (doseq [[key {:keys [command disabled fn type]}] shortcuts-config] - (when-not disabled - (if (vector? command) - (doseq [cmd (seq command)] - (bind-fn cmd (cb-fn key fn) type)) - (bind-fn command (cb-fn key fn) type)))))) - -(defn remove-shortcuts - [] - (mousetrap/reset)) - -(defn meta [key] +(defn meta + [key] ;; If the key is "+" we need to surround with quotes ;; otherwise will not be very readable (let [key (if (and (not (cfg/check-platform? :macos)) @@ -80,37 +66,120 @@ "Ctrl+") key))) -(defn shift [key] +(defn shift + [key] (str (if (cfg/check-platform? :macos) mac-shift "Shift+") key)) -(defn alt [key] +(defn alt + [key] (str (if (cfg/check-platform? :macos) mac-option "Alt+") key)) -(defn meta-shift [key] +(defn meta-shift + [key] (-> key meta shift)) -(defn meta-alt [key] +(defn meta-alt + [key] (-> key meta alt)) -(defn supr [] +(defn supr + [] (if (cfg/check-platform? :macos) mac-delete "Supr")) -(defn esc [] +(defn esc + [] (if (cfg/check-platform? :macos) mac-esc "Escape")) -(defn enter [] +(defn enter + [] (if (cfg/check-platform? :macos) mac-enter "Enter")) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Events +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; --- EVENT: push + +(s/def ::tooltip ::us/string) +(s/def ::fn fn?) + +(s/def ::command + (s/or :str ::us/string + :vec vector?)) + +(s/def ::shortcut + (s/keys :req-un [::command] + :opt-un [::fn + ::tooltip])) + +(s/def ::shortcuts + (s/map-of ::us/keyword + ::shortcut)) + +(defn- wrap-cb + [key cb] + (fn [event] + (log/debug :msg (str "Shortcut" key)) + (.preventDefault event) + (cb event))) + +(defn- bind! + [shortcuts] + (->> shortcuts + (remove #(:disabled (second %))) + (run! (fn [[key {:keys [command fn type]}]] + (if (vector? command) + (run! #(mousetrap/bind % (wrap-cb key fn) type) command) + (mousetrap/bind command (wrap-cb key fn) type)))))) + +(defn- reset! + ([] + (mousetrap/reset)) + ([shortcuts] + (mousetrap/reset) + (bind! shortcuts))) + +(defn push-shortcuts + [key shortcuts] + (us/assert ::us/keyword key) + (us/assert ::shortcuts shortcuts) + (ptk/reify ::push-shortcuts + ptk/UpdateEvent + (update [_ state] + (-> state + (update :shortcuts (fnil conj '()) [key shortcuts]))) + + ptk/EffectEvent + (effect [_ state stream] + (let [[key shortcuts] (peek (:shortcuts state))] + (reset! shortcuts))))) + +(defn pop-shortcuts + [key] + (ptk/reify ::pop-shortcuts + ptk/UpdateEvent + (update [_ state] + (update state :shortcuts (fn [shortcuts] + (let [current-key (first (peek shortcuts))] + (if (= key current-key) + (pop shortcuts) + shortcuts))))) + ptk/EffectEvent + (effect [_ state stream] + (let [[key* shortcuts] (peek (:shortcuts state))] + (when (not= key key*) + (reset! shortcuts)))))) diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs index 64b41594f5..7d2fe9bf4f 100644 --- a/frontend/src/app/main/data/workspace/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/shortcuts.cljs @@ -33,7 +33,7 @@ :toggle-assets {:tooltip (ds/alt "I") :command (ds/a-mod "i") :fn #(st/emit! (dw/go-to-layout :assets))} - + :toggle-history {:tooltip (ds/alt "H") :command (ds/a-mod "h") :fn #(st/emit! (dw/go-to-layout :document-history))} @@ -45,7 +45,7 @@ :toggle-rules {:tooltip (ds/meta-shift "R") :command (ds/c-mod "shift+r") :fn #(st/emit! (dw/toggle-layout-flags :rules))} - + :select-all {:tooltip (ds/meta "A") :command (ds/c-mod "a") :fn #(st/emit! (dw/select-all))} @@ -73,7 +73,7 @@ :decrease-zoom {:tooltip "-" :command "-" :fn #(st/emit! (dw/decrease-zoom nil))} - + :group {:tooltip (ds/meta "G") :command (ds/c-mod "g") :fn #(st/emit! dw/group-selected)} @@ -173,7 +173,8 @@ :paste {:tooltip (ds/meta "V") :disabled true - :command (ds/c-mod "v")} + :command (ds/c-mod "v") + :fn (constantly nil)} :delete {:tooltip (ds/supr) :command ["del" "backspace"] diff --git a/frontend/src/app/main/ui/handoff.cljs b/frontend/src/app/main/ui/handoff.cljs index 0fd4817711..ee82788f08 100644 --- a/frontend/src/app/main/ui/handoff.cljs +++ b/frontend/src/app/main/ui/handoff.cljs @@ -91,7 +91,7 @@ (events/unlistenByKey key1))))] (mf/use-effect on-mount) - (hooks/use-shortcuts sc/shortcuts) + (hooks/use-shortcuts ::handoff sc/shortcuts) [:div.handoff-layout {:class (dom/classnames :force-visible (:show-thumbnails state))} diff --git a/frontend/src/app/main/ui/hooks.cljs b/frontend/src/app/main/ui/hooks.cljs index bc2a8fd2df..5b0b0645e8 100644 --- a/frontend/src/app/main/ui/hooks.cljs +++ b/frontend/src/app/main/ui/hooks.cljs @@ -9,10 +9,11 @@ (:require [app.common.spec :as us] [app.main.data.shortcuts :as dsc] + [app.main.store :as st] [app.util.dom :as dom] - [app.util.object :as obj] [app.util.dom.dnd :as dnd] [app.util.logging :as log] + [app.util.object :as obj] [app.util.timers :as ts] [app.util.transit :as t] [app.util.webapi :as wapi] @@ -35,11 +36,13 @@ state)) (defn use-shortcuts - [shortcuts] + [key shortcuts] (mf/use-effect + #js [(str key) shortcuts] (fn [] - (dsc/bind-shortcuts shortcuts) - (fn [] (dsc/remove-shortcuts))))) + (st/emit! (dsc/push-shortcuts key shortcuts)) + (fn [] + (st/emit! (dsc/pop-shortcuts key)))))) (defn invisible-image [] diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index bbb9404134..930968526a 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -237,7 +237,7 @@ (events/unlistenByKey key3))))] (mf/use-effect on-mount) - (hooks/use-shortcuts sc/shortcuts) + (hooks/use-shortcuts ::viewer sc/shortcuts) [:div.viewer-layout {:class (dom/classnames :force-visible (:show-thumbnails state))} diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index d5837c2e45..c79651342e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -153,18 +153,6 @@ (utils/update-transform render-node roots modifiers) (utils/remove-transform render-node roots)))))) -(defn setup-shortcuts [path-editing? drawing-path?] - (mf/use-effect - (mf/deps path-editing? drawing-path?) - (fn [] - (cond - (or drawing-path? path-editing?) - (dsc/bind-shortcuts psc/shortcuts) - - :else - (dsc/bind-shortcuts wsc/shortcuts)) - dsc/remove-shortcuts))) - (defn inside-vbox [vbox objects frame-id] (let [frame (get objects frame-id)] @@ -195,3 +183,17 @@ (:frame-id @hover))] (when (not (contains? @active-frames frame-id)) (swap! active-frames assoc frame-id true)))))) + +;; NOTE: this is executed on each page change, maybe we need to move +;; this shortcuts outside the viewport? + +(defn setup-shortcuts + [path-editing? drawing-path?] + (hooks/use-shortcuts ::workspace wsc/shortcuts) + + (mf/use-effect + (mf/deps path-editing? drawing-path?) + (fn [] + (when (or drawing-path? path-editing?) + (st/emit! (dsc/push-shortcuts ::path psc/shortcuts)) + (st/emitf (dsc/pop-shortcuts ::path))))))