page_menu.cljs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. (ns frontend.components.page-menu
  2. (:require [cljs.pprint :as pprint]
  3. [frontend.commands :as commands]
  4. [frontend.components.export :as export]
  5. [frontend.context.i18n :refer [t]]
  6. [frontend.db :as db]
  7. [frontend.handler.notification :as notification]
  8. [frontend.handler.page :as page-handler]
  9. [frontend.handler.route :as route-handler]
  10. [frontend.state :as state]
  11. [frontend.ui :as ui]
  12. [frontend.util :as util]
  13. [frontend.util.url :as url-util]
  14. [frontend.handler.shell :as shell]
  15. [frontend.mobile.util :as mobile-util]
  16. [electron.ipc :as ipc]
  17. [frontend.config :as config]
  18. [frontend.handler.user :as user-handler]
  19. [frontend.handler.file-sync :as file-sync-handler]
  20. [logseq.graph-parser.mldoc :as gp-mldoc]))
  21. (defn- delete-page!
  22. [page-name]
  23. (page-handler/delete! page-name
  24. (fn []
  25. (notification/show! (str "Page " page-name " was deleted successfully!")
  26. :success)))
  27. (state/close-modal!)
  28. (route-handler/redirect-to-home!))
  29. (defn delete-page-dialog
  30. [page-name]
  31. (fn [close-fn]
  32. [:div
  33. [:div.sm:flex.items-center
  34. [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-error.sm:mx-0.sm:h-10.sm:w-10
  35. [:span.text-error.text-xl
  36. (ui/icon "alert-triangle")]]
  37. [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
  38. [:h3#modal-headline.text-lg.leading-6.font-medium
  39. (t :page/delete-confirmation)]]]
  40. [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
  41. [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
  42. [: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
  43. {:type "button"
  44. :class "ui__modal-enter"
  45. :on-click (fn []
  46. (delete-page! page-name))}
  47. (t :yes)]]
  48. [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
  49. [: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
  50. {:type "button"
  51. :on-click close-fn}
  52. (t :cancel)]]]]))
  53. (defn ^:large-vars/cleanup-todo page-menu
  54. [page-name]
  55. (when-let [page-name (or
  56. page-name
  57. (state/get-current-page)
  58. (state/get-current-whiteboard))]
  59. (let [page-name (util/page-name-sanity-lc page-name)
  60. repo (state/sub :git/current-repo)
  61. page (db/entity repo [:block/name page-name])
  62. page-original-name (:block/original-name page)
  63. whiteboard? (= "whiteboard" (:block/type page))
  64. block? (and page (util/uuid-string? page-name) (not whiteboard?))
  65. contents? (= page-name "contents")
  66. properties (:block/properties page)
  67. public? (true? (:public properties))
  68. favorites (:favorites (state/sub-config))
  69. favorited? (contains? (set (map util/page-name-sanity-lc favorites))
  70. page-name)
  71. developer-mode? (state/sub [:ui/developer-mode?])
  72. file-path (when (util/electron?) (page-handler/get-page-file-path))
  73. _ (state/sub :auth/id-token)
  74. file-sync-graph-uuid (and (user-handler/logged-in?)
  75. (file-sync-handler/enable-sync?)
  76. (file-sync-handler/get-current-graph-uuid))]
  77. (when (and page (not block?))
  78. (->>
  79. [{:title (if favorited?
  80. (t :page/unfavorite)
  81. (t :page/add-to-favorites))
  82. :options {:on-click
  83. (fn []
  84. (if favorited?
  85. (page-handler/unfavorite-page! page-original-name)
  86. (page-handler/favorite-page! page-original-name)))}}
  87. (when (or (util/electron?) file-sync-graph-uuid)
  88. {:title (t :page/version-history)
  89. :options {:on-click
  90. (fn []
  91. (cond
  92. file-sync-graph-uuid
  93. (state/pub-event! [:graph/pick-page-histories file-sync-graph-uuid page-name])
  94. (util/electron?)
  95. (shell/get-file-latest-git-log page 100)
  96. :else
  97. nil))
  98. :class "cp__btn_history_version"}})
  99. (when (or (util/electron?)
  100. (mobile-util/native-platform?))
  101. {:title (t :page/copy-page-url)
  102. :options {:on-click #(util/copy-to-clipboard!
  103. (url-util/get-logseq-graph-page-url nil repo page-original-name))}})
  104. (when-not contents?
  105. {:title (t :page/delete)
  106. :options {:on-click #(state/set-modal! (delete-page-dialog page-name))}})
  107. (when (and (not (mobile-util/native-platform?))
  108. (state/get-current-page))
  109. {:title (t :page/presentation-mode)
  110. :options {:on-click (fn []
  111. (state/sidebar-add-block!
  112. repo
  113. (:db/id page)
  114. :page-presentation))}})
  115. ;; TODO: In the future, we'd like to extract file-related actions
  116. ;; (such as open-in-finder & open-with-default-app) into a sub-menu of
  117. ;; this one. However this component doesn't yet exist. PRs are welcome!
  118. ;; Details: https://github.com/logseq/logseq/pull/3003#issuecomment-952820676
  119. (when file-path
  120. [{:title (t :page/open-in-finder)
  121. :options {:on-click #(js/window.apis.showItemInFolder file-path)}}
  122. {:title (t :page/open-with-default-app)
  123. :options {:on-click #(js/window.apis.openPath file-path)}}])
  124. (when (state/get-current-page)
  125. {:title (t :export-page)
  126. :options {:on-click #(state/set-modal!
  127. (fn []
  128. (export/export-blocks [(:block/uuid page)])))}})
  129. (when (util/electron?)
  130. {:title (t (if public? :page/make-private :page/make-public))
  131. :options {:on-click
  132. (fn []
  133. (page-handler/update-public-attribute!
  134. page-name
  135. (if public? false true))
  136. (state/close-modal!))}})
  137. (when (and (util/electron?) file-path
  138. (not (file-sync-handler/synced-file-graph? repo)))
  139. {:title (t :page/open-backup-directory)
  140. :options {:on-click
  141. (fn []
  142. (ipc/ipc "openFileBackupDir" (config/get-local-dir repo) file-path))}})
  143. (when config/lsp-enabled?
  144. (for [[_ {:keys [label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
  145. {:title label
  146. :options {:on-click #(commands/exec-plugin-simple-command!
  147. pid (assoc cmd :page page-name) action)}}))
  148. (when developer-mode?
  149. {:title "(Dev) Show page data"
  150. :options {:on-click (fn []
  151. (let [page-data (with-out-str (pprint/pprint (db/pull (:db/id page))))]
  152. (println page-data)
  153. (notification/show!
  154. [:div
  155. [:pre.code page-data]
  156. [:br]
  157. (ui/button
  158. "Copy to clipboard"
  159. :on-click #(.writeText js/navigator.clipboard page-data))]
  160. :success
  161. false)))}})
  162. (when developer-mode?
  163. {:title "(Dev) Show page AST"
  164. :options {:on-click (fn []
  165. (let [page (db/pull '[:block/format {:block/file [:file/content]}] (:db/id page))
  166. page-data (-> (gp-mldoc/->edn (get-in page [:block/file :file/content])
  167. (gp-mldoc/default-config (:block/format page)))
  168. pprint/pprint
  169. with-out-str)]
  170. (println page-data)
  171. (notification/show!
  172. [:div
  173. (ui/button
  174. "Copy to clipboard"
  175. :on-click #(.writeText js/navigator.clipboard page-data))
  176. [:br]
  177. [:pre.code page-data]]
  178. :success
  179. false)))}})]
  180. (flatten)
  181. (remove nil?))))))