0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-12 07:41:43 -05:00

Merge pull request #1970 from penpot/eva-shortcuts2

 Shortcuts improvements
This commit is contained in:
Pablo Alba 2022-06-02 16:50:42 +02:00 committed by GitHub
commit 65cda41245
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 342 additions and 241 deletions

View file

@ -7,9 +7,6 @@
.left-toolbar { .left-toolbar {
background-color: $color-gray-50; background-color: $color-gray-50;
}
.left-toolbar-inside {
align-items: center; align-items: center;
border-right: 1px solid $color-gray-60; border-right: 1px solid $color-gray-60;
display: flex; display: flex;
@ -25,44 +22,47 @@
margin: 0; margin: 0;
li { li {
align-items: center;
background-color: transparent;
border: 1px solid transparent;
cursor: pointer;
display: flex;
flex-shrink: 0;
height: 48px;
justify-content: center;
position: relative; position: relative;
width: 48px;
color: $color-gray-20; color: $color-gray-20;
button {
svg { background-color: transparent;
fill: $color-gray-20; border: none;
height: 16px; cursor: pointer;
width: 16px; height: 48px;
} width: 48px;
display: flex;
&:hover { align-items: center;
background-color: $color-primary; justify-content: center;
color: $color-gray-50; flex-shrink: 0;
color: inherit;
svg { svg {
fill: $color-gray-50; fill: $color-gray-20;
height: 16px;
width: 16px;
} }
}
&.selected { &:hover {
background-color: $color-gray-60; background-color: $color-primary;
color: $color-primary; color: $color-gray-50;
svg { svg {
fill: $color-primary; fill: $color-gray-50;
}
} }
}
&.separator { &.selected {
border-top: 1px solid $color-gray-60; background-color: $color-gray-60;
color: $color-primary;
svg {
fill: $color-primary;
}
}
&.separator {
border-top: 1px solid $color-gray-60;
}
} }
} }

View file

@ -305,6 +305,12 @@ button.collapse-sidebar {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex-grow: 1; flex-grow: 1;
svg {
height: 18px;
width: 18px;
transform: rotate(45deg);
fill: $color-gray-20;
}
} }
.shortcuts-close-button { .shortcuts-close-button {
display: flex; display: flex;
@ -380,6 +386,7 @@ button.collapse-sidebar {
cursor: pointer; cursor: pointer;
margin-top: 4px; margin-top: 4px;
font-size: $fs12; font-size: $fs12;
.section-name { .section-name {
color: $color-white; color: $color-white;
} }
@ -408,6 +415,20 @@ button.collapse-sidebar {
} }
} }
.section-title,
.subsection-title {
&:hover {
background-color: $color-primary;
.subsection-name,
.section-name {
color: $color-gray-60;
}
svg {
fill: $color-gray-60;
}
}
}
.shortcut-name { .shortcut-name {
border: 1px solid $color-gray-60; border: 1px solid $color-gray-60;
border-radius: 4px; border-radius: 4px;
@ -441,4 +462,13 @@ button.collapse-sidebar {
} }
} }
} }
.not-found {
background-color: $color-gray-60;
padding: 4px 0;
color: $color-white;
display: flex;
justify-content: center;
margin-top: 4px;
font-size: $fs12;
}
} }

View file

