header.cljs 9.9 KB

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