فهرست منبع

enhance(ux): right-click to display page menu options

Tienson Qin 4 سال پیش
والد
کامیت
643c57f9a9

+ 25 - 3
src/main/frontend/components/content.cljs

@@ -4,6 +4,7 @@
             [dommy.core :as d]
             [frontend.commands :as commands]
             [frontend.components.editor :as editor]
+            [frontend.components.page-menu :as page-menu]
             [frontend.components.export :as export]
             [frontend.config :as config]
             [frontend.context.i18n :as i18n]
@@ -280,6 +281,19 @@
         :on-click (fn [] (editor-handler/replace-ref-with-embed! block block-ref-id))}
        "Replace with embed")]]))
 
+(rum/defc page-title-custom-context-menu-content
+  [page]
+  (when-not (string/blank? page)
+    (let [page-menu-options (page-menu/page-menu page)]
+      [:div#custom-context-menu
+       [:div.py-1.rounded-md.bg-base-3.shadow-xs
+        (for [{:keys [title options]} page-menu-options]
+          (ui/menu-link
+           (merge
+            {:key title}
+            options)
+           title))]])))
+
 ;; TODO: content could be changed
 ;; Also, keyboard bindings should only be activated after
 ;; blocks were already selected.
@@ -303,13 +317,21 @@
                     (fn [e]
                       (let [target (gobj/get e "target")
                             block-id (d/attr target "blockid")
-                            {:keys [block block-ref]} (state/sub :block-ref/context)]
+                            {:keys [block block-ref]} (state/sub :block-ref/context)
+                            {:keys [page]} (state/sub :page-title/context)]
                         (cond
+                          page
+                          (do
+                            (common-handler/show-custom-context-menu!
+                             e
+                             (page-title-custom-context-menu-content page))
+                            (state/set-state! :page-title/context nil))
+
                           block-ref
                           (do
                             (common-handler/show-custom-context-menu!
-                            e
-                            (block-ref-custom-context-menu-content block block-ref))
+                             e
+                             (block-ref-custom-context-menu-content block block-ref))
                             (state/set-state! :block-ref/context nil))
 
                           (state/selection?)

+ 2 - 1
src/main/frontend/components/header.cljs

@@ -3,6 +3,7 @@
             [frontend.components.plugins :as plugins]
             [frontend.components.repo :as repo]
             [frontend.components.page :as page]
+            [frontend.components.page-menu :as page-menu]
             [frontend.components.right-sidebar :as sidebar]
             [frontend.components.search :as search]
             [frontend.components.svg :as svg]
@@ -79,7 +80,7 @@
   (let [projects (state/sub [:me :projects])
         developer-mode? (state/sub [:ui/developer-mode?])
         logged? (state/logged?)
-        page-menu (page/page-menu t)
+        page-menu (page-menu/page-menu nil)
         page-menu-and-hr (when (seq page-menu)
                            (concat page-menu [{:hr true}]))]
     (ui/dropdown-with-links

+ 3 - 0
src/main/frontend/components/journal.cljs

@@ -66,6 +66,9 @@
       (ui/foldable
        [:a.initial-color.title.journal-title
         {:href     (rfe/href :page {:name page})
+         :on-mouse-down (fn [e]
+                          (when (util/right-click? e)
+                            (state/set-state! :page-title/context {:page page})))
          :on-click (fn [e]
                      (when (gobj/get e "shiftKey")
                        (when-let [page page-entity]

+ 4 - 132
src/main/frontend/components/page.cljs

@@ -170,48 +170,6 @@
                                   :page page} query)
              (str repo "-custom-query-" (:query query))))]))))
 
