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:
commit
65cda41245
6 changed files with 342 additions and 241 deletions
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 []
|
||||||
|
|
|
@ -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}]]]))
|
|
||||||
|
|
|
@ -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"
|
|
@ -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"
|
Loading…
Add table
Reference in a new issue