Refactor of shortcuts and adaptations for macosx

This commit is contained in:
alonso.torres 2021-02-01 17:47:54 +01:00 committed by Hirunatan
parent 526e0afc70
commit 816db29f9c
19 changed files with 762 additions and 434 deletions

View file

@ -0,0 +1,75 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns app.main.data.shortcuts
(:require
[app.main.data.colors :as mdc]
[app.main.data.workspace.transforms :as dwt]
[app.main.store :as st]
[app.util.dom :as dom]
[potok.core :as ptk]
[beicon.core :as rx]
[app.config :as cfg])
(:refer-clojure :exclude [meta]))
(def mac-command "\u2318")
(def mac-option "\u2325")
(def mac-delete "\u232B")
(def mac-shift "\u21E7")
(def mac-control "\u2303")
(def mac-esc "\u238B")
(def left-arrow "\u2190")
(def up-arrow "\u2191")
(def right-arrow "\u2192")
(def down-arrow "\u2193")
(defn c-mod
"Adds the control/command modifier to a shortcuts depending on the
operating system for the user"
[shortcut]
(if (cfg/check-platform? :macos)
(str "command+" shortcut)
(str "ctrl+" shortcut)))
(defn bind-shortcuts [shortcuts bind-fn cb-fn]
(doseq [[key {:keys [command disabled fn]}] shortcuts]
(when-not disabled
(if (vector? command)
(doseq [cmd (seq command)]
(bind-fn cmd (cb-fn key fn)))
(bind-fn command (cb-fn key fn))))))
(defn meta [key]
(str
(if (cfg/check-platform? :macos)
mac-command
"Ctrl+")
key))
(defn shift [key]
(str
(if (cfg/check-platform? :macos)
mac-shift
"Shift+")
key))
(defn meta-shift [key]
(-> key meta shift))
(defn supr []
(if (cfg/check-platform? :macos)
mac-delete
"Supr"))
(defn esc []
(if (cfg/check-platform? :macos)
mac-esc
"Escape"))

View file

@ -415,15 +415,3 @@
(update [_ state]
(assoc-in state [:viewer-local :hover] (when hover? id)))))
;; --- Shortcuts
(def shortcuts
{"+" (st/emitf increase-zoom)
"-" (st/emitf decrease-zoom)
"ctrl+a" (st/emitf (select-all))
"shift+0" (st/emitf zoom-to-50)
"shift+1" (st/emitf reset-zoom)
"shift+2" (st/emitf zoom-to-200)
"left" (st/emitf select-prev-frame)
"right" (st/emitf select-next-frame)})

View file

@ -0,0 +1,57 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns app.main.data.viewer.shortcuts
(:require
[app.config :as cfg]
[app.main.data.colors :as mdc]
[app.main.data.shortcuts :as ds]
[app.main.data.shortcuts :refer [c-mod]]
[app.main.data.viewer :as dv]
[app.main.store :as st]
[app.util.dom :as dom]
[beicon.core :as rx]
[potok.core :as ptk]))
(def shortcuts
{:increase-zoom {:tooltip "+"
:command "+"
:fn (st/emitf dv/increase-zoom)}
:decrease-zoom {:tooltip "-"
:command "-"
:fn (st/emitf dv/decrease-zoom)}
:select-all {:tooltip (ds/meta "A")
:command (ds/c-mod "a")
:fn (st/emitf (dv/select-all))}
:zoom-50 {:tooltip (ds/shift "0")
:command "shift+0"
:fn (st/emitf dv/zoom-to-50)}
:reset-zoom {:tooltip (ds/shift "1")
:command "shift+1"
:fn (st/emitf dv/reset-zoom)}
:zoom-200 {:tooltip (ds/shift "2")
:command "shift+2"
:fn (st/emitf dv/zoom-to-200)}
:next-frame {:tooltip ds/left-arrow
:command "left"
:fn (st/emitf dv/select-prev-frame)}
:prev-frame {:tooltip ds/right-arrow
:command "right"
:fn (st/emitf dv/select-next-frame)}})
(defn get-tooltip [shortcut]
(assert (contains? shortcuts shortcut) (str shortcut))
(get-in shortcuts [shortcut :tooltip]))

View file

