header.cljs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. (ns frontend.components.header
  2. (:require [frontend.components.export :as export]
  3. [frontend.components.plugins :as plugins]
  4. [frontend.components.repo :as repo]
  5. [frontend.components.page :as page]
  6. [clojure.string :as str]
  7. [frontend.components.page-menu :as page-menu]
  8. [frontend.components.right-sidebar :as sidebar]
  9. [frontend.components.search :as search]
  10. [frontend.components.svg :as svg]
  11. [frontend.config :as config]
  12. [frontend.context.i18n :as i18n]
  13. [frontend.handler :as handler]
  14. [frontend.handler.page :as page-handler]
  15. [frontend.handler.plugin :as plugin-handler]
  16. [frontend.handler.user :as user-handler]
  17. [frontend.handler.route :as route-handler]
  18. [frontend.handler.web.nfs :as nfs]
  19. [frontend.modules.shortcut.core :as shortcut]
  20. [frontend.state :as state]
  21. [frontend.ui :as ui]
  22. [frontend.util :as util]
  23. [cljs-bean.core :as bean]
  24. [reitit.frontend.easy :as rfe]
  25. [rum.core :as rum]
  26. [frontend.mobile.util :as mobile-util]
  27. [frontend.components.widgets :as widgets]
  28. [frontend.handler.web.nfs :as nfs-handler]))
  29. (rum/defc home-button []
  30. (ui/with-shortcut :go/home "left"
  31. [:a.button
  32. {:href (rfe/href :home)
  33. :on-click route-handler/go-to-journals!}
  34. (ui/icon "home" {:style {:fontSize ui/icon-size}})]))
  35. (rum/defc login
  36. [logged?]
  37. (rum/with-context [[t] i18n/*tongue-context*]
  38. (when (and (not logged?)
  39. (not config/publishing?))
  40. (ui/dropdown-with-links
  41. (fn [{:keys [toggle-fn]}]
  42. [:a.button.text-sm.font-medium.block {:on-click toggle-fn}
  43. [:span (t :login)]])
  44. (let [list [;; {:title (t :login-google)
  45. ;; :url (str config/website "/login/google")}
  46. {:title (t :login-github)
  47. :url (str config/website "/login/github")}]]
  48. (mapv
  49. (fn [{:keys [title url]}]
  50. {:title title
  51. :options
  52. {:on-click
  53. (fn [_] (set! (.-href js/window.location) url))}})
  54. list))
  55. nil))))
  56. (rum/defc left-menu-button < rum/reactive
  57. [{:keys [on-click]}]
  58. (ui/with-shortcut :ui/toggle-left-sidebar "bottom"
  59. [:a#left-menu.cp__header-left-menu.button
  60. {:on-click on-click
  61. :style {:margin-left 12}}
  62. (ui/icon "menu-2" {:style {:fontSize ui/icon-size}})]))
  63. (rum/defc dropdown-menu < rum/reactive
  64. [{:keys [me current-repo t default-home]}]
  65. (let [projects (state/sub [:me :projects])
  66. developer-mode? (state/sub [:ui/developer-mode?])
  67. logged? (state/logged?)
  68. page-menu (page-menu/page-menu nil)
  69. page-menu-and-hr (when (seq page-menu)
  70. (concat page-menu [{:hr true}]))]
  71. (ui/dropdown-with-links
  72. (fn [{:keys [toggle-fn]}]
  73. [:a.button
  74. {:on-click toggle-fn}
  75. (ui/icon "dots" {:style {:fontSize ui/icon-size}})])
  76. (->>
  77. [(when-not (state/publishing-enable-editing?)
  78. {:title (t :settings)
  79. :options {:on-click state/open-settings!}
  80. :icon svg/settings-sm})
  81. (when (and developer-mode? (util/electron?))
  82. {:title (t :plugins)
  83. :options {:href (rfe/href :plugins)}})
  84. (when developer-mode?
  85. {:title (t :themes)
  86. :options {:on-click #(plugins/open-select-theme!)}})
  87. (when current-repo
  88. {:title (t :export-graph)
  89. :options {:on-click #(state/set-modal! export/export)}
  90. :icon nil})
  91. (when current-repo
  92. {:title (t :import)
  93. :options {:href (rfe/href :import)}
  94. :icon svg/import-sm})
  95. {:title [:div.flex-row.flex.justify-between.items-center
  96. [:span (t :join-community)]]
  97. :options {:href "https://discord.gg/KpN4eHY"
  98. :title (t :discord-title)
  99. :target "_blank"}
  100. :icon svg/discord}
  101. (when logged?
  102. {:title (t :sign-out)
  103. :options {:on-click user-handler/sign-out!}
  104. :icon svg/logout-sm})]
  105. (concat page-menu-and-hr)
  106. (remove nil?))
  107. {}
  108. ;; {:links-footer (when (and (util/electron?) (not logged?))
  109. ;; [:div.px-2.py-2 (login logged?)])}
  110. )))
  111. (rum/defc back-and-forward
  112. []
  113. [:div.flex.flex-row
  114. (ui/with-shortcut :go/backward "bottom"
  115. [:a.it.navigation.nav-left.button
  116. {:title "Go back" :on-click #(js/window.history.back)}
  117. (ui/icon "arrow-left" {:style {:fontSize ui/icon-size}})])
  118. (ui/with-shortcut :go/forward "bottom"
  119. [:a.it.navigation.nav-right.button
  120. {:title "Go forward" :on-click #(js/window.history.forward)}
  121. (ui/icon "arrow-right" {:style {:fontSize ui/icon-size}})])])
  122. (rum/defc updater-tips-new-version
  123. [t]
  124. (let [[downloaded, set-downloaded] (rum/use-state nil)
  125. _ (rum/use-effect!
  126. (fn []
  127. (when-let [channel (and (util/electron?) "auto-updater-downloaded")]
  128. (let [callback (fn [_ args]
  129. (js/console.debug "[new-version downloaded] args:" args)
  130. (let [args (bean/->clj args)]
  131. (set-downloaded args)
  132. (state/set-state! :electron/auto-updater-downloaded args))
  133. nil)]
  134. (js/apis.addListener channel callback)
  135. #(js/apis.removeListener channel callback))))
  136. [])]
  137. (when downloaded
  138. [:div.cp__header-tips
  139. [:p (t :updater/new-version-install)
  140. [:a.restart.ml-2
  141. {:on-click #(handler/quit-and-install-new-version!)}
  142. (svg/reload 16) [:strong (t :updater/quit-and-install)]]]])))
  143. (rum/defc header < rum/reactive
  144. [{:keys [open-fn current-repo logged? me default-home new-block-mode]}]
  145. (let [repos (->> (state/sub [:me :repos])
  146. (remove #(= (:url %) config/local-repo)))
  147. electron-mac? (and util/mac? (util/electron?))
  148. vw-state (state/sub :ui/visual-viewport-state)
  149. vw-pending? (state/sub :ui/visual-viewport-pending?)
  150. show-open-folder? (and (or (nfs/supported?)
  151. (mobile-util/is-native-platform?))
  152. (empty? repos)
  153. (not config/publishing?))
  154. refreshing? (state/sub :nfs/refreshing?)]
  155. (rum/with-context [[t] i18n/*tongue-context*]
  156. [:div.cp__header#head
  157. {:class (util/classnames [{:electron-mac electron-mac?
  158. :native-ios (mobile-util/native-ios?)
  159. :native-android (mobile-util/native-android?)
  160. :is-vw-pending (boolean vw-pending?)}])
  161. :on-double-click (fn [^js e]
  162. (when-let [target (.-target e)]
  163. (when (and (util/electron?)
  164. (or (.. target -classList (contains "cp__header"))))
  165. (js/window.apis.toggleMaxOrMinActiveWindow))))
  166. :style {:fontSize 50
  167. :transform (str "translateY(" (or (:offset-top vw-state) 0) "px)")}}
  168. [:div.l.flex
  169. (left-menu-button {:on-click (fn []
  170. (open-fn)
  171. (state/set-left-sidebar-open!
  172. (not (:ui/left-sidebar-open? @state/state))))})
  173. (when current-repo ;; this is for the Search button
  174. (ui/with-shortcut :go/search "right"
  175. [:a.button#search-button
  176. {:on-click #(state/pub-event! [:go/search])}
  177. (ui/icon "search" {:style {:fontSize ui/icon-size}})]))]
  178. [:div.r.flex
  179. (when (and (not (mobile-util/is-native-platform?))
  180. (not (util/electron?)))
  181. (login logged?))
  182. (when plugin-handler/lsp-enabled?
  183. (plugins/hook-ui-items :toolbar))
  184. (when (not= (state/get-current-route) :home)
  185. (home-button))
  186. (when (or (util/electron?)
  187. ;; (mobile-util/is-native-platform?)
  188. )
  189. (back-and-forward))
  190. (new-block-mode)
  191. (when (mobile-util/is-native-platform?)
  192. [:a.text-sm.font-medium.button
  193. {:on-click
  194. (fn []
  195. (state/pub-event!
  196. [:modal/show
  197. [:div {:style {:max-width 700}}
  198. [:p "Refresh detects and processes files modified on your disk and diverged from the actual Logseq page content. Continue?"]
  199. (ui/button
  200. "Yes"
  201. :on-click (fn []
  202. (state/close-modal!)
  203. (nfs-handler/refresh! (state/get-current-repo) repo/refresh-cb)))]]))}
  204. (if refreshing?
  205. [:div {:class "animate-spin-reverse"}
  206. svg/refresh]
  207. (when (seq repos)
  208. [:div.flex.flex-row.text-center.open-button__inner.items-center
  209. (ui/icon "refresh" {:style {:fontSize ui/icon-size}})]))])
  210. (repo/sync-status current-repo)
  211. (when (and
  212. show-open-folder?
  213. (not (mobile-util/is-native-platform?)))
  214. [:a.text-sm.font-medium.button
  215. {:on-click #(page-handler/ls-dir-files! shortcut/refresh!)}
  216. [:div.flex.flex-row.text-center.open-button__inner.items-center
  217. (ui/icon "folder-plus")
  218. (when-not config/mobile?
  219. [:span.ml-1 {:style {:margin-top (if electron-mac? 0 2)}}
  220. (t :open)])]])
  221. (when config/publishing?
  222. [:a.text-sm.font-medium.button {:href (rfe/href :graph)}
  223. (t :graph)])
  224. (dropdown-menu {:me me
  225. :t t
  226. :current-repo current-repo
  227. :default-home default-home})
  228. (when (not (state/sub :ui/sidebar-open?))
  229. (sidebar/toggle))
  230. (updater-tips-new-version t)]])))