-(defn- delete-page!
-  [page-name]
-  (page-handler/delete! page-name
-                        (fn []
-                          (notification/show! (str "Page " page-name " was deleted successfully!")
-                                              :success)))
-  (state/close-modal!)
-  (route-handler/redirect-to-home!))
-
-(defn delete-page-dialog
-  [page-name]
-  (fn [close-fn]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div
-       [:div.sm:flex.sm:items-start
-        [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
-         [:svg.h-6.w-6.text-red-600
-          {:stroke "currentColor", :view-box "0 0 24 24", :fill "none"}
-          [:path
-           {:d
-            "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
-            :stroke-width "2"
-            :stroke-linejoin "round"
-            :stroke-linecap "round"}]]]
-        [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
-         [:h3#modal-headline.text-lg.leading-6.font-medium
-          (t :page/delete-confirmation)]]]
-
-       [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
-        [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
-         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-          {:type "button"
-           :class "ui__modal-enter"
-           :on-click (fn []
-                       (delete-page! page-name))}
-          (t :yes)]]
-        [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
-         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-          {:type "button"
-           :on-click close-fn}
-          (t :cancel)]]]])))
-
 (rum/defcs rename-page-dialog-inner <
   (shortcut/disable-all-shortcuts)
   (rum/local "" ::input)
@@ -267,95 +225,6 @@
               original-name]])]
          {:default-collapsed? false})]])))
 