@ -9,14 +9,13 @@
(ns app.main.data.workspace
(:require
[goog.string.path :as path]
[app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.geom.align :as gal]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.geom.proportions :as gpr]
[app.common.geom.align :as gal]
[app.common.geom.shapes :as gsh]
[app.common.math :as mth]
[app.common.pages :as cp]
[app.common.pages.helpers :as cph]
@ -27,33 +26,33 @@
[app.main.data.colors :as mdc]
[app.main.data.messages :as dm]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.drawing :as dwd]
[app.main.data.workspace.drawing.path :as dwdp]
[app.main.data.workspace.groups :as dwg]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.notifications :as dwn]
[app.main.data.workspace.persistence :as dwp]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.texts :as dwtxt]
[app.main.data.workspace.transforms :as dwt]
[app.main.data.workspace.groups :as dwg]
[app.main.data.workspace.drawing :as dwd]
[app.main.data.workspace.drawing.path :as dwdp]
[app.main.repo :as rp]
[app.main.store :as st]
[app.main.streams :as ms]
[app.main.worker :as uw]
[app.util.dom :as dom]
[app.util.http :as http]
[app.util.i18n :refer [tr] :as i18n]
[app.util.logging :as log]
[app.util.object :as obj]
[app.util.router :as rt]
[app.util.timers :as ts]
[app.util.transit :as t]
[app.util.webapi :as wapi]
[app.util.i18n :refer [tr] :as i18n]
[app.util.object :as obj]
[app.util.dom :as dom]
[app.util.http :as http]
[beicon.core :as rx]
[cljs.spec.alpha :as s]
[clojure.set :as set]
[cuerdas.core :as str]
;; [cljs.pprint :refer [pprint]]
[goog.string.path :as path]
[potok.core :as ptk]))
;; (log/set-level! :trace)
@ -1225,20 +1224,26 @@
(defn go-to-viewer
[{:keys [file-id page-id] :as params}]
(ptk/reify ::go-to-viewer
ptk/WatchEvent
(watch [_ state stream]
(rx/of ::dwp/force-persist
(rt/nav :viewer params {:index 0})))))
([] (go-to-viewer {}))
([{:keys [file-id page-id]}]
(ptk/reify ::go-to-viewer
ptk/WatchEvent
(watch [_ state stream]
(let [{:keys [current-file-id current-page-id]} state
params {:file-id (or file-id current-file-id)
:page-id (or page-id current-page-id)}]
(rx/of ::dwp/force-persist
(rt/nav :viewer params {:index 0})))))))
(defn go-to-dashboard
[{:keys [team-id] :as project}]
(ptk/reify ::go-to-viewer
ptk/WatchEvent
(watch [_ state stream]
(rx/of ::dwp/force-persist
(rt/nav :dashboard-projects {:team-id team-id})))))
([] (go-to-dashboard nil))
([{:keys [team-id]}]
(ptk/reify ::go-to-dashboard
ptk/WatchEvent
(watch [_ state stream]
(let [team-id (or team-id (get-in state [:workspace-project :team-id]))]
(rx/of ::dwp/force-persist
(rt/nav :dashboard-projects {:team-id team-id})))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Context Menu
@ -1743,80 +1748,3 @@
(d/export dwg/unmask-group)
(d/export dwg/group-selected)
(d/export dwg/ungroup-selected)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shortcuts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shortcuts impl https://github.com/ccampbell/mousetrap
(defn esc-pressed []
(ptk/reify :esc-pressed
ptk/WatchEvent
(watch [_ state stream]
;; Not interrupt when we're editing a path
(let [edition-id (or (get-in state [:workspace-drawing :object :id])
(get-in state [:workspace-local :edition]))
path-edit-mode (get-in state [:workspace-local :edit-path edition-id :edit-mode])]
(if-not (= :draw path-edit-mode)
(rx/of :interrupt (deselect-all true))
(rx/empty))))))
(defn c-mod
"Adds the control/command modifier to a shortcuts depending on the
operating system for the user"
[shortcut]
(if (cfg/check-platform? :macos)
(str "command+" shortcut)
(str "ctrl+" shortcut)))
(def shortcuts
{(c-mod "i") #(st/emit! (toggle-layout-flags :assets))
(c-mod "l") #(st/emit! (toggle-layout-flags :sitemap :layers))
(c-mod "shift+r") #(st/emit! (toggle-layout-flags :rules))
(c-mod "a") #(st/emit! (select-all))
(c-mod "p") #(st/emit! (toggle-layout-flags :colorpalette))
(c-mod "'") #(st/emit! (toggle-layout-flags :display-grid))
(c-mod "shift+'") #(st/emit! (toggle-layout-flags :snap-grid))
"+" #(st/emit! (increase-zoom nil))
"-" #(st/emit! (decrease-zoom nil))
(c-mod "g") #(st/emit! group-selected)
"shift+g" #(st/emit! ungroup-selected)
(c-mod "m") #(st/emit! mask-group)
"shift+m" #(st/emit! unmask-group)
(c-mod "k") #(st/emit! dwl/add-component)
"shift+0" #(st/emit! reset-zoom)
"shift+1" #(st/emit! zoom-to-fit-all)
"shift+2" #(st/emit! zoom-to-selected-shape)
(c-mod "d") #(st/emit! duplicate-selected)
(c-mod "z") #(st/emit! dwc/undo)
(c-mod "shift+z") #(st/emit! dwc/redo)
(c-mod "y") #(st/emit! dwc/redo)
(c-mod "q") #(st/emit! dwc/reinitialize-undo)
"a" #(st/emit! (dwd/select-for-drawing :frame))
"r" #(st/emit! (dwd/select-for-drawing :rect))
"e" #(st/emit! (dwd/select-for-drawing :circle))
"t" #(st/emit! dwtxt/start-edit-if-selected
(dwd/select-for-drawing :text))
"p" #(st/emit! (dwd/select-for-drawing :path))
"k" (fn [event]
(let [image-upload (dom/get-element "image-upload")]
(dom/click image-upload)))
(c-mod "c") #(st/emit! (copy-selected))
(c-mod "x") #(st/emit! (copy-selected) delete-selected)
"escape" #(st/emit! (esc-pressed))
"del" #(st/emit! delete-selected)
"backspace" #(st/emit! delete-selected)
(c-mod "up") #(st/emit! (vertical-order-selected :up))
(c-mod "down") #(st/emit! (vertical-order-selected :down))
(c-mod "shift+up") #(st/emit! (vertical-order-selected :top))
(c-mod "shift+down") #(st/emit! (vertical-order-selected :bottom))
"shift+up" #(st/emit! (dwt/move-selected :up true))
"shift+down" #(st/emit! (dwt/move-selected :down true))
"shift+right" #(st/emit! (dwt/move-selected :right true))
"shift+left" #(st/emit! (dwt/move-selected :left true))
"up" #(st/emit! (dwt/move-selected :up false))
"down" #(st/emit! (dwt/move-selected :down false))
"right" #(st/emit! (dwt/move-selected :right false))
"left" #(st/emit! (dwt/move-selected :left false))
"i" #(st/emit! (mdc/picker-for-selected-shape ))})

View file

@ -0,0 +1,254 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns app.main.data.workspace.shortcuts
(:require
[app.config :as cfg]
[app.main.data.colors :as mdc]
[app.main.data.shortcuts :as ds]
[app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.drawing :as dwd]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.texts :as dwtxt]
[app.main.data.workspace.transforms :as dwt]
[app.main.store :as st]
[app.util.dom :as dom]
[beicon.core :as rx]
[potok.core :as ptk]))
;; \u2318P
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shortcuts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shortcuts impl https://github.com/ccampbell/mousetrap
(defn esc-pressed []
(ptk/reify :esc-pressed
ptk/WatchEvent
(watch [_ state stream]
;; Not interrupt when we're editing a path
(let [edition-id (or (get-in state [:workspace-drawing :object :id])
(get-in state [:workspace-local :edition]))
path-edit-mode (get-in state [:workspace-local :edit-path edition-id :edit-mode])]
(if-not (= :draw path-edit-mode)
(rx/of :interrupt (dw/deselect-all true))
(rx/empty))))))
(def shortcuts
{:toggle-layers {:tooltip (ds/meta "L")
:command (ds/c-mod "l")
:fn #(st/emit! (dw/go-to-layout :layers))}
:toggle-assets {:tooltip (ds/meta "I")
:command (ds/c-mod "i")
:fn #(st/emit! (dw/go-to-layout :assets))}
:toggle-history {:tooltip (ds/meta "H")
:command (ds/c-mod "h")
:fn #(st/emit! (dw/go-to-layout :document-history))}
:toggle-palette {:tooltip (ds/meta "P")
:command (ds/c-mod "p")
:fn #(st/emit! (dw/toggle-layout-flags :colorpalette))}
: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))}
:toggle-grid {:tooltip (ds/meta "'")
:command (ds/c-mod "'")
:fn #(st/emit! (dw/toggle-layout-flags :display-grid))}
:toggle-snap-grid {:tooltip (ds/meta-shift "'")
:command (ds/c-mod "shift+'")
:fn #(st/emit! (dw/toggle-layout-flags :snap-grid))}
:toggle-alignment {:tooltip (ds/meta "\\")
:command (ds/c-mod "\\")
:fn #(st/emit! (dw/toggle-layout-flags :dynamic-alignment))}
:increase-zoom {:tooltip "+"
:command "+"
:fn #(st/emit! (dw/increase-zoom nil))}
: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)}
:ungroup {:tooltip (ds/shift "G")
:command "shift+g"
:fn #(st/emit! dw/ungroup-selected)}
:mask {:tooltip (ds/meta "M")
:command (ds/c-mod "m")
:fn #(st/emit! dw/mask-group)}
:unmask {:tooltip (ds/meta-shift "M")
:command (ds/c-mod "shift+m")
:fn #(st/emit! dw/unmask-group)}
:create-component {:tooltip (ds/meta "K")
:command (ds/c-mod "k")
:fn #(st/emit! dwl/add-component)}
:reset-zoom {:tooltip (ds/shift "0")
:command "shift+0"
:fn #(st/emit! dw/reset-zoom)}
:fit-all {:tooltip (ds/shift "1")
:command "shift+1"
:fn #(st/emit! dw/zoom-to-fit-all)}
:zoom-selected {:tooltip (ds/shift "2")
:command "shift+2"
:fn #(st/emit! dw/zoom-to-selected-shape)}
:duplicate {:tooltip (ds/meta "D")
:command (ds/c-mod "d")
:fn #(st/emit! dw/duplicate-selected)}
:undo {:tooltip (ds/meta "Z")
:command (ds/c-mod "z")
:fn #(st/emit! dwc/undo)}
:redo {:tooltip (ds/meta "Y")
:command [(ds/c-mod "shift+z") (ds/c-mod "y")]
:fn #(st/emit! dwc/redo)}
:clear-undo {:tooltip (ds/meta "Q")
:command (ds/c-mod "q")
:fn #(st/emit! dwc/reinitialize-undo)}
:draw-frame {:tooltip "A"
:command "a"
:fn #(st/emit! (dwd/select-for-drawing :frame))}
:draw-rect {:tooltip "R"
:command "r"
:fn #(st/emit! (dwd/select-for-drawing :rect))}
:draw-ellipse {:tooltip "E"
:command "e"
:fn #(st/emit! (dwd/select-for-drawing :circle))}
:draw-text {:tooltip "T"
:command "t"
:fn #(st/emit! dwtxt/start-edit-if-selected
(dwd/select-for-drawing :text))}
:draw-path {:tooltip "P"
:command "p"
:fn #(st/emit! (dwd/select-for-drawing :path))}
:draw-curve {:tooltip (ds/shift "C")
:command "shift+c"
:fn #(st/emit! (dwd/select-for-drawing :curve))}
:add-comment {:tooltip "C"
:command "c"
:fn #(st/emit! (dwd/select-for-drawing :comments))}
:insert-image {:tooltip "K"
:command "k"
:fn #(-> "image-upload" dom/get-element dom/click)}
:copy {:tooltip (ds/meta "C")
:command (ds/c-mod "c")
:fn #(st/emit! (dw/copy-selected))}
:cut {:tooltip (ds/meta "X")
:command (ds/c-mod "x")
:fn #(st/emit! (dw/copy-selected) dw/delete-selected)}
:paste {:tooltip (ds/meta "V")
:disabled true
:command (ds/c-mod "v")}
:delete {:tooltip (ds/supr)
:command ["del" "backspace"]
:fn #(st/emit! dw/delete-selected)}
:bring-forward {:tooltip (ds/meta ds/up-arrow)
:command (ds/c-mod "up")
:fn #(st/emit! (dw/vertical-order-selected :up))}
:bring-backward {:tooltip (ds/meta ds/down-arrow)
:command (ds/c-mod "down")
:fn #(st/emit! (dw/vertical-order-selected :down))}
:bring-front {:tooltip (ds/meta-shift ds/up-arrow)
:command (ds/c-mod "shift+up")
:fn #(st/emit! (dw/vertical-order-selected :top))}
:bring-back {:tooltip (ds/meta-shift ds/down-arrow)
:command (ds/c-mod "shift+down")
:fn #(st/emit! (dw/vertical-order-selected :bottom))}
:move-fast-up {:tooltip (ds/shift ds/up-arrow)
:command "shift+up"
:fn #(st/emit! (dwt/move-selected :up true))}
:move-fast-down {:tooltip (ds/shift ds/down-arrow)
:command "shift+down"
:fn #(st/emit! (dwt/move-selected :down true))}
:move-fast-right {:tooltip (ds/shift ds/right-arrow)
:command "shift+right"
:fn #(st/emit! (dwt/move-selected :right true))}
:move-fast-left {:tooltip (ds/shift ds/left-arrow)
:command "shift+left"
:fn #(st/emit! (dwt/move-selected :left true))}
:move-unit-up {:tooltip ds/up-arrow
:command "up"
:fn #(st/emit! (dwt/move-selected :up false))}
:move-unit-down {:tooltip ds/down-arrow
:command "down"
:fn #(st/emit! (dwt/move-selected :down false))}
:move-unit-left {:tooltip ds/right-arrow
:command "right"
:fn #(st/emit! (dwt/move-selected :right false))}
:move-unit-right {:tooltip ds/left-arrow
:command "left"
:fn #(st/emit! (dwt/move-selected :left false))}
:open-color-picker {:tooltip "I"
:command "i"
:fn #(st/emit! (mdc/picker-for-selected-shape ))}
:open-viewer {:tooltip "G V"
:command "g v"
:fn #(st/emit! (dw/go-to-viewer))}
:open-dashboard {:tooltip "G D"
:command "g d"
:fn #(st/emit! (dw/go-to-dashboard))}
:escape {:tooltip (ds/esc)
:command "escape"
:fn #(st/emit! (esc-pressed))}})
(defn get-tooltip [shortcut]
(assert (contains? shortcuts shortcut) (str shortcut))
(get-in shortcuts [shortcut :tooltip]))

View file

@ -11,6 +11,7 @@
(:require
[app.common.exceptions :as ex]
[app.main.data.viewer :as dv]
[app.main.data.viewer.shortcuts :as sc]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.fullscreen :as fs]
@ -75,7 +76,7 @@
(let [on-mouse-wheel
(mf/use-callback
(fn [event]
(when (kbd/ctrl? event)
(when (or (kbd/ctrl? event) (kbd/meta? event))
(dom/prevent-default event)
(let [event (.getBrowserEvent ^js event)
delta (+ (.-deltaY ^js event)
@ -94,7 +95,7 @@
(events/unlistenByKey key1))))]
(mf/use-effect on-mount)
(hooks/use-shortcuts dv/shortcuts)
(hooks/use-shortcuts sc/shortcuts)
[:& fs/fullscreen-wrapper {}
[:div.handoff-layout

View file

@ -15,6 +15,7 @@
[app.main.store :as st]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.keyboard :as kbd]
[app.main.ui.workspace.sidebar.layers :refer [element-icon layer-name frame-wrapper]]
[app.util.dom :as dom]
[okulary.core :as l]
@ -52,10 +53,10 @@
(dom/prevent-default event)
(let [id (:id item)]
(cond
(.-ctrlKey event)
(or (kbd/ctrl? event) (kbd/meta? event))
(st/emit! (dv/toggle-selection id))
(.-shiftKey event)
(kbd/shift? event)
(st/emit! (dv/shift-select-to id))
:else

View file

@ -10,19 +10,23 @@
(ns app.main.ui.hooks
"A collection of general purpose react hooks."
(:require
[cljs.spec.alpha :as s]
["mousetrap" :as mousetrap]
[app.common.spec :as us]
[beicon.core :as rx]
[goog.events :as events]
[rumext.alpha :as mf]
[app.util.transit :as t]
[app.main.data.shortcuts :refer [bind-shortcuts]]
[app.util.dom :as dom]
[app.util.dom.dnd :as dnd]
[app.util.webapi :as wapi]
[app.util.logging :as log]
[app.util.timers :as ts]
["mousetrap" :as mousetrap])
[app.util.transit :as t]
[app.util.webapi :as wapi]
[beicon.core :as rx]
[cljs.spec.alpha :as s]
[goog.events :as events]
[rumext.alpha :as mf])
(:import goog.events.EventType))
(log/set-level! :warn)
(defn use-rxsub
[ob]
(let [[state reset-state!] (mf/useState @ob)]
@ -33,20 +37,18 @@
#js [ob])
state))
(s/def ::shortcuts
(s/map-of ::us/string fn?))
(defn use-shortcuts
[shortcuts]
(us/assert ::shortcuts shortcuts)
(mf/use-effect
(fn []
(->> (seq shortcuts)
(run! (fn [[key f]]
(mousetrap/bind key (fn [event]
(js/console.log "[debug]: shortcut:" key)
(.preventDefault event)
(f event))))))
(bind-shortcuts
shortcuts
mousetrap/bind
(fn [key cb]
(fn [event]
(log/debug :msg (str "Shortcut" key))
(.preventDefault event)
(cb event))))
(fn [] (mousetrap/reset))))
nil)

View file

@ -13,6 +13,10 @@
[event]
(.-ctrlKey event))
(defn ^boolean meta?
[event]
(.-metaKey event))
(defn ^boolean shift?
[event]
(.-shiftKey event))

View file

@ -16,6 +16,7 @@
[app.common.geom.shapes :as geom]
[app.common.pages :as cp]
[app.main.data.viewer :as dv]
[app.main.data.viewer.shortcuts :as sc]
[app.main.data.comments :as dcm]
[app.main.refs :as refs]
[app.main.store :as st]
@ -214,7 +215,7 @@
on-mouse-wheel
(fn [event]
(when (kbd/ctrl? event)
(when (or (kbd/ctrl? event) (kbd/meta? event))
(dom/prevent-default event)
(let [event (.getBrowserEvent ^js event)
delta (+ (.-deltaY ^js event) (.-deltaX ^js event))]
@ -240,7 +241,7 @@
(events/unlistenByKey key3))))]
(mf/use-effect on-mount)
(hooks/use-shortcuts dv/shortcuts)
(hooks/use-shortcuts sc/shortcuts)
[:& fs/fullscreen-wrapper {}
[:div.viewer-layout

View file

@ -11,9 +11,10 @@
(:require
[app.common.math :as mth]
[app.common.uuid :as uuid]
[app.main.data.comments :as dcm]
[app.main.data.messages :as dm]
[app.main.data.viewer :as dv]
[app.main.data.comments :as dcm]
[app.main.data.viewer.shortcuts :as sc]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
@ -44,15 +45,15 @@
:on-close #(reset! show-dropdown? false)}
[:ul.dropdown.zoom-dropdown
[:li {:on-click on-increase}
"Zoom in" [:span "+"]]
"Zoom in" [:span (sc/get-tooltip :increase-zoom)]]
[:li {:on-click on-decrease}
"Zoom out" [:span "-"]]
"Zoom out" [:span (sc/get-tooltip :decrease-zoom)]]
[:li {:on-click on-zoom-to-50}
"Zoom to 50%" [:span "Shift + 0"]]
"Zoom to 50%" [:span (sc/get-tooltip :zoom-50)]]
[:li {:on-click on-zoom-to-100}
"Zoom to 100%" [:span "Shift + 1"]]
"Zoom to 100%" [:span (sc/get-tooltip :reset-zoom)]]
[:li {:on-click on-zoom-to-200}
"Zoom to 200%" [:span "Shift + 2"]]]]]))
"Zoom to 200%" [:span (sc/get-tooltip :zoom-200)]]]]]))
(mf/defc share-link
[{:keys [page token] :as props}]
@ -272,7 +273,7 @@
:on-zoom-to-100 (st/emitf dv/reset-zoom)
:on-zoom-to-200 (st/emitf dv/zoom-to-200)}]
[:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom
[:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
{:alt (t locale "viewer.header.fullscreen")
:on-click #(if @fullscreen (fullscreen false) (fullscreen true))}
(if @fullscreen

View file

@ -12,15 +12,16 @@
[app.common.geom.point :as gpt]
[app.main.constants :as c]
[app.main.data.history :as udh]
[app.main.data.workspace :as dw]
[app.main.data.messages :as dm]
[app.main.data.workspace :as dw]
[app.main.data.workspace.shortcuts :as sc]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.streams :as ms]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.context :as ctx]
[app.main.ui.workspace.colorpalette :refer [colorpalette]]
[app.main.ui.workspace.colorpicker]
[app.main.ui.workspace.context-menu :refer [context-menu]]
@ -30,8 +31,8 @@
[app.main.ui.workspace.rules :refer [horizontal-rule vertical-rule]]
[app.main.ui.workspace.sidebar :refer [left-sidebar right-sidebar]]
[app.main.ui.workspace.viewport :refer [viewport viewport-actions coordinates]]
[app.util.object :as obj]
[app.util.dom :as dom]
[app.util.object :as obj]
[beicon.core :as rx]
[cuerdas.core :as str]
[okulary.core :as l]
@ -128,7 +129,7 @@
;; Close any non-modal dialog that may be still open
(st/emitf dm/hide)))
(hooks/use-shortcuts dw/shortcuts)
(hooks/use-shortcuts sc/shortcuts)
(let [file (mf/deref refs/workspace-file)
project (mf/deref refs/workspace-project)

View file

@ -14,11 +14,12 @@
[app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shortcuts :as sc]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.streams :as ms]
[app.main.ui.context :as ctx]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :refer [use-rxsub]]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
@ -99,52 +100,52 @@
(:component-file shape)))]
[:*
[:& menu-entry {:title (t locale "workspace.shape.menu.copy")
:shortcut "Ctrl + c"
:shortcut (sc/get-tooltip :copy)
:on-click do-copy}]
[:& menu-entry {:title (t locale "workspace.shape.menu.cut")
:shortcut "Ctrl + x"
:shortcut (sc/get-tooltip :cut)
:on-click do-cut}]
[:& menu-entry {:title (t locale "workspace.shape.menu.paste")
:shortcut "Ctrl + v"
:shortcut (sc/get-tooltip :paste)
:on-click do-paste}]
[:& menu-entry {:title (t locale "workspace.shape.menu.duplicate")
:shortcut "Ctrl + d"
:shortcut (sc/get-tooltip :duplicate)
:on-click do-duplicate}]
[:& menu-separator]
[:& menu-entry {:title (t locale "workspace.shape.menu.forward")
:shortcut "Ctrl + ↑"
:shortcut (sc/get-tooltip :bring-forward)
:on-click do-bring-forward}]
[:& menu-entry {:title (t locale "workspace.shape.menu.front")
:shortcut "Ctrl + Shift + ↑"
:shortcut (sc/get-tooltip :bring-front)
:on-click do-bring-to-front}]
[:& menu-entry {:title (t locale "workspace.shape.menu.backward")
:shortcut "Ctrl + ↓"
:shortcut (sc/get-tooltip :bring-backward)
:on-click do-send-backward}]
[:& menu-entry {:title (t locale "workspace.shape.menu.back")
:shortcut "Ctrl + Shift + ↓"
:shortcut (sc/get-tooltip :bring-back)
:on-click do-send-to-back}]
[:& menu-separator]
(when (> (count selected) 1)
[:*
[:& menu-entry {:title (t locale "workspace.shape.menu.group")
:shortcut "Ctrl + g"
:shortcut (sc/get-tooltip :group)
:on-click do-create-group}]
[:& menu-entry {:title (t locale "workspace.shape.menu.mask")
:shortcut "Ctrl + M"
:shortcut (sc/get-tooltip :mask)
:on-click do-mask-group}]])
(when (and (= (count selected) 1) (= (:type shape) :group))
[:*
[:& menu-entry {:title (t locale "workspace.shape.menu.ungroup")
:shortcut "Shift + g"
:shortcut (sc/get-tooltip :ungroup)
:on-click do-remove-group}]
(if (:masked-group? shape)
[:& menu-entry {:title (t locale "workspace.shape.menu.unmask")
:shortcut "Shift + M"
:shortcut (sc/get-tooltip :unmask)
:on-click do-unmask-group}]
[:& menu-entry {:title "Mask"
:shortcut "Ctrl + M"
[:& menu-entry {:title (t locale "workspace.shape.menu.mask")
:shortcut (sc/get-tooltip :group)
:on-click do-mask-group}])])
(if (:hidden shape)
@ -165,7 +166,7 @@
[:*
[:& menu-separator]
[:& menu-entry {:title (t locale "workspace.shape.menu.create-component")
:shortcut "Ctrl + K"
:shortcut (sc/get-tooltip :create-component)
:on-click do-add-component}]])
(when (and (:component-id shape)
@ -197,7 +198,7 @@
[:& menu-separator]
[:& menu-entry {:title (t locale "workspace.shape.menu.delete")
:shortcut "Supr"
:shortcut (sc/get-tooltip :delete)
:on-click do-delete}]]))
(mf/defc viewport-context-menu
@ -206,7 +207,7 @@
do-paste (st/emitf dw/paste)]
[:*
[:& menu-entry {:title (t locale "workspace.shape.menu.paste")
:shortcut "Ctrl + v"
:shortcut (sc/get-tooltip :paste)
:on-click do-paste}]]))
(mf/defc context-menu

View file

@ -52,7 +52,7 @@
drawing? @refs/selected-drawing-tool
button (.-which (.-nativeEvent event))
shift? (kbd/shift? event)
ctrl? (kbd/ctrl? event)
ctrl? (or (kbd/ctrl? event) (kbd/meta? event))
allow-click? (and (not blocked)
(not drawing?)

View file

@ -13,6 +13,8 @@
[app.config :as cfg]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.data.workspace.shortcuts :as sc]
[app.main.data.workspace.shortcuts :as sc]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
@ -73,15 +75,15 @@
:on-close #(reset! show-dropdown? false)}
[:ul.zoom-dropdown
[:li {:on-click on-increase}
"Zoom in" [:span "+"]]
"Zoom in" [:span (sc/get-tooltip :increase-zoom)]]
[:li {:on-click on-decrease}
"Zoom out" [:span "-"]]
"Zoom out" [:span (sc/get-tooltip :decrease-zoom)]]
[:li {:on-click on-zoom-reset}
"Zoom to 100%" [:span "Shift + 0"]]
"Zoom to 100%" [:span (sc/get-tooltip :reset-zoom)]]
[:li {:on-click on-zoom-fit}
"Zoom to fit all" [:span "Shift + 1"]]
"Zoom to fit all" [:span (sc/get-tooltip :fit-all)]]
[:li {:on-click on-zoom-selected}
"Zoom to selected" [:span "Shift + 2"]]]]]))
"Zoom to selected" [:span (sc/get-tooltip :zoom-selected)]]]]]))
;; --- Header Users
@ -171,52 +173,53 @@
(if (contains? layout :rules)
(tr "workspace.header.menu.hide-rules")
(tr "workspace.header.menu.show-rules"))]
[:span.shortcut "Ctrl+shift+R"]]
[:span.shortcut (sc/get-tooltip :toggle-rules)]]
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :display-grid))}
[:span
(if (contains? layout :display-grid)
(tr "workspace.header.menu.hide-grid")
(tr "workspace.header.menu.show-grid"))]
[:span.shortcut "Ctrl+'"]]
[:span.shortcut (sc/get-tooltip :toggle-grid)]]
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :snap-grid))}
[:span
(if (contains? layout :snap-grid)
(tr "workspace.header.menu.disable-snap-grid")
(tr "workspace.header.menu.enable-snap-grid"))]
[:span.shortcut "Ctrl+Shift+'"]]
[:span.shortcut (sc/get-tooltip :toggle-snap-grid)]]
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :sitemap :layers))}
[:span
(if (or (contains? layout :sitemap) (contains? layout :layers))
(tr "workspace.header.menu.hide-layers")
(tr "workspace.header.menu.show-layers"))]
[:span.shortcut "Ctrl+l"]]
[:span.shortcut (sc/get-tooltip :toggle-layers)]]
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :colorpalette))}
[:span
(if (contains? layout :colorpalette)
(tr "workspace.header.menu.hide-palette")
(tr "workspace.header.menu.show-palette"))]
[:span.shortcut "Ctrl+p"]]
[:span.shortcut (sc/get-tooltip :toggle-palette)]]
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :assets))}
[:span
(if (contains? layout :assets)
(tr "workspace.header.menu.hide-assets")
(tr "workspace.header.menu.show-assets"))]
[:span.shortcut "Ctrl+i"]]
[:span.shortcut (sc/get-tooltip :toggle-assets)]]
[:li {:on-click #(st/emit! (dw/select-all))}
[:span (tr "workspace.header.menu.select-all")]
[:span.shortcut "Ctrl+a"]]
[:span.shortcut (sc/get-tooltip :select-all)]]
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :dynamic-alignment))}
[:span
(if (contains? layout :dynamic-alignment)
(tr "workspace.header.menu.disable-dynamic-alignment")
(tr "workspace.header.menu.enable-dynamic-alignment"))]]
(tr "workspace.header.menu.enable-dynamic-alignment"))]
[:span.shortcut (sc/get-tooltip :toggle-alignment)]]
(if (:is-shared file)
[:li {:on-click on-remove-shared}
@ -272,8 +275,8 @@
:on-zoom-fit #(st/emit! dw/zoom-to-fit-all)
:on-zoom-selected #(st/emit! dw/zoom-to-selected-shape)}]
[:a.btn-icon-dark.btn-small.tooltip.tooltip-bottom
{:alt (tr "workspace.header.viewer")
[:a.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
{:alt (tr "workspace.header.viewer" (sc/get-tooltip :open-viewer))
:href (str "#" view-url)
:on-click go-viewer}
i/play]]]))

