Browse Source

feat: add block page-search autocomplete with page preview

Peng Xiao 4 years ago
parent
commit
60de6516e4

+ 39 - 42
src/main/frontend/components/block.cljs

@@ -371,58 +371,55 @@
        :else
        (get page-entity :block/original-name page-name)))])
 
+(rum/defc page-preview-trigger
+  [{:keys [children sidebar? tippy-position fixed-position?] :as config} page-name]
+  (let [page-entity (db/entity [:block/name page-name])
+        redirect-page-name (model/get-redirect-page-name page-name (:block/alias? config))
+        page-original-name (model/get-page-original-name redirect-page-name)]
+    (ui/tippy {:html        (fn []
+                              [:div.tippy-wrapper.overflow-y-auto.p-4
+                               {:style {:width          600
+                                        :text-align     "left"
+                                        :font-weight    500
+                                        :max-height     600
+                                        :padding-bottom 64}}
+                               (if (and (string? page-original-name) (string/includes? page-original-name "/"))
+                                 [:div.my-2
+                                  (->>
+                                    (for [page (string/split page-original-name #"/")]
+                                      (when (and (string? page) page)
+                                        (page-reference false page {} nil)))
+                                    (interpose [:span.mx-2.opacity-30 "/"]))]
+                                 [:h2.font-bold.text-lg (if (= page-name redirect-page-name)
+                                                          page-original-name
+                                                          [:span
+                                                           [:span.text-sm.mr-2 "Alias:"]
+                                                           page-original-name])])
+                               (let [page (db/entity [:block/name (string/lower-case redirect-page-name)])]
+                                 (editor-handler/insert-first-page-block-if-not-exists! redirect-page-name)
+                                 (when-let [f (state/get-page-blocks-cp)]
+                                   (f (state/get-current-repo) page {:sidebar? sidebar? :preview? true})))])
+               :interactive true
+               :delay       [1000, 100]
+               :fixed-position? fixed-position?
+               :position    (or tippy-position "top")}
+              children)))
+
 (rum/defc page-cp
   [{:keys [html-export? label children contents-page? sidebar? preview?] :as config} page]
   (when-let [page-name (:block/name page)]
-    (let [page (string/lower-case page-name)
-          page-entity (db/entity [:block/name page])
-          redirect-page-name (cond
-                               (:block/alias? config)
-                               page
-
-                               (db/page-empty-or-dummy? (state/get-current-repo) (:db/id page-entity))
-                               (let [source-page (model/get-alias-source-page (state/get-current-repo)
-                                                                              (string/lower-case page-name))]
-                                 (or (when source-page (:block/name source-page))
-                                     page))
-
-                               :else
-                               page)
+    (let [page-name (string/lower-case page-name)
+          page-entity (db/entity [:block/name page-name])
+          redirect-page-name (model/get-redirect-page-name page-name (:block/alias? config))
           page-original-name (model/get-page-original-name redirect-page-name)
           href (if html-export?
-                 (util/encode-str page)
+                 (util/encode-str page-name)
                  (rfe/href :page {:name redirect-page-name}))
           inner (page-inner config
                             page-name
                             href redirect-page-name page-entity contents-page? children html-export? label)]
       (if (and (not (util/mobile?)) (not preview?))
-        (ui/tippy {:html        (fn []
-                                  [:div.tippy-wrapper.overflow-y-auto.p-4
-                                   {:style {:width          600
-                                            :text-align     "left"
-                                            :font-weight    500
-                                            :max-height     600
-                                            :padding-bottom 64}}
-                                   (if (and (string? page-original-name) (string/includes? page-original-name "/"))
-                                     [:div.my-2
-                                      (->>
-                                       (for [page (string/split page-original-name #"/")]
-                                         (when (and (string? page) page)
-                                           (page-reference false page {} nil)))
-                                       (interpose [:span.mx-2.opacity-30 "/"]))]
-                                     [:h2.font-bold.text-lg (if (= page redirect-page-name)
-                                                              page-original-name
-                                                              [:span
-                                                               [:span.text-sm.mr-2 "Alias:"]
-                                                               page-original-name])])
-
-                                   (let [page (db/entity [:block/name (string/lower-case redirect-page-name)])]
-                                     (editor-handler/insert-first-page-block-if-not-exists! redirect-page-name)
-                                     (when-let [f (state/get-page-blocks-cp)]
-                                       (f (state/get-current-repo) page {:sidebar? sidebar? :preview? true})))])
-                   :interactive true
-                   :delay       [1000, 100]}
-                  inner)
+        (page-preview-trigger (assoc config :children inner) page-name)
         inner))))
 
 (rum/defc asset-reference

+ 14 - 5
src/main/frontend/components/editor.cljs

@@ -6,6 +6,7 @@
             [frontend.components.datetime :as datetime-comp]
             [frontend.components.search :as search]
             [frontend.components.svg :as svg]
+            [frontend.components.block :as block]
             [frontend.config :as config]
             [frontend.db :as db]
             [frontend.handler.editor :as editor-handler :refer [get-state]]
@@ -94,11 +95,19 @@
                               (editor-handler/get-matched-pages q))]
           (ui/auto-complete
            matched-pages
-           {:on-chosen (page-handler/on-chosen-handler input id q pos format)
-            :on-enter #(page-handler/page-not-exists-handler input id q current-pos)
-            :item-render (fn [item] [:div.py-2 (search/highlight-exact-query item q)])
-            :empty-div [:div.text-gray-500.pl-4.pr-4 "Search for a page"]
-            :class     "black"}))))))
+           {:on-chosen   (page-handler/on-chosen-handler input id q pos format)
+            :on-enter    #(page-handler/page-not-exists-handler input id q current-pos)
+            :item-render (fn [item chosen?]
+                           [:div.py-2.flex.page-search-menu-item
+                            [[:div (search/highlight-exact-query item q)]
+                             [:div.flex-1]
+                             ;; Ideally, we may want to trigger preview on focused
+                             (block/page-preview-trigger
+                               {:children [:div.page-search-menu-item-preview "Preview"]
+                                :tippy-position "right"}
+                               item)]])
+            :empty-div   [:div.text-gray-500.pl-4.pr-4 "Search for a page"]
+            :class       "black"}))))))
 
 (rum/defcs block-search-auto-complete < rum/reactive
   {:init (fn [state]

+ 14 - 0
src/main/frontend/components/editor.css

@@ -63,3 +63,17 @@ pre {
   background: #f6f8fa;
   background: var(--ls-secondary-background-color);
 }
+
+
+.page-search-menu-item-preview {
+  opacity: 0;
+}
+
+.page-search-menu-item:hover {
+  .page-search-menu-item-preview {
+    opacity: 0.5;
+    &:hover {
+      opacity: 1;
+    }
+  }
+}

+ 17 - 0
src/main/frontend/db/model.cljs

@@ -710,6 +710,23 @@
    (vector? block)
    (= "Heading" (first block))))
 
+(defn get-redirect-page-name
+  ([page-name] (get-redirect-page-name page-name false))
+  ([page-name alias?]
+   (let [page-entity (db-utils/entity [:block/name page-name])]
+     (cond
+       alias?
+       page-name
+
+       (page-empty-or-dummy? (state/get-current-repo) (:db/id page-entity))
+       (let [source-page (get-alias-source-page (state/get-current-repo)
+                                                      (string/lower-case page-name))]
+         (or (when source-page (:block/name source-page))
+             page-name))
+
+       :else
+       page-name))))
+
 (defn get-page-original-name
   [page-name]
   (when page-name

+ 17 - 11
src/main/frontend/ui.cljs

@@ -368,16 +368,16 @@
            {:key idx}
            (let [item-cp
                  [:div {:key idx}
-                  (menu-link
-                   {:id       (str "ac-" idx)
-                    :class    (when (= @current-idx idx)
-                                "chosen")
-                    :on-mouse-down (fn [e]
-                                     (util/stop e)
-                                     (if (and (gobj/get e "shiftKey") on-shift-chosen)
-                                       (on-shift-chosen item)
-                                       (on-chosen item)))}
-                   (if item-render (item-render item) item))]]
+                  (let [chosen? (= @current-idx idx)]
+                    (menu-link
+                      {:id            (str "ac-" idx)
+                       :class         (when chosen? "chosen")
+                       :on-mouse-down (fn [e]
+                                        (util/stop e)
+                                        (if (and (gobj/get e "shiftKey") on-shift-chosen)
+                                          (on-shift-chosen item)
+                                          (on-chosen item)))}
+                      (if item-render (item-render item chosen?) item)))]]
 
              (if get-group-name
                (if-let [group-name (get-group-name item)]
@@ -628,7 +628,7 @@
 
 (rum/defcs tippy < rum/static
   (rum/local false ::mounted?)
-  [state opts child]
+  [state {:keys [fixed-position?] :as opts} child]
   (let [*mounted? (::mounted? state)
         mounted? @*mounted?]
     (Tippy (->
@@ -638,6 +638,12 @@
                     :disabled (not (state/enable-tooltip?))
                     :unmountHTMLWhenHide true
                     :open @*mounted?
+                    ;; See https://github.com/tvkhoa/react-tippy/issues/13
+                    :popperOptions (if fixed-position?
+                                      {:modifiers {:preventOverflow {:enabled false}
+                                                   :flip {:enabled false}
+                                                   :hide {:enabled false}}}
+                                      {})
                     :onShow #(reset! *mounted? true)
                     :onHide #(reset! *mounted? false)}
                    opts)