header.cljs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. (ns frontend.components.header
  2. (:require [rum.core :as rum]
  3. [reitit.frontend.easy :as rfe]
  4. [clojure.string :as string]
  5. [frontend.db :as db]
  6. [frontend.ui :as ui]
  7. [frontend.util :as util]
  8. [frontend.state :as state]
  9. [frontend.storage :as storage]
  10. [frontend.config :as config]
  11. [frontend.context.i18n :as i18n]
  12. [frontend.handler.user :as user-handler]
  13. [frontend.handler.export :as export]
  14. [frontend.components.svg :as svg]
  15. [frontend.components.repo :as repo]
  16. [frontend.components.search :as search]
  17. [frontend.handler.project :as project-handler]
  18. [frontend.handler.web.nfs :as nfs]
  19. [goog.dom :as gdom]
  20. [goog.object :as gobj]))
  21. (rum/defc logo < rum/reactive
  22. [{:keys [white?]}]
  23. [:a.cp__header-logo
  24. {:href "/"
  25. :on-click (fn []
  26. (util/scroll-to-top)
  27. (state/set-journals-length! 1))}
  28. (if-let [logo (and config/publishing?
  29. (get-in (state/get-config) [:project :logo]))]
  30. [:img.cp__header-logo-img {:src logo}]
  31. (svg/logo (not white?)))])
  32. (rum/defc left-menu-button < rum/reactive
  33. [{:keys [on-click]}]
  34. [:button#left-menu.cp__header-left-menu
  35. {:on-click on-click}
  36. [:svg.h-6.w-6
  37. {:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
  38. [:path
  39. {:d "M4 6h16M4 12h16M4 18h7"
  40. :stroke-width "2"
  41. :stroke-linejoin "round"
  42. :stroke-linecap "round"}]]])
  43. (rum/defc dropdown-menu < rum/reactive
  44. [{:keys [me current-repo t default-home]}]
  45. (let [projects (state/sub [:me :projects])]
  46. (ui/dropdown-with-links
  47. (fn [{:keys [toggle-fn]}]
  48. [:button.max-w-xs.flex.items-center.text-sm.rounded-full.focus:outline-none.focus:shadow-outline.h-7.w-7.ml-2
  49. {:on-click toggle-fn}
  50. (if-let [avatar (:avatar me)]
  51. [:img#avatar.h-7.w-7.rounded-full
  52. {:src avatar
  53. :on-error (fn [this]
  54. (let [elem (gdom/getElement "avatar")]
  55. (gobj/set elem "src" (config/asset-uri "/static/img/broken-avatar.png"))))}]
  56. [:div.h-7.w-7.rounded-full.bg-base-2.opacity-70.hover:opacity-100 {:style {:padding 1.5}}
  57. [:a svg/user]])])
  58. (let [logged? (:name me)]
  59. (->>
  60. [(when current-repo
  61. {:title (t :graph)
  62. :options {:href (rfe/href :graph)}
  63. :icon svg/graph-sm})
  64. (when (or logged? (and (nfs/supported?) current-repo))
  65. {:title (t :all-graphs)
  66. :options {:href (rfe/href :repos)}
  67. :icon svg/repos-sm})
  68. (when current-repo
  69. {:title (t :all-pages)
  70. :options {:href (rfe/href :all-pages)}
  71. :icon svg/pages-sm})
  72. (when current-repo
  73. {:title (t :all-files)
  74. :options {:href (rfe/href :all-files)}
  75. :icon svg/folder-sm})
  76. (when (and default-home current-repo)
  77. {:title (t :all-journals)
  78. :options {:href (rfe/href :all-journals)}
  79. :icon svg/calendar-sm})
  80. (when (project-handler/get-current-project current-repo projects)
  81. {:title (t :my-publishing)
  82. :options {:href (rfe/href :my-publishing)}})
  83. (when-let [project (and current-repo
  84. (project-handler/get-current-project current-repo projects))]
  85. (let [link (str config/website "/" project)]
  86. {:title (str (t :go-to) "/" project)
  87. :options {:href link
  88. :target "_blank"}
  89. :icon svg/external-link}))
  90. {:title (t :settings)
  91. :options {:href (rfe/href :settings)}
  92. :icon svg/settings-sm}
  93. (when (and logged? current-repo)
  94. {:title (t :export)
  95. :options {:on-click (fn []
  96. (export/export-repo-as-html! current-repo))}
  97. :icon nil})
  98. (when current-repo
  99. {:title (t :import)
  100. :options {:href (rfe/href :import)}
  101. :icon svg/import-sm})
  102. {:title [:div.flex-row.flex.justify-between.items-center
  103. [:span (t :join-community)]]
  104. :options {:href "https://discord.gg/KpN4eHY"
  105. :title (t :discord-title)
  106. :target "_blank"}
  107. :icon svg/discord}
  108. {:title [:div.flex-row.flex.justify-between.items-center
  109. [:span (t :sponsor-us)]]
  110. :options {:href "https://opencollective.com/logseq"
  111. :target "_blank"}}
  112. (when logged?
  113. {:title (t :sign-out)
  114. :options {:on-click user-handler/sign-out!}
  115. :icon svg/logout-sm})]
  116. (remove nil?)))
  117. {})))
  118. (rum/defc right-menu-button < rum/reactive
  119. []
  120. [:a.cp__right-menu-button
  121. {:on-click state/toggle-sidebar-open?!}
  122. (svg/menu)])
  123. (rum/defc header
  124. < rum/reactive
  125. [{:keys [open-fn current-repo white? logged? page? route-match me default-home new-block-mode]}]
  126. (let [local-repo? (= current-repo config/local-repo)
  127. repos (->> (state/sub [:me :repos])
  128. (remove #(= (:url %) config/local-repo)))]
  129. (rum/with-context [[t] i18n/*tongue-context*]
  130. [:div.cp__header#head
  131. (left-menu-button {:on-click (fn []
  132. (open-fn)
  133. (state/set-left-sidebar-open! true))})
  134. (logo {:white? white?})
  135. (if current-repo
  136. (search/search)
  137. [:div.flex-1])
  138. (new-block-mode)
  139. (when (and (not logged?)
  140. (not config/publishing?))
  141. (ui/dropdown-with-links
  142. (fn [{:keys [toggle-fn]}]
  143. [:a {:on-click toggle-fn}
  144. [:span.ml-1.text-sm (t :login)]])
  145. (let [list [{:title (t :login-google)
  146. :url "/login/google"}
  147. {:title (t :login-github)
  148. :url "/login/github"}]]
  149. (mapv
  150. (fn [{:keys [title url]}]
  151. {:title title
  152. :options
  153. {:on-click
  154. (fn [_] (set! (.-href js/window.location) url))}})
  155. list))))
  156. (repo/sync-status)
  157. [:div.repos.hidden.md:block
  158. (repo/repos-dropdown true)]
  159. (when (and (nfs/supported?) (empty? repos))
  160. [:a.text-sm.font-medium.opacity-70.hover:opacity-100.ml-3.block
  161. {:on-click (fn []
  162. (nfs/ls-dir-files))}
  163. [:div.flex.flex-row.text-center
  164. [:span.inline-block svg/folder-add]
  165. (when-not config/mobile?
  166. [:span.ml-1 {:style {:margin-top 2}}
  167. (t :open)])]])
  168. (if config/publishing?
  169. [:a.text-sm.font-medium.ml-3 {:href (rfe/href :graph)}
  170. (t :graph)]
  171. (dropdown-menu {:me me
  172. :t t
  173. :current-repo current-repo
  174. :default-home default-home}))
  175. [:a#download-as-html.hidden]
  176. [:a#download-as-zip.hidden]
  177. (right-menu-button)])))