View file

@ -12,6 +12,7 @@
[app.common.geom.point :as gpt]
[app.common.media :as cm]
[app.main.data.workspace :as dw]
[app.main.data.workspace.shortcuts :as sc]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.file-uploader :refer [file-uploader]]
@ -67,22 +68,22 @@
:on-click (st/emitf :interrupt)}
i/pointer-inner]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.frame")
{:alt (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
:class (when (= selected-drawtool :frame) "selected")
:on-click (partial select-drawtool :frame)}
i/artboard]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.rect")
{:alt (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
:class (when (= selected-drawtool :rect) "selected")
:on-click (partial select-drawtool :rect)}
i/box]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.ellipse")
{:alt (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
:class (when (= selected-drawtool :circle) "selected")
:on-click (partial select-drawtool :circle)}
i/circle]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.text")
{:alt (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
:class (when (= selected-drawtool :text) "selected")
:on-click (partial select-drawtool :text)}
i/text]
@ -90,40 +91,40 @@
[:& image-upload]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.curve")
{:alt (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
:class (when (= selected-drawtool :curve) "selected")
:on-click (partial select-drawtool :curve)}
i/pencil]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.path")
{:alt (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
:class (when (= selected-drawtool :path) "selected")
:on-click (partial select-drawtool :path)}
i/pen]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.comments")
{:alt (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment))
:class (when (= selected-drawtool :comments) "selected")
:on-click (partial select-drawtool :comments)}
i/chat]]
[:ul.left-toolbar-options.panels
[:li.tooltip.tooltip-right
{:alt "Layers"
{:alt (tr "workspace.sidebar.layers" (sc/get-tooltip :toggle-layers))
:class (when (contains? layout :layers) "selected")
:on-click (st/emitf (dw/go-to-layout :layers))}
i/layers]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.assets")
{:alt (tr "workspace.toolbar.assets" (sc/get-tooltip :toggle-assets))
:class (when (contains? layout :assets) "selected")
:on-click (st/emitf (dw/go-to-layout :assets))}
i/library]
[:li.tooltip.tooltip-right
{:alt "History"
{:alt (tr "workspace.sidebar.history" (sc/get-tooltip :toggle-history))
:class (when (contains? layout :document-history) "selected")
:on-click (st/emitf (dw/go-to-layout :document-history))}
i/undo-history]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.color-palette")
{:alt (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-palette))
:class (when (contains? layout :colorpalette) "selected")
:on-click (st/emitf (dw/toggle-layout-flags :colorpalette))}
i/palette]]]]))

View file

@ -19,6 +19,7 @@
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.keyboard :as kbd]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t]]
[app.util.object :as obj]
@ -140,10 +141,10 @@
(:hidden item))
nil
(.-shiftKey event)
(kbd/shift? event)
(st/emit! (dw/shift-select-shapes id))
(.-ctrlKey event)
(or (kbd/ctrl? event) (kbd/meta? event))
(st/emit! (dw/select-shape id true))
(> (count selected) 1)

View file

@ -508,7 +508,7 @@
(let [node (mf/ref-val viewport-ref)
target (dom/get-target event)]
(cond
(kbd/ctrl? event)
(or (kbd/ctrl? event) (kbd/meta? event))
(let [event (.getBrowserEvent ^js event)
pos @ms/mouse-position]
(dom/prevent-default event)