Browse Source

enhance: shortcuts for ai regenerate/replace/insert

Tienson Qin 2 years ago
parent
commit
709a482ed4

+ 34 - 24
src/main/frontend/components/ai.cljs

@@ -21,7 +21,8 @@
             [frontend.modules.ai.prompts :as prompts]
             [frontend.modules.ai.prompts :as prompts]
             [promesa.core :as p]
             [promesa.core :as p]
             [cljs-bean.core :as bean]
             [cljs-bean.core :as bean]
-            [frontend.modules.ai.core :as ai]))
+            [frontend.modules.ai.core :as ai]
+            [frontend.modules.shortcut.core :as shortcut]))
 
 
 (defonce *messages (atom []))
 (defonce *messages (atom []))
 
 
@@ -171,6 +172,7 @@
             (reset! (::result state) result)))))))
             (reset! (::result state) result)))))))
 
 
 (rum/defcs ai-prompt-body < rum/static
 (rum/defcs ai-prompt-body < rum/static
+  (shortcut/mixin :shortcut.handler/ai-prompt)
   (rum/local nil ::result)
   (rum/local nil ::result)
   (rum/local false ::loading?)
   (rum/local false ::loading?)
   (rum/local nil ::error)
   (rum/local nil ::error)
@@ -187,7 +189,7 @@
         *error (::error state)
         *error (::error state)
         target-block-id (or (:block/uuid editing-block) (last selected-blocks))
         target-block-id (or (:block/uuid editing-block) (last selected-blocks))
         target-block (when target-block-id (db/pull [:block/uuid target-block-id]))]
         target-block (when target-block-id (db/pull [:block/uuid target-block-id]))]
