Browse Source

Merge branch 'feat/db' into feat/capacitor-new

charlie 8 months ago
parent
commit
936618c43a

+ 12 - 3
clj-e2e/src/logseq/e2e/assert.clj

@@ -5,12 +5,15 @@
 (def assert-that PlaywrightAssertions/assertThat)
 
 (defn assert-is-visible
+  "Multiple elements may match `q`, check and wait for the first element to be visible."
   [q]
-  (-> (w/-query q) assert-that .isVisible))
+  (-> q w/query first assert-that .isVisible)
+  true)
 
 (defn assert-is-hidden
   [q]
-  (-> (w/-query q) assert-that .isHidden))
+  (-> (w/-query q) assert-that .isHidden)
+  true)
 
 (defn assert-in-normal-mode?
   "- not editing mode
@@ -19,4 +22,10 @@
   []
   (assert-is-hidden (w/get-by-label "editing block"))
   (assert-is-hidden ".selection-action-bar")
-  (assert-is-visible "#search-button"))
+  (assert-is-visible "#search-button")
+  true)
+
+(defn assert-graph-loaded?
+  []
+  ;; there's some blocks visible now
+  (assert-is-visible "span.block-title-wrap"))

+ 47 - 0
clj-e2e/src/logseq/e2e/block.clj

@@ -0,0 +1,47 @@
+(ns logseq.e2e.block
+  (:require [clojure.string :as string]
+            [logseq.e2e.assert :as assert]
+            [logseq.e2e.keyboard :as k]
+            [logseq.e2e.util :as util]
+            [wally.main :as w]))
+
+(defn open-last-block
+  []
+  (util/double-esc)
+  (assert/assert-in-normal-mode?)
+  (w/click (last (w/query ".ls-page-blocks .ls-block .block-content"))))
+
+(defn new-block
+  [title]
+  (k/enter)
+  (util/input title))
+
+(defn save-block
+  [text]
+  (util/input text))
+
+(defn delete-blocks
+  "Delete the current block if in editing mode, otherwise, delete all the selected blocks."
+  []
+  (let [editor (util/get-editor)]
+    (when editor (util/exit-edit))
+    (k/backspace)))
+
+;; TODO: support tree
+(defn new-blocks
+  [titles]
+  (open-last-block)
+  (let [value (util/get-edit-content)]
+    (if (string/blank? value)           ; empty block
+      (do
+        (save-block (first titles))
+        (doseq [title (rest titles)]
+          (new-block title)))
+      (doseq [title titles]
+        (new-block title)))))
+
+(defn assert-blocks-visible
+  "blocks - coll of :block/title"
+  [blocks]
+  (doseq [block blocks]
+    (assert/assert-is-visible (format ".ls-page-blocks .ls-block :text('%s')" block))))

+ 43 - 0
clj-e2e/src/logseq/e2e/graph.clj

@@ -0,0 +1,43 @@
+(ns logseq.e2e.graph
+  (:require [logseq.e2e.assert :as assert]
+            [logseq.e2e.util :as util]
+            [wally.main :as w]))
+
+(defn- refresh-all-remote-graphs
+  []
+  (w/click "span:text(\"Refresh\")"))
+
+(defn goto-all-graphs
+  []
+  (util/search-and-click "Go to all graphs"))
+
+(defn new-graph
+  [graph-name enable-sync?]
+  (util/search-and-click "Add a DB graph")
+  (w/wait-for "h2:text(\"Create a new graph\")")
+  (w/click "input[placeholder=\"your graph name\"]")
+  (util/input graph-name)
+  (when enable-sync?
+    (w/click "button#rtc-sync"))
+  (w/click "button:text(\"Submit\")")
+  (when enable-sync?
+    (w/wait-for "button.cloud.on.idle" {:timeout 20000})))
+
+(defn wait-for-remote-graph
+  [graph-name]
+  (goto-all-graphs)
+  (util/repeat-until-visible 5
+                             (format "div[aria-label='e2e logseq_db_%s']" graph-name)
+                             refresh-all-remote-graphs))
+
+(defn remove-remote-graph
+  [graph-name]
+  (wait-for-remote-graph graph-name)
+  (w/click (format "div[aria-label='e2e logseq_db_%s'] a:has-text(\"Remove (server)\")" graph-name))
+  (w/click "div[role='alertdialog'] button:text('ok')"))
+
+(defn switch-graph
+  [to-graph-name]
+  (goto-all-graphs)
+  (w/click (format "div[aria-label='e2e logseq_db_%1$s'] span:text('%1$s')" to-graph-name))
+  (assert/assert-graph-loaded?))

+ 3 - 2
clj-e2e/src/logseq/e2e/playwright_page.clj

