浏览代码

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?
Tienson Qin 1 年之前
父节点
当前提交
623043d363

+ 3 - 0
src/main/frontend/components/container.cljs

@@ -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?

+ 45 - 0
src/main/frontend/components/jump.cljs

@@ -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)])))

+ 3 - 2
src/main/frontend/components/property.cljs

@@ -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))

+ 5 - 1
src/main/frontend/components/property.css

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

+ 45 - 41
src/main/frontend/components/property/value.cljs

@@ -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)
-
-                    :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))))))]))]))))
+              (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)
+
+                  (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]}]

+ 2 - 1
src/main/frontend/components/select.cljs

@@ -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

+ 28 - 0
src/main/frontend/handler/jump.cljs

@@ -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)))

+ 5 - 1
src/main/frontend/modules/shortcut/config.cljs

@@ -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

+ 1 - 0
src/main/frontend/state.cljs

@@ -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)

+ 1 - 0
src/resources/dicts/en.edn

@@ -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"