Browse Source

feat: search

Tienson Qin 7 months ago
parent
commit
c9044afb3d

+ 4 - 10
src/main/capacitor/components/app.cljs

@@ -1,6 +1,7 @@
 (ns capacitor.components.app
   (:require ["../externals.js"]
             ["@capacitor/app" :refer [App]]
+            [capacitor.components.search :as search]
             [capacitor.components.settings :as settings]
             [capacitor.components.ui :as ui]
             [capacitor.ionic :as ion]
@@ -151,15 +152,6 @@
          (ion/tabler-icon "loader" {:class "animate animate-spin opacity-50" :size 30})])
        (journals)))))
 
-(rum/defc search
-  []
-  (ion/page
-   {:id "search-tab"}
-   (ion/header
-    (ion/toolbar
-     "Search"))
-   [:div.flex.flex-1.p-4 "Search results"]))
-
 (rum/defc settings
   []
   (ion/page
@@ -180,6 +172,8 @@
        #())
      [(rum/deref nav-ref)])
     (ion/tabs
+     {:onIonTabsDidChange (fn [^js e]
+                            (state/set-tab! (.-tab (.-detail e))))}
      (ion/tab
       {:tab "home"}
       (ion/nav {:ref nav-ref
@@ -189,7 +183,7 @@
      (ion/tab
       {:tab "search"}
       (ion/content
-       (search)))
+       (search/search)))
      (ion/tab
       {:tab "settings"}
       (ion/content

+ 67 - 0
src/main/capacitor/components/search.cljs

@@ -0,0 +1,67 @@
+(ns capacitor.components.search
+  (:require [capacitor.ionic :as ion]
+            [capacitor.nav :as nav]
+            [capacitor.state :as state]
+            [clojure.string :as string]
+            [dommy.core :as dom]
+            [frontend.components.cmdk.core :as cmdk]
+            [frontend.search :as search]
+            [frontend.state :as fstate]
+            [frontend.ui :as ui]
+            [logseq.shui.hooks :as hooks]
+            [promesa.core :as p]
+            [rum.core :as rum]))
+
+(defn- search-blocks
+  [input]
+  (p/let [repo (fstate/get-current-repo)
+          blocks (search/block-search repo input
+                                      {:limit 100 :built-in? true})
+          blocks (remove nil? blocks)
+          blocks (search/fuzzy-search blocks input {:limit 100
+                                                    :extract-fn :block/title})
+          items (keep (fn [block]
+                        (if (:page? block)
+                          (cmdk/page-item repo block)
+                          (cmdk/block-item repo block nil input))) blocks)]
+    items))
+
+(rum/defc result-item
+  [item]
+  [:div.flex.flex-1
+   (:text item)])
+
+(rum/defc search
+  []
+  (let [*ref (hooks/use-ref nil)
+        [search-result set-search-result!] (hooks/use-state nil)]
+    (ion/page
+     {:id "search-tab"}
+     (ion/header
+      (ion/toolbar
+       (ion/searchbar
+        {:ref *ref
+         :slot "start"
+         :placeholder "Search"
+         :on-ion-input (fn [^js e]
+                         (let [input (.-value (.-detail e))]
+                           (when-not (string/blank? input)
+                             (p/let [result (search-blocks input)]
+                               (set-search-result! result)))))})))
+     (ion/content
+      (ion/list
+       (for [{:keys [icon text header source-page source-block]} search-result]
+         (let [block (or source-page source-block)]
+           (ion/item
+            {:on-click (fn []
+                         (state/set-tab! "home")
+                         (.select (dom/sel1 "ion-tabs") "home")
+                         (nav/nav-to-block! block {}))}
+            [:div.flex.flex-col.gap-1.py-1
+             (when header
+               [:div.opacity-50.text-sm
+                header])
+             [:div.flex.flex-row.items-center.gap-2
+              (when icon (ui/icon icon {:size 14
+                                        :class "text-muted-foreground"}))
+              [:div text]]]))))))))

+ 2 - 0
src/main/capacitor/ionic.cljs

@@ -1,4 +1,5 @@
 (ns capacitor.ionic
+  (:refer-clojure :exclude [list])
   (:require ["@capacitor/camera" :as ionicCamera]
             ["@ionic/react" :as ionicReact]
             [logseq.shui.icon.v2 :as shui-icon]
@@ -43,3 +44,4 @@
 (defonce menu (shui-util/react->rum (.-IonMenu ionic-react) false))
 (defonce menu-button (shui-util/react->rum (.-IonMenuButton ionic-react) false))
 (defonce action-sheet (shui-util/react->rum (.-IonActionSheet ionic-react) false))
+(defonce searchbar (shui-util/react->rum (.-IonSearchbar ionic-react) false))

+ 7 - 0
src/main/capacitor/state.cljs

@@ -4,3 +4,10 @@
 (defonce *nav-root (atom nil))
 
 (defn use-nav-root [] (r/use-atom *nav-root))
+
+(defonce *tab (atom "home"))
+(defn set-tab!
+  [tab]
+  (reset! *tab tab))
+
+(defn use-tab [] (r/use-atom *tab))

+ 5 - 5
src/main/frontend/components/cmdk/core.cljs

@@ -272,7 +272,7 @@
                 (recur e-cut new-result)
                 new-result)))]))
 
-(defn- page-item
+(defn page-item
   [repo page]
   (let [entity (db/entity [:block/uuid (:block/uuid page)])
         source-page (model/get-alias-source-page repo (:db/id entity))
@@ -284,14 +284,14 @@
               :text title'
               :source-page (or source-page page))))
 
-(defn- block-item
-  [repo block current-page !input]
+(defn block-item
+  [repo block current-page input]
   (let [id (:block/uuid block)
         text (block-handler/block-unique-title block)
         icon "letter-n"]
     {:icon icon
      :icon-theme :gray
-     :text (highlight-content-query text @!input)
+     :text (highlight-content-query text input)
      :header (when-not (db/page? block) (block/breadcrumb {:search? true} repo id {}))
      :current-page? (when-let [page-id (:block/page block)]
                       (= page-id (:block/uuid current-page)))
@@ -314,7 +314,7 @@
             items (keep (fn [block]
                           (if (:page? block)
                             (page-item repo block)
-                            (block-item repo block current-page !input))) blocks)]
+                            (block-item repo block current-page @!input))) blocks)]
       (if (= group :current-page)
         (let [items-on-current-page (filter :current-page? items)]
           (swap! !results update group         merge {:status :success :items items-on-current-page}))