enhance(ux): search support both recent search and updates

This commit is contained in:
Tienson Qin
2025-05-28 10:40:26 +08:00
parent 87beb7fdaf
commit 26113f47c7
4 changed files with 105 additions and 20 deletions

View File

@@ -302,14 +302,15 @@
(defn get-recent-updated-pages
[db]
(some->>
(d/datoms db :avet :block/updated-at)
rseq
(keep (fn [datom]
(let [e (d/entity db (:e datom))]
(when (and (common-entity-util/page? e) (not (entity-util/hidden? e)))
e))))
(take 30)))
(when db
(some->>
(d/datoms db :avet :block/updated-at)
rseq
(keep (fn [datom]
(let [e (d/entity db (:e datom))]
(when (and (common-entity-util/page? e) (not (entity-util/hidden? e)))
e))))
(take 30))))
(defn get-initial-data
"Returns current database schema and initial data.

View File

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

View File

@@ -194,7 +194,7 @@
;; Each result group has it's own load-results function
(defmulti load-results (fn [group _state] group))
(defn- get-page-icon
(defn get-page-icon
[entity]
(cond
(ldb/class? entity)

View File

@@ -1,17 +1,18 @@
(ns frontend.handler.search
"Provides util handler fns for search"
(:require [clojure.string :as string]
[frontend.config :as config]
[dommy.core :as dom]
[electron.ipc :as ipc]
[frontend.common.search-fuzzy :as fuzzy]
[frontend.config :as config]
[frontend.db :as db]
[frontend.handler.notification :as notification]
[frontend.search :as search]
[frontend.state :as state]
[frontend.storage :as storage]
[frontend.util :as util]
[promesa.core :as p]
[logseq.graph-parser.text :as text]
[electron.ipc :as ipc]
[dommy.core :as dom]))
[promesa.core :as p]))
(defn sanity-search-content
"Convert a block to the display contents for searching"
@@ -84,9 +85,9 @@
(defn loop-find-in-page!
[backward?]
(if (and (get-in @state/state [:ui/find-in-page :active?])
(not (state/editing?)))
(not (state/editing?)))
(do (state/set-state! [:ui/find-in-page :backward?] backward?)
(debounced-search))
(debounced-search))
;; return false to skip prevent default event behavior (Enter key)
false))
@@ -157,3 +158,18 @@
result)))
(conj result [:span content])))]
[:p {:class "m-0"} elements]))))))
(defn get-recents
[]
(storage/get :recent-search-items))
(defn add-recent!
[item]
(when-not (string/blank? item)
(let [recents (get-recents)]
(storage/set :recent-search-items
(distinct (take 20 (cons item recents)))))))
(defn clear-recents!
[]
(storage/remove :recent-search-items))