@@ -1,6 +1,7 @@
 (ns logseq.e2e.playwright-page
   "operations on playwright pages."
-  (:require [logseq.e2e.config :as config]
+  (:require [logseq.e2e.assert :as assert]
+            [logseq.e2e.config :as config]
             [wally.main :as w]))
 
 (defn get-pages
@@ -16,7 +17,7 @@
         (.navigate page url)
         ;; wait the demo graph loaded
         (w/with-page page
-          (w/wait-for "span.block-title-wrap"))))))
+          (assert/assert-graph-loaded?))))))
 
 (defn close-pages
   [pages]

+ 29 - 67
clj-e2e/src/logseq/e2e/util.clj

@@ -1,13 +1,27 @@
 (ns logseq.e2e.util
   (:refer-clojure :exclude [type])
-  (:require [clojure.string :as string]
-            [clojure.test :refer [is]]
+  (:require [clojure.test :refer [is]]
             [logseq.e2e.assert :as assert]
             [logseq.e2e.keyboard :as k]
             [wally.main :as w]
             [wally.selectors :as ws])
   (:import [com.microsoft.playwright TimeoutError]))
 
+(defn repeat-until-visible
+  [n q repeat-fn]
+  (when-not (w/visible? q)
+    (loop [i n]
+      (repeat-fn)
+      (let [visible?
+            (try
+              (assert/assert-is-visible q)
+              (catch TimeoutError e
+                (if (zero? i)
+                  (throw e)
+                  false)))]
+        (when-not visible?
+          (recur (dec i)))))))
+
 (defn wait-timeout
   [ms]
   (.waitForTimeout (w/get-page) ms))
@@ -50,6 +64,11 @@
   (w/click :#search-button)
   (w/fill ".cp__cmdk-search-input" text))
 
+(defn search-and-click
+  [search-text]
+  (search search-text)
+  (w/click (w/get-by-label search-text)))
+
 (defn new-page
   [title]
   ;; Question: what's the best way to close all the popups?
@@ -72,26 +91,10 @@
   []
   (count-elements ".ls-page-blocks .ls-block"))
 
-(defn new-block
-  [title]
-  (k/enter)
-  (input title))
-
-(defn save-block
-  [text]
-  (input text))
-
 (defn exit-edit
   []
   (k/esc))
 
-(defn delete-blocks
-  "Delete the current block if in editing mode, otherwise, delete all the selected blocks."
-  []
-  (let [editor (get-editor)]
-    (when editor (exit-edit))
-    (k/backspace)))
-
 (defn get-text
   [locator]
   (if (string? locator)
@@ -126,25 +129,6 @@
   []
   (indent-outdent false))
 
-(defn open-last-block
-  []
-  (double-esc)
-  (assert/assert-in-normal-mode?)
-  (w/click (last (w/query ".ls-page-blocks .ls-block .block-content"))))
-
-;; TODO: support tree
-(defn new-blocks
-  [titles]
-  (open-last-block)
-  (let [value (get-edit-content)]
-    (if (string/blank? value)           ; empty block
-      (do
-        (save-block (first titles))
-        (doseq [title (rest titles)]
-          (new-block title)))
-      (doseq [title titles]
-        (new-block title)))))
-
 (defn repeat-keyboard
   [n shortcut]
   (dotimes [_i n]
@@ -169,33 +153,11 @@
   (w/click "button[type=\"submit\"]:text(\"Sign in\")")
   (w/wait-for-not-visible ".cp__user-login"))
 
-(defn new-graph
-  [graph-name enable-sync?]
-  (search "add a db graph")
-  (w/click (w/get-by-label "Add a DB graph"))
-  (w/wait-for "h2:text(\"Create a new graph\")")
-  (w/click "input[placeholder=\"your graph name\"]")
-  (input graph-name)
-  (when enable-sync?
-    (w/click "button#rtc-sync"))
-  (w/click "button:text(\"Submit\")")
-  (when enable-sync?
-    (w/wait-for "button.cloud.on.idle" {:timeout 20000})))
-
-(defn wait-for-remote-graph
-  [graph-name]
-  (search "all graphs")
-  (w/click (w/get-by-label "Go to all graphs"))
-  (let [max-try 5]
-    (loop [i 0]
-      (prn :wait-for-remote-graph-try i)
-      (w/click "span:text(\"Refresh\")")
-      (let [succ?
-            (try
-              (w/wait-for (str "span:has-text(\"" graph-name "\")"))
-              true
-              (catch TimeoutError e
-                (if (= max-try i)
-                  (throw e)
-                  false)))]
-        (when-not succ? (recur (inc i)))))))
+(defn goto-journals
+  []
+  (search-and-click "Go to journals"))
+
+(defn refresh-until-graph-loaded
+  []
+  (w/refresh)
+  (assert/assert-graph-loaded?))

+ 4 - 3
clj-e2e/test/logseq/e2e/editor_test.clj

@@ -2,6 +2,7 @@
   (:require
    [clojure.string :as string]
    [clojure.test :refer [deftest testing is use-fixtures]]
+   [logseq.e2e.block :as b]
    [logseq.e2e.fixtures :as fixtures]
    [logseq.e2e.keyboard :as k]
    [logseq.e2e.util :as util]
@@ -12,7 +13,7 @@
 (deftest commands-test
   (testing "/command trigger popup"
     (util/new-page "Test")
-    (util/save-block "b1")
+    (b/save-block "b1")
     (util/type " /")
     (w/wait-for ".ui__popover-content")
     (is (some? (w/find-one-by-text "span" "Node reference")))
@@ -21,7 +22,7 @@
 
   (testing "Node reference"
     (testing "Page reference"
-      (util/new-block "/")
+      (b/new-block "/")
       (util/type "Node eferen")
       (w/wait-for ".ui__popover-content")
       (k/enter)
@@ -31,7 +32,7 @@
       (util/exit-edit)
       (is (= "Another page" (util/get-text "a.page-ref"))))
     (testing "Block reference"
-      (util/new-block "/")
+      (b/new-block "/")
       (util/type "Node eferen")
       (w/wait-for ".ui__popover-content")
       (k/enter)

+ 47 - 13
clj-e2e/test/logseq/e2e/multi_tabs_test.clj

@@ -1,23 +1,57 @@
 (ns logseq.e2e.multi-tabs-test
-  (:require
-   [clojure.test :refer [deftest testing is use-fixtures]]
-   [logseq.e2e.fixtures :as fixtures]
-   [logseq.e2e.playwright-page :as pw-page]
-   [logseq.e2e.util :as util]
-   [wally.main :as w]
-   [wally.repl :as repl]))
+  (:require [clojure.test :refer [deftest is testing use-fixtures]]
+            [logseq.e2e.assert :as assert]
+            [logseq.e2e.block :as b]
+            [logseq.e2e.fixtures :as fixtures]
+            [logseq.e2e.graph :as graph]
+            [logseq.e2e.playwright-page :as pw-page]
+            [logseq.e2e.util :as util]
+            [wally.main :as w]
+            [wally.repl :as repl]))
 
 (use-fixtures :once fixtures/open-new-context)
 
+(defn- add-blocks-and-check-on-other-tabs
+  [new-blocks add-blocks-tab check-blocks-tabs]
+  (w/with-page add-blocks-tab
+    (b/new-blocks new-blocks))
+  (run!
+   #(w/with-page %
+      (b/assert-blocks-visible new-blocks))
+   check-blocks-tabs))
+
 (deftest multi-tabs-test
   (testing "edit on one tab, check all tab's blocks are same"
     (pw-page/open-pages fixtures/*pw-ctx* 3)
     (let [[p1 p2 p3 :as pages] (pw-page/get-pages fixtures/*pw-ctx*)
           blocks-to-add (map #(str "b" %) (range 10))]
       (is (= 3 (count pages)))
-      (w/with-page p1
-        (util/new-blocks blocks-to-add))
-      (w/with-page p2
-        (is (= (util/page-blocks-count) (count blocks-to-add))))
-      (w/with-page p3
-        (is (= (util/page-blocks-count) (count blocks-to-add)))))))
+      (add-blocks-and-check-on-other-tabs blocks-to-add p1 [p2 p3])))
+
+  (testing "add new graphs and switch graphs + edit + check on tabs"
+    (let [[p1 p2 p3] (pw-page/get-pages fixtures/*pw-ctx*)]
+      (letfn [(switch-to-graph-then-edit-and-check [graph-name]
+                (w/with-page p2
+                  (util/goto-journals)
+                  (assert/assert-in-normal-mode?)
+                  (graph/switch-graph graph-name))
+                (w/with-page p3
+                  (util/goto-journals)
+                  (assert/assert-in-normal-mode?)
+                  (graph/switch-graph graph-name))
+                (w/with-page p1
+                  (util/goto-journals)
+                  (assert/assert-in-normal-mode?)
+                  (graph/switch-graph graph-name))
+                (let [graph-new-blocks (map #(str graph-name "-b1-" %) (range 5))]
+                  (add-blocks-and-check-on-other-tabs graph-new-blocks p1 [p2 p3])))]
+        (w/with-page p1
+          (graph/new-graph "graph1" false)
+          (graph/new-graph "graph2" false)
+          (graph/new-graph "graph3" false))
+        ;; FIXME: since all-graphs isn't auto-update when other tabs add new graphs, so refresh here
+        (w/with-page p2 (util/refresh-until-graph-loaded))
+        (w/with-page p3 (util/refresh-until-graph-loaded))
+        (switch-to-graph-then-edit-and-check "graph1")
+        (switch-to-graph-then-edit-and-check "graph2")
+        (switch-to-graph-then-edit-and-check "graph3")))))

+ 12 - 11
clj-e2e/test/logseq/e2e/outliner_test.clj

@@ -3,6 +3,7 @@
    [clojure.test :refer [deftest testing is use-fixtures]]
    [logseq.e2e.fixtures :as fixtures]
    [logseq.e2e.keyboard :as k]
+   [logseq.e2e.block :as b]
    [logseq.e2e.util :as util]
    [wally.main :as w]))
 
@@ -12,19 +13,19 @@
   (util/new-page "p1")
   ;; a page block and a child block
   (is (= 2 (util/blocks-count)))
-  (util/new-blocks ["first block" "second block"])
+  (b/new-blocks ["first block" "second block"])
   (util/exit-edit)
   (is (= 3 (util/blocks-count))))
 
 (deftest indent-and-outdent-test
   (util/new-page "p2")
-  (util/new-blocks ["b1" "b2"])
+  (b/new-blocks ["b1" "b2"])
   (testing "simple indent and outdent"
     (util/indent)
     (util/outdent))
 
   (testing "indent a block with its children"
-    (util/new-block "b3")
+    (b/new-block "b3")
     (util/indent)
     (k/arrow-up)
     (util/indent)
@@ -33,8 +34,8 @@
       (is (< x1 x2 x3))))
 
   (testing "unindent a block with its children"
-    (util/open-last-block)
-    (util/new-blocks ["b4" "b5"])
+    (b/open-last-block)
+    (b/new-blocks ["b4" "b5"])
     (util/indent)
     (k/arrow-up)
     (util/outdent)
@@ -44,7 +45,7 @@
 
 (deftest move-up-down-test
   (util/new-page "p3")
-  (util/new-blocks ["b1" "b2" "b3" "b4"])
+  (b/new-blocks ["b1" "b2" "b3" "b4"])
   (util/repeat-keyboard 2 "Shift+ArrowUp")
   (let [contents (util/get-page-blocks-contents)]
     (is (= contents ["b1" "b2" "b3" "b4"])))
@@ -58,20 +59,20 @@
 (deftest delete-test
   (testing "Delete blocks case 1"
     (util/new-page "p4")
-    (util/new-blocks ["b1" "b2" "b3" "b4"])
-    (util/delete-blocks)                   ; delete b4
+    (b/new-blocks ["b1" "b2" "b3" "b4"])
+    (b/delete-blocks)                   ; delete b4
     (util/repeat-keyboard 2 "Shift+ArrowUp") ; select b3 and b2
-    (util/delete-blocks)
+    (b/delete-blocks)
     (is (= "b1" (util/get-edit-content)))
     (is (= 1 (util/page-blocks-count))))
 
   (testing "Delete block with its children"
     (util/new-page "p5")
-    (util/new-blocks ["b1" "b2" "b3" "b4"])
+    (b/new-blocks ["b1" "b2" "b3" "b4"])
     (util/indent)
     (k/arrow-up)
     (util/indent)
     (k/arrow-up)
-    (util/delete-blocks)
+    (b/delete-blocks)
     (is (= "b1" (util/get-edit-content)))
     (is (= 1 (util/page-blocks-count)))))

+ 7 - 4
clj-e2e/test/logseq/e2e/rtc_basic_test.clj

@@ -3,20 +3,23 @@
    [clojure.test :refer [deftest testing is use-fixtures]]
    [com.climate.claypoole :as cp]
    [logseq.e2e.fixtures :as fixtures :refer [*page1 *page2]]
+   [logseq.e2e.graph :as graph]
    [logseq.e2e.util :as util]
-   [wally.main :as w]))
+   [wally.main :as w]
+   [wally.repl :as repl]))
 
 (use-fixtures :once fixtures/open-2-pages)
 
 (deftest rtc-basic-test
   (let [graph-name (str "rtc-graph-" (.toEpochMilli (java.time.Instant/now)))]
-    (testing "open 2 app instances"
+    (testing "open 2 app instances, add a rtc graph, check this graph available on other instance"
       (cp/prun!
        2
        #(w/with-page %
           (util/login-test-account))
        [@*page1 @*page2])
       (w/with-page @*page1
-        (util/new-graph graph-name true))
+        (graph/new-graph graph-name true))
       (w/with-page @*page2
-        (util/wait-for-remote-graph graph-name)))))
+        (graph/wait-for-remote-graph graph-name)
+        (graph/remove-remote-graph graph-name)))))

+ 2 - 1
deps/db/src/logseq/db/common/sqlite.cljs

@@ -262,7 +262,8 @@
   "Favorites page and its blocks"
   [db]
   (let [page-id (get-first-page-by-name db common-config/favorites-page-name)
-        {:keys [block children]} (get-block-and-children db page-id {:children? true})]
+        block (d/entity db page-id)
+        children (:block/_page block)]
     (when block
       (concat (d/datoms db :eavt (:db/id block))
               (->> (keep :block/link children)

+ 30 - 25
deps/shui/src/logseq/shui/popup/core.cljs

@@ -71,10 +71,9 @@
             (d/add-class! target "ls-popup-closed")
             (.focus target)))))))
 
-(defonce *last-show-target (atom nil))
-
 (defn show!
-  [^js event content & {:keys [id as-dropdown? as-content? align root-props content-props
+  [^js event content & {:keys [id as-mask? as-dropdown? as-content?
+                               focus-trigger? align root-props content-props
                                on-before-hide on-after-hide trigger-id] :as opts}]
   (let [id (or id (gen-id))
         *target (volatile! nil)
@@ -97,27 +96,30 @@
                                 :start 0
                                 :end width
                                 (/ width 2)))
-                      (- bottom height)
-                      width height])
+                      (- (- bottom height)
+                        ;; minus default offset
+                         (if as-mask? 6 0))
+                      width (if as-mask? 1 height)])
                    :else [0 0])]
-    (reset! *last-show-target @*target)
-    (js/setTimeout #(reset! *last-show-target nil) 64)
-    (some-> @*target
-            (d/set-attr! "data-popup-active"
-                         (if (keyword? id) (name id) (str id))))
-    (upsert-popup!
-     (merge opts
-            {:id id :target (deref *target)
-             :trigger-id trigger-id
-             :open? true :content content :position position
-             :as-dropdown? as-dropdown?
-             :as-content? as-content?
-             :root-props root-props
-             :on-before-hide on-before-hide
-             :on-after-hide on-after-hide
-             :content-props (cond-> content-props
-                              (not (nil? align))
-                              (assoc :align (name align)))}))))
+    (some-> @*target (d/set-attr! "data-popup-active" (if (keyword? id) (name id) (str id))))
+    (let [on-before-hide (fn []
+                           (some-> on-after-hide (apply nil))
+                           (when-let [^js trigger (and (not (false? focus-trigger?))
+                                                       (some-> @*target (.closest "[tabindex='0']")))]
+                             (js/setTimeout #(.focus trigger) 16)))]
+      (upsert-popup!
+       (merge opts
+              {:id id :target (deref *target)
+               :trigger-id trigger-id
+               :open? true :content content :position position
+               :as-dropdown? as-dropdown?
+               :as-content? as-content?
+               :root-props root-props
+               :on-before-hide on-before-hide
+               :on-after-hide on-after-hide
+               :content-props (cond-> content-props
+                                (not (nil? align))
+                                (assoc :align (name align)))})))))
 
 (defn hide!
   ([] (when-let [id (some-> (get-popups) (last) :id)] (hide! id 0)))
@@ -143,7 +145,7 @@
 
 (rum/defc x-popup
   [{:keys [id open? content position as-dropdown? as-content? force-popover?
-           auto-side? _auto-focus? _target root-props content-props
+           auto-side? as-mask? _auto-focus? _target root-props content-props
            _on-before-hide _on-after-hide]
     :as _props}]
   (when-let [[x y _ height] position]
@@ -159,7 +161,7 @@
                                "top" "bottom"))))
           auto-side? (if (boolean? auto-side?) auto-side? true)
           content-props (cond-> content-props
-                          auto-side? (assoc :side (auto-side-fn)))
+                          (and (not as-mask?) auto-side?) (assoc :side (auto-side-fn)))
           handle-key-escape! (fn [^js e]
                                (when-not (false? (some-> content-props (:onEscapeKeyDown) (apply [e])))
                                  (hide! id 1)))
@@ -179,6 +181,9 @@
                          :left x}} ""))
        (let [content-props (cond-> (merge content-props {:onEscapeKeyDown handle-key-escape!
                                                          :onPointerDownOutside handle-pointer-outside!})
+                             as-mask?
+                             (assoc :data-as-mask true)
+
                              (and (not force-popover?)
                                   (not as-dropdown?))
                              (assoc :on-key-down (fn [^js e]

+ 61 - 51
src/main/frontend/components/block.cljs

@@ -655,7 +655,8 @@
 
    All page-names are sanitized except page-name-in-block"
   [state
-   {:keys [contents-page? whiteboard-page? html-export? meta-click? show-unique-title? stop-click-event?]
+   {:keys [contents-page? whiteboard-page? html-export? other-position? show-unique-title? stop-click-event?
+           on-context-menu]
     :or {stop-click-event? true}
     :as config}
    page-entity children label]
@@ -669,44 +670,50 @@
         untitled? (when page-name (model/untitled-page? (:block/title page-entity)))
         show-icon? (:show-icon? config)]
     [:a.relative
-     {:tabIndex "0"
-      :class (cond->
-              (if tag? "tag" "page-ref")
-               (:property? config) (str " page-property-key block-property")
-               untitled? (str " opacity-50"))
-      :data-ref page-name
-      :draggable true
-      :on-drag-start (fn [e]
-                       (editor-handler/block->data-transfer! page-name e true))
-      :on-mouse-over #(reset! *hover? true)
-      :on-mouse-leave #(reset! *hover? false)
-      :on-click (fn [e]
-                  (when stop-click-event? (util/stop e)))
-      :on-pointer-down (fn [^js e]
-                         (cond
-                           (and meta-click? (util/meta-key? e))
-                           (reset! *mouse-down? true)
-
-                           (and meta-click? (not (util/shift-key? e)))
-                           (some-> (.-target e) (.closest ".jtrigger") (.click))
-
-                           breadcrumb?
-                           (.preventDefault e)
-
-                           :else
-                           (do
-                             (.preventDefault e)
-                             (reset! *mouse-down? true))))
-      :on-pointer-up (fn [e]
-                       (when @*mouse-down?
-                         (state/clear-edit!)
-                         (when-not (or (:disable-click? config)
-                                       (:disable-redirect? config))
-                           (open-page-ref config page-entity e page-name contents-page?))
-                         (reset! *mouse-down? false)))
-      :on-key-up (fn [e] (when (and e (= (.-key e) "Enter") (not meta-click?))
-                           (state/clear-edit!)
-                           (open-page-ref config page-entity e page-name contents-page?)))}
+     (cond->
+      {:tabIndex "0"
+       :class (cond->
+               (if tag? "tag" "page-ref")
+                (:property? config) (str " page-property-key block-property")
+                untitled? (str " opacity-50"))
+       :data-ref page-name
+       :draggable true
+       :on-drag-start (fn [e]
+                        (editor-handler/block->data-transfer! page-name e true))
+       :on-mouse-over #(reset! *hover? true)
+       :on-mouse-leave #(reset! *hover? false)
+       :on-click (fn [e]
+                   (when stop-click-event? (util/stop e)))
+       :on-pointer-down (fn [^js e]
+                          (cond
+                            (and on-context-menu (= 2 (.-button e)))
+                            nil
+
+                            (and other-position? (util/meta-key? e))
+                            (reset! *mouse-down? true)
+
+                            (and other-position? (not (util/shift-key? e)))
+                            (some-> (.-target e) (.closest ".jtrigger") (.click))
+
+                            breadcrumb?
+                            (.preventDefault e)
+
+                            :else
+                            (do
+                              (.preventDefault e)
+                              (reset! *mouse-down? true))))
+       :on-pointer-up (fn [e]
+                        (when @*mouse-down?
+                          (state/clear-edit!)
+                          (when-not (or (:disable-click? config)
+                                        (:disable-redirect? config))
+                            (open-page-ref config page-entity e page-name contents-page?))
+                          (reset! *mouse-down? false)))
+       :on-key-up (fn [e] (when (and e (= (.-key e) "Enter") (not other-position?))
+                            (state/clear-edit!)
+                            (open-page-ref config page-entity e page-name contents-page?)))}
+       on-context-menu
+       (assoc :on-context-menu on-context-menu))
      (when (and show-icon? (not tag?))
        (let [own-icon (get page-entity (pu/get-pid :logseq.property/icon))
              emoji? (and (map? own-icon) (= (:type own-icon) :emoji))]
@@ -2701,7 +2708,7 @@
                               (shui/dropdown-menu-item
                                {:key "Open tag in sidebar"
                                 :on-click #(state/sidebar-add-block! (state/get-current-repo) (:db/id tag) :page)}
-                               "Open tag in sidebar"
+                               "Open in sidebar"
                                (shui/dropdown-menu-shortcut (shortcut-utils/decorate-binding "shift+click")))
                               (shui/dropdown-menu-item
                                {:key "Remove tag"
@@ -2957,7 +2964,8 @@
                    (not hidden?))
                  (not (and block-ref? (or (seq ast-title) (seq ast-body))))
                  (not (:slide? config))
-                 (not= block-type :whiteboard-shape))
+                 (not= block-type :whiteboard-shape)
+                 (not (:table-block-title? config)))
         (properties-cp config block))
 
       (block-content-inner config block ast-body plugin-slotted? collapsed? block-ref-with-title?)
@@ -3053,7 +3061,8 @@
            (block-content config block edit-input-id block-id slide? *show-query?))
 
           (when (and (not hide-block-refs-count?)
-                     (not named?))
+                     (not named?)
+                     (not (:table-block-title? config)))
             [:div.flex.flex-row.items-center
              (when (and (:embed? config)
                         (:embed-parent config))
@@ -3071,16 +3080,17 @@
                                     (editor-handler/edit-block! block :max))}
                 svg/edit])])])
 
-       [:div.flex.flex-row.items-center.self-start.gap-1
-        (when (and db-based? (not table?)) (block-positioned-properties config block :block-right))
+       (when-not (:table-block-title? config)
+         [:div.flex.flex-row.items-center.self-start.gap-1
+          (when (and db-based? (not table?)) (block-positioned-properties config block :block-right))
 
-        (when-not (or (:table? config) (:property? config) (:page-title? config))
-          (block-refs-count block refs-count *hide-block-refs?))
+          (when-not (or (:table? config) (:property? config) (:page-title? config))
+            (block-refs-count block refs-count *hide-block-refs?))
 
-        (when-not (or (:block-ref? config) (:table? config) (:gallery-view? config)
-                      (:property? config))
-          (when (and db-based? (seq (:block/tags block)))
-            (tags-cp (assoc config :block/uuid (:block/uuid block)) block)))]]]]))
+          (when-not (or (:block-ref? config) (:table? config) (:gallery-view? config)
+                        (:property? config))
+            (when (and db-based? (seq (:block/tags block)))
+              (tags-cp (assoc config :block/uuid (:block/uuid block)) block)))])]]]))
 
 (rum/defcs single-block-cp < mixins/container-id
   [state _config block-uuid]
@@ -3579,7 +3589,7 @@
          :on-mouse-leave (fn [_e]
                            (block-mouse-leave *control-show? block-id doc-mode?))}
 
-        (when (and (not slide?) (not in-whiteboard?) (not property?))
+        (when (and (not slide?) (not in-whiteboard?) (not property?) (not (:table-block-title? config)))
           (let [edit? (or editing?
                           (= uuid (:block/uuid (state/get-edit-block))))]
             (block-control (assoc config :hide-bullet? (:page-title? config))

+ 5 - 3
src/main/frontend/components/container.cljs

@@ -739,7 +739,7 @@
          (journal/all-journals))])))
 
 (defn- hide-context-menu-and-clear-selection
-  [e]
+  [e & {:keys [esc?]}]
   (state/hide-custom-context-menu!)
   (when-not (or (gobj/get e "shiftKey")
                 (util/meta-key? e)
@@ -748,7 +748,9 @@
                 (= (shui-dialog/get-last-modal-id) :property-dialog)
                 (some-> (.-target e) (.closest ".ls-block"))
                 (some-> (.-target e) (.closest "[data-keep-selection]")))
-    (editor-handler/clear-selection!)))
+    (if (and esc? (editor-handler/popup-exists? :selection-action-bar))
+      (state/pub-event! [:editor/hide-action-bar])
+      (editor-handler/clear-selection!))))
 
 (rum/defc render-custom-context-menu
   [links position]
@@ -944,7 +946,7 @@
                                    util/node-test?
                                    (state/editing?))))
                           (state/close-modal!)
-                          (hide-context-menu-and-clear-selection e)))
+                          (hide-context-menu-and-clear-selection e {:esc? true})))
                       (state/set-ui-last-key-code! (.-key e))))
      (mixins/listen state js/window "keyup"
                     (fn [_e]

+ 1 - 1
src/main/frontend/components/property.css

@@ -42,7 +42,7 @@
 }
 
 .property-value-container .jtrigger {
-  @apply focus-visible:outline-none focus-visible:bg-gray-02 focus-visible:rounded;
+  @apply focus-visible:outline-none focus-visible:bg-gray-03 focus-visible:rounded;
 }
 
 .ls-properties-area {

+ 101 - 15
src/main/frontend/components/property/value.cljs

@@ -27,6 +27,7 @@
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.util :as util]
+            [frontend.util.cursor :as cursor]
             [goog.dom :as gdom]
             [goog.functions :refer [debounce]]
             [lambdaisland.glogi :as log]
@@ -746,7 +747,8 @@
                                                                [:div.text-xs.opacity-70
                                                                 (breadcrumb {:search? true} (state/get-current-repo) (:block/uuid block) {})]))
                                                     label [:div.flex.flex-row.items-center.gap-1
-                                                           (when-not (:logseq.property/classes property)
+                                                           (when-not (or (:logseq.property/classes property)
+                                                                         (= (:db/ident property) :block/tags))
                                                              (ui/icon icon {:size 14}))
                                                            [:div title]]]
                                                 [header label])
@@ -1080,14 +1082,31 @@
                 ;; support this case and maybe other complex cases.
                 (not (string/includes? (:block/title value) "[["))))
        (when value
-         (rum/with-key
-           (page-cp {:disable-preview? true
+         (let [opts {:disable-preview? true
                      :tag? tag?
                      :property-position property-position
-                     :meta-click? other-position?
+                     :other-position? other-position?
                      :table-view? table-view?
-                     :ignore-alias? (= :block/alias (:db/ident property))} value)
-           (:db/id value)))
+                     :ignore-alias? (= :block/alias (:db/ident property))
+                     :on-context-menu
+                     (fn [e]
+                       (util/stop e)
+                       (shui/popup-show! (.-target e)
+                                         (fn []
+                                           [:<>
+                                            (shui/dropdown-menu-item
+                                             {:key "open"
+                                              :on-click #(route-handler/redirect-to-page! (:block/uuid value))}
+                                             (str "Open " (:block/title value)))
+
+                                            (shui/dropdown-menu-item
+                                             {:key "open sidebar"
+                                              :on-click #(state/sidebar-add-block! (state/get-current-repo) (:db/id value) :page)}
+                                             "Open in sidebar")])
+                                         {:as-dropdown? true
+                                          :content-props {:on-click (fn [] (shui/popup-hide!))}
+                                          :align "start"}))}]
+           (rum/with-key (page-cp opts value) (:db/id value))))
 
        (contains? #{:node :class :property :page} type)
        (when-let [reference (state/get-component :block/reference)]
@@ -1179,6 +1198,64 @@
        :else
        (inline-text {} :markdown (macro-util/expand-value-if-macro (str value) (state/get-macros))))]))
 
+(rum/defc single-number-input
+  [block property value-block table-view?]
+  (let [[editing? set-editing!] (rum/use-state false)
+        *ref (rum/use-ref nil)
+        *input-ref (rum/use-ref nil)
+        number-value (db-property/property-value-content value-block)
+        [value set-value!] (rum/use-state number-value)
+        set-property-value! (fn [value & {:keys [exit-editing?]
+                                          :or {exit-editing? true}}]
+                              (p/do!
+                               (when (and (not (string/blank? value))
+                                          (not= (string/trim (str number-value))
+                                                (string/trim (str value))))
+                                 (db-property-handler/set-block-property! (:db/id block)
+                                                                          (:db/ident property)
+                                                                          value))
+
+                               (when exit-editing?
+                                 (set-editing! false))))]
+    [:div.ls-number.flex.flex-1.jtrigger
+     {:ref *ref
+      :on-click #(set-editing! true)}
+     (if editing?
+       (shui/input
+        {:ref *input-ref
+         :auto-focus true
+         :class (str "ls-number-input h-6 px-0 py-0 border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 text-base"
+                     (when table-view? " text-sm"))
+         :value value
+         :on-change (fn [e] (set-value! (util/evalue e)))
+         :on-blur (fn [_e] (set-property-value! value))
+         :on-key-down (fn [e]
+                        (let [input (rum/deref *input-ref)
+                              pos (cursor/pos input)
+                              k (util/ekey e)]
+                          (when-not (util/input-text-selected? input)
+                            (case k
+                              ("ArrowUp" "ArrowDown")
+                              (do
+                                (util/stop-propagation e)
+                                (set-editing! false)
+                                (editor-handler/move-cross-boundary-up-down (if (= "ArrowUp" (util/ekey e)) :up :down) {})
+                                (set-property-value! value {:exit-editing? false}))
+
+                              "Backspace"
+                              (when (zero? pos)
+                                (p/do!
+                                 (db-property-handler/remove-block-property! (:db/id block) (:db/ident property))
+                                 (editor-handler/move-cross-boundary-up-down :up {:pos :max})))
+
+                              ("Escape" "Enter")
+                              (p/do!
+                               (set-property-value! value)
+                               (.focus (rum/deref *ref)))
+
+                              nil))))})
+       value)]))
+
 (rum/defcs property-scalar-value-aux < rum/static rum/reactive
   [state block property value* {:keys [editing? on-chosen]
                                 :as opts}]
@@ -1192,8 +1269,14 @@
         value (if (and (entity-map? value*) (= (:db/ident value*) :logseq.property/empty-placeholder))
                 nil
                 value*)]
-    (if (= :logseq.property/icon (:db/ident property))
+    (cond
+      (= :logseq.property/icon (:db/ident property))
       (icon-row block editing?)
+
+      (and (= type :number) (not editing?))
+      (single-number-input block property value (:table-view? opts))
+
+      :else
       (if (and select-type?'
                (not (and (not closed-values?) (= type :date))))
         (let [classes (outliner-property/get-block-classes (db/get-db) (:db/id block))
@@ -1278,16 +1361,17 @@
       (select-cp {})
       (let [toggle-fn shui/popup-hide!
             content-fn (fn [{:keys [_id content-props]}]
-                         (select-cp {:content-props content-props}))]
+                         (select-cp {:content-props content-props}))
+            show-popup! (fn [^js e]
+                          (let [target (.-target e)]
+                            (when-not (or (util/link? target) (.closest target "a") config/publishing?)
+                              (shui/popup-show! (rum/deref *el) content-fn
+                                                {:as-dropdown? true :as-content? false
+                                                 :align "start" :auto-focus? true}))))]
         [:div.multi-values.jtrigger
          {:tab-index "0"
           :ref *el
-          :on-click (fn [^js e]
-                      (let [target (.-target e)]
-                        (when-not (or (util/link? target) (.closest target "a") config/publishing?)
-                          (shui/popup-show! (rum/deref *el) content-fn
-                                            {:as-dropdown? true :as-content? false
-                                             :align "start" :auto-focus? true}))))
+          :on-click show-popup!
           :on-key-down (fn [^js e]
                          (case (.-key e)
                            (" " "Enter")
@@ -1301,7 +1385,9 @@
            (if (and (seq items) not-empty-value?)
              (concat
               (->> (for [item items]
-                     (rum/with-key (select-item property type item opts) (or (:block/uuid item) (str item))))
+                     (rum/with-key
+                       (select-item property type item (assoc opts :show-popup! show-popup!))
+                       (or (:block/uuid item) (str item))))
                    (interpose [:span.opacity-50.-ml-1 ","]))
               (when date?
                 [(property-value-date-picker block property nil {:toggle-fn toggle-fn})]))

+ 6 - 1
src/main/frontend/components/property/value.css

@@ -1,4 +1,4 @@
-.property-value-inner:not([data-type="default"]):not([data-type="url"]):not([data-type="property"]) {
+.property-value-inner:not([data-type="default"]):not([data-type="url"]):not([data-type="property"]):not([data-type="number"]) {
   @apply cursor-pointer;
   &:hover, .as-scalar-value-wrap:hover {
     @apply bg-gray-02 rounded transition-[background-color] duration-300;
@@ -31,3 +31,8 @@
 .ls-property-key .cp__select-input, .property-select .cp__select-input {
     @apply text-sm;
 }
+
+.ls-number {
+  @apply cursor-text;
+  min-height: 20px;
+}

+ 3 - 2
src/main/frontend/components/repo.cljs

@@ -68,14 +68,15 @@
         (sort-repos-with-metadata-local repos)
         :let [only-cloud? (and remote? (nil? root))
               db-based? (config/db-based-graph? url)]]
-    [:div.flex.justify-between.mb-4.items-center.group {:key (or url GraphUUID)}
+    [:div.flex.justify-between.mb-4.items-center.group {:key (or url GraphUUID)
+                                                        :aria-label (str "e2e " url)}
      [:div
       [:span.flex.items-center.gap-1
        (normalized-graph-label repo
                                (fn []
                                  (when-not (state/sub :rtc/downloading-graph-uuid)
                                    (cond
-                                     root                                         ; exists locally
+                                     root ; exists locally
                                      (state/pub-event! [:graph/switch url])
 
                                      (and db-based? remote?)

+ 1 - 0
src/main/frontend/components/selection.cljs

@@ -41,6 +41,7 @@
               :on-pointer-down (fn [e]
                                  (util/stop e)
                                  (on-copy)
+                                 (state/clear-selection!)
                                  (state/pub-event! [:editor/hide-action-bar])))
        "Copy")
       (when db-graph?

+ 85 - 50
src/main/frontend/components/views.cljs

@@ -35,7 +35,6 @@
             [frontend.ui :as ui]
             [frontend.util :as util]
             [goog.dom :as gdom]
-            [goog.object :as gobj]
             [logseq.common.config :as common-config]
             [logseq.db :as ldb]
             [logseq.db.common.view :as db-view]
@@ -191,36 +190,70 @@
 
 (rum/defc block-title
   "Used on table view"
-  [block {:keys [create-new-block property-ident width sidebar?]}]
-  (let [inline-title (state/get-component :block/inline-title)]
-    [:div.table-block-title.flex.items-center.w-full.h-full.cursor-pointer.items-center
-     {:on-click (fn [e]
-                  (p/let [block (or block (and (fn? create-new-block) (create-new-block)))]
+  [block {:keys [create-new-block width]}]
+  (let [inline-title (state/get-component :block/inline-title)
+        [opacity set-opacity!] (hooks/use-state 0)
+        add-to-sidebar! #(state/sidebar-add-block! (state/get-current-repo) (:db/id block) :block)]
+    [:div.table-block-title.relative.flex.items-center.w-full.h-full.cursor-pointer.items-center
+     {:on-mouse-over #(set-opacity! 100)
+      :on-mouse-out #(set-opacity! 0)
+      :on-click (fn [e]
+                  (p/let [block (or block (and (fn? create-new-block) (create-new-block)))
+                          redirect! #(some-> (:block/uuid block) route-handler/redirect-to-page!)]
                     (when block
                       (cond
-                        (and (= property-ident :block/title) sidebar?)
-                        (route-handler/redirect-to-page! (:block/uuid block))
-                        (= property-ident :block/title)
-                        (let [selection-type (some-> (js/window.getSelection)
-                                                     (gobj/get "type"))]
-                          (when-not (= selection-type "Range")
-                            (state/sidebar-add-block! (state/get-current-repo) (:db/id block) :block)))
+                        (util/meta-key? e)
+                        (redirect!)
+
+                        (.-shiftKey e)
+                        (add-to-sidebar!)
+
                         :else
                         (p/do!
                          (shui/popup-show!
-                          (.-target e)
-                          (fn []
-                            [:div {:style {:min-width (max 160 width)}}
-                             (block-container {:popup? true} block)])
-                          {:align :start})
-                         (editor-handler/edit-block! block :max {:container-id :unknown-container}))))))}
+                           (.closest (.-target e) ".ls-table-cell")
+                           (fn []
+                             (let [width (-> (max 160 width)
+                                           (- 18))]
+                               [:div.ls-table-block.flex.flex-row.items-start
+                                {:style {:width width :max-width width :margin-right "6px"}
+                                 :on-click util/stop-propagation}
+                                (block-container {:popup? true
+                                                  :view? true
+                                                  :table-block-title? true} block)
+                                (shui/button
+                                  {:variant :ghost
+                                   :title "Open node"
+                                   :on-click (fn [e]
+                                               (util/stop-propagation e)
+                                               (shui/popup-hide!)
+                                               (redirect!))
+                                   :class (str "h-6 w-6 !p-0 text-muted-foreground transition-opacity duration-100 ease-in bg-gray-01 "
+                                            "opacity-" opacity)}
+                                  (ui/icon "arrow-right"))]))
+                           {:id :ls-table-block-editor
+                            :as-mask? true})
+                          (editor-handler/edit-block! block :max {:container-id :unknown-container}))))))}
      (if block
-       [:div (inline-title
-              (some->> (:block/title block)
-                       string/trim
-                       string/split-lines
-                       first))]
-       [:div])]))
+       [:div
+        (inline-title
+          (some->> (:block/title block)
+            string/trim
+            string/split-lines
+            first))]
+       [:div])
+
+     [:div.absolute.right-0.p-1
+      {:on-click (fn [e]
+                   (util/stop-propagation e)
+                   (add-to-sidebar!))}
+      [:div.flex.items-center
+       (shui/button
+         {:variant :ghost
+          :title "Open in sidebar"
+          :class (str "h-5 w-5 !p-0 text-muted-foreground transition-opacity duration-100 ease-in bg-gray-01 "
+                   "opacity-" opacity)}
+         (ui/icon "layout-sidebar-right"))]]]))
 
 (defn build-columns
   [config properties & {:keys [with-object-name? with-id? add-tags-column?]
@@ -230,32 +263,34 @@
   (let [;; FIXME: Shouldn't file graphs have :block/tags?
         add-tags-column?' (and (config/db-based-graph? (state/get-current-repo)) add-tags-column?)
         properties' (->>
-                     (if (or (some #(= (:db/ident %) :block/tags) properties) (not add-tags-column?'))
-                       properties
-                       (conj properties (db/entity :block/tags)))
-                     (remove nil?))]
+                      (if (or (some #(= (:db/ident %) :block/tags) properties) (not add-tags-column?'))
+                        properties
+                        (conj properties (db/entity :block/tags)))
+                      (remove nil?))]
     (->> (concat
-          [{:id :select
-            :name "Select"
-            :header (fn [table _column] (header-checkbox table))
-            :cell (fn [table row column]
-                    (row-checkbox table row column))
-            :column-list? false
-            :resizable? false}
-           (when with-id?
-             {:id :id
-              :name "ID"
-              :header (fn [_table _column] (header-index))
-              :cell (fn [table row _column]
-                      (inc (.indexOf (:rows table) (:db/id row))))
-              :resizable? false})
-           (when with-object-name?
-             {:id :block/title
-              :name "Name"
-              :type :string
-              :header header-cp
-              :cell (fn [_table row _column]
-                      (block-title row {:property-ident :block/title :sidebar? (:sidebar? config)}))
+           [{:id :select
+             :name "Select"
+             :header (fn [table _column] (header-checkbox table))
+             :cell (fn [table row column]
+                     (row-checkbox table row column))
+             :column-list? false
+             :resizable? false}
+            (when with-id?
+              {:id :id
+               :name "ID"
+               :header (fn [_table _column] (header-index))
+               :cell (fn [table row _column]
+                       (inc (.indexOf (:rows table) (:db/id row))))
+               :resizable? false})
+            (when with-object-name?
+              {:id :block/title
+               :name "Name"
+               :type :string
+               :header header-cp
+              :cell (fn [_table row _column style]
+                      (block-title row {:property-ident :block/title
+                                        :sidebar? (:sidebar? config)
+                                        :width (:width style)}))
               :disable-hide? true})]
           (keep
            (fn [property]

+ 1 - 1
src/main/frontend/db/react.cljs

@@ -90,7 +90,7 @@
         q (if util/node-test?
             (fn [query inputs] (apply d/q query db inputs))
             (fn [query inputs]
-              (let [q-f #(apply db-async-util/<q repo {} (cons query inputs))]
+              (let [q-f #(apply db-async-util/<q repo {:transact-db? false} (cons query inputs))]
                 (if built-in-query?
                   ;; delay built-in-queries to not block journal rendering
                   (p/let [_ (p/delay 100)]

+ 13 - 8
src/main/frontend/handler/editor.cljs

@@ -2694,6 +2694,14 @@
   [node]
   (some-> node (dom/has-class? "property-value-container")))
 
+(defn- focus-trigger
+  [_current-block sibling-block]
+  (when-let [trigger (first (dom/by-class sibling-block "jtrigger"))]
+    (state/clear-edit!)
+    (if (dom/has-class? trigger "ls-number")
+      (.click trigger)
+      (.focus trigger))))
+
 (defn move-cross-boundary-up-down
   [direction move-opts]
   (let [input (or (:input move-opts) (state/get-input))
@@ -2725,9 +2733,7 @@
                (save-block! repo uuid value))
 
              (if property-value-container?
-               (when-let [trigger (first (dom/by-class sibling-block "jtrigger"))]
-                 (state/clear-edit!)
-                 (.focus trigger))
+               (focus-trigger current-block sibling-block)
                (let [new-uuid (cljs.core/uuid sibling-block-id)
                      block (db/entity [:block/uuid new-uuid])]
                  (edit-block! block
@@ -2793,9 +2799,7 @@
                 block (db/entity repo [:block/uuid (cljs.core/uuid sibling-block-id)])]
             (edit-block! block pos {:container-id container-id})))
         (when (property-value-node? sibling-block)
-          (when-let [trigger (first (dom/by-class sibling-block "jtrigger"))]
-            (state/clear-edit!)
-            (.focus trigger)))))))
+          (focus-trigger editing-block sibling-block))))))
 
 (defn keydown-arrow-handler
   [direction]
@@ -4025,9 +4029,10 @@
   (let [block (or (db/entity (:db/id block)) block)]
     (or
      (util/collapsed? block)
-     (and (:view? config)
+     (and (or (:view? config) (:popup? config))
           (or (ldb/page? block)
-              (some? (:block/_parent block)))))))
+              (some? (:block/_parent block))
+              (:table-block-title? config))))))
 
 (defn batch-set-heading!
   [block-ids heading]

+ 3 - 1
src/main/frontend/handler/events/ui.cljs

@@ -312,8 +312,10 @@
        (fn []
          (selection/action-bar))
        {:id :selection-action-bar
+        :root-props {:modal false}
         :content-props {:side "top"
-                        :class "!py-0 !px-0 !border-none"}
+                        :class "!py-0 !px-0 !border-none"
+                        :modal? false}
         :auto-side? false
         :align :start}))))
 

+ 2 - 0
src/main/frontend/handler/route.cljs

@@ -17,12 +17,14 @@
             [logseq.common.util :as common-util]
             [logseq.db :as ldb]
             [logseq.graph-parser.text :as text]
+            [logseq.shui.ui :as shui]
             [reitit.frontend.easy :as rfe]))
 
 (defn redirect!
   "If `push` is truthy, previous page will be left in history."
   [{:keys [to path-params query-params push]
     :or {push true}}]
+  (shui/popup-hide!)
   (let [route-fn (if push rfe/push-state rfe/replace-state)]
     (route-fn to path-params query-params))
   ;; force return nil for usage in render phase of React

+ 1 - 3
src/main/frontend/util.cljc

@@ -1248,9 +1248,7 @@
 #?(:cljs
    (defn scroll-editor-cursor
      [^js/HTMLElement el & {:keys [to-vw-one-quarter?]}]
-     (when (and el (or web-platform?
-                       (mobile-util/native-platform?)
-                       (mobile?)))
+     (when (and el (mobile?))
        (let [box-rect    (.getBoundingClientRect el)
              box-top     (.-top box-rect)
              box-bottom  (.-bottom box-rect)