-(defn page-menu
-  [t]
-  (when-let [page-name (and (state/get-current-page)
-                            (string/lower-case (state/get-current-page)))]
-    (let [repo (state/sub :git/current-repo)
-          page (and page-name (db/entity repo [:block/name page-name]))
-          page-original-name (:block/original-name page)
-          journal? (db/journal-page? page-name)
-          block? (and page (util/uuid-string? page-name))
-          contents? (= (string/lower-case (str page-name)) "contents")
-          {:keys [title] :as properties} (:block/properties page)
-          title (or title page-original-name page-name)
-          public? (true? (:public properties))
-          favorites (:favorites (state/sub-graph-config))
-          favorited? (contains? (set (map string/lower-case favorites))
-                                (string/lower-case page-name))
-          developer-mode? (state/sub [:ui/developer-mode?])]
-      (when (and page (not block?))
-        (->>
-         [{:title   (if favorited?
-                      (t :page/unfavorite)
-                      (t :page/add-to-favorites))
-           :options {:on-click
-                     (fn []
-                       (if favorited?
-                         (page-handler/unfavorite-page! page-original-name)
-                         (page-handler/favorite-page! page-original-name)))}}
-
-          {:title (t :page/presentation-mode)
-           :options {:on-click (fn []
-                                 (state/sidebar-add-block!
-                                  repo
-                                  (:db/id page)
-                                  :page-presentation
-                                  {:page page}))}}
-
-          (when-let [file-path (and (util/electron?) (page-handler/get-page-file-path))]
-            [{:title   (t :page/open-in-finder)
-              :options {:on-click #(js/window.apis.showItemInFolder file-path)}}
-             {:title   (t :page/open-with-default-app)
-              :options {:on-click #(js/window.apis.openPath file-path)}}])
-
-          (when-not contents?
-            {:title   (t :page/delete)
-             :options {:on-click #(state/set-modal! (delete-page-dialog page-name))}})
-
-          (when (state/get-current-page)
-            {:title   (t :export-page)
-             :options {:on-click #(state/set-modal!
-                                   (fn []
-                                     (export/export-blocks [(:block/uuid page)])))}})
-
-          (when (util/electron?)
-            {:title   (t (if public? :page/make-private :page/make-public))
-             :options {:on-click
-                       (fn []
-                         (page-handler/update-public-attribute!
-                          page-name
-                          (if public? false true))
-                         (state/close-modal!))}})
-
-          (when (util/electron?)
-            {:title   (t :page/version-history)
-             :options {:on-click
-                       (fn []
-                         (shell/get-file-latest-git-log page 100))}})
-
-          (when plugin-handler/lsp-enabled?
-            (for [[_ {:keys [key label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
-              {:title label
-               :options {:on-click #(commands/exec-plugin-simple-command!
-                                     pid (assoc cmd :page (state/get-current-page)) action)}}))
-
-          (when developer-mode?
-            {:title   "(Dev) Show page data"
-             :options {:on-click (fn []
-                                   (let [page-data (with-out-str (pprint/pprint (db/pull (:db/id page))))]
-                                     (println page-data)
-                                     (notification/show!
-                                      [:div
-                                       [:pre.code page-data]
-                                       [:br]
-                                       (ui/button "Copy to clipboard"
-                                         :on-click #(.writeText js/navigator.clipboard page-data))]
-                                      :success
-                                      false)))}})]
-         (flatten)
-         (remove nil?))))))
-
 (rum/defcs page-title <
   {:will-update (fn [state]
                   (assoc state ::title-value (atom (second (:rum/args state)))))}
@@ -391,7 +260,10 @@
                             (page-handler/rename! (or title page-name) @*title-value)
                             (reset! *edit? false)
                             (reset! *title-value ""))}]]
-        [:a.page-title {:on-click (fn [e]
+        [:a.page-title {:on-mouse-down (fn [e]
+                                         (when (util/right-click? e)
+                                           (state/set-state! :page-title/context {:page page-name})))
+                        :on-click (fn [e]
                                     (.preventDefault e)
                                     (if (gobj/get e "shiftKey")
                                       (when-let [page (db/pull repo '[*] [:block/name page-name])]

+ 151 - 0
src/main/frontend/components/page_menu.cljs

@@ -0,0 +1,151 @@
+(ns frontend.components.page-menu
+  (:require [cljs.pprint :as pprint]
+            [clojure.string :as string]
+            [frontend.commands :as commands]
+            [frontend.components.editor :as editor]
+            [frontend.components.export :as export]
+            [frontend.context.i18n :as i18n]
+            [frontend.db :as db]
+            [frontend.handler.notification :as notification]
+            [frontend.handler.page :as page-handler]
+            [frontend.handler.route :as route-handler]
+            [frontend.state :as state]
+            [frontend.ui :as ui]
+            [frontend.util :as util]
+            [rum.core :as rum]
+            [frontend.handler.shell :as shell]
+            [frontend.handler.plugin :as plugin-handler]))
+
+(defn- delete-page!
+  [page-name]
+  (page-handler/delete! page-name
+                        (fn []
+                          (notification/show! (str "Page " page-name " was deleted successfully!")
+                                              :success)))
+  (state/close-modal!)
+  (route-handler/redirect-to-home!))
+
+(defn delete-page-dialog
+  [page-name]
+  (fn [close-fn]
+    (rum/with-context [[t] i18n/*tongue-context*]
+      [:div
+       [:div.sm:flex.sm:items-start
+        [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
+         [:svg.h-6.w-6.text-red-600
+          {:stroke "currentColor", :view-box "0 0 24 24", :fill "none"}
+          [:path
+           {:d
+            "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
+            :stroke-width "2"
+            :stroke-linejoin "round"
+            :stroke-linecap "round"}]]]
+        [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
+         [:h3#modal-headline.text-lg.leading-6.font-medium
+          (t :page/delete-confirmation)]]]
+
+       [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
+        [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
+         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+          {:type "button"
+           :class "ui__modal-enter"
+           :on-click (fn []
+                       (delete-page! page-name))}
+          (t :yes)]]
+        [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
+         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+          {:type "button"
+           :on-click close-fn}
+          (t :cancel)]]]])))
+
+(defn page-menu
+  [page-name]
+  (when-let [page-name (or
+                        page-name
+                        (and (state/get-current-page)
+                             (string/lower-case (state/get-current-page))))]
+    (let [t i18n/t
+          repo (state/sub :git/current-repo)
+          page (and page-name (db/entity repo [:block/name page-name]))
+          page-original-name (:block/original-name page)
+          journal? (db/journal-page? page-name)
+          block? (and page (util/uuid-string? page-name))
+          contents? (= (string/lower-case (str page-name)) "contents")
+          {:keys [title] :as properties} (:block/properties page)
+          title (or title page-original-name page-name)
+          public? (true? (:public properties))
+          favorites (:favorites (state/sub-graph-config))
+          favorited? (contains? (set (map string/lower-case favorites))
+                                (string/lower-case page-name))
+          developer-mode? (state/sub [:ui/developer-mode?])]
+      (when (and page (not block?))
+        (->>
+         [{:title   (if favorited?
+                      (t :page/unfavorite)
+                      (t :page/add-to-favorites))
+           :options {:on-click
+                     (fn []
+                       (if favorited?
+                         (page-handler/unfavorite-page! page-original-name)
+                         (page-handler/favorite-page! page-original-name)))}}
+
+          {:title (t :page/presentation-mode)
+           :options {:on-click (fn []
+                                 (state/sidebar-add-block!
+                                  repo
+                                  (:db/id page)
+                                  :page-presentation
+                                  {:page page}))}}
+
+          (when-let [file-path (and (util/electron?) (page-handler/get-page-file-path))]
+            [{:title   (t :page/open-in-finder)
+              :options {:on-click #(js/window.apis.showItemInFolder file-path)}}
+             {:title   (t :page/open-with-default-app)
+              :options {:on-click #(js/window.apis.openPath file-path)}}])
+
+          (when-not contents?
+            {:title   (t :page/delete)
+             :options {:on-click #(state/set-modal! (delete-page-dialog page-name))}})
+
+          (when (state/get-current-page)
+            {:title   (t :export-page)
+             :options {:on-click #(state/set-modal!
+                                   (fn []
+                                     (export/export-blocks [(:block/uuid page)])))}})
+
+          (when (util/electron?)
+            {:title   (t (if public? :page/make-private :page/make-public))
+             :options {:on-click
+                       (fn []
+                         (page-handler/update-public-attribute!
+                          page-name
+                          (if public? false true))
+                         (state/close-modal!))}})
+
+          (when (util/electron?)
+            {:title   (t :page/version-history)
+             :options {:on-click
+                       (fn []
+                         (shell/get-file-latest-git-log page 100))}})
+
+          (when plugin-handler/lsp-enabled?
+            (for [[_ {:keys [key label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
+              {:title label
+               :options {:on-click #(commands/exec-plugin-simple-command!
+                                     pid (assoc cmd :page (state/get-current-page)) action)}}))
+
+          (when developer-mode?
+            {:title   "(Dev) Show page data"
+             :options {:on-click (fn []
+                                   (let [page-data (with-out-str (pprint/pprint (db/pull (:db/id page))))]
+                                     (println page-data)
+                                     (notification/show!
+                                      [:div
+                                       [:pre.code page-data]
+                                       [:br]
+                                       (ui/button "Copy to clipboard"
+                                         :on-click #(.writeText js/navigator.clipboard page-data))]
+                                      :success
+                                      false)))}})]
+         (flatten)
+         (remove nil?))))))

+ 11 - 0
src/main/frontend/context/i18n.cljs

@@ -17,6 +17,17 @@
 
 (rum/defcontext *tongue-context*)
 
+;; FIXME: reactive
+(defonce t
+  (let [preferred-language (keyword (state/sub :preferred-language))
+        set-preferred-language state/set-preferred-language!
+        all-dicts (deep-merge dicts/dicts shortcut-dict/dict)
+        t (partial (dicts/translate all-dicts) preferred-language)]
+    (if (nil? preferred-language)
+      (set-preferred-language (fetch-local-language))
+      :ok)
+    t))
+
 (rum/defc tongue-provider [children]
   (let [preferred-language (keyword (state/sub :preferred-language))
         set-preferred-language state/set-preferred-language!