mirror of
https://github.com/penpot/penpot.git
synced 2025-01-25 07:58:49 -05:00
✨ Shortcuts improvements
This commit is contained in:
parent
32540f1ba5
commit
c029948cce
6 changed files with 342 additions and 241 deletions
|
@ -7,9 +7,6 @@
|
|||
|
||||
.left-toolbar {
|
||||
background-color: $color-gray-50;
|
||||
}
|
||||
|
||||
.left-toolbar-inside {
|
||||
align-items: center;
|
||||
border-right: 1px solid $color-gray-60;
|
||||
display: flex;
|
||||
|
@ -25,44 +22,47 @@
|
|||
margin: 0;
|
||||
|
||||
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;
|
||||
width: 48px;
|
||||
color: $color-gray-20;
|
||||
|
||||
svg {
|
||||
fill: $color-gray-20;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-primary;
|
||||
color: $color-gray-50;
|
||||
button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
color: inherit;
|
||||
|
||||
svg {
|
||||
fill: $color-gray-50;
|
||||
fill: $color-gray-20;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: $color-gray-60;
|
||||
color: $color-primary;
|
||||
&:hover {
|
||||
background-color: $color-primary;
|
||||
color: $color-gray-50;
|
||||
|
||||
svg {
|
||||
fill: $color-primary;
|
||||
svg {
|
||||
fill: $color-gray-50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.separator {
|
||||
border-top: 1px solid $color-gray-60;
|
||||
&.selected {
|
||||
background-color: $color-gray-60;
|
||||
color: $color-primary;
|
||||
|
||||
svg {
|
||||
fill: $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
&.separator {
|
||||
border-top: 1px solid $color-gray-60;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -305,6 +305,12 @@ button.collapse-sidebar {
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
svg {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
transform: rotate(45deg);
|
||||
fill: $color-gray-20;
|
||||
}
|
||||
}
|
||||
.shortcuts-close-button {
|
||||
display: flex;
|
||||
|
@ -380,6 +386,7 @@ button.collapse-sidebar {
|
|||
cursor: pointer;
|
||||
margin-top: 4px;
|
||||
font-size: $fs12;
|
||||
|
||||
.section-name {
|
||||
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 {
|
||||
border: 1px solid $color-gray-60;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,16 +47,17 @@
|
|||
:position (gpt/point x y)}]
|
||||
(st/emit! (dwm/upload-media-workspace params)))))]
|
||||
|
||||
[:li.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
|
||||
:on-click on-click}
|
||||
[:*
|
||||
i/image
|
||||
[:& file-uploader {:input-id "image-upload"
|
||||
:accept cm/str-image-types
|
||||
:multi true
|
||||
:ref ref
|
||||
:on-selected on-files-selected}]]]))
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
|
||||
:on-click on-click}
|
||||
[:*
|
||||
i/image
|
||||
[:& file-uploader {:input-id "image-upload"
|
||||
:accept cm/str-image-types
|
||||
:multi true
|
||||
:ref ref
|
||||
:on-selected on-files-selected}]]]]))
|
||||
|
||||
(mf/defc left-toolbar
|
||||
{::mf/wrap [mf/memo]
|
||||
|
@ -67,61 +68,69 @@
|
|||
select-drawtool #(st/emit! :interrupt (dw/select-for-drawing %))
|
||||
edition (mf/deref refs/selected-edition)]
|
||||
[:aside.left-toolbar
|
||||
[:div.left-toolbar-inside
|
||||
[:ul.left-toolbar-options
|
||||
[:li.tooltip.tooltip-right
|
||||
[:ul.left-toolbar-options
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.move" (sc/get-tooltip :move))
|
||||
:class (when (and (nil? selected-drawtool)
|
||||
(not edition)) "selected")
|
||||
:on-click #(st/emit! :interrupt)}
|
||||
i/pointer-inner]
|
||||
[:li.tooltip.tooltip-right
|
||||
i/pointer-inner]]
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
|
||||
:class (when (= selected-drawtool :frame) "selected")
|
||||
:on-click (partial select-drawtool :frame)
|
||||
:data-test "artboard-btn"}
|
||||
i/artboard]
|
||||
[:li.tooltip.tooltip-right
|
||||
i/artboard]]
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
|
||||
:class (when (= selected-drawtool :rect) "selected")
|
||||
:on-click (partial select-drawtool :rect)
|
||||
:data-test "rect-btn"}
|
||||
i/box]
|
||||
[:li.tooltip.tooltip-right
|
||||
i/box]]
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
|
||||
:class (when (= selected-drawtool :circle) "selected")
|
||||
:on-click (partial select-drawtool :circle)
|
||||
:data-test "ellipse-btn"}
|
||||
i/circle]
|
||||
[:li.tooltip.tooltip-right
|
||||
i/circle]]
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
|
||||
:class (when (= selected-drawtool :text) "selected")
|
||||
: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))
|
||||
:class (when (= selected-drawtool :curve) "selected")
|
||||
:on-click (partial select-drawtool :curve)
|
||||
:data-test "curve-btn"}
|
||||
i/pencil]
|
||||
[:li.tooltip.tooltip-right
|
||||
i/pencil]]
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
|
||||
:class (when (= selected-drawtool :path) "selected")
|
||||
:on-click (partial select-drawtool :path)
|
||||
: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))
|
||||
:class (when (= selected-drawtool :comments) "selected")
|
||||
:on-click (partial select-drawtool :comments)}
|
||||
i/chat]]
|
||||
i/chat]]]
|
||||
|
||||
[:ul.left-toolbar-options.panels
|
||||
[:li.tooltip.tooltip-right
|
||||
[:ul.left-toolbar-options.panels
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right
|
||||
{:alt (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette))
|
||||
:class (when (contains? layout :textpalette) "selected")
|
||||
:on-click (fn []
|
||||
|
@ -130,9 +139,10 @@
|
|||
(ts/schedule 300 #(st/emit! (dw/remove-layout-flag :colorpalette)
|
||||
(-> (dw/toggle-layout-flag :textpalette)
|
||||
(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))
|
||||
:class (when (contains? layout :colorpalette) "selected")
|
||||
:on-click (fn []
|
||||
|
@ -141,8 +151,9 @@
|
|||
(ts/schedule 300 #(st/emit! (dw/remove-layout-flag :textpalette)
|
||||
(-> (dw/toggle-layout-flag :colorpalette)
|
||||
(vary-meta assoc ::ev/origin "workspace-left-toolbar")))))}
|
||||
i/palette]
|
||||
[:li.tooltip.tooltip-right.separator
|
||||
i/palette]]
|
||||
[:li
|
||||
[:button.tooltip.tooltip-right.separator
|
||||
{:alt (tr "workspace.toolbar.shortcuts" (sc/get-tooltip :show-shortcuts))
|
||||
:class (when (contains? layout :shortcuts) "selected")
|
||||
:on-click (fn []
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
[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.alpha :as mf]))
|
||||
|
@ -40,12 +41,24 @@
|
|||
:esc "\u238B"
|
||||
:enter "\u23CE"}
|
||||
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)
|
||||
unique-key (str (d/name command) "-" 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
|
||||
"A function to obtain the list of subsections and their
|
||||
associated shortcus from the general map of shortcuts"
|
||||
|
@ -53,24 +66,24 @@
|
|||
(let [subsections (into #{} (mapcat :subsections) (vals shortcuts))
|
||||
get-sc-by-subsection
|
||||
(fn [subsection [k v]]
|
||||
(when (some #(= subsection %) (:subsections v)) k))
|
||||
(when (some #(= subsection %) (:subsections v)) {k v}))
|
||||
reduce-sc
|
||||
(fn [acc subsection]
|
||||
(let [shortcuts-by-subsection (keep (partial get-sc-by-subsection subsection) shortcuts)]
|
||||
(assoc acc subsection shortcuts-by-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] :as props}]
|
||||
(let [managed-list (if (coll? content)
|
||||
content
|
||||
(conj () content))
|
||||
split-sc (fn [sc]
|
||||
(let [sc (cond-> sc (str/includes? sc "++")
|
||||
(str/replace "++" "+plus"))]
|
||||
(if (= (count sc) 1)
|
||||
[sc]
|
||||
(str/split sc #"\+| "))))
|
||||
(let [managed-list (if (coll? content)
|
||||
content
|
||||
(conj () content))
|
||||
split-sc (fn [sc]
|
||||
(let [sc (cond-> sc (str/includes? sc "++")
|
||||
(str/replace "++" "+plus"))]
|
||||
(if (= (count sc) 1)
|
||||
[sc]
|
||||
(str/split sc #"\+| "))))
|
||||
chars-list (map split-sc managed-list)
|
||||
last-element (last chars-list)
|
||||
short-char-list (if (= 1 (count chars-list))
|
||||
|
@ -82,175 +95,230 @@
|
|||
[:*
|
||||
(for [char chars]
|
||||
[:& converted-chars {:char char :command command}])
|
||||
|
||||
(when (not= chars penultimate) [:span.space ","])])
|
||||
(when (not= last-element penultimate)
|
||||
[:*
|
||||
[:span.space " or "]
|
||||
[:span.space (tr "shortcuts.or")]
|
||||
(for [char last-element]
|
||||
[:& converted-chars {:char char
|
||||
:command command}])])]))
|
||||
|
||||
(mf/defc shortcut-row
|
||||
[{:keys [shortcuts elements filter-term match-section? match-subsection?] :as props}]
|
||||
(let [reduce-translation (fn [acc element] (assoc acc element (tr (str "shortcuts." (d/name element)))))
|
||||
translations (reduce reduce-translation {} elements)
|
||||
filtered (if (or match-section? match-subsection?)
|
||||
(vals translations)
|
||||
(filter #(matches-search % (:term @filter-term)) (vals translations)))
|
||||
sorted-filtered (sort filtered)]
|
||||
[{:keys [elements filter-term match-section? match-subsection?] :as props}]
|
||||
(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 match-section? match-subsection?) (not match-shortcut?))
|
||||
shortcut-translations
|
||||
(filter #(matches-search % @filter-term) shortcut-translations))
|
||||
sorted-filtered (sort filtered)]
|
||||
[:ul.sub-menu
|
||||
(for [command-translate sorted-filtered]
|
||||
(let [command (first (filter (comp #{command-translate} translations) (keys translations)))
|
||||
content (:command (command shortcuts))
|
||||
name (tr (str "shortcuts." (d/name command)))]
|
||||
[:li.shortcut-name {:key command}
|
||||
[:span.command-name name]
|
||||
(let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements))
|
||||
[command comand-info] sc-by-translate
|
||||
content (:command comand-info)]
|
||||
[:li.shortcut-name {:key command-translate}
|
||||
[:span.command-name command-translate]
|
||||
[:& shortcuts-keys {:content content
|
||||
:command command}]]))]))
|
||||
|
||||
(mf/defc section-title
|
||||
[{:keys [is-visible? section elem-n] :as props}]
|
||||
(let [name (tr (str "shortcut-section." (d/name section)))]
|
||||
[:div.section-title
|
||||
[:span.collapesed-shortcuts {:class (when is-visible? "open")} i/arrow-slide]
|
||||
[: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 ")"]]))
|
||||
[{:keys [is-visible? name is-sub?] :as props}]
|
||||
[:div {:class (if is-sub? "subsection-title" "section-title")}
|
||||
[:span.collapesed-shortcuts {:class (when is-visible? "open")} i/arrow-slide]
|
||||
[:span {:class (if is-sub? "subsection-name" "section-name")} name]])
|
||||
|
||||
(mf/defc shortcut-subsection
|
||||
[{:keys [shortcuts-by-group manage-sections shortcuts filter-term match-section? open-sections] :as props}]
|
||||
(let [reduce-translation (fn [acc subsection] (assoc acc subsection (tr (str "shortcut-subsection." (d/name subsection)))))
|
||||
translations (reduce reduce-translation {} (keys shortcuts-by-group))
|
||||
sorted-translations (sort (vals translations))]
|
||||
[:ul.subsection-menu
|
||||
(for [sub-translate sorted-translations]
|
||||
(let [subsection (first (filter (comp #{sub-translate} translations) (keys translations)))
|
||||
elements (subsection shortcuts-by-group)
|
||||
visible? (some #(= % subsection) (:subsection @open-sections))
|
||||
match-subsection? (matches-search sub-translate (:term @filter-term))
|
||||
[{:keys [subsections manage-sections filter-term match-section? open-sections] :as props}]
|
||||
(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
|
||||
:match-section? match-section?
|
||||
:match-subsection? true}])
|
||||
|
||||
keywords (subsection shortcuts-by-group)
|
||||
matched-map (into {} (map (fn [element] {element (:translation (element shortcuts))}) keywords))
|
||||
translations (vals matched-map)
|
||||
match-shortcut-in-sub? (some #(matches-search % (:term @filter-term)) translations)
|
||||
shortcut-count (count (filter #(matches-search % (:term @filter-term)) translations))]
|
||||
(when (and (or match-section? match-subsection? match-shortcut-in-sub?) (not= subsection :basics))
|
||||
[:li {:key subsection
|
||||
:on-click (manage-sections subsection true)}
|
||||
[:& subsection-title {:subsection-name subsection
|
||||
:open-sections open-sections
|
||||
:elements shortcut-count}]
|
||||
[:div {:style {:display (if visible? "initial" "none")}}
|
||||
[:& shortcut-row {:shortcuts shortcuts
|
||||
:elements elements
|
||||
:filter-term filter-term
|
||||
:match-section? match-section?
|
||||
:match-subsection? match-subsection?}]]])))]))
|
||||
[:ul.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? match-section?)
|
||||
[:li {:key sub-translated
|
||||
:on-click (manage-sections (:id sub-info))}
|
||||
[:& section-title {:name sub-translated
|
||||
:is-sub? true
|
||||
:is-visible? visible?}]
|
||||
|
||||
[:div {:style {:display (if visible? "initial" "none")}}
|
||||
[:& shortcut-row {:elements (:children sub-info)
|
||||
:filter-term filter-term
|
||||
:match-section? match-section?
|
||||
:match-subsection? match-subsection?}]]])))])))
|
||||
|
||||
(mf/defc shortcut-section
|
||||
[{:keys [section shortcuts shortcuts-by-group manage-sections filter-term open-sections] :as props}]
|
||||
(let [section-name (d/name section)
|
||||
visible? (some #(= % section) (:section @open-sections))
|
||||
section-translation (tr (str "shortcut-section." section-name))
|
||||
match-section? (matches-search section-translation (:term @filter-term))
|
||||
subsections (map (fn [subsection] (tr (str "shortcut-subsection." (d/name subsection)))) (filter #(not= % :basics) (keys shortcuts-by-group)))
|
||||
match-subsection? (some #(matches-search % (:term @filter-term)) subsections)
|
||||
keywords (keys shortcuts)
|
||||
matched-map (into {} (map (fn [element] {element (:translation (element shortcuts))}) keywords))
|
||||
translations (vals matched-map)
|
||||
match-shortcut? (some #(matches-search % (:term @filter-term)) translations)
|
||||
filtered-shortcuts (count (filter #(matches-search % (:term @filter-term)) translations))]
|
||||
[{:keys [section manage-sections open-sections filter-term] :as props}]
|
||||
(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 {:on-click (manage-sections section false)}
|
||||
[:div {:on-click (manage-sections section-id)}
|
||||
[:& section-title {:is-visible? visible?
|
||||
:section section
|
||||
:elem-n filtered-shortcuts}]
|
||||
[: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}]]])))
|
||||
:is-sub? false
|
||||
:name section-translation}]
|
||||
|
||||
(defn add-translation-to-shorcuts
|
||||
[shortcuts]
|
||||
(map (fn [[k v]] [k (assoc v :translation (tr (str "shortcuts." (d/name k))))]) shortcuts))
|
||||
[:div {:style {:display (if visible? "initial" "none")}}
|
||||
[:& shortcut-subsection {:subsections subsections
|
||||
:open-sections open-sections
|
||||
:manage-sections manage-sections
|
||||
:match-section? match-section?
|
||||
:filter-term filter-term}]]])))
|
||||
|
||||
(mf/defc shortcuts-container
|
||||
[]
|
||||
(let [workspace-shortcuts app.main.data.workspace.shortcuts/shortcuts
|
||||
path-shortcuts app.main.data.workspace.path.shortcuts/shortcuts
|
||||
all-workspace-shortcuts (->> (d/deep-merge path-shortcuts workspace-shortcuts)
|
||||
(add-translation-to-shorcuts)
|
||||
(add-translation :sc)
|
||||
(into {}))
|
||||
|
||||
dashboard-shortcuts (->> app.main.data.dashboard.shortcuts/shortcuts
|
||||
(add-translation-to-shorcuts)
|
||||
(add-translation :sc)
|
||||
(into {}))
|
||||
viewer-shortcuts (->> app.main.data.viewer.shortcuts/shortcuts
|
||||
(add-translation-to-shorcuts)
|
||||
(add-translation :sc)
|
||||
(into {}))
|
||||
|
||||
all-shortcuts (d/deep-merge all-workspace-shortcuts dashboard-shortcuts viewer-shortcuts)
|
||||
|
||||
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))
|
||||
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)))))
|
||||
|
||||
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
|
||||
(mf/use-callback
|
||||
(fn [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
|
||||
(mf/use-callback
|
||||
(fn [_]
|
||||
(swap! search-term assoc :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)))))]
|
||||
(reset! open-sections [[1]])
|
||||
(reset! filter-term "")))]
|
||||
|
||||
[:div.shortcuts
|
||||
[:div.shortcuts-header
|
||||
|
@ -263,48 +331,22 @@
|
|||
{:id "shortcut-search"
|
||||
:placeholder (tr "shortcuts.search-placeholder")
|
||||
:type "text"
|
||||
:value (:term @search-term)
|
||||
:value @filter-term
|
||||
:on-change on-search-term-change
|
||||
:auto-complete "off"}]
|
||||
(if (str/empty? (:term @search-term))
|
||||
(if (str/empty? @filter-term)
|
||||
[:span.icon-wrapper
|
||||
i/search]
|
||||
[:span.icon-wrapper.close
|
||||
{:on-click on-search-clear-click}
|
||||
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
|
||||
(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}]]]))
|
||||
[:div.not-found (tr "shortcuts.not-found")])]))
|
||||
|
|
|
@ -4152,3 +4152,12 @@ msgstr "Update"
|
|||
|
||||
msgid "workspace.viewport.click-to-close-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"
|
|
@ -4335,3 +4335,12 @@ msgstr "Actualizar"
|
|||
|
||||
msgid "workspace.viewport.click-to-close-path"
|
||||
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"
|
Loading…
Add table
Reference in a new issue