mirror of
https://github.com/penpot/penpot.git
synced 2026-07-31 18:36:18 +00:00
WIP 2
This commit is contained in:
parent
fac7e457bd
commit
f891f4237d
@ -200,7 +200,8 @@
|
||||
:settings-feedback
|
||||
:settings-subscription
|
||||
:settings-integrations
|
||||
:settings-notifications)
|
||||
:settings-notifications
|
||||
:settings-shortcuts)
|
||||
(let [params (get params :query)
|
||||
error-report-id (some-> params :error-report-id uuid/parse*)]
|
||||
[:? [:> settings-page*
|
||||
|
||||
@ -41,7 +41,8 @@
|
||||
["/options" :settings-options]
|
||||
["/subscriptions" :settings-subscription]
|
||||
["/integrations" :settings-integrations]
|
||||
["/notifications" :settings-notifications]]
|
||||
["/notifications" :settings-notifications]
|
||||
["/shortcuts" :settings-shortcuts]]
|
||||
|
||||
["/frame-preview" :frame-preview]
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
[app.main.ui.settings.options :refer [options-page*]]
|
||||
[app.main.ui.settings.password :refer [password-page*]]
|
||||
[app.main.ui.settings.profile :refer [profile-page*]]
|
||||
[app.main.ui.settings.shortcuts :refer [shortcuts-page*]]
|
||||
[app.main.ui.settings.sidebar :refer [sidebar*]]
|
||||
[app.main.ui.settings.subscription :refer [subscription-page*]]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
@ -77,7 +78,10 @@
|
||||
[:> integrations-page*]
|
||||
|
||||
:settings-notifications
|
||||
[:> notifications-page* {:profile profile}])]]]]))
|
||||
[:> notifications-page* {:profile profile}]
|
||||
|
||||
:settings-shortcuts
|
||||
[:> shortcuts-page* {:profile profile}])]]]]))
|
||||
|
||||
(mf/defc settings-page*
|
||||
{::mf/lazy-load true}
|
||||
|
||||
179
frontend/src/app/main/ui/settings/shortcuts.cljs
Normal file
179
frontend/src/app/main/ui/settings/shortcuts.cljs
Normal file
@ -0,0 +1,179 @@
|
||||
(ns app.main.ui.settings.shortcuts
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.main.data.dashboard.shortcuts]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.shortcuts :as ds]
|
||||
[app.main.data.viewer.shortcuts]
|
||||
[app.main.data.workspace.path.shortcuts]
|
||||
[app.main.data.workspace.shortcuts]
|
||||
[app.main.data.workspace.shortcuts.customize :as customize]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
||||
[app.main.ui.shortcuts :as ss]
|
||||
[app.util.dom :as dom]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private workspace-shortcuts-raw
|
||||
(d/deep-merge app.main.data.workspace.path.shortcuts/shortcuts
|
||||
app.main.data.workspace.shortcuts/shortcuts))
|
||||
|
||||
(mf/defc shortcuts-list*
|
||||
[{:keys [profile workspace-sc dashboard-sc viewer-sc]}]
|
||||
(let [open-sections* (mf/use-state [[1]])
|
||||
open-sections (deref open-sections*)
|
||||
custom-shortcuts (get-in profile [:props :custom-shortcuts])
|
||||
|
||||
workspace-translated (->> workspace-sc
|
||||
(ss/add-translation :sc)
|
||||
(into {}))
|
||||
dashboard-translated (->> dashboard-sc
|
||||
(ss/add-translation :sc)
|
||||
(into {}))
|
||||
viewer-translated (->> viewer-sc
|
||||
(ss/add-translation :sc)
|
||||
(into {}))
|
||||
|
||||
filter-term (mf/use-state "")
|
||||
|
||||
{:keys [all-shortcuts]}
|
||||
(ss/build-all-shortcuts workspace-translated dashboard-translated viewer-translated)
|
||||
|
||||
section-has-content?
|
||||
(fn [section]
|
||||
(let [children (:children section)]
|
||||
(if (and (= (count children) 1) (contains? children :none))
|
||||
(seq (:children (:none children)))
|
||||
(seq children))))
|
||||
|
||||
all-shortcuts (into {} (filter (fn [[_ v]] (section-has-content? v)) all-shortcuts))
|
||||
|
||||
on-edit-shortcut
|
||||
(mf/use-callback
|
||||
(mf/deps custom-shortcuts workspace-sc)
|
||||
(fn [shortcut-key]
|
||||
(let [default-command (:command (get workspace-shortcuts-raw shortcut-key))
|
||||
current-command (or (get custom-shortcuts shortcut-key) default-command)]
|
||||
(st/emit! (modal/show :shortcut-edit
|
||||
{:shortcut-key shortcut-key
|
||||
:shortcut-name (ss/translation-keyname :sc shortcut-key)
|
||||
:current-command current-command
|
||||
:default-command default-command
|
||||
:all-shortcuts all-shortcuts})))))
|
||||
|
||||
on-reset-shortcut
|
||||
(mf/use-callback
|
||||
(fn [shortcut-key]
|
||||
(st/emit! (customize/reset-custom-shortcut shortcut-key))))
|
||||
manage-sections
|
||||
(fn [item]
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [is-present? (some #(= % item) open-sections)
|
||||
new-value (if is-present?
|
||||
(filterv (fn [element] (not= element item)) open-sections)
|
||||
(conj open-sections item))]
|
||||
(reset! open-sections* new-value))))]
|
||||
|
||||
(for [section all-shortcuts]
|
||||
(let [[section-key _] section]
|
||||
[:> ss/shortcut-section* {:key (name section-key)
|
||||
:section section
|
||||
:manage-sections manage-sections
|
||||
:open-sections open-sections*
|
||||
:filter-term filter-term
|
||||
:editable? true
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit-shortcut
|
||||
:on-reset on-reset-shortcut}]))))
|
||||
|
||||
(mf/defc all-shortcuts-section*
|
||||
[{:keys [profile]}]
|
||||
(let [custom-shortcuts (get-in profile [:props :custom-shortcuts])
|
||||
workspace-shortcuts-custom (ds/apply-custom-overrides workspace-shortcuts-raw custom-shortcuts)]
|
||||
[:div {:class (stl/css :shortcuts-section)}
|
||||
[:> shortcuts-list* {:profile profile
|
||||
:workspace-sc workspace-shortcuts-custom
|
||||
:dashboard-sc app.main.data.dashboard.shortcuts/shortcuts
|
||||
:viewer-sc app.main.data.viewer.shortcuts/shortcuts}]]))
|
||||
|
||||
(mf/defc personalized-shortcuts-section*
|
||||
[{:keys [profile]}]
|
||||
(let [custom-shortcuts (get-in profile [:props :custom-shortcuts])
|
||||
workspace-shortcuts-custom (ds/apply-custom-overrides workspace-shortcuts-raw custom-shortcuts)
|
||||
personalized (select-keys workspace-shortcuts-custom (keys custom-shortcuts))]
|
||||
[:div {:class (stl/css :shortcuts-section)}
|
||||
(if (seq personalized)
|
||||
[:> shortcuts-list* {:profile profile
|
||||
:workspace-sc personalized
|
||||
:dashboard-sc {}
|
||||
:viewer-sc {}}]
|
||||
[:p "There are no personalized shortcuts."])]))
|
||||
|
||||
(mf/defc not-assigned-shortcuts-section*
|
||||
[{:keys [profile]}]
|
||||
(let [custom-shortcuts (get-in profile [:props :custom-shortcuts])
|
||||
workspace-shortcuts-custom (ds/apply-custom-overrides workspace-shortcuts-raw custom-shortcuts)
|
||||
not-assigned (into {} (filter (fn [[_ v]]
|
||||
(empty? (:command v)))
|
||||
workspace-shortcuts-custom))]
|
||||
[:div {:class (stl/css :shortcuts-section)}
|
||||
(if (seq not-assigned)
|
||||
[:> shortcuts-list* {:profile profile
|
||||
:workspace-sc not-assigned
|
||||
:dashboard-sc {}
|
||||
:viewer-sc {}}]
|
||||
[:p "There are no not-assigned shortcuts."])]))
|
||||
|
||||
|
||||
|
||||
(mf/defc shortcuts-page*
|
||||
[{:keys [profile]}]
|
||||
(let [section* (mf/use-state :all)
|
||||
section (deref section*)
|
||||
|
||||
tabs
|
||||
(mf/with-memo []
|
||||
[{:label "All shortcuts"
|
||||
:id "all"}
|
||||
{:label "Personalized shortcuts"
|
||||
:data-testid "personalized"
|
||||
:id "personalized"}
|
||||
{:label "Not assigned shortcuts"
|
||||
:data-testid "not-assigned"
|
||||
:id "not-assigned"}])
|
||||
|
||||
handle-change-tab
|
||||
(mf/use-fn
|
||||
(mf/deps)
|
||||
(fn [new-section]
|
||||
(reset! section* (keyword new-section))))]
|
||||
|
||||
|
||||
[:section {:class (stl/css :shortcuts-page)
|
||||
:aria-label "Shortcuts page"}
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :color-primary)}
|
||||
"Shortcuts page"]
|
||||
|
||||
[:div {:class (stl/css :shortcuts-content)}
|
||||
[:p "search-bar"]
|
||||
[:button "restore all"]
|
||||
[:p "This is the shortcuts page content."]
|
||||
[:> tab-switcher* {:tabs tabs
|
||||
:selected (name section)
|
||||
:on-change handle-change-tab
|
||||
:class (stl/css :viewer-tab-switcher)}
|
||||
(case section
|
||||
:all
|
||||
[:> all-shortcuts-section* {:profile profile}]
|
||||
|
||||
:personalized
|
||||
[:> personalized-shortcuts-section* {:profile profile}]
|
||||
|
||||
:not-assigned
|
||||
[:> not-assigned-shortcuts-section* {:profile profile}])]]]))
|
||||
17
frontend/src/app/main/ui/settings/shortcuts.scss
Normal file
17
frontend/src/app/main/ui/settings/shortcuts.scss
Normal file
@ -0,0 +1,17 @@
|
||||
// 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/.
|
||||
//
|
||||
// Copyright (c) KALEIDOS INC Sucursal en España SL
|
||||
|
||||
.shortcuts-page {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.shortcuts-content {
|
||||
padding: var(--sp-xl);
|
||||
}
|
||||
|
||||
.shortcuts-section {
|
||||
margin-bottom: var(--sp-lg);
|
||||
}
|
||||
@ -48,6 +48,9 @@
|
||||
(def ^:private go-settings-notifications
|
||||
#(st/emit! (rt/nav :settings-notifications)))
|
||||
|
||||
(def ^:private go-settings-shortcuts
|
||||
#(st/emit! (rt/nav :settings-shortcuts)))
|
||||
|
||||
(defn- show-release-notes
|
||||
[event]
|
||||
(let [version (:main cf/version)]
|
||||
@ -66,6 +69,7 @@
|
||||
subscription? (= section :settings-subscription)
|
||||
integrations? (= section :settings-integrations)
|
||||
notifications? (= section :settings-notifications)
|
||||
shortcuts? (= section :settings-shortcuts)
|
||||
team-id (or (dtm/get-last-team-id)
|
||||
(:default-team-id profile))
|
||||
|
||||
@ -99,6 +103,11 @@
|
||||
:settings-item true)
|
||||
:on-click go-settings-notifications}
|
||||
[:span {:class (stl/css :element-title)} (tr "labels.notifications")]]
|
||||
|
||||
[:li {:class (stl/css-case :current shortcuts?
|
||||
:settings-item true)
|
||||
:on-click go-settings-shortcuts}
|
||||
[:span {:class (stl/css :element-title)} "shortcuts"]]
|
||||
|
||||
[:li {:class (stl/css-case :current options?
|
||||
:settings-item true)
|
||||
|
||||
281
frontend/src/app/main/ui/shortcuts.cljs
Normal file
281
frontend/src/app/main/ui/shortcuts.cljs
Normal file
@ -0,0 +1,281 @@
|
||||
;; 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/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC Sucursal en España SL
|
||||
|
||||
(ns app.main.ui.shortcuts
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.config :as cf]
|
||||
[app.main.data.shortcuts :as ds]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.strings :refer [matches-search]]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn translation-keyname
|
||||
[type keyname]
|
||||
(let [translat-pre (case type
|
||||
:sc "shortcuts."
|
||||
:sec "shortcut-section."
|
||||
:sub-sec "shortcut-subsection.")]
|
||||
(tr (str translat-pre (d/name keyname)))))
|
||||
|
||||
(defn add-translation
|
||||
[type item]
|
||||
(map (fn [[k v]] [k (assoc v :translation (translation-keyname type k))]) item))
|
||||
|
||||
(defn shortcuts->subsections
|
||||
[shortcuts]
|
||||
(let [subsections (into #{} (mapcat :subsections) (vals shortcuts))
|
||||
get-sc-by-subsection
|
||||
(fn [subsection [k v]]
|
||||
(when (some #(= subsection %) (:subsections v)) {k v}))
|
||||
reduce-sc
|
||||
(fn [acc subsection]
|
||||
(let [shortcuts-by-subsection (into {} (keep (partial get-sc-by-subsection subsection) shortcuts))]
|
||||
(assoc acc subsection {:children shortcuts-by-subsection})))]
|
||||
(reduce reduce-sc {} subsections)))
|
||||
|
||||
(defn build-all-shortcuts
|
||||
[workspace-sc dashboard-sc viewer-sc]
|
||||
(let [walk (fn walk [element parent-id]
|
||||
(if (nil? element)
|
||||
element
|
||||
(let [rec-fn (fn [index [k item]]
|
||||
(let [item-id (if (nil? parent-id)
|
||||
[index]
|
||||
(conj parent-id index))]
|
||||
[k (assoc item :id item-id :children (walk (:children item) item-id))]))]
|
||||
(into {} (map-indexed (partial rec-fn) element)))))
|
||||
ws-subs (->> (shortcuts->subsections workspace-sc)
|
||||
(add-translation :sub-sec)
|
||||
(into {}))
|
||||
db-subs (->> (shortcuts->subsections dashboard-sc)
|
||||
(add-translation :sub-sec)
|
||||
(into {}))
|
||||
vw-subs (->> (shortcuts->subsections viewer-sc)
|
||||
(add-translation :sub-sec)
|
||||
(into {}))
|
||||
basics (into {} (concat (:children (:basics ws-subs))
|
||||
(:children (:basics db-subs))
|
||||
(:children (:basics vw-subs))))
|
||||
ws-subs (dissoc ws-subs :basics)
|
||||
db-subs (dissoc db-subs :basics)
|
||||
vw-subs (dissoc vw-subs :basics)
|
||||
all {:basics {:id [1]
|
||||
:children {:none {:children basics}}
|
||||
:translation (tr "shortcut-section.basics")}
|
||||
:workspace {:id [2]
|
||||
:children ws-subs
|
||||
:translation (tr "shortcut-section.workspace")}
|
||||
:dashboard {:id [3]
|
||||
:children db-subs
|
||||
:translation (tr "shortcut-section.dashboard")}
|
||||
:viewer {:id [4]
|
||||
:children vw-subs
|
||||
:translation (tr "shortcut-section.viewer")}}
|
||||
all (walk all nil)
|
||||
all-sc-names (map #(translation-keyname :sc %)
|
||||
(concat (keys workspace-sc)
|
||||
(keys dashboard-sc)
|
||||
(keys viewer-sc)))
|
||||
all-sub-names (map #(translation-keyname :sub-sec %)
|
||||
(concat (keys ws-subs)
|
||||
(keys db-subs)
|
||||
(keys vw-subs)))
|
||||
all-section-names (map #(translation-keyname :sec %) (keys all))]
|
||||
{:all-shortcuts all
|
||||
:all-sc-names all-sc-names
|
||||
:all-sub-names all-sub-names
|
||||
:all-section-names all-section-names}))
|
||||
|
||||
(mf/defc converted-chars*
|
||||
[{:keys [char command]}]
|
||||
(let [modified-keys {:up ds/up-arrow
|
||||
:down ds/down-arrow
|
||||
:left ds/left-arrow
|
||||
:right ds/right-arrow
|
||||
:plus "+"}
|
||||
macos-keys {:command "\u2318"
|
||||
:option "\u2325"
|
||||
:alt "\u2325"
|
||||
:delete "\u232B"
|
||||
:del "\u232B"
|
||||
:shift "\u21E7"
|
||||
:control "\u2303"
|
||||
:esc "\u238B"
|
||||
:enter "\u23CE"}
|
||||
is-macos? (cf/check-platform? :macos)
|
||||
char (if (contains? modified-keys (keyword char)) ((keyword char) modified-keys) char)
|
||||
char (if (and is-macos? (contains? macos-keys (keyword char))) ((keyword char) macos-keys) char)
|
||||
unique-key (str (d/name command) "-" char)]
|
||||
[:span {:class (stl/css :key)
|
||||
:key unique-key} char]))
|
||||
|
||||
(mf/defc shortcuts-keys*
|
||||
[{:keys [content command]}]
|
||||
(let [managed-list (if (coll? content)
|
||||
content
|
||||
(conj () content))
|
||||
chars-list (map ds/split-sc managed-list)
|
||||
last-element (last chars-list)
|
||||
short-char-list (if (= 1 (count chars-list))
|
||||
chars-list
|
||||
(drop-last chars-list))
|
||||
penultimate (last short-char-list)]
|
||||
[:span {:class (stl/css :keys)}
|
||||
(for [chars short-char-list]
|
||||
[:* {:key (str/join chars)}
|
||||
(for [char chars]
|
||||
[:> converted-chars* {:key (dm/str char "-" (name command))
|
||||
:char char
|
||||
:command command}])
|
||||
(when (not= chars penultimate) [:span {:class (stl/css :space)} ","])])
|
||||
(when (not= last-element penultimate)
|
||||
[:*
|
||||
[:span {:class (stl/css :space)} (tr "shortcuts.or")]
|
||||
(for [char last-element]
|
||||
[:> converted-chars* {:key (dm/str char "-" (name command))
|
||||
:char char
|
||||
:command command}])])]))
|
||||
|
||||
(mf/defc shortcut-row*
|
||||
[{:keys [elements filter-term is-match-section is-match-subsection
|
||||
editable? custom-shortcuts on-edit on-reset]}]
|
||||
(let [shortcut-name (keys elements)
|
||||
shortcut-translations (map #(translation-keyname :sc %) shortcut-name)
|
||||
match-shortcut? (some #(matches-search % @filter-term) shortcut-translations)
|
||||
filtered (if (and (or is-match-section is-match-subsection) (not match-shortcut?))
|
||||
shortcut-translations
|
||||
(filter #(matches-search % @filter-term) shortcut-translations))
|
||||
sorted-filtered (sort filtered)]
|
||||
|
||||
[:ul {:class (stl/css :sub-menu)}
|
||||
(for [command-translate sorted-filtered]
|
||||
(let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements))
|
||||
[command comand-info] sc-by-translate
|
||||
content (or (:show-command comand-info) (:command comand-info))
|
||||
customized? (and editable? (contains? custom-shortcuts command))]
|
||||
[:li {:class (stl/css-case :shortcuts-name true
|
||||
:customized customized?)
|
||||
:key command-translate}
|
||||
[:span {:class (stl/css :command-name)}
|
||||
command-translate]
|
||||
[:div {:class (stl/css :shortcut-actions)}
|
||||
[:> shortcuts-keys* {:content content
|
||||
:command command}]
|
||||
(when editable?
|
||||
[:div {:class (stl/css :edit-buttons)}
|
||||
(when customized?
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "shortcuts.reset")
|
||||
:on-click (fn [e]
|
||||
(dom/stop-propagation e)
|
||||
(on-reset command))
|
||||
:icon i/reload
|
||||
:icon-size "s"}])
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "shortcuts.edit")
|
||||
:on-click (fn [e]
|
||||
(dom/stop-propagation e)
|
||||
(on-edit command))
|
||||
:icon i/curve
|
||||
:icon-size "s"}]])]]))]))
|
||||
|
||||
(mf/defc section-title*
|
||||
[{:keys [name is-visible is-sub]}]
|
||||
[:div {:class (if is-sub
|
||||
(stl/css :subsection-title)
|
||||
(stl/css :section-title))}
|
||||
[:> icon* {:icon-id (if is-visible i/arrow-down i/arrow-right)
|
||||
:size "s"}]
|
||||
[:span {:class (if is-sub
|
||||
(stl/css :subsection-name)
|
||||
(stl/css :section-name))} name]])
|
||||
|
||||
(mf/defc shortcut-subsection*
|
||||
[{:keys [subsections manage-sections filter-term is-match-section open-sections
|
||||
editable? custom-shortcuts on-edit on-reset]}]
|
||||
(let [subsections-names (keys subsections)
|
||||
subsection-translations (if (= :none (first subsections-names))
|
||||
(map #(translation-keyname :sc %) subsections-names)
|
||||
(map #(translation-keyname :sub-sec %) subsections-names))
|
||||
sorted-translations (sort subsection-translations)]
|
||||
(if (= :none (first subsections-names))
|
||||
(let [basic-shortcuts (:none subsections)]
|
||||
[:> shortcut-row* {:elements (:children basic-shortcuts)
|
||||
:filter-term filter-term
|
||||
:is-match-section is-match-section
|
||||
:is-match-subsection true
|
||||
:editable? editable?
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit
|
||||
:on-reset on-reset}])
|
||||
|
||||
[:ul {:class (stl/css :subsection-menu)}
|
||||
(for [sub-translated sorted-translations]
|
||||
(let [sub-by-translate (first (filter #(= (:translation (second %)) sub-translated) subsections))
|
||||
[sub-name sub-info] sub-by-translate
|
||||
visible? (some #(= % (:id sub-info)) @open-sections)
|
||||
match-subsection? (matches-search (translation-keyname :sub-sec sub-name) @filter-term)
|
||||
shortcut-names (map #(translation-keyname :sc %) (keys (:children sub-info)))
|
||||
match-shortcuts? (some #(matches-search % @filter-term) shortcut-names)]
|
||||
(when (or match-subsection? match-shortcuts? is-match-section)
|
||||
[:li {:key sub-translated
|
||||
:on-click (manage-sections (:id sub-info))}
|
||||
[:> section-title* {:name sub-translated
|
||||
:is-visible visible?
|
||||
:is-sub true}]
|
||||
|
||||
[:div {:style {:display (if visible? "initial" "none")}}
|
||||
[:> shortcut-row* {:elements (:children sub-info)
|
||||
:filter-term filter-term
|
||||
:is-match-section is-match-section
|
||||
:is-match-subsection match-subsection?
|
||||
:editable? editable?
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit
|
||||
:on-reset on-reset}]]])))])))
|
||||
|
||||
(mf/defc shortcut-section*
|
||||
[{:keys [section manage-sections open-sections filter-term
|
||||
editable? custom-shortcuts on-edit on-reset]}]
|
||||
(let [[section-key section-info] section
|
||||
section-id (:id section-info)
|
||||
section-translation (translation-keyname :sec section-key)
|
||||
match-section? (matches-search section-translation @filter-term)
|
||||
subsections (:children section-info)
|
||||
subs-names (keys subsections)
|
||||
subs-bodys (reduce #(conj %1 (:children (%2 subsections))) {} subs-names)
|
||||
sub-trans (map #(if (= "none" (d/name %))
|
||||
nil
|
||||
(translation-keyname :sub-sec %)) subs-names)
|
||||
match-subsection? (some #(matches-search % @filter-term) sub-trans)
|
||||
translations (map #(translation-keyname :sc %) (keys subs-bodys))
|
||||
match-shortcut? (some #(matches-search % @filter-term) translations)
|
||||
visible? (some #(= % section-id) @open-sections)]
|
||||
|
||||
(when (or match-section? match-subsection? match-shortcut?)
|
||||
[:div {:class (stl/css :section)
|
||||
:on-click (manage-sections section-id)}
|
||||
[:> section-title* {:name section-translation
|
||||
:is-visible visible?
|
||||
:is-sub false}]
|
||||
|
||||
[:div {:style {:display (if visible? "initial" "none")}}
|
||||
[:> shortcut-subsection* {:subsections subsections
|
||||
:open-sections open-sections
|
||||
:manage-sections manage-sections
|
||||
:is-match-section match-section?
|
||||
:filter-term filter-term
|
||||
:editable? editable?
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit
|
||||
:on-reset on-reset}]]])))
|
||||
122
frontend/src/app/main/ui/shortcuts.scss
Normal file
122
frontend/src/app/main/ui/shortcuts.scss
Normal file
@ -0,0 +1,122 @@
|
||||
// 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/.
|
||||
//
|
||||
// Copyright (c) KALEIDOS INC Sucursal en España SL
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
|
||||
.section {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.shortcuts-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: deprecated.$s-12;
|
||||
overflow-y: auto;
|
||||
font-size: deprecated.$fs-12;
|
||||
color: var(--title-foreground-color);
|
||||
}
|
||||
|
||||
.section-title,
|
||||
.subsection-title {
|
||||
@include deprecated.uppercase-title-typography;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: deprecated.$s-8 0;
|
||||
cursor: pointer;
|
||||
|
||||
.subsection-name,
|
||||
.section-name {
|
||||
padding-left: deprecated.$s-4;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--title-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.subsection-title {
|
||||
text-transform: none;
|
||||
padding-left: deprecated.$s-12;
|
||||
}
|
||||
|
||||
.subsection-menu {
|
||||
margin-bottom: deprecated.$s-4;
|
||||
}
|
||||
|
||||
.sub-menu {
|
||||
margin-bottom: deprecated.$s-4;
|
||||
|
||||
.shortcuts-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
min-height: deprecated.$s-32;
|
||||
padding: deprecated.$s-6;
|
||||
margin-bottom: deprecated.$s-4;
|
||||
border-radius: deprecated.$br-8;
|
||||
background-color: var(--pill-background-color);
|
||||
|
||||
.command-name {
|
||||
@include deprecated.body-small-typography;
|
||||
|
||||
margin-left: deprecated.$s-2;
|
||||
color: var(--pill-foreground-color);
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.shortcut-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: deprecated.$s-2;
|
||||
}
|
||||
|
||||
.edit-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
|
||||
&:hover .edit-buttons {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.customized {
|
||||
background-color: var(--pill-background-color-hover, var(--pill-background-color));
|
||||
|
||||
.edit-buttons {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.keys {
|
||||
@include deprecated.flex-center;
|
||||
|
||||
gap: deprecated.$s-2;
|
||||
color: var(--pill-foreground-color);
|
||||
|
||||
.key {
|
||||
@include deprecated.body-small-typography;
|
||||
@include deprecated.flex-center;
|
||||
|
||||
text-transform: capitalize;
|
||||
height: deprecated.$s-20;
|
||||
padding: deprecated.$s-2 deprecated.$s-6;
|
||||
border-radius: deprecated.$s-6;
|
||||
background-color: var(--menu-shortcut-background-color);
|
||||
}
|
||||
|
||||
.space {
|
||||
margin: 0 deprecated.$s-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,6 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.config :as cf]
|
||||
[app.main.data.dashboard.shortcuts]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.shortcuts :as ds]
|
||||
@ -22,385 +21,16 @@
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.search-bar :refer [search-bar*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.product.panel-title :refer [panel-title*]]
|
||||
[app.main.ui.shortcuts :as ss]
|
||||
[app.main.ui.workspace.sidebar.shortcuts.edit-modal]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.strings :refer [matches-search]]
|
||||
[clojure.set :as set]
|
||||
[clojure.string]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc converted-chars*
|
||||
[{:keys [char command]}]
|
||||
(let [modified-keys {:up ds/up-arrow
|
||||
:down ds/down-arrow
|
||||
:left ds/left-arrow
|
||||
:right ds/right-arrow
|
||||
:plus "+"}
|
||||
macos-keys {:command "\u2318"
|
||||
:option "\u2325"
|
||||
:alt "\u2325"
|
||||
:delete "\u232B"
|
||||
:del "\u232B"
|
||||
:shift "\u21E7"
|
||||
:control "\u2303"
|
||||
:esc "\u238B"
|
||||
:enter "\u23CE"}
|
||||
is-macos? (cf/check-platform? :macos)
|
||||
char (if (contains? modified-keys (keyword char)) ((keyword char) modified-keys) char)
|
||||
char (if (and is-macos? (contains? macos-keys (keyword char))) ((keyword char) macos-keys) char)
|
||||
unique-key (str (d/name command) "-" char)]
|
||||
[:span {:class (stl/css :key)
|
||||
:key unique-key} char]))
|
||||
|
||||
(defn translation-keyname
|
||||
[type keyname]
|
||||
;; Execution time translation strings:
|
||||
(comment
|
||||
(tr "shortcut-subsection.alignment")
|
||||
(tr "shortcut-subsection.edit")
|
||||
(tr "shortcut-subsection.general-dashboard")
|
||||
(tr "shortcut-subsection.general-viewer")
|
||||
(tr "shortcut-subsection.main-menu")
|
||||
(tr "shortcut-subsection.modify-layers")
|
||||
(tr "shortcut-subsection.navigation-dashboard")
|
||||
(tr "shortcut-subsection.navigation-viewer")
|
||||
(tr "shortcut-subsection.navigation-workspace")
|
||||
(tr "shortcut-subsection.panels")
|
||||
(tr "shortcut-subsection.path-editor")
|
||||
(tr "shortcut-subsection.shape")
|
||||
(tr "shortcut-subsection.text-editor")
|
||||
(tr "shortcut-subsection.tools")
|
||||
(tr "shortcut-subsection.zoom-viewer")
|
||||
(tr "shortcut-subsection.zoom-workspace")
|
||||
(tr "shortcuts.add-comment")
|
||||
(tr "shortcuts.add-node")
|
||||
(tr "shortcuts.align-bottom")
|
||||
(tr "shortcuts.align-center")
|
||||
(tr "shortcuts.align-hcenter")
|
||||
(tr "shortcuts.align-justify")
|
||||
(tr "shortcuts.align-left")
|
||||
(tr "shortcuts.align-right")
|
||||
(tr "shortcuts.align-top")
|
||||
(tr "shortcuts.align-vcenter")
|
||||
(tr "shortcuts.artboard-selection")
|
||||
(tr "shortcuts.bold")
|
||||
(tr "shortcuts.bool-difference")
|
||||
(tr "shortcuts.bool-exclude")
|
||||
(tr "shortcuts.bool-intersection")
|
||||
(tr "shortcuts.bool-union")
|
||||
(tr "shortcuts.bring-back")
|
||||
(tr "shortcuts.bring-backward")
|
||||
(tr "shortcuts.bring-forward")
|
||||
(tr "shortcuts.bring-front")
|
||||
(tr "shortcuts.clear-undo")
|
||||
(tr "shortcuts.copy")
|
||||
(tr "shortcuts.copy-link")
|
||||
(tr "shortcuts.create-component-variant")
|
||||
(tr "shortcuts.create-new-project")
|
||||
(tr "shortcuts.cut")
|
||||
(tr "shortcuts.decrease-zoom")
|
||||
(tr "shortcuts.delete")
|
||||
(tr "shortcuts.delete-node")
|
||||
(tr "shortcuts.detach-component")
|
||||
(tr "shortcuts.draw-curve")
|
||||
(tr "shortcuts.draw-ellipse")
|
||||
(tr "shortcuts.draw-frame")
|
||||
(tr "shortcuts.draw-nodes")
|
||||
(tr "shortcuts.draw-path")
|
||||
(tr "shortcuts.draw-rect")
|
||||
(tr "shortcuts.draw-text")
|
||||
(tr "shortcuts.duplicate")
|
||||
(tr "shortcuts.escape")
|
||||
(tr "shortcuts.export-shapes")
|
||||
(tr "shortcuts.find")
|
||||
(tr "shortcuts.find-and-replace")
|
||||
(tr "shortcuts.fit-all")
|
||||
(tr "shortcuts.flip-horizontal")
|
||||
(tr "shortcuts.flip-vertical")
|
||||
(tr "shortcuts.font-size-dec")
|
||||
(tr "shortcuts.font-size-inc")
|
||||
(tr "shortcuts.go-to-drafts")
|
||||
(tr "shortcuts.go-to-libs")
|
||||
(tr "shortcuts.go-to-search")
|
||||
(tr "shortcuts.group")
|
||||
(tr "shortcuts.h-distribute")
|
||||
(tr "shortcuts.hide-ui")
|
||||
(tr "shortcuts.increase-zoom")
|
||||
(tr "shortcuts.insert-image")
|
||||
(tr "shortcuts.italic")
|
||||
(tr "shortcuts.join-nodes")
|
||||
(tr "shortcuts.line-through")
|
||||
(tr "shortcuts.make-corner")
|
||||
(tr "shortcuts.make-curve")
|
||||
(tr "shortcuts.mask")
|
||||
(tr "shortcuts.merge-nodes")
|
||||
(tr "shortcuts.move")
|
||||
(tr "shortcuts.move-fast-down")
|
||||
(tr "shortcuts.move-fast-left")
|
||||
(tr "shortcuts.move-fast-right")
|
||||
(tr "shortcuts.move-fast-up")
|
||||
(tr "shortcuts.move-nodes")
|
||||
(tr "shortcuts.move-unit-down")
|
||||
(tr "shortcuts.move-unit-left")
|
||||
(tr "shortcuts.move-unit-right")
|
||||
(tr "shortcuts.move-unit-up")
|
||||
(tr "shortcuts.next-frame")
|
||||
(tr "shortcuts.opacity-0")
|
||||
(tr "shortcuts.opacity-1")
|
||||
(tr "shortcuts.opacity-2")
|
||||
(tr "shortcuts.opacity-3")
|
||||
(tr "shortcuts.opacity-4")
|
||||
(tr "shortcuts.opacity-5")
|
||||
(tr "shortcuts.opacity-6")
|
||||
(tr "shortcuts.opacity-7")
|
||||
(tr "shortcuts.opacity-8")
|
||||
(tr "shortcuts.opacity-9")
|
||||
(tr "shortcuts.open-color-picker")
|
||||
(tr "shortcuts.open-comments")
|
||||
(tr "shortcuts.open-dashboard")
|
||||
(tr "shortcuts.open-inspect")
|
||||
(tr "shortcuts.open-interactions")
|
||||
(tr "shortcuts.open-viewer")
|
||||
(tr "shortcuts.open-workspace")
|
||||
(tr "shortcuts.paste")
|
||||
(tr "shortcuts.paste-replace")
|
||||
(tr "shortcuts.prev-frame")
|
||||
(tr "shortcuts.redo")
|
||||
(tr "shortcuts.rename")
|
||||
(tr "shortcuts.reset-zoom")
|
||||
(tr "shortcuts.scale")
|
||||
(tr "shortcuts.search-placeholder")
|
||||
(tr "shortcuts.select-all")
|
||||
(tr "shortcuts.select-next")
|
||||
(tr "shortcuts.select-parent-layer")
|
||||
(tr "shortcuts.select-prev")
|
||||
(tr "shortcuts.separate-nodes")
|
||||
(tr "shortcuts.show-pixel-grid")
|
||||
(tr "shortcuts.show-shortcuts")
|
||||
(tr "shortcuts.snap-nodes")
|
||||
(tr "shortcuts.snap-pixel-grid")
|
||||
(tr "shortcuts.start-editing")
|
||||
(tr "shortcuts.start-measure")
|
||||
(tr "shortcuts.stop-measure")
|
||||
(tr "shortcuts.thumbnail-set")
|
||||
(tr "shortcuts.toggle-alignment")
|
||||
(tr "shortcuts.toggle-assets")
|
||||
(tr "shortcuts.toggle-colorpalette")
|
||||
(tr "shortcuts.toggle-focus-mode")
|
||||
(tr "shortcuts.toggle-fullscreen")
|
||||
(tr "shortcuts.toggle-guides")
|
||||
(tr "shortcuts.toggle-history")
|
||||
(tr "shortcuts.toggle-layers")
|
||||
(tr "shortcuts.toggle-layout-flex")
|
||||
(tr "shortcuts.toggle-layout-grid")
|
||||
(tr "shortcuts.toggle-lock")
|
||||
(tr "shortcuts.toggle-lock-size")
|
||||
(tr "shortcuts.toggle-rulers")
|
||||
(tr "shortcuts.toggle-snap-guides")
|
||||
(tr "shortcuts.toggle-snap-ruler-guide")
|
||||
(tr "shortcuts.toggle-textpalette")
|
||||
(tr "shortcuts.toggle-theme")
|
||||
(tr "shortcuts.toggle-visibility")
|
||||
(tr "shortcuts.toggle-zoom-style")
|
||||
(tr "shortcuts.underline")
|
||||
(tr "shortcuts.undo")
|
||||
(tr "shortcuts.ungroup")
|
||||
(tr "shortcuts.unmask")
|
||||
(tr "shortcuts.v-distribute")
|
||||
(tr "shortcuts.zoom-lense-decrease")
|
||||
(tr "shortcuts.zoom-lense-increase")
|
||||
(tr "shortcuts.zoom-selected"))
|
||||
|
||||
(let [translat-pre (case type
|
||||
:sc "shortcuts."
|
||||
:sec "shortcut-section."
|
||||
:sub-sec "shortcut-subsection.")]
|
||||
(tr (str translat-pre (d/name keyname)))))
|
||||
|
||||
(defn add-translation
|
||||
[type item]
|
||||
(map (fn [[k v]] [k (assoc v :translation (translation-keyname type k))]) item))
|
||||
|
||||
(defn shortcuts->subsections
|
||||
"A function to obtain the list of subsections and their
|
||||
associated shortcus from the general map of shortcuts"
|
||||
[shortcuts]
|
||||
(let [subsections (into #{} (mapcat :subsections) (vals shortcuts))
|
||||
get-sc-by-subsection
|
||||
(fn [subsection [k v]]
|
||||
(when (some #(= subsection %) (:subsections v)) {k v}))
|
||||
reduce-sc
|
||||
(fn [acc subsection]
|
||||
(let [shortcuts-by-subsection (into {} (keep (partial get-sc-by-subsection subsection) shortcuts))]
|
||||
(assoc acc subsection {:children shortcuts-by-subsection})))]
|
||||
(reduce reduce-sc {} subsections)))
|
||||
|
||||
(mf/defc shortcuts-keys*
|
||||
[{:keys [content command]}]
|
||||
(let [managed-list (if (coll? content)
|
||||
content
|
||||
(conj () content))
|
||||
chars-list (map ds/split-sc managed-list)
|
||||
last-element (last chars-list)
|
||||
short-char-list (if (= 1 (count chars-list))
|
||||
chars-list
|
||||
(drop-last chars-list))
|
||||
penultimate (last short-char-list)]
|
||||
[:span {:class (stl/css :keys)}
|
||||
(for [chars short-char-list]
|
||||
[:* {:key (str/join chars)}
|
||||
(for [char chars]
|
||||
[:> converted-chars* {:key (dm/str char "-" (name command))
|
||||
:char char
|
||||
:command command}])
|
||||
(when (not= chars penultimate) [:span {:class (stl/css :space)} ","])])
|
||||
(when (not= last-element penultimate)
|
||||
[:*
|
||||
[:span {:class (stl/css :space)} (tr "shortcuts.or")]
|
||||
(for [char last-element]
|
||||
[:> converted-chars* {:key (dm/str char "-" (name command))
|
||||
:char char
|
||||
:command command}])])]))
|
||||
|
||||
(mf/defc shortcut-row*
|
||||
[{:keys [elements filter-term is-match-section is-match-subsection
|
||||
editable? custom-shortcuts on-edit on-reset]}]
|
||||
(let [shortcut-name (keys elements)
|
||||
shortcut-translations (map #(translation-keyname :sc %) shortcut-name)
|
||||
match-shortcut? (some #(matches-search % @filter-term) shortcut-translations)
|
||||
filtered (if (and (or is-match-section is-match-subsection) (not match-shortcut?))
|
||||
shortcut-translations
|
||||
(filter #(matches-search % @filter-term) shortcut-translations))
|
||||
sorted-filtered (sort filtered)]
|
||||
|
||||
[:ul {:class (stl/css :sub-menu)}
|
||||
(for [command-translate sorted-filtered]
|
||||
(let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements))
|
||||
[command comand-info] sc-by-translate
|
||||
content (or (:show-command comand-info) (:command comand-info))
|
||||
customized? (and editable? (contains? custom-shortcuts command))]
|
||||
[:li {:class (stl/css-case :shortcuts-name true
|
||||
:customized customized?)
|
||||
:key command-translate}
|
||||
[:span {:class (stl/css :command-name)}
|
||||
command-translate]
|
||||
[:div {:class (stl/css :shortcut-actions)}
|
||||
[:> shortcuts-keys* {:content content
|
||||
:command command}]
|
||||
(when editable?
|
||||
[:div {:class (stl/css :edit-buttons)}
|
||||
(when customized?
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "shortcuts.reset")
|
||||
:on-click (fn [e]
|
||||
(dom/stop-propagation e)
|
||||
(on-reset command))
|
||||
:icon i/reload
|
||||
:icon-size "s"}])
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "shortcuts.edit")
|
||||
:on-click (fn [e]
|
||||
(dom/stop-propagation e)
|
||||
(on-edit command))
|
||||
:icon i/curve
|
||||
:icon-size "s"}]])]]))]))
|
||||
|
||||
(mf/defc section-title*
|
||||
[{:keys [name is-visible is-sub]}]
|
||||
[:div {:class (if is-sub
|
||||
(stl/css :subsection-title)
|
||||
(stl/css :section-title))}
|
||||
[:> icon* {:icon-id (if is-visible i/arrow-down i/arrow-right)
|
||||
:size "s"}]
|
||||
[:span {:class (if is-sub
|
||||
(stl/css :subsection-name)
|
||||
(stl/css :section-name))} name]])
|
||||
|
||||
(mf/defc shortcut-subsection*
|
||||
[{:keys [subsections manage-sections filter-term is-match-section open-sections
|
||||
editable? custom-shortcuts on-edit on-reset]}]
|
||||
(let [subsections-names (keys subsections)
|
||||
subsection-translations (if (= :none (first subsections-names))
|
||||
(map #(translation-keyname :sc %) subsections-names)
|
||||
(map #(translation-keyname :sub-sec %) subsections-names))
|
||||
sorted-translations (sort subsection-translations)]
|
||||
;; Basics section is treated different because it has no sub sections
|
||||
(if (= :none (first subsections-names))
|
||||
(let [basic-shortcuts (:none subsections)]
|
||||
[:> shortcut-row* {:elements (:children basic-shortcuts)
|
||||
:filter-term filter-term
|
||||
:is-match-section is-match-section
|
||||
:is-match-subsection true
|
||||
:editable? editable?
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit
|
||||
:on-reset on-reset}])
|
||||
|
||||
[:ul {:class (stl/css :subsection-menu)}
|
||||
(for [sub-translated sorted-translations]
|
||||
(let [sub-by-translate (first (filter #(= (:translation (second %)) sub-translated) subsections))
|
||||
[sub-name sub-info] sub-by-translate
|
||||
visible? (some #(= % (:id sub-info)) @open-sections)
|
||||
match-subsection? (matches-search (translation-keyname :sub-sec sub-name) @filter-term)
|
||||
shortcut-names (map #(translation-keyname :sc %) (keys (:children sub-info)))
|
||||
match-shortcuts? (some #(matches-search % @filter-term) shortcut-names)]
|
||||
(when (or match-subsection? match-shortcuts? is-match-section)
|
||||
[:li {:key sub-translated
|
||||
:on-click (manage-sections (:id sub-info))}
|
||||
[:> section-title* {:name sub-translated
|
||||
:is-visible visible?
|
||||
:is-sub true}]
|
||||
|
||||
[:div {:style {:display (if visible? "initial" "none")}}
|
||||
[:> shortcut-row* {:elements (:children sub-info)
|
||||
:filter-term filter-term
|
||||
:is-match-section is-match-section
|
||||
:is-match-subsection match-subsection?
|
||||
:editable? editable?
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit
|
||||
:on-reset on-reset}]]])))])))
|
||||
|
||||
(mf/defc shortcut-section*
|
||||
[{:keys [section manage-sections open-sections filter-term
|
||||
editable? custom-shortcuts on-edit on-reset]}]
|
||||
(let [[section-key section-info] section
|
||||
section-id (:id section-info)
|
||||
section-translation (translation-keyname :sec section-key)
|
||||
match-section? (matches-search section-translation @filter-term)
|
||||
subsections (:children section-info)
|
||||
subs-names (keys subsections)
|
||||
subs-bodys (reduce #(conj %1 (:children (%2 subsections))) {} subs-names)
|
||||
sub-trans (map #(if (= "none" (d/name %))
|
||||
nil
|
||||
(translation-keyname :sub-sec %)) subs-names)
|
||||
match-subsection? (some #(matches-search % @filter-term) sub-trans)
|
||||
translations (map #(translation-keyname :sc %) (keys subs-bodys))
|
||||
match-shortcut? (some #(matches-search % @filter-term) translations)
|
||||
visible? (some #(= % section-id) @open-sections)]
|
||||
|
||||
(when (or match-section? match-subsection? match-shortcut?)
|
||||
[:div {:class (stl/css :section)
|
||||
:on-click (manage-sections section-id)}
|
||||
[:> section-title* {:name section-translation
|
||||
:is-visible visible?
|
||||
:is-sub false}]
|
||||
|
||||
[:div {:style {:display (if visible? "initial" "none")}}
|
||||
[:> shortcut-subsection* {:subsections subsections
|
||||
:open-sections open-sections
|
||||
:manage-sections manage-sections
|
||||
:is-match-section match-section?
|
||||
:filter-term filter-term
|
||||
:editable? editable?
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit
|
||||
:on-reset on-reset}]]])))
|
||||
|
||||
(def ^:private workspace-shortcuts-raw
|
||||
(d/deep-merge app.main.data.workspace.path.shortcuts/shortcuts
|
||||
app.main.data.workspace.shortcuts/shortcuts))
|
||||
@ -413,71 +43,23 @@
|
||||
workspace-shortcuts-custom (ds/apply-custom-overrides workspace-shortcuts-raw custom-shortcuts)
|
||||
|
||||
all-workspace-shortcuts (->> workspace-shortcuts-custom
|
||||
(add-translation :sc)
|
||||
(ss/add-translation :sc)
|
||||
(into {}))
|
||||
|
||||
dashboard-shortcuts (->> app.main.data.dashboard.shortcuts/shortcuts
|
||||
(add-translation :sc)
|
||||
(ss/add-translation :sc)
|
||||
(into {}))
|
||||
viewer-shortcuts (->> app.main.data.viewer.shortcuts/shortcuts
|
||||
(add-translation :sc)
|
||||
(ss/add-translation :sc)
|
||||
(into {}))
|
||||
open-sections (mf/use-state [[1]])
|
||||
filter-term (mf/use-state "")
|
||||
|
||||
close-fn #(st/emit! (dw/toggle-layout-flag :shortcuts))
|
||||
|
||||
walk (fn walk [element parent-id]
|
||||
(if (nil? element)
|
||||
element
|
||||
(let [rec-fn (fn [index [k item]]
|
||||
(let [item-id (if (nil? parent-id)
|
||||
[index]
|
||||
(conj parent-id index))]
|
||||
[k (assoc item :id item-id :children (walk (:children item) item-id))]))]
|
||||
(into {} (map-indexed (partial rec-fn) element)))))
|
||||
{:keys [all-shortcuts all-sc-names all-sub-names all-section-names]}
|
||||
(ss/build-all-shortcuts all-workspace-shortcuts dashboard-shortcuts viewer-shortcuts)
|
||||
|
||||
workspace-sc-by-subsections (->> (shortcuts->subsections all-workspace-shortcuts)
|
||||
(add-translation :sub-sec)
|
||||
(into {}))
|
||||
dashboard-sc-by-subsections (->> (shortcuts->subsections dashboard-shortcuts)
|
||||
(add-translation :sub-sec)
|
||||
(into {}))
|
||||
viewer-sc-by-subsections (->> (shortcuts->subsections viewer-shortcuts)
|
||||
(add-translation :sub-sec)
|
||||
(into {}))
|
||||
basics-elements (into {} (concat (:children (:basics workspace-sc-by-subsections))
|
||||
(:children (:basics dashboard-sc-by-subsections))
|
||||
(:children (:basics viewer-sc-by-subsections))))
|
||||
|
||||
workspace-sc-by-subsections (dissoc workspace-sc-by-subsections :basics)
|
||||
dashboard-sc-by-subsections (dissoc dashboard-sc-by-subsections :basics)
|
||||
viewer-sc-by-subsections (dissoc viewer-sc-by-subsections :bassics)
|
||||
|
||||
all-shortcuts {:basics {:id [1]
|
||||
:children {:none {:children basics-elements}}
|
||||
:translation (tr "shortcut-section.basics")}
|
||||
:workspace {:id [2]
|
||||
:children workspace-sc-by-subsections
|
||||
:translation (tr "shortcut-section.workspace")}
|
||||
:dashboard {:id [3]
|
||||
:children dashboard-sc-by-subsections
|
||||
:translation (tr "shortcut-section.dashboard")}
|
||||
:viewer {:id [4]
|
||||
:children viewer-sc-by-subsections
|
||||
:translation (tr "shortcut-section.viewer")}}
|
||||
all-shortcuts (walk all-shortcuts nil)
|
||||
|
||||
all-sc-names (map #(translation-keyname :sc %) (concat
|
||||
(keys all-workspace-shortcuts)
|
||||
(keys dashboard-shortcuts)
|
||||
(keys viewer-shortcuts)))
|
||||
|
||||
all-sub-names (map #(translation-keyname :sub-sec %) (concat
|
||||
(keys workspace-sc-by-subsections)
|
||||
(keys dashboard-sc-by-subsections)
|
||||
(keys viewer-sc-by-subsections)))
|
||||
all-section-names (map #(translation-keyname :sec %) (keys all-shortcuts))
|
||||
all-item-names (concat all-sc-names all-sub-names all-section-names)
|
||||
match-any? (some #(matches-search % @filter-term) all-item-names)
|
||||
|
||||
@ -541,7 +123,7 @@
|
||||
current-command (or (get custom-shortcuts shortcut-key) default-command)]
|
||||
(st/emit! (modal/show :shortcut-edit
|
||||
{:shortcut-key shortcut-key
|
||||
:shortcut-name (translation-keyname :sc shortcut-key)
|
||||
:shortcut-name (ss/translation-keyname :sc shortcut-key)
|
||||
:current-command current-command
|
||||
:default-command default-command
|
||||
:all-shortcuts workspace-shortcuts-custom})))))
|
||||
@ -580,13 +162,13 @@
|
||||
(for [section all-shortcuts]
|
||||
(let [[section-key _] section
|
||||
ws-editable? (contains? #{:basics :workspace} section-key)]
|
||||
[:> shortcut-section* {:key (->> section second :id first)
|
||||
:section section
|
||||
:manage-sections manage-sections
|
||||
:open-sections open-sections
|
||||
:filter-term filter-term
|
||||
:editable? ws-editable?
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit-shortcut
|
||||
:on-reset on-reset-shortcut}]))]
|
||||
[:> ss/shortcut-section* {:key (name section-key)
|
||||
:section section
|
||||
:manage-sections manage-sections
|
||||
:open-sections open-sections
|
||||
:filter-term filter-term
|
||||
:editable? false
|
||||
:custom-shortcuts custom-shortcuts
|
||||
:on-edit on-edit-shortcut
|
||||
:on-reset on-reset-shortcut}]))]
|
||||
[:div {:class (stl/css :not-found)} (tr "shortcuts.not-found")])]))
|
||||
|
||||
@ -32,17 +32,6 @@
|
||||
margin: var(--sp-s) var(--sp-s) 0 var(--sp-s);
|
||||
}
|
||||
|
||||
.section {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.not-found {
|
||||
@include deprecated.body-small-typography;
|
||||
|
||||
color: var(--empty-message-foreground-color);
|
||||
margin: deprecated.$s-12;
|
||||
}
|
||||
|
||||
.shortcuts-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -51,105 +40,11 @@
|
||||
overflow-y: auto;
|
||||
font-size: deprecated.$fs-12;
|
||||
color: var(--title-foreground-color);
|
||||
|
||||
.section-title,
|
||||
.subsection-title {
|
||||
@include deprecated.uppercase-title-typography;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: deprecated.$s-8 0;
|
||||
cursor: pointer;
|
||||
|
||||
.subsection-name,
|
||||
.section-name {
|
||||
padding-left: deprecated.$s-4;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--title-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.subsection-title {
|
||||
text-transform: none;
|
||||
padding-left: deprecated.$s-12;
|
||||
}
|
||||
|
||||
.subsection-menu {
|
||||
margin-bottom: deprecated.$s-4;
|
||||
}
|
||||
|
||||
.sub-menu {
|
||||
margin-bottom: deprecated.$s-4;
|
||||
|
||||
.shortcuts-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
min-height: deprecated.$s-32;
|
||||
padding: deprecated.$s-6;
|
||||
margin-bottom: deprecated.$s-4;
|
||||
border-radius: deprecated.$br-8;
|
||||
background-color: var(--pill-background-color);
|
||||
|
||||
.command-name {
|
||||
@include deprecated.body-small-typography;
|
||||
|
||||
margin-left: deprecated.$s-2;
|
||||
color: var(--pill-foreground-color);
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.shortcut-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: deprecated.$s-2;
|
||||
}
|
||||
|
||||
.edit-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
|
||||
&:hover .edit-buttons {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.customized {
|
||||
background-color: var(--pill-background-color-hover, var(--pill-background-color));
|
||||
|
||||
.edit-buttons {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.keys {
|
||||
@include deprecated.flex-center;
|
||||
|
||||
gap: deprecated.$s-2;
|
||||
color: var(--pill-foreground-color);
|
||||
|
||||
.key {
|
||||
@include deprecated.body-small-typography;
|
||||
@include deprecated.flex-center;
|
||||
|
||||
text-transform: capitalize;
|
||||
height: deprecated.$s-20;
|
||||
padding: deprecated.$s-2 deprecated.$s-6;
|
||||
border-radius: deprecated.$s-6;
|
||||
background-color: var(--menu-shortcut-background-color);
|
||||
}
|
||||
|
||||
.space {
|
||||
margin: 0 deprecated.$s-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.not-found {
|
||||
@include deprecated.body-small-typography;
|
||||
|
||||
color: var(--empty-message-foreground-color);
|
||||
margin: deprecated.$s-12;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user