|
@@ -5,9 +5,14 @@
|
|
|
[clojure.string :as string]
|
|
|
[dommy.core :as dom]
|
|
|
[frontend.components.cmdk.core :as cmdk]
|
|
|
+ [frontend.db :as db]
|
|
|
+ [frontend.handler.block :as block-handler]
|
|
|
+ [frontend.handler.search :as search-handler]
|
|
|
[frontend.search :as search]
|
|
|
[frontend.state :as fstate]
|
|
|
[frontend.ui :as ui]
|
|
|
+ [frontend.util :as util]
|
|
|
+ [logseq.db :as ldb]
|
|
|
[logseq.shui.hooks :as hooks]
|
|
|
[promesa.core :as p]
|
|
|
[rum.core :as rum]))
|
|
@@ -26,10 +31,47 @@
|
|
|
(cmdk/block-item repo block nil input))) blocks)]
|
|
|
items))
|
|
|
|
|
|
+(defn- get-recent-pages
|
|
|
+ []
|
|
|
+ (let [recent-pages (->> (ldb/get-recent-updated-pages (db/get-db))
|
|
|
+ (remove ldb/built-in?))]
|
|
|
+ (map (fn [block]
|
|
|
+ (let [text (block-handler/block-unique-title block)
|
|
|
+ icon (cmdk/get-page-icon block)]
|
|
|
+ {:icon icon
|
|
|
+ :icon-theme :gray
|
|
|
+ :text text
|
|
|
+ :source-block block}))
|
|
|
+ recent-pages)))
|
|
|
+
|
|
|
(rum/defc search
|
|
|
[]
|
|
|
(let [*ref (hooks/use-ref nil)
|
|
|
- [search-result set-search-result!] (hooks/use-state nil)]
|
|
|
+ [input set-input!] (hooks/use-state "")
|
|
|
+ [search-result set-search-result!] (hooks/use-state nil)
|
|
|
+ [last-input-at set-last-input-at!] (hooks/use-state nil)
|
|
|
+ [recents set-recents!] (hooks/use-state (search-handler/get-recents))
|
|
|
+ result (if (string/blank? input)
|
|
|
+ (get-recent-pages)
|
|
|
+ search-result)]
|
|
|
+ (hooks/use-effect!
|
|
|
+ (fn []
|
|
|
+ (let [*timeout (atom nil)]
|
|
|
+ (when-not (string/blank? input)
|
|
|
+ (p/let [result (search-blocks input)]
|
|
|
+ (set-search-result! result)
|
|
|
+ (when (seq result)
|
|
|
+ (reset! *timeout
|
|
|
+ (js/setTimeout
|
|
|
+ (fn []
|
|
|
+ (let [now (util/time-ms)]
|
|
|
+ (when (and last-input-at (>= (- now last-input-at) 2000))
|
|
|
+ (search-handler/add-recent! input)
|
|
|
+ (set-recents! (search-handler/get-recents)))))
|
|
|
+ 2000)))))
|
|
|
+ #(when-let [timeout @*timeout]
|
|
|
+ (js/clearTimeout timeout))))
|
|
|
+ [(hooks/use-debounced-value input 150)])
|
|
|
(ion/page
|
|
|
{:id "search-tab"}
|
|
|
(ion/header
|
|
@@ -38,14 +80,40 @@
|
|
|
{:ref *ref
|
|
|
:slot "start"
|
|
|
:placeholder "Search"
|
|
|
+ :value input
|
|
|
: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)))))})))
|
|
|
+ (set-input! input)
|
|
|
+ (set-last-input-at! (util/time-ms))))})))
|
|
|
(ion/content
|
|
|
+ (when (string/blank? input)
|
|
|
+ [:<>
|
|
|
+ [:div.mb-4
|
|
|
+ [:div.px-4.text-sm.text-muted-foreground.border-b
|
|
|
+ [:div.flex.flex-item.items-center.justify-between
|
|
|
+ [:div "Recent search"]
|
|
|
+ (ion/button
|
|
|
+ {:fill "clear"
|
|
|
+ :size "small"
|
|
|
+ :mode "ios"
|
|
|
+ :class "text-muted-foreground"
|
|
|
+ :on-click (fn []
|
|
|
+ (search-handler/clear-recents!)
|
|
|
+ (set-recents! nil))}
|
|
|
+ "Clear all")]]
|
|
|
+ (ion/list
|
|
|
+ (for [item recents]
|
|
|
+ (ion/item
|
|
|
+ {:on-click #(set-input! item)}
|
|
|
+ [:div.flex.flex-row.items-center.gap-1
|
|
|
+ (ui/icon "search" {:size 14
|
|
|
+ :class "text-muted-foreground"})
|
|
|
+ item])))]
|
|
|
+
|
|
|
+ [:div.px-4.py-2.text-sm.text-muted-foreground.border-b
|
|
|
+ "Recent updates"]])
|
|
|
(ion/list
|
|
|
- (for [{:keys [icon text header source-page source-block]} search-result]
|
|
|
+ (for [{:keys [icon text header source-page source-block]} result]
|
|
|
(let [block (or source-page source-block)]
|
|
|
(ion/item
|
|
|
{:on-click (fn []
|