@ -47,16 +47,17 @@
:position (gpt/point x y)}] :position (gpt/point x y)}]
(st/emit! (dwm/upload-media-workspace params)))))] (st/emit! (dwm/upload-media-workspace params)))))]
[:li.tooltip.tooltip-right [:li
{:alt (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image)) [:button.tooltip.tooltip-right
:on-click on-click} {:alt (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
[:* :on-click on-click}
i/image [:*
[:& file-uploader {:input-id "image-upload" i/image
:accept cm/str-image-types [:& file-uploader {:input-id "image-upload"
:multi true :accept cm/str-image-types
:ref ref :multi true
:on-selected on-files-selected}]]])) :ref ref
:on-selected on-files-selected}]]]]))
(mf/defc left-toolbar (mf/defc left-toolbar
{::mf/wrap [mf/memo] {::mf/wrap [mf/memo]
@ -67,61 +68,69 @@
select-drawtool #(st/emit! :interrupt (dw/select-for-drawing %)) select-drawtool #(st/emit! :interrupt (dw/select-for-drawing %))
edition (mf/deref refs/selected-edition)] edition (mf/deref refs/selected-edition)]
[:aside.left-toolbar [:aside.left-toolbar
[:div.left-toolbar-inside [:ul.left-toolbar-options
[:ul.left-toolbar-options [:li
[:li.tooltip.tooltip-right [:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.move" (sc/get-tooltip :move)) {:alt (tr "workspace.toolbar.move" (sc/get-tooltip :move))
:class (when (and (nil? selected-drawtool) :class (when (and (nil? selected-drawtool)
(not edition)) "selected") (not edition)) "selected")
:on-click #(st/emit! :interrupt)} :on-click #(st/emit! :interrupt)}
i/pointer-inner] i/pointer-inner]]
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame)) {:alt (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
:class (when (= selected-drawtool :frame) "selected") :class (when (= selected-drawtool :frame) "selected")
:on-click (partial select-drawtool :frame) :on-click (partial select-drawtool :frame)
:data-test "artboard-btn"} :data-test "artboard-btn"}
i/artboard] i/artboard]]
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) {:alt (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
:class (when (= selected-drawtool :rect) "selected") :class (when (= selected-drawtool :rect) "selected")
:on-click (partial select-drawtool :rect) :on-click (partial select-drawtool :rect)
:data-test "rect-btn"} :data-test "rect-btn"}
i/box] i/box]]
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) {:alt (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
:class (when (= selected-drawtool :circle) "selected") :class (when (= selected-drawtool :circle) "selected")
:on-click (partial select-drawtool :circle) :on-click (partial select-drawtool :circle)
:data-test "ellipse-btn"} :data-test "ellipse-btn"}
i/circle] i/circle]]
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) {:alt (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
:class (when (= selected-drawtool :text) "selected") :class (when (= selected-drawtool :text) "selected")
:on-click (partial select-drawtool :text)} :on-click (partial select-drawtool :text)}
i/text] i/text]]
[:& image-upload] [:& image-upload]
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) {:alt (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
:class (when (= selected-drawtool :curve) "selected") :class (when (= selected-drawtool :curve) "selected")
:on-click (partial select-drawtool :curve) :on-click (partial select-drawtool :curve)
:data-test "curve-btn"} :data-test "curve-btn"}
i/pencil] i/pencil]]
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) {:alt (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
:class (when (= selected-drawtool :path) "selected") :class (when (= selected-drawtool :path) "selected")
:on-click (partial select-drawtool :path) :on-click (partial select-drawtool :path)
:data-test "path-btn"} :data-test "path-btn"}
i/pen] i/pen]]
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment)) {:alt (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment))
:class (when (= selected-drawtool :comments) "selected") :class (when (= selected-drawtool :comments) "selected")
:on-click (partial select-drawtool :comments)} :on-click (partial select-drawtool :comments)}
i/chat]] i/chat]]]
[:ul.left-toolbar-options.panels [:ul.left-toolbar-options.panels
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette)) {:alt (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette))
:class (when (contains? layout :textpalette) "selected") :class (when (contains? layout :textpalette) "selected")
:on-click (fn [] :on-click (fn []
@ -130,9 +139,10 @@
(ts/schedule 300 #(st/emit! (dw/remove-layout-flag :colorpalette) (ts/schedule 300 #(st/emit! (dw/remove-layout-flag :colorpalette)
(-> (dw/toggle-layout-flag :textpalette) (-> (dw/toggle-layout-flag :textpalette)
(vary-meta assoc ::ev/origin "workspace-left-toolbar")))))} (vary-meta assoc ::ev/origin "workspace-left-toolbar")))))}
"Ag"] "Ag"]]
[:li.tooltip.tooltip-right [:li
[:button.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette)) {:alt (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette))
:class (when (contains? layout :colorpalette) "selected") :class (when (contains? layout :colorpalette) "selected")
:on-click (fn [] :on-click (fn []
@ -141,8 +151,9 @@
(ts/schedule 300 #(st/emit! (dw/remove-layout-flag :textpalette) (ts/schedule 300 #(st/emit! (dw/remove-layout-flag :textpalette)
(-> (dw/toggle-layout-flag :colorpalette) (-> (dw/toggle-layout-flag :colorpalette)
(vary-meta assoc ::ev/origin "workspace-left-toolbar")))))} (vary-meta assoc ::ev/origin "workspace-left-toolbar")))))}
i/palette] i/palette]]
[:li.tooltip.tooltip-right.separator [:li
[:button.tooltip.tooltip-right.separator
{:alt (tr "workspace.toolbar.shortcuts" (sc/get-tooltip :show-shortcuts)) {:alt (tr "workspace.toolbar.shortcuts" (sc/get-tooltip :show-shortcuts))
:class (when (contains? layout :shortcuts) "selected") :class (when (contains? layout :shortcuts) "selected")
:on-click (fn [] :on-click (fn []

View file

@ -19,6 +19,7 @@
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :refer [tr]] [app.util.i18n :refer [tr]]
[app.util.strings :refer [matches-search]] [app.util.strings :refer [matches-search]]
[clojure.set :as set]
[clojure.string] [clojure.string]
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.alpha :as mf])) [rumext.alpha :as mf]))
@ -40,12 +41,24 @@
:esc "\u238B" :esc "\u238B"
:enter "\u23CE"} :enter "\u23CE"}
is-macos? (cf/check-platform? :macos) is-macos? (cf/check-platform? :macos)
char (if (contains? modified-keys (keyword key)) ((keyword char) modified-keys) char) 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) char (if (and is-macos? (contains? macos-keys (keyword char))) ((keyword char) macos-keys) char)
unique-key (str (d/name command) "-" char)] unique-key (str (d/name command) "-" char)]
[:* [:*
[:span.char-box {:key unique-key} char]])) [:span.char-box {:key unique-key} char]]))
(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 (defn shortcuts->subsections
"A function to obtain the list of subsections and their "A function to obtain the list of subsections and their
associated shortcus from the general map of shortcuts" associated shortcus from the general map of shortcuts"
@ -53,24 +66,24 @@
(let [subsections (into #{} (mapcat :subsections) (vals shortcuts)) (let [subsections (into #{} (mapcat :subsections) (vals shortcuts))
get-sc-by-subsection get-sc-by-subsection
(fn [subsection [k v]] (fn [subsection [k v]]
(when (some #(= subsection %) (:subsections v)) k)) (when (some #(= subsection %) (:subsections v)) {k v}))
reduce-sc reduce-sc
(fn [acc subsection] (fn [acc subsection]
(let [shortcuts-by-subsection (keep (partial get-sc-by-subsection subsection) shortcuts)] (let [shortcuts-by-subsection (into {} (keep (partial get-sc-by-subsection subsection) shortcuts))]
(assoc acc subsection shortcuts-by-subsection)))] (assoc acc subsection {:children shortcuts-by-subsection})))]
(reduce reduce-sc {} subsections))) (reduce reduce-sc {} subsections)))
(mf/defc shortcuts-keys (mf/defc shortcuts-keys
[{:keys [content command] :as props}] [{:keys [content command] :as props}]
(let [managed-list (if (coll? content) (let [managed-list (if (coll? content)
content content
(conj () content)) (conj () content))
split-sc (fn [sc] split-sc (fn [sc]
(let [sc (cond-> sc (str/includes? sc "++") (let [sc (cond-> sc (str/includes? sc "++")
(str/replace "++" "+plus"))] (str/replace "++" "+plus"))]
(if (= (count sc) 1) (if (= (count sc) 1)
[sc] [sc]
(str/split sc #"\+| ")))) (str/split sc #"\+| "))))
chars-list (map split-sc managed-list) chars-list (map split-sc managed-list)
last-element (last chars-list) last-element (last chars-list)
short-char-list (if (= 1 (count chars-list)) short-char-list (if (= 1 (count chars-list))
@ -82,175 +95,230 @@
[:* [:*
(for [char chars] (for [char chars]
[:& converted-chars {:char char :command command}]) [:& converted-chars {:char char :command command}])
(when (not= chars penultimate) [:span.space ","])]) (when (not= chars penultimate) [:span.space ","])])
(when (not= last-element penultimate) (when (not= last-element penultimate)
[:* [:*
[:span.space " or "] [:span.space (tr "shortcuts.or")]
(for [char last-element] (for [char last-element]
[:& converted-chars {:char char [:& converted-chars {:char char
:command command}])])])) :command command}])])]))
(mf/defc shortcut-row (mf/defc shortcut-row
[{:keys [shortcuts elements filter-term match-section? match-subsection?] :as props}] [{:keys [elements filter-term match-section? match-subsection?] :as props}]
(let [reduce-translation (fn [acc element] (assoc acc element (tr (str "shortcuts." (d/name element))))) (let [shortcut-name (keys elements)
translations (reduce reduce-translation {} elements) shortcut-translations (map #(translation-keyname :sc %) shortcut-name)
filtered (if (or match-section? match-subsection?) match-shortcut? (some #(matches-search % @filter-term) shortcut-translations)
(vals translations) filtered (if (and (or match-section? match-subsection?) (not match-shortcut?))
(filter #(matches-search % (:term @filter-term)) (vals translations))) shortcut-translations
sorted-filtered (sort filtered)] (filter #(matches-search % @filter-term) shortcut-translations))
sorted-filtered (sort filtered)]
[:ul.sub-menu [:ul.sub-menu
(for [command-translate sorted-filtered] (for [command-translate sorted-filtered]
(let [command (first (filter (comp #{command-translate} translations) (keys translations))) (let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements))
content (:command (command shortcuts)) [command comand-info] sc-by-translate
name (tr (str "shortcuts." (d/name command)))] content (:command comand-info)]
[:li.shortcut-name {:key command} [:li.shortcut-name {:key command-translate}
[:span.command-name name] [:span.command-name command-translate]
[:& shortcuts-keys {:content content [:& shortcuts-keys {:content content
:command command}]]))])) :command command}]]))]))
(mf/defc section-title (mf/defc section-title
[{:keys [is-visible? section elem-n] :as props}] [{:keys [is-visible? name is-sub?] :as props}]
(let [name (tr (str "shortcut-section." (d/name section)))] [:div {:class (if is-sub? "subsection-title" "section-title")}
[:div.section-title [:span.collapesed-shortcuts {:class (when is-visible? "open")} i/arrow-slide]
[:span.collapesed-shortcuts {:class (when is-visible? "open")} i/arrow-slide] [:span {:class (if is-sub? "subsection-name" "section-name")} name]])
[:span.section-name name]
[:span.shortcut-count "(" elem-n ")"]]))
(mf/defc subsection-title
[{:keys [subsection-name elements open-sections] :as props}]
(let [subsection-name2 (tr (str "shortcut-subsection." (d/name subsection-name)))]
[:div.subsection-title
[:span.collapesed-shortcuts {:class (when (some #(= % subsection-name) (:subsection @open-sections)) "open")} i/arrow-slide]
[:span.subsection-name subsection-name2]
[:span.shortcut-count "(" elements ")"]]))
(mf/defc shortcut-subsection (mf/defc shortcut-subsection
[{:keys [shortcuts-by-group manage-sections shortcuts filter-term match-section? open-sections] :as props}] [{:keys [subsections manage-sections filter-term match-section? open-sections] :as props}]
(let [reduce-translation (fn [acc subsection] (assoc acc subsection (tr (str "shortcut-subsection." (d/name subsection))))) (let [subsections-names (keys subsections)
translations (reduce reduce-translation {} (keys shortcuts-by-group)) subsection-translations (if (= :none (first subsections-names))
sorted-translations (sort (vals translations))] (map #(translation-keyname :sc %) subsections-names)
[:ul.subsection-menu (map #(translation-keyname :sub-sec %) subsections-names))
(for [sub-translate sorted-translations] sorted-translations (sort subsection-translations)]
(let [subsection (first (filter (comp #{sub-translate} translations) (keys translations))) ;; Basics section is treated different because it has no sub sections
elements (subsection shortcuts-by-group) (if (= :none (first subsections-names))
visible? (some #(= % subsection) (:subsection @open-sections)) (let [basic-shortcuts (:none subsections)]
match-subsection? (matches-search sub-translate (:term @filter-term)) [:& shortcut-row {:elements (:children basic-shortcuts)
:filter-term filter-term
:match-section? match-section?
:match-subsection? true}])
keywords (subsection shortcuts-by-group) [:ul.subsection-menu
matched-map (into {} (map (fn [element] {element (:translation (element shortcuts))}) keywords)) (for [sub-translated sorted-translations]
translations (vals matched-map) (let [sub-by-translate (first (filter #(= (:translation (second %)) sub-translated) subsections))
match-shortcut-in-sub? (some #(matches-search % (:term @filter-term)) translations) [sub-name sub-info] sub-by-translate
shortcut-count (count (filter #(matches-search % (:term @filter-term)) translations))] visible? (some #(= % (:id sub-info)) @open-sections)
(when (and (or match-section? match-subsection? match-shortcut-in-sub?) (not= subsection :basics)) match-subsection? (matches-search (translation-keyname :sub-sec sub-name) @filter-term)
[:li {:key subsection shortcut-names (map #(translation-keyname :sc %) (keys (:children sub-info)))
:on-click (manage-sections subsection true)} match-shortcuts? (some #(matches-search % @filter-term) shortcut-names)]
[:& subsection-title {:subsection-name subsection (when (or match-subsection? match-shortcuts? match-section?)
:open-sections open-sections [:li {:key sub-translated
:elements shortcut-count}] :on-click (manage-sections (:id sub-info))}
[:div {:style {:display (if visible? "initial" "none")}} [:& section-title {:name sub-translated
[:& shortcut-row {:shortcuts shortcuts :is-sub? true
:elements elements :is-visible? visible?}]
:filter-term filter-term
:match-section? match-section? [:div {:style {:display (if visible? "initial" "none")}}
:match-subsection? match-subsection?}]]])))])) [:& shortcut-row {:elements (:children sub-info)
:filter-term filter-term
:match-section? match-section?
:match-subsection? match-subsection?}]]])))])))
(mf/defc shortcut-section (mf/defc shortcut-section
[{:keys [section shortcuts shortcuts-by-group manage-sections filter-term open-sections] :as props}] [{:keys [section manage-sections open-sections filter-term] :as props}]
(let [section-name (d/name section) (let [[section-key section-info] section
visible? (some #(= % section) (:section @open-sections)) section-id (:id section-info)
section-translation (tr (str "shortcut-section." section-name)) section-translation (translation-keyname :sec section-key)
match-section? (matches-search section-translation (:term @filter-term)) match-section? (matches-search section-translation @filter-term)
subsections (map (fn [subsection] (tr (str "shortcut-subsection." (d/name subsection)))) (filter #(not= % :basics) (keys shortcuts-by-group))) subsections (:children section-info)
match-subsection? (some #(matches-search % (:term @filter-term)) subsections) subs-names (keys subsections)
keywords (keys shortcuts) subs-bodys (reduce #(conj %1 (:children (%2 subsections))) {} subs-names)
matched-map (into {} (map (fn [element] {element (:translation (element shortcuts))}) keywords)) sub-trans (map #(if (= "none" (d/name %))
translations (vals matched-map) nil
match-shortcut? (some #(matches-search % (:term @filter-term)) translations) (translation-keyname :sub-sec %)) subs-names)
filtered-shortcuts (count (filter #(matches-search % (:term @filter-term)) translations))] 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?) (when (or match-section? match-subsection? match-shortcut?)
[:div {:on-click (manage-sections section false)} [:div {:on-click (manage-sections section-id)}
[:& section-title {:is-visible? visible? [:& section-title {:is-visible? visible?
:section section :is-sub? false
:elem-n filtered-shortcuts}] :name section-translation}]
[:div {:style {:display (if visible? "initial" "none")}}
[:& shortcut-subsection {:shortcuts-by-group shortcuts-by-group
:manage-sections manage-sections
:match-section? match-section?
:open-sections open-sections
:filter-term filter-term
:shortcuts shortcuts}]]])))
(defn add-translation-to-shorcuts [:div {:style {:display (if visible? "initial" "none")}}
[shortcuts] [:& shortcut-subsection {:subsections subsections
(map (fn [[k v]] [k (assoc v :translation (tr (str "shortcuts." (d/name k))))]) shortcuts)) :open-sections open-sections
:manage-sections manage-sections
:match-section? match-section?
:filter-term filter-term}]]])))
(mf/defc shortcuts-container (mf/defc shortcuts-container
[] []
(let [workspace-shortcuts app.main.data.workspace.shortcuts/shortcuts (let [workspace-shortcuts app.main.data.workspace.shortcuts/shortcuts
path-shortcuts app.main.data.workspace.path.shortcuts/shortcuts path-shortcuts app.main.data.workspace.path.shortcuts/shortcuts
all-workspace-shortcuts (->> (d/deep-merge path-shortcuts workspace-shortcuts) all-workspace-shortcuts (->> (d/deep-merge path-shortcuts workspace-shortcuts)
(add-translation-to-shorcuts) (add-translation :sc)
(into {})) (into {}))
dashboard-shortcuts (->> app.main.data.dashboard.shortcuts/shortcuts dashboard-shortcuts (->> app.main.data.dashboard.shortcuts/shortcuts
(add-translation-to-shorcuts) (add-translation :sc)
(into {})) (into {}))
viewer-shortcuts (->> app.main.data.viewer.shortcuts/shortcuts viewer-shortcuts (->> app.main.data.viewer.shortcuts/shortcuts
(add-translation-to-shorcuts) (add-translation :sc)
(into {})) (into {}))
open-sections (mf/use-state [[1]])
all-shortcuts (d/deep-merge all-workspace-shortcuts dashboard-shortcuts viewer-shortcuts) filter-term (mf/use-state "")
workspace-sc-by-subsections (shortcuts->subsections all-workspace-shortcuts)
dashboard-sc-by-subsections (shortcuts->subsections dashboard-shortcuts)
viewer-sc-by-subsections (shortcuts->subsections viewer-shortcuts)
;; The basics section is treated separately because these elements
;; are obtained from the rest of the listings of shortcuts.
basics-elements (concat (:basics workspace-sc-by-subsections)
(:basics dashboard-sc-by-subsections)
(:basics viewer-sc-by-subsections))
reduce-translation (fn [acc sc] (assoc acc sc (tr (str "shortcuts." (d/name sc)))))
basics-translations (reduce reduce-translation {} basics-elements)
open-sections (mf/use-state {:section [:workspace] :subsection []})
basics-open? (some #(= % :basics) (:section @open-sections))
search-term (mf/use-state {:term ""})
search-match-basics-items? (some #(matches-search % (:term @search-term)) (vals basics-translations))
search-match-basics? (matches-search :basics (:term @search-term))
close-fn #(st/emit! (dw/toggle-layout-flag :shortcuts)) 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)))))
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)
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))))
add-ids (fn [acc node]
(let [id (:id node)
addition (case (count id)
1 id
2 [[(first id)] id]
3 [[(first id)] [(first id) (second id)]]
"default" nil)]
(if (= 1 (count addition))
(conj acc addition)
(into [] (concat acc addition)))))
manage-section-on-search
(fn [section term]
(let [node-seq (tree-seq :children #(vals (:children %)) (get all-shortcuts section))]
(reduce (fn [acc node]
(if (matches-search (:translation node) term)
(add-ids acc node)
acc))
[]
node-seq)))
manage-sections-on-search
(fn [term]
(if (= term "")
(reset! open-sections [[1]])
(let [ids (set/union (manage-section-on-search :basics term)
(manage-section-on-search :workspace term)
(manage-section-on-search :dashboard term)
(manage-section-on-search :viewer term))]
(reset! open-sections ids))))
on-search-term-change on-search-term-change
(mf/use-callback (mf/use-callback
(fn [event] (fn [event]
(let [value (dom/get-target-val event)] (let [value (dom/get-target-val event)]
(swap! search-term assoc :term value)))) (manage-sections-on-search value)
(reset! filter-term value))))
on-search-clear-click on-search-clear-click
(mf/use-callback (mf/use-callback
(fn [_] (fn [_]
(swap! search-term assoc :term ""))) (reset! open-sections [[1]])
(reset! filter-term "")))]
manage-sections
(fn [item is-sub?]
(fn [event]
(dom/stop-propagation event)
(let [modify-atom
(fn [is-sub? item atom-name]
(let [keyword-name (if is-sub?
:subsection
:section)
is-present? (some #(= % item) (keyword-name atom-name))
value-vector (get atom-name keyword-name)
new-value (if is-present?
(filterv (fn [element] (not= element item)) value-vector)
(conj value-vector item))]
(assoc atom-name keyword-name new-value)))]
(reset! open-sections (modify-atom is-sub? item @open-sections)))))]
[:div.shortcuts [:div.shortcuts
[:div.shortcuts-header [:div.shortcuts-header
@ -263,48 +331,22 @@
{:id "shortcut-search" {:id "shortcut-search"
:placeholder (tr "shortcuts.search-placeholder") :placeholder (tr "shortcuts.search-placeholder")
:type "text" :type "text"
:value (:term @search-term) :value @filter-term
:on-change on-search-term-change :on-change on-search-term-change
:auto-complete "off"}] :auto-complete "off"}]
(if (str/empty? (:term @search-term)) (if (str/empty? @filter-term)
[:span.icon-wrapper [:span.icon-wrapper
i/search] i/search]
[:span.icon-wrapper.close [:span.icon-wrapper.close
{:on-click on-search-clear-click} {:on-click on-search-clear-click}
i/close])]] i/close])]]
(if match-any?
[:div.shortcut-list
(for [section all-shortcuts]
[:& shortcut-section
{:section section
:manage-sections manage-sections
:open-sections open-sections
:filter-term filter-term}])]
[:div.shortcut-list [:div.not-found (tr "shortcuts.not-found")])]))
(when (or search-match-basics-items? search-match-basics?)
[:div {:on-click (manage-sections :basics false)}
[:& section-title {:section :basics
:is-visible? basics-open?
:elem-n (count basics-elements)}]
[:div {:style {:display (if basics-open? "initial" "none")}}
[:& shortcut-row {:shortcuts all-shortcuts
:elements basics-elements
:filter-term search-term
:match-section? search-match-basics?}]]])
[:& shortcut-section
{:shortcuts-by-group workspace-sc-by-subsections
:manage-sections manage-sections
:open-sections open-sections
:filter-term search-term
:shortcuts all-workspace-shortcuts
:section :workspace}]
[:& shortcut-section
{:shortcuts-by-group dashboard-sc-by-subsections
:manage-sections manage-sections
:open-sections open-sections
:filter-term search-term
:shortcuts dashboard-shortcuts
:section :dashboard}]
[:& shortcut-section
{:shortcuts-by-group viewer-sc-by-subsections
:manage-sections manage-sections
:open-sections open-sections
:filter-term search-term
:shortcuts viewer-shortcuts
:section :viewer}]]]))

View file

@ -4152,3 +4152,12 @@ msgstr "Update"
msgid "workspace.viewport.click-to-close-path" msgid "workspace.viewport.click-to-close-path"
msgstr "Click to close the path" msgstr "Click to close the path"
msgid "shortcut-subsection.zoom-viewer"
msgstr "Zoom"
msgid "shortcuts.or"
msgstr " or "
msgid "shortcuts.not-found"
msgstr "No shortcuts found"

View file

@ -4335,3 +4335,12 @@ msgstr "Actualizar"
msgid "workspace.viewport.click-to-close-path" msgid "workspace.viewport.click-to-close-path"
msgstr "Pulsar para cerrar la ruta" msgstr "Pulsar para cerrar la ruta"
msgid "shortcut-subsection.zoom-viewer"
msgstr "Zoom"
msgid "shortcuts.or"
msgstr " o "
msgid "shortcuts.not-found"
msgstr "No hay resultados"