mirror of
https://github.com/penpot/penpot.git
synced 2026-08-07 13:29:07 +00:00
🎉 Add search by commands
This commit is contained in:
parent
90f73b877b
commit
a12f9aa0eb
@ -381,7 +381,8 @@
|
||||
(mf/with-memo []
|
||||
(fn [_ shortcut search-term]
|
||||
(or (str/blank? search-term)
|
||||
(matches-search (:translation shortcut) search-term))))
|
||||
(matches-search (:translation shortcut) search-term)
|
||||
(matches-search (ss/shortcut->command-string shortcut) search-term))))
|
||||
|
||||
filter-personalized
|
||||
(mf/use-fn
|
||||
@ -395,7 +396,8 @@
|
||||
(and customized?
|
||||
(not (false? (:customizable shortcut)))
|
||||
(or (str/blank? search-term)
|
||||
(matches-search (:translation shortcut) search-term))))))
|
||||
(matches-search (:translation shortcut) search-term)
|
||||
(matches-search (ss/shortcut->command-string shortcut) search-term))))))
|
||||
|
||||
filter-disabled
|
||||
(mf/use-fn
|
||||
@ -409,7 +411,8 @@
|
||||
(and in-group? blank?
|
||||
(not (false? (:customizable shortcut)))
|
||||
(or (str/blank? search-term)
|
||||
(matches-search (:translation shortcut) search-term))))))
|
||||
(matches-search (:translation shortcut) search-term)
|
||||
(matches-search (ss/shortcut->command-string shortcut) search-term))))))
|
||||
|
||||
on-import-file
|
||||
(mf/use-fn
|
||||
|
||||
@ -162,6 +162,20 @@
|
||||
[type item]
|
||||
(map (fn [[k v]] [k (assoc v :translation (translation-keyname type k))]) item))
|
||||
|
||||
(defn shortcut->command-string
|
||||
"Extract a lowercase searchable string from a shortcut entry's key combo(s).
|
||||
Prefers `:show-command` (display override) over `:command` (Mousetrap format),
|
||||
matching what the keycap UI renders. Joins vector commands (key sequences)
|
||||
with a space so every token is searchable. Returns \"\" when there is no
|
||||
command (e.g. a section/subsection node)."
|
||||
[shortcut]
|
||||
(let [cmd (or (:show-command shortcut) (:command shortcut))]
|
||||
(-> (cond
|
||||
(nil? cmd) ""
|
||||
(vector? cmd) (str/join " " cmd)
|
||||
:else (str cmd))
|
||||
(str/lower))))
|
||||
|
||||
(defn shortcuts->subsections
|
||||
[shortcuts]
|
||||
(let [subsections (into #{} (mapcat :subsections) (vals shortcuts))
|
||||
@ -591,11 +605,19 @@
|
||||
[{:keys [elements filter-term is-match-section is-match-subsection
|
||||
editable? custom-shortcuts section-key conflicts hidden subsection-name]}]
|
||||
(let [shortcut-translations (->> elements vals (map :translation) sort)
|
||||
match-shortcut? (some #(matches-search % filter-term) shortcut-translations)
|
||||
match-shortcut? (some (fn [info]
|
||||
(or (matches-search (:translation info) filter-term)
|
||||
(matches-search (shortcut->command-string info) filter-term)))
|
||||
(vals elements))
|
||||
filtered (if (and (or is-match-section is-match-subsection) (not match-shortcut?))
|
||||
shortcut-translations
|
||||
(filter #(matches-search % filter-term) shortcut-translations))
|
||||
sorted-filtered (sort filtered)
|
||||
(->> (vals elements)
|
||||
(filter (fn [info]
|
||||
(or (matches-search (:translation info) filter-term)
|
||||
(matches-search (shortcut->command-string info) filter-term))))
|
||||
(map :translation)
|
||||
sort))
|
||||
sorted-filtered filtered
|
||||
trigger-ref (mf/use-ref nil)]
|
||||
|
||||
[:ul {:class (stl/css :sub-menu)
|
||||
|
||||
@ -66,7 +66,12 @@
|
||||
(ss/build-all-shortcuts workspace-shortcuts dashboard-shortcuts viewer-shortcuts)
|
||||
|
||||
all-item-names (concat all-sc-names all-sub-names all-section-names)
|
||||
match-any? (some #(matches-search % filter-term) all-item-names)
|
||||
all-command-strings (->> (concat (vals workspace-shortcuts)
|
||||
(vals dashboard-shortcuts)
|
||||
(vals viewer-shortcuts))
|
||||
(map ss/shortcut->command-string))
|
||||
all-searchable-names (concat all-item-names all-command-strings)
|
||||
match-any? (some #(matches-search % filter-term) all-searchable-names)
|
||||
|
||||
manage-sections
|
||||
(fn [item]
|
||||
@ -89,7 +94,8 @@
|
||||
(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)
|
||||
(if (or (matches-search (:translation node) term)
|
||||
(matches-search (ss/shortcut->command-string node) term))
|
||||
(add-ids acc node)
|
||||
acc))
|
||||
[]
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
[app.main.ui.settings.restore-shortcuts-modal :as restore-modal]
|
||||
[app.main.ui.settings.shortcuts :as sut]
|
||||
[app.main.ui.shortcuts :as ui-shortcuts]
|
||||
[app.util.strings :refer [matches-search]]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[clojure.string :as str]))
|
||||
|
||||
@ -221,3 +222,72 @@
|
||||
(let [result (restore-modal/extract-shortcut-keys :next-frame {} :viewer)]
|
||||
(t/is (nth result 3)
|
||||
"Should return a default command for :next-frame in :viewer context")))
|
||||
|
||||
;; --- shortcut->command-string + command-based search --------------------
|
||||
;; The search in both the settings shortcuts page and the workspace sidebar
|
||||
;; matches shortcut entries by their translated name AND by their key-combo
|
||||
;; string. `shortcut->command-string` (in `app.main.ui.shortcuts`) extracts the
|
||||
;; searchable form from `:command`/`:show-command`; `matches-search` does the
|
||||
;; case-insensitive substring match. These tests pin that contract so searching
|
||||
;; e.g. "ctrl" surfaces every shortcut whose combo includes ctrl.
|
||||
|
||||
(t/deftest shortcut->command-string-extracts-string-command
|
||||
(t/testing "a plain string command is returned lowercased"
|
||||
(t/is (= "ctrl+z" (ui-shortcuts/shortcut->command-string
|
||||
{:command "ctrl+z"})))))
|
||||
|
||||
(t/deftest shortcut->command-string-joins-vector-command
|
||||
(t/testing "a vector command (key sequence) is joined with spaces so every
|
||||
token is individually searchable"
|
||||
(t/is (= "g v" (ui-shortcuts/shortcut->command-string
|
||||
{:command ["g" "v"]})))))
|
||||
|
||||
(t/deftest shortcut->command-string-prefers-show-command
|
||||
(t/testing ":show-command (display override) wins over :command"
|
||||
(t/is (= "shift+x" (ui-shortcuts/shortcut->command-string
|
||||
{:command "ctrl+z" :show-command "shift+x"})))))
|
||||
|
||||
(t/deftest shortcut->command-string-empty-for-section-node
|
||||
(t/testing "a node without :command/:show-command (e.g. a section or
|
||||
subsection heading) yields an empty string so it never matches a
|
||||
non-blank command search"
|
||||
(t/is (= "" (ui-shortcuts/shortcut->command-string
|
||||
{:translation "workspace"})))))
|
||||
|
||||
(t/deftest shortcut->command-string-lowercases
|
||||
(t/testing "the result is lowercased so search is case-insensitive"
|
||||
(t/is (= "ctrl+shift+z" (ui-shortcuts/shortcut->command-string
|
||||
{:command "Ctrl+Shift+Z"})))))
|
||||
|
||||
(t/deftest command-search-matches-ctrl-prefix
|
||||
(t/testing "searching 'ctrl' matches a shortcut whose command contains ctrl"
|
||||
(let [shortcut {:command "ctrl+shift+s"
|
||||
:translation "Save all"}]
|
||||
(t/is (matches-search (ui-shortcuts/shortcut->command-string shortcut)
|
||||
"ctrl")))))
|
||||
|
||||
(t/deftest command-search-does-not-match-when-command-lacks-term
|
||||
(t/testing "searching 'alt' does not match a shortcut with no alt in its combo"
|
||||
(let [shortcut {:command "ctrl+z"
|
||||
:translation "Undo"}]
|
||||
(t/is (not (matches-search (ui-shortcuts/shortcut->command-string shortcut)
|
||||
"alt"))))))
|
||||
|
||||
(t/deftest command-search-matches-key-sequence-vector
|
||||
(t/testing "searching a single key in a key-sequence vector command matches"
|
||||
(let [shortcut {:command ["g" "v"]
|
||||
:translation "Group"}]
|
||||
(t/is (matches-search (ui-shortcuts/shortcut->command-string shortcut)
|
||||
"g")))))
|
||||
|
||||
(t/deftest search-matches-by-translation-or-command
|
||||
(t/testing "a search term matches if it appears in either the translation or
|
||||
the command string — the OR that the filter predicates use"
|
||||
(let [shortcut {:command "ctrl+s"
|
||||
:translation "Save"}]
|
||||
;; by translation
|
||||
(t/is (or (matches-search (:translation shortcut) "save")
|
||||
(matches-search (ui-shortcuts/shortcut->command-string shortcut) "save")))
|
||||
;; by command
|
||||
(t/is (or (matches-search (:translation shortcut) "ctrl")
|
||||
(matches-search (ui-shortcuts/shortcut->command-string shortcut) "ctrl"))))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user