enhance: `j` jump to a property key or value (selection mode)

We can support jump to any block in the future.
More enhancements need to be done including:
1. still focus on the block or property key/value after any property
operation
2. up/down/left/right support maybe?
pull/11102/head
Tienson Qin 2024-02-28 21:30:49 +08:00
parent 7cec0e696f
commit 623043d363
10 changed files with 136 additions and 44 deletions

View File

@ -48,6 +48,7 @@
[frontend.util :as util]
[frontend.util.cursor :as cursor]
[frontend.components.window-controls :as window-controls]
[frontend.components.jump :as jump]
[medley.core :as medley]
[goog.dom :as gdom]
[goog.object :as gobj]
@ -920,6 +921,8 @@
(when (util/electron?)
(find-in-page/search))
(jump/jump)
(main {:route-match route-match
:margin-less-pages? margin-less-pages?
:logged? logged?

View File

@ -0,0 +1,45 @@
(ns frontend.components.jump
"Jump to"
(:require [frontend.ui :as ui]
[frontend.state :as state]
[rum.core :as rum]
[frontend.util :as util]
[frontend.handler.jump :as jump-handler]))
(defn- exit!
[]
(state/set-state! :editor/jump-data nil)
(jump-handler/clear-jump-hints!))
(rum/defcs input <
(rum/local "" ::q)
[state {:keys [triggers _mode]}] ; TODO: jump to block
(let [*q (::q state)]
[:div.flex.w-full.relative
[:input.form-input.block.sm:text-sm.my-2.border-none.outline-none
{:auto-focus true
:placeholder "Jump to"
:aria-label "Jump to"
:value @*q
:on-change (fn [e] (reset! *q (util/evalue e)))
:on-key-down (fn [e]
(util/stop-propagation e)
(case (util/ekey e)
"Enter"
(when-let [idx (util/safe-parse-int @*q)]
(when (> idx 0)
(when-let [elem (nth triggers (dec idx))]
(state/clear-selection!)
(exit!)
(.click elem))))
"Escape"
(exit!)
nil))}]]))
(rum/defc jump < rum/reactive
[]
(let [data (state/sub :editor/jump-data)]
(when data
[:div#bottom-console.flex.flex-1.flex-row.absolute.top-10.right-2.shadow-lg.px-2.py-1.faster-fade-in.items-center
(input data)])))

View File

@ -587,8 +587,9 @@
{:on-click #(route-handler/redirect-to-page! (:block/name property))}
[:div {:style {:padding-left 6}} (:block/original-name property)]]
[:a.property-k.select-none
{:title (str "Configure property: " (:block/original-name property))
[:a.property-k.flex.select-none.jtrigger
{:tabIndex 0
:title (str "Configure property: " (:block/original-name property))
:on-mouse-down (fn [^js e]
(when (util/meta-key? e)
(route-handler/redirect-to-page! (:block/name property))

View File

@ -241,4 +241,8 @@ a.control-link {
&.no-mode {
@apply hidden;
}
}
}
.property-k:focus {
@apply pr-1;
}

View File

@ -98,7 +98,7 @@
(shui/popup-hide! id)
(when-let [toggle (:toggle-fn opts)]
(toggle)))))}))]
[:a.w-fit.flex.items-center
[:a.w-fit.flex.items-center.jtrigger
{:tabIndex "0"
;; meta-click or just click in publishing to navigate to date's page
:on-click (if config/publishing?
@ -587,10 +587,11 @@
(select-f)
(ui/dropdown
(fn [{:keys [toggle-fn]}]
[:a.control-link
{:on-mouse-down (if config/publishing?
(constantly nil)
toggle-fn)
[:a.control-link.jtrigger
{:tabIndex 0
:on-click (if config/publishing?
(constantly nil)
toggle-fn)
:class "flex flex-1"}
(if (and (string/blank? value) (not editing?))
[:div.opacity-50.pointer.text-sm "Empty"]
@ -631,6 +632,7 @@
(let [add-property! (fn []
(<add-property! block (:block/original-name property) (boolean (not value))))]
(ui/checkbox {:tabIndex "0"
:class "jtrigger"
:checked value
:on-change (fn [_e] (add-property!))
:on-key-down (fn [e]
@ -653,44 +655,46 @@
multiple-values?
(assoc :property-value value)))]))]
(let [class (str (when-not row? "flex flex-1 ")
(when multiple-values? "property-value-content"))]
[:div.cursor-text
(when multiple-values? "property-value-content"))
type (or (when (and (= type :default) (uuid? value)) :block)
type
:default)
type (if (= :block type)
(let [v-block (db/entity [:block/uuid value])]
(if (get-in v-block [:block/metadata :created-from-template])
:template
type))
type)
template? (= :template type)]
[:div.cursor-text.jtrigger
{:id (or dom-id (random-uuid))
:tabIndex 0
:class class
:style {:min-height 24}
:on-click (fn []
(when (and (= type :default) (not (uuid? value)))
(set-editing! property editor-id dom-id value {:ref @*ref})))}
(let [type (or (when (and (= type :default) (uuid? value)) :block)
type
:default)
type (if (= :block type)
(let [v-block (db/entity [:block/uuid value])]
(if (get-in v-block [:block/metadata :created-from-template])
:template
type))
type)]
(if (string/blank? value)
(if (= :template type)
(let [id (first (:classes schema))
template (when id (db/entity [:block/uuid id]))]
(when template
[:a.fade-link.pointer.text-sm
{:on-click (fn [e]
(util/stop e)
(<create-new-block-from-template! block property template))}
(str "Use template #" (:block/original-name template))]))
[:div.opacity-50.pointer.text-sm "Empty"])
(case type
:template
(property-template-value {:editor-id editor-id}
value
opts)
(if (string/blank? value)
(if template?
(let [id (first (:classes schema))
template (when id (db/entity [:block/uuid id]))]
(when template
[:a.fade-link.pointer.text-sm.jtrigger
{:on-click (fn [e]
(util/stop e)
(<create-new-block-from-template! block property template))}
(str "Use template #" (:block/original-name template))]))
[:div.opacity-50.pointer.text-sm "Empty"])
(case type
:template
(property-template-value {:editor-id editor-id}
value
opts)
:block
(property-block-value value block property block-cp editor-box opts page-cp editor-id)
:block
(property-block-value value block property block-cp editor-box opts page-cp editor-id)
(inline-text {} :markdown (macro-util/expand-value-if-macro (str value) (state/get-macros))))))]))]))))
(inline-text {} :markdown (macro-util/expand-value-if-macro (str value) (state/get-macros)))))]))]))))
(rum/defc multiple-values < rum/reactive
[block property v {:keys [on-chosen dropdown? editing?]
@ -722,10 +726,10 @@
(if (and dropdown? (not editing?))
(ui/dropdown
(fn [{:keys [toggle-fn]}]
[:a.control-link
{:on-mouse-down (if config/publishing?
(constantly nil)
toggle-fn)
[:a.control-link.jtrigger
{:on-click (if config/publishing?
(constantly nil)
toggle-fn)
:class "flex flex-1 flex-row items-center flex-wrap gap-x-2 gap-y-2 pr-4"}
(values-cp toggle-fn)])
(fn [{:keys [_toggle-fn]}]

View File

@ -150,7 +150,8 @@
(when (fn? tap-*input-val)
(tap-*input-val input))
[:div.cp__select
(merge {:class "cp__select-main"} host-opts)
(merge {:class "cp__select-main"}
host-opts)
(if dropdown?
(ui/dropdown

View File

@ -0,0 +1,28 @@
(ns frontend.handler.jump
"Jump to property key/value"
(:require [frontend.state :as state]
[dommy.core :as d]))
(defn clear-jump-hints!
[]
(dorun (map d/remove! (d/sel ".jtrigger-id"))))
(defn jump-to
[]
(let [selected-block (first (state/get-selection-blocks))]
(cond
selected-block
(let [triggers (d/sel selected-block ".jtrigger")]
(when (seq triggers)
(state/set-state! :editor/jump-data {:mode :property
:triggers (d/sel selected-block ".jtrigger")})
(doall
(map-indexed
(fn [id dom]
(d/append! dom (-> (d/create-element :span)
(d/set-attr! :class "jtrigger-id text-sm border rounded ml-2 px-1 shadow-xs")
(d/set-text! (str (inc id))))))
triggers))))
:else ; add block jump support
nil)))

View File

@ -18,6 +18,7 @@
[frontend.handler.whiteboard :as whiteboard-handler]
[frontend.handler.plugin-config :as plugin-config-handler]
[frontend.handler.window :as window-handler]
[frontend.handler.jump :as jump-handler]
[frontend.modules.editor.undo-redo :as undo-redo]
[frontend.dicts :as dicts]
[frontend.modules.shortcut.before :as m]
@ -507,6 +508,8 @@
:command/toggle-favorite {:binding "mod+shift+f"
:fn page-handler/toggle-favorite!}
:editor/jump {:binding "j"
:fn jump-handler/jump-to}
:editor/open-file-in-default-app {:binding "mod+d mod+a"
:inactive (not (util/electron?))
:file-graph? true
@ -711,7 +714,8 @@
:editor/copy
:editor/copy-text
:editor/cut
:command/toggle-favorite])
:command/toggle-favorite
:editor/jump])
(with-meta {:before m/enable-when-not-component-editing!}))
:shortcut.handler/global-prevent-default

View File

@ -121,6 +121,7 @@
:block/component-editing-mode? false
:editor/start-pos (atom nil)
:editor/op (atom nil)
:editor/jump-data (atom nil)
:editor/hidden-editors #{} ;; page names
:editor/draw-mode? false
:editor/action (atom nil)

View File

@ -730,6 +730,7 @@
:editor/toggle-undo-redo-mode "Toggle undo redo mode (global or page only)"
:editor/toggle-number-list "Toggle number list"
:editor/add-property "Add property"
:editor/jump "Jump to a property key or value (selection mode)"
:whiteboard/select "Select tool"
:whiteboard/pan "Pan tool"
:whiteboard/portal "Portal tool"