/
select.cljs
123 lines (117 loc) · 5.24 KB
/
select.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
(ns frontend.components.select
"Generic component for fuzzy searching items to select an item. See
select-config to add a new use or select-type for this component. To use the
new select-type, set :ui/open-select to the select-type. See
:graph/open command for an example."
(:require [frontend.modules.shortcut.core :as shortcut]
[frontend.context.i18n :refer [t]]
[frontend.search :as search]
[frontend.state :as state]
[frontend.ui :as ui]
[frontend.util :as util]
[frontend.db :as db]
[logseq.graph-parser.text :as text]
[rum.core :as rum]
[frontend.config :as config]
[frontend.handler.repo :as repo-handler]
[reitit.frontend.easy :as rfe]))
(rum/defc render-item
[{:keys [id value]} chosen?]
[:div.inline-grid.grid-cols-4.gap-x-4.w-full
{:class (when chosen? "chosen")}
[:span.col-span-3 value]
[:div.col-span-1.justify-end.tip.flex
(when id
[:code.opacity-20.bg-transparent id])]])
(rum/defcs select <
(shortcut/disable-all-shortcuts)
(rum/local "" ::input)
{:will-unmount (fn [state]
(state/set-state! [:ui/open-select] nil)
state)}
[state {:keys [items limit on-chosen empty-placeholder prompt-key]
:or {limit 100
prompt-key :select/default-prompt
empty-placeholder (fn [_t] [:div])}}]
(let [input (::input state)]
[:div.cp__select.cp__select-main
[:div.input-wrap
[:input.cp__select-input.w-full
{:type "text"
:placeholder (t prompt-key)
:auto-focus true
:value @input
:on-change (fn [e] (reset! input (util/evalue e)))}]]
[:div.item-results-wrap
(ui/auto-complete
(search/fuzzy-search items @input :limit limit :extract-fn :value)
{:item-render render-item
:class "cp__select-results"
:on-chosen (fn [x]
(state/close-modal!)
(on-chosen x))
:empty-placeholder (empty-placeholder t)})]]))
(defn select-config
"Config that supports multiple types (uses) of this component. To add a new
type, add a key with the value being a map with the following keys:
* :items-fn - fn that returns items with a :value key that are used for the
fuzzy search and selection. Items can have an optional :id and are displayed
lightly for a given item.
* :on-chosen - fn that is given item when it is chosen.
* :empty-placeholder (optional) - fn that returns hiccup html to render if no
matched graphs found.
* :prompt-key (optional) - dictionary keyword that prompts when components is
first open. Defaults to :select/default-prompt."
[]
{:graph-open
{:items-fn (fn []
(->>
(state/get-repos)
(remove (fn [{:keys [url]}]
(or (config/demo-graph? url)
(= url (state/get-current-repo)))))
(map (fn [{:keys [url]}]
{:value (text/get-graph-name-from-path
;; TODO: Use helper when a common one is refactored
;; from components.repo
(if (config/local-db? url)
(config/get-local-dir url)
(db/get-repo-path url)))
:id (config/get-repo-dir url)
:graph url}))))
:prompt-key :select.graph/prompt
:on-chosen #(state/pub-event! [:graph/switch (:graph %)])
:empty-placeholder (fn [t]
[:div.px-4.py-2
[:div.mb-2 (t :select.graph/empty-placeholder-description)]
(ui/button
(t :select.graph/add-graph)
:href (rfe/href :repo-add)
:on-click state/close-modal!)])}
:graph-remove
{:items-fn (fn []
(->> (state/get-repos)
(remove (fn [{:keys [url]}]
(config/demo-graph? url)))
(map (fn [{:keys [url] :as original-graph}]
{:value (text/get-graph-name-from-path
;; TODO: Use helper when a common one is refactored
;; from components.repo
(if (config/local-db? url)
(config/get-local-dir url)
(db/get-repo-path url)))
:id (config/get-repo-dir url)
:graph url
:original-graph original-graph}))))
:on-chosen #(repo-handler/remove-repo! (:original-graph %))}})
(rum/defc select-modal < rum/reactive
[]
(when-let [select-type (state/sub [:ui/open-select])]
(let [select-type-config (get (select-config) select-type)]
(state/set-modal!
#(select (-> select-type-config
(select-keys [:on-chosen :empty-placeholder :prompt-key])
(assoc :items ((:items-fn select-type-config)))))
{:fullscreen? false
:close-btn? false}))
nil))