diff --git a/src/main/frontend/components/command_palette.css b/src/main/frontend/components/command_palette.css index 4eaa705fb..5d1c16f46 100644 --- a/src/main/frontend/components/command_palette.css +++ b/src/main/frontend/components/command_palette.css @@ -1,4 +1,4 @@ -.cp__palette { +.cp__palette, .cp__select { --palettle-input-height: 64px; --palettle-container-height: 75vh; @@ -27,6 +27,7 @@ } .command-results-wrap, + .item-results-wrap, .search-results-wrap > div:first-child { overflow-x: hidden; overflow-y: auto; diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index 3570a79a1..2cdd11054 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -52,10 +52,10 @@ [:div.has-help command-name (ui/tippy - {:html doc - :interactive true - :fixed-position? true - :position "right"} + {:html doc + :interactive true + :fixed-position? true + :position "right"} [:small (svg/help-circle)])] @@ -148,7 +148,7 @@ :tippy-distance 24 :tippy-position (if sidebar? "left" "right")} page-name)]) - :empty-div [:div.text-gray-500.text-sm.px-4.py-2 "Search for a page"] + :empty-placeholder [:div.text-gray-500.text-sm.px-4.py-2 "Search for a page"] :class "black"})))))) (rum/defcs block-search-auto-complete < rum/reactive @@ -170,7 +170,7 @@ result {:on-chosen chosen-handler :on-enter non-exist-block-handler - :empty-div [:div.text-gray-500.pl-4.pr-4 "Search for a block"] + :empty-placeholder [:div.text-gray-500.pl-4.pr-4 "Search for a block"] :item-render (fn [{:block/keys [page uuid]}] ;; content returned from search engine is normalized (let [page (or (:block/original-name page) (:block/name page)) @@ -222,7 +222,7 @@ matched-templates {:on-chosen (editor-handler/template-on-chosen-handler id) :on-enter non-exist-handler - :empty-div [:div.text-gray-500.px-4.py-2.text-sm "Search for a template"] + :empty-placeholder [:div.text-gray-500.px-4.py-2.text-sm "Search for a template"] :item-render (fn [[template _block-db-id]] template) :class "black"})))))) @@ -441,23 +441,23 @@ [:input.form-input.block.w-full.pl-2.sm:text-sm.sm:leading-5 (merge (cond-> - {:key (str "modal-input-" (name id)) - :id (str "modal-input-" (name id)) - :type (or type "text") - :on-change (fn [e] - (swap! input-value assoc id (util/evalue e))) - :auto-complete (if (util/chrome?) "chrome-off" "off")} - placeholder - (assoc :placeholder placeholder) - autoFocus - (assoc :auto-focus true)) + {:key (str "modal-input-" (name id)) + :id (str "modal-input-" (name id)) + :type (or type "text") + :on-change (fn [e] + (swap! input-value assoc id (util/evalue e))) + :auto-complete (if (util/chrome?) "chrome-off" "off")} + placeholder + (assoc :placeholder placeholder) + autoFocus + (assoc :auto-focus true)) (dissoc input-item :id))]]) (ui/button - "Submit" - :on-click - (fn [e] - (util/stop e) - (on-submit command @input-value pos)))]))))) + "Submit" + :on-click + (fn [e] + (util/stop e) + (on-submit command @input-value pos)))]))))) (rum/defc absolute-modal < rum/static [cp set-default-width? {:keys [top left rect]}] @@ -501,7 +501,7 @@ {:top (+ top offset-top (if (int? y-diff) y-diff 0)) :max-height to-max-height :max-width 700 - ;; TODO: auto responsive fixed size + ;; TODO: auto responsive fixed size :width "fit-content" :z-index 11} (when set-default-width? diff --git a/src/main/frontend/components/repo.cljs b/src/main/frontend/components/repo.cljs index a005aa9ea..a00ab43b5 100644 --- a/src/main/frontend/components/repo.cljs +++ b/src/main/frontend/components/repo.cljs @@ -12,45 +12,19 @@ [frontend.handler.export :as export-handler] [frontend.handler.page :as page-handler] [frontend.handler.repo :as repo-handler] - [frontend.handler.route :as route-handler] [frontend.handler.ui :as ui-handler] [frontend.handler.web.nfs :as nfs-handler] - [frontend.handler.notification :as notification] [frontend.modules.shortcut.core :as shortcut] [frontend.state :as state] [frontend.ui :as ui] [frontend.util :as util] - [frontend.fs :as fs] [frontend.version :as version] [reitit.frontend.easy :as rfe] - [frontend.modules.outliner.file :as outliner-file] [rum.core :as rum] [frontend.mobile.util :as mobile-util] [frontend.text :as text] [promesa.core :as p] - [electron.ipc :as ipc] - [frontend.extensions.srs :as srs])) - -;; TODO: move to events -(defn- open-repo-url [url] - (repo-handler/push-if-auto-enabled! (state/get-current-repo)) - (state/set-current-repo! url) - ;; load config - (common-handler/reset-config! url nil) - (shortcut/refresh!) - (when-not (= :draw (state/get-current-route)) - (route-handler/redirect-to-home!)) - (when-let [dir-name (config/get-repo-dir url)] - (fs/watch-dir! dir-name)) - (srs/update-cards-due-count!)) - -(defn- switch-repo-if-writes-finished? - [url] - (if (outliner-file/writes-finished?) - (open-repo-url url) - (notification/show! - "Please wait seconds until all changes are saved for the current graph." - :warning))) + [electron.ipc :as ipc])) (rum/defc add-repo [args] @@ -95,7 +69,7 @@ (let [local-dir (config/get-local-dir url) graph-name (text/get-graph-name-from-path local-dir)] [:a {:title local-dir - :on-click #(switch-repo-if-writes-finished? url)} + :on-click #(state/pub-event! [:graph/switch url])} graph-name]) [:a {:target "_blank" :href url} @@ -239,7 +213,7 @@ {:title short-repo-name :hover-detail repo-path ;; show full path on hover :options {:class "ml-1" - :on-click #(switch-repo-if-writes-finished? url)}})) + :on-click #(state/pub-event! [:graph/switch url])}})) switch-repos) links (->> (concat repo-links diff --git a/src/main/frontend/components/select.cljs b/src/main/frontend/components/select.cljs new file mode 100644 index 000000000..aa56f0616 --- /dev/null +++ b/src/main/frontend/components/select.cljs @@ -0,0 +1,105 @@ +(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 + :select-graph/open command for an example." + (:require [frontend.modules.shortcut.core :as shortcut] + [frontend.context.i18n :as i18n] + [frontend.search :as search] + [frontend.state :as state] + [frontend.ui :as ui] + [frontend.util :as util] + [frontend.db :as db] + [frontend.text :as text] + [rum.core :as rum] + [frontend.config :as config] + [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}}] + (rum/with-context [[t] i18n/*tongue-context*] + (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 - fn that returns hiccup html to render if no matched graphs found. + * :prompt-key - dictionary keyword that prompts when components is first open. + Defaults to :select/default-prompt." + [] + {:select-graph + {: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!)])}}) + +(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)) diff --git a/src/main/frontend/components/sidebar.cljs b/src/main/frontend/components/sidebar.cljs index 78219b0ab..93ee4c48f 100644 --- a/src/main/frontend/components/sidebar.cljs +++ b/src/main/frontend/components/sidebar.cljs @@ -10,6 +10,7 @@ [frontend.components.theme :as theme] [frontend.components.widgets :as widgets] [frontend.components.plugins :as plugins] + [frontend.components.select :as select] [frontend.config :as config] [frontend.context.i18n :as i18n] [frontend.db :as db] @@ -545,6 +546,7 @@ (ui/modal) (ui/sub-modal) (command-palette/command-palette-modal) + (select/select-modal) (custom-context-menu) (plugins/custom-js-installer {:t t :current-repo current-repo diff --git a/src/main/frontend/components/widgets.cljs b/src/main/frontend/components/widgets.cljs index 48e449a31..0df37dbd9 100644 --- a/src/main/frontend/components/widgets.cljs +++ b/src/main/frontend/components/widgets.cljs @@ -172,7 +172,7 @@ :local [(rum/with-key (android-permission-alert) - "andoird-permission-alert") + "android-permission-alert") (rum/with-key (add-local-directory) "add-local-directory")] diff --git a/src/main/frontend/config.cljs b/src/main/frontend/config.cljs index 5542be9cc..c520070bd 100644 --- a/src/main/frontend/config.cljs +++ b/src/main/frontend/config.cljs @@ -307,8 +307,10 @@ (defonce local-repo "local") (defn demo-graph? - [] - (= (state/get-current-repo) local-repo)) + ([] + (demo-graph? (state/get-current-repo))) + ([graph] + (= graph local-repo))) (defonce local-assets-dir "assets") (defonce recycle-dir ".recycle") diff --git a/src/main/frontend/dicts.cljs b/src/main/frontend/dicts.cljs index b326779d7..90c4e21d2 100644 --- a/src/main/frontend/dicts.cljs +++ b/src/main/frontend/dicts.cljs @@ -390,7 +390,11 @@ :tips/all-done "All Done" - :command-palette/prompt "Type a command"} + :command-palette/prompt "Type a command" + :select/default-prompt "Select one" + :select.graph/prompt "Select a graph" + :select.graph/empty-placeholder-description "No matched graphs. Do you want to add another one?" + :select.graph/add-graph "Yes, add another graph"} :de {:help/about "Über Logseq" :on-boarding/demo-graph "This is a demo graph, changes will not be saved until you open a local folder." @@ -1958,7 +1962,12 @@ :user/delete-your-account "Eliminar su cuenta" :user/delete-account-notice "Todas sus páginas publicadas en Logseq serán eliminadas." - :help/shortcut-page-title "Atajos personalizados"} + :help/shortcut-page-title "Atajos personalizados" + + :select/prompt "Seleccione uno" + :select.graph/prompt "Seleccione un grafo" + :select.graph/empty-placeholder-description "No encontramos un grafo. Queries añadir otro?" + :select.graph/add-graph "Si, añadame otro grafo"} :nb-NO {:on-boarding/title "Hei, og velkommen til Logseq!" :on-boarding/sharing "deling" diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index 3599fb17a..e51c8f398 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -21,7 +21,10 @@ [frontend.handler.notification :as notification] [frontend.handler.page :as page-handler] [frontend.handler.ui :as ui-handler] + [frontend.handler.repo :as repo-handler] + [frontend.handler.route :as route-handler] [frontend.modules.shortcut.core :as st] + [frontend.modules.outliner.file :as outliner-file] [frontend.commands :as commands] [frontend.spec :as spec] [frontend.state :as state] @@ -32,7 +35,8 @@ [frontend.modules.instrumentation.posthog :as posthog] [frontend.mobile.util :as mobile-util] [frontend.encrypt :as encrypt] - [promesa.core :as p])) + [promesa.core :as p] + [frontend.fs :as fs])) ;; TODO: should we move all events here? @@ -77,6 +81,25 @@ (db/set-key-value repo :ast/version db-schema/ast-version) (srs/update-cards-due-count!))) +(defn- graph-switch [graph] + (repo-handler/push-if-auto-enabled! (state/get-current-repo)) + (state/set-current-repo! graph) + ;; load config + (common-handler/reset-config! graph nil) + (st/refresh!) + (when-not (= :draw (state/get-current-route)) + (route-handler/redirect-to-home!)) + (when-let [dir-name (config/get-repo-dir graph)] + (fs/watch-dir! dir-name)) + (srs/update-cards-due-count!)) + +(defmethod handle :graph/switch [[_ graph]] + (if (outliner-file/writes-finished?) + (graph-switch graph) + (notification/show! + "Please wait seconds until all changes are saved for the current graph." + :warning))) + (defmethod handle :graph/migrated [[_ _repo]] (js/alert "Graph migrated.")) diff --git a/src/main/frontend/modules/shortcut/config.cljs b/src/main/frontend/modules/shortcut/config.cljs index e9b94eb46..42c662374 100644 --- a/src/main/frontend/modules/shortcut/config.cljs +++ b/src/main/frontend/modules/shortcut/config.cljs @@ -182,13 +182,11 @@ :editor/up {:desc "Move cursor up / Select up" :binding "up" - :fn (editor-handler/shortcut-up-down :up) - :force? true} + :fn (editor-handler/shortcut-up-down :up)} :editor/down {:desc "Move cursor down / Select down" :binding "down" - :fn (editor-handler/shortcut-up-down :down) - :force? true} + :fn (editor-handler/shortcut-up-down :down)} :editor/left {:desc "Move cursor left / Open selected block at beginning" :binding "left" @@ -225,13 +223,11 @@ :editor/expand-block-children {:desc "Expand" :binding "mod+down" - :fn editor-handler/expand! - :force? true} + :fn editor-handler/expand!} :editor/collapse-block-children {:desc "Collapse" :binding "mod+up" - :fn editor-handler/collapse! - :force? true} + :fn editor-handler/collapse!} :editor/indent {:desc "Indent block" :binding "tab" @@ -316,8 +312,11 @@ :command-palette/toggle {:desc "Toggle command palette" :binding "mod+shift+p" - :fn (fn [] (state/toggle! :ui/command-palette-open?)) - :force? true} + :fn (fn [] (state/toggle! :ui/command-palette-open?))} + + :select-graph/open {:desc "Open select graph component" + :fn (fn [] (state/set-state! :ui/open-select :select-graph)) + :binding "mod+shift+g"} :command/run (when (util/electron?) {:desc "Run git command" @@ -432,7 +431,7 @@ :ui/toggle-cards {:desc "Toggle cards" :binding "t c" :fn ui-handler/toggle-cards!} - ;; :ui/toggle-between-page-and-file route-handler/toggle-between-page-and-file! + ;; :ui/toggle-between-page-and-file route-handler/toggle-between-page-and-file! :git/commit {:desc "Git commit message" :binding "c" @@ -499,6 +498,7 @@ :shortcut.handler/editor-global (-> (build-category-map [:command-palette/toggle + :select-graph/open :editor/cycle-todo :editor/up :editor/down @@ -680,6 +680,7 @@ :pdf/next-page :command/run :command-palette/toggle + :select-graph/open :sidebar/clear :sidebar/open-today-page :search/re-index diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 1fb46a019..407461c5e 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -1216,7 +1216,8 @@ :modal/label "" :modal/show? false :modal/fullscreen? false - :modal/panel-content nil))) + :modal/panel-content nil + :ui/open-select nil))) (defn get-db-batch-txs-chan [] diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index b7df19f62..7186ef7d1 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -420,7 +420,7 @@ {:keys [on-chosen on-shift-chosen get-group-name - empty-div + empty-placeholder item-render class]}] (let [current-idx (get state ::current-idx)] @@ -452,8 +452,8 @@ item-cp) item-cp))])] - (when empty-div - empty-div))])) + (when empty-placeholder + empty-placeholder))])) (def datepicker frontend.ui.date-picker/date-picker)