-    [:div.my-4
+    [:div#ai-prompt-modal.my-4
      [:div.whitespace-pre-wrap.my-2
      [:div.whitespace-pre-wrap.my-2
       (::initial-content state)]
       (::initial-content state)]
      (when @*loading?
      (when @*loading?
@@ -200,29 +202,37 @@
           [:hr]
           [:hr]
           (str @*result)]))
           (str @*result)]))
      [:div.flex.flex-row.justify-between.my-4
      [:div.flex.flex-row.justify-between.my-4
-      (ui/button "Regenerate" :on-click (fn [] (send-request state)))
+      (ui/btn-with-shortcut {:btn-text "Regenerate"
+                             :shortcut "g"
+                             :id       "ai-regenerate"
+                             :on-click (fn [] (send-request state))})
       [:div.flex.flex-row.justify-between
       [:div.flex.flex-row.justify-between
-       (ui/button "Replace"
-         :on-click (fn []
-                     (let [repo (state/get-current-repo)]
-                       (when target-block
-                         (if (or editing-block (= 1 (count selected-blocks)))
-                           ;; replace the content
-                           (editor-handler/edit-block! target-block :max
-                                                       (:block/uuid target-block)
-                                                       {:custom-content @*result})
-                           (paste-handler/delete-blocks-and-new-block! selected-blocks @*result))
-                         (state/close-modal!))))
-         :class "mr-2")
-       (ui/button "Insert"
-         :on-click (fn []
-                     (when target-block
-                       (paste-handler/paste-text-parseable
-                        (state/get-preferred-format)
-                        @*result
-                        {:target-block target-block
-                         :sibling? (not (or editing-block (= 1 (count selected-blocks))))})
-                       (state/close-modal!))))]]]))
+       (when target-block
+         (ui/btn-with-shortcut {:btn-text "Replace"
+                                :shortcut "r"
+                                :id       "ai-replace"
+                                :class "mr-2"
+                                :on-click (fn []
+                                            (let [repo (state/get-current-repo)]
+                                              (when target-block
+                                                (if (or editing-block (= 1 (count selected-blocks)))
+                                                  ;; replace the content
+                                                  (editor-handler/edit-block! target-block :max
+                                                                              (:block/uuid target-block)
+                                                                              {:custom-content @*result})
+                                                  (paste-handler/delete-blocks-and-new-block! selected-blocks @*result))
+                                                (state/close-modal!))))}))
+       (ui/btn-with-shortcut {:btn-text "Insert"
+                              :shortcut "Enter"
+                              :id       "ai-insert"
+                              :on-click (fn []
+                                          (when target-block
+                                            (paste-handler/paste-text-parseable
+                                             (state/get-preferred-format)
+                                             @*result
+                                             {:target-block target-block
+                                              :sibling? (not (or editing-block (= 1 (count selected-blocks))))})
+                                            (state/close-modal!)))})]]]))
 
 
 (def langs ["English"
 (def langs ["English"
             "中文"
             "中文"

+ 34 - 45
src/main/frontend/extensions/srs.cljs

@@ -411,17 +411,6 @@
 (def review-finished
 (def review-finished
   [:p.p-2 "Congrats, you've reviewed all the cards for this query, see you next time! 💯"])
   [:p.p-2 "Congrats, you've reviewed all the cards for this query, see you next time! 💯"])
 
 
-(defn- btn-with-shortcut [{:keys [shortcut id btn-text background on-click class]}]
-  (ui/button
-   [:span btn-text (when-not (util/sm-breakpoint?)
-                     [" " (ui/render-keyboard-shortcut shortcut)])]
-   :id id
-   :class (str id " " class)
-   :background background
-   :on-mouse-down (fn [e] (util/stop-propagation e))
-   :on-click (fn [_e]
-               (js/setTimeout #(on-click) 10))))
-
 (rum/defcs view < rum/reactive db-mixins/query
 (rum/defcs view < rum/reactive db-mixins/query
   (rum/local 1 ::phase)
   (rum/local 1 ::phase)
   (rum/local {} ::review-records)
   (rum/local {} ::review-records)
@@ -456,46 +445,46 @@
          (if (or preview? modal?)
          (if (or preview? modal?)
            [:div.flex.my-4.justify-between
            [:div.flex.my-4.justify-between
             (when-not (and (not preview?) (= next-phase 1))
             (when-not (and (not preview?) (= next-phase 1))
-              (btn-with-shortcut {:btn-text (case next-phase
-                                              1 "Hide answers"
-                                              2 "Show answers"
-                                              3 "Show clozes")
-                                  :shortcut  "s"
-                                  :id "card-answers"
-                                  :class "mr-2"
-                                  :on-click #(reset! phase next-phase)}))
+              (ui/btn-with-shortcut {:btn-text (case next-phase
+                                                 1 "Hide answers"
+                                                 2 "Show answers"
+                                                 3 "Show clozes")
+                                     :shortcut  "s"
+                                     :id "card-answers"
+                                     :class "mr-2"
+                                     :on-click #(reset! phase next-phase)}))
             (when (and (not= @card-index (count blocks))
             (when (and (not= @card-index (count blocks))
                        cards?
                        cards?
                        preview?)
                        preview?)
-              (btn-with-shortcut {:btn-text "Next"
-                                  :shortcut "n"
-                                  :id       "card-next"
-                                  :class    "mr-2"
-                                  :on-click (fn [e]
-                                              (util/stop e)
-                                              (skip-card card card-index finished? phase review-records cb))}))
+              (ui/btn-with-shortcut {:btn-text "Next"
+                                     :shortcut "n"
+                                     :id       "card-next"
+                                     :class    "mr-2"
+                                     :on-click (fn [e]
+                                                 (util/stop e)
+                                                 (skip-card card card-index finished? phase review-records cb))}))
 
 
             (when (and (not preview?) (= 1 next-phase))
             (when (and (not preview?) (= 1 next-phase))
               [:<>
               [:<>
-               (btn-with-shortcut {:btn-text   "Forgotten"
-                                   :shortcut   "f"
-                                   :id         "card-forgotten"
-                                   :background "red"
-                                   :on-click   (fn []
-                                                 (score-and-next-card 1 card card-index finished? phase review-records cb)
-                                                 (let [tomorrow (tc/to-string (t/plus (t/today) (t/days 1)))]
-                                                   (editor-property/set-block-property! root-block-id card-next-schedule-property tomorrow)))})
-
-               (btn-with-shortcut {:btn-text (if (util/mobile?) "Hard" "Took a while to recall")
-                                   :shortcut "t"
-                                   :id       "card-recall"
-                                   :on-click #(score-and-next-card 3 card card-index finished? phase review-records cb)})
-
-               (btn-with-shortcut {:btn-text   "Remembered"
-                                   :shortcut   "r"
-                                   :id         "card-remembered"
-                                   :background "green"
-                                   :on-click   #(score-and-next-card 5 card card-index finished? phase review-records cb)})])
+               (ui/btn-with-shortcut {:btn-text   "Forgotten"
+                                      :shortcut   "f"
+                                      :id         "card-forgotten"
+                                      :background "red"
+                                      :on-click   (fn []
+                                                    (score-and-next-card 1 card card-index finished? phase review-records cb)
+                                                    (let [tomorrow (tc/to-string (t/plus (t/today) (t/days 1)))]
+                                                      (editor-property/set-block-property! root-block-id card-next-schedule-property tomorrow)))})
+
+               (ui/btn-with-shortcut {:btn-text (if (util/mobile?) "Hard" "Took a while to recall")
+                                      :shortcut "t"
+                                      :id       "card-recall"
+                                      :on-click #(score-and-next-card 3 card card-index finished? phase review-records cb)})
+
+               (ui/btn-with-shortcut {:btn-text   "Remembered"
+                                      :shortcut   "r"
+                                      :id         "card-remembered"
+                                      :background "green"
+                                      :on-click   #(score-and-next-card 5 card card-index finished? phase review-records cb)})])
 
 
             (when preview?
             (when preview?
               (ui/tippy {:html [:div.text-sm
               (ui/tippy {:html [:div.text-sm

+ 18 - 1
src/main/frontend/handler/ai.cljs

@@ -12,7 +12,8 @@
             [frontend.db.model :as db-model]
             [frontend.db.model :as db-model]
             [frontend.modules.ai.prompts :as prompts]
             [frontend.modules.ai.prompts :as prompts]
             [frontend.util :as util]
             [frontend.util :as util]
-            [logseq.common.path :as path]))
+            [logseq.common.path :as path]
+            [dommy.core :refer-macros [sel]]))
 
 
 (defn- text->segments
 (defn- text->segments
   [text]
   [text]
@@ -137,3 +138,19 @@
            (p/catch (fn [error]
            (p/catch (fn [error]
                       (reset! *transcribing? false)
                       (reset! *transcribing? false)
                       (prn "Transcribed failed:" error)))))))))
                       (prn "Transcribed failed:" error)))))))))
+
+
+(defn click
+  [id]
+  (let [nodes (sel [:#ai-prompt-modal (str "." id)])]
+    (doseq [node nodes]
+      (.click node))))
+
+(defn regenerate []
+  (click "ai-regenerate"))
+
+(defn insert []
+  (click "ai-insert"))
+
+(defn replace []
+  (click "ai-replace"))

+ 15 - 0
src/main/frontend/modules/shortcut/config.cljs

@@ -502,6 +502,15 @@
    :ai/ask                          {:binding "mod+;"
    :ai/ask                          {:binding "mod+;"
                                      :fn      ai-handler/open-ask}
                                      :fn      ai-handler/open-ask}
 
 
+   :ai/regenerate                   {:binding "g"
+                                     :fn      ai-handler/regenerate}
+
+   :ai/replace                      {:binding "r"
+                                     :fn      ai-handler/replace}
+
+   :ai/insert                       {:binding "enter"
+                                     :fn      ai-handler/insert}
+
    :ui/toggle-wide-mode             {:binding "t w"
    :ui/toggle-wide-mode             {:binding "t w"
                                      :fn      ui-handler/toggle-wide-mode!}
                                      :fn      ui-handler/toggle-wide-mode!}
 
 
@@ -631,6 +640,12 @@
                              :cards/recall])
                              :cards/recall])
         (with-meta {:before m/enable-when-not-editing-mode!}))
         (with-meta {:before m/enable-when-not-editing-mode!}))
 
 
+    :shortcut.handler/ai-prompt
+    (-> (build-category-map [:ai/regenerate
+                             :ai/insert
+                             :ai/replace])
+        (with-meta {:before m/enable-when-not-editing-mode!}))
+
     :shortcut.handler/block-editing-only
     :shortcut.handler/block-editing-only
     (->
     (->
      (build-category-map [:editor/escape-editing
      (build-category-map [:editor/escape-editing

+ 3 - 0
src/main/frontend/modules/shortcut/dicts.cljc

@@ -152,6 +152,9 @@
    :editor/copy-page-url            "Copy page url"
    :editor/copy-page-url            "Copy page url"
    :ui/toggle-wide-mode             "Toggle wide mode"
    :ui/toggle-wide-mode             "Toggle wide mode"
    :ai/ask                          "Ask AI"
    :ai/ask                          "Ask AI"
+   :ai/regenerate                   "AI: regenerate"
+   :ai/replace                      "AI: replace"
+   :ai/insert                       "AI: insert"
    :ui/select-theme-color           "Select available theme colors"
    :ui/select-theme-color           "Select available theme colors"
    :ui/goto-plugins                 "Go to plugins dashboard"
    :ui/goto-plugins                 "Go to plugins dashboard"
    :ui/install-plugins-from-file    "Install plugins from plugins.edn"
    :ui/install-plugins-from-file    "Install plugins from plugins.edn"

+ 12 - 0
src/main/frontend/ui.cljs

@@ -1023,6 +1023,18 @@
      (when icon (frontend.ui/icon icon (merge icon-props {:class (when-not (empty? text) "mr-1")})))
      (when icon (frontend.ui/icon icon (merge icon-props {:class (when-not (empty? text) "mr-1")})))
      text]))
      text]))
 
 
+(defn btn-with-shortcut
+  [{:keys [shortcut id btn-text background on-click class]}]
+  (button
+    [:span btn-text (when-not (util/sm-breakpoint?)
+                      [" " (render-keyboard-shortcut shortcut)])]
+    :id id
+    :class (str id " " class)
+    :background background
+    :on-mouse-down (fn [e] (util/stop-propagation e))
+    :on-click (fn [_e]
+                (js/setTimeout #(on-click) 10))))
+
 (rum/defc point
 (rum/defc point
   ([] (point "bg-red-600" 5 nil))
   ([] (point "bg-red-600" 5 nil))
   ([klass size {:keys [class style] :as opts}]
   ([klass size {:keys [class style] :as opts}]