right_sidebar.cljs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. (ns frontend.components.right-sidebar
  2. (:require [rum.core :as rum]
  3. [frontend.ui :as ui]
  4. [frontend.components.svg :as svg]
  5. [frontend.components.page :as page]
  6. [frontend.components.block :as block]
  7. [frontend.extensions.graph-2d :as graph-2d]
  8. [frontend.components.onboarding :as onboarding]
  9. [frontend.handler.route :as route-handler]
  10. [frontend.handler.page :as page-handler]
  11. [frontend.handler.graph :as graph-handler]
  12. [frontend.state :as state]
  13. [frontend.db :as db]
  14. [frontend.db.model :as db-model]
  15. [frontend.util :as util]
  16. [frontend.date :as date]
  17. [medley.core :as medley]
  18. [clojure.string :as string]
  19. [frontend.extensions.slide :as slide]
  20. [cljs-bean.core :as bean]
  21. [goog.object :as gobj]
  22. [frontend.graph :as graph]
  23. [frontend.context.i18n :as i18n]
  24. [reitit.frontend.easy :as rfe]
  25. [frontend.db-mixins :as db-mixins]
  26. [frontend.config :as config]))
  27. (rum/defc block-cp < rum/reactive
  28. [repo idx block]
  29. (let [id (:block/uuid block)]
  30. (page/page {:parameters {:path {:name (str id)}}
  31. :sidebar? true
  32. :sidebar/idx idx
  33. :repo repo})))
  34. (rum/defc page-cp < rum/reactive
  35. [repo page-name]
  36. (page/page {:parameters {:path {:name page-name}}
  37. :sidebar? true
  38. :repo repo}))
  39. (rum/defc page-graph < db-mixins/query
  40. [page]
  41. (let [theme (:ui/theme @state/state)
  42. dark? (= theme "dark")
  43. graph (if (util/uuid-string? page)
  44. (graph-handler/build-block-graph (uuid page) theme)
  45. (graph-handler/build-page-graph page theme))]
  46. (when (seq (:nodes graph))
  47. [:div.sidebar-item.flex-col.flex-1
  48. (graph-2d/graph
  49. (graph/build-graph-opts
  50. graph dark? false
  51. {:width 600
  52. :height 600}))])))
  53. (defn recent-pages
  54. []
  55. (let [pages (->> (db/get-key-value :recent/pages)
  56. (remove #(= (string/lower-case %) "contents")))]
  57. [:div.recent-pages.text-sm.flex-col.flex.ml-3.mt-2
  58. (if (seq pages)
  59. (for [page pages]
  60. [:a.mb-1 {:key (str "recent-page-" page)
  61. :href (rfe/href :page {:name page})
  62. :on-click (fn [e]
  63. (when (gobj/get e "shiftKey")
  64. (when-let [page (db/pull [:block/name (string/lower-case page)])]
  65. (state/sidebar-add-block!
  66. (state/get-current-repo)
  67. (:db/id page)
  68. :page
  69. {:page page}))
  70. (.preventDefault e)))}
  71. page]))]))
  72. (rum/defc contents < rum/reactive db-mixins/query
  73. []
  74. [:div.contents.flex-col.flex.ml-3
  75. (when-let [contents (db/entity [:block/name "contents"])]
  76. (page/contents-page contents))])
  77. (defn build-sidebar-item
  78. [repo idx db-id block-type block-data t]
  79. (case block-type
  80. :contents
  81. [[:a {:on-click (fn [e]
  82. (util/stop e)
  83. (if-not (db/entity [:block/name "contents"])
  84. (page-handler/create! "contents")
  85. (route-handler/redirect! {:to :page
  86. :path-params {:name "contents"}})))}
  87. (t :right-side-bar/contents)]
  88. (contents)]
  89. :recent
  90. [(t :right-side-bar/recent) (recent-pages)]
  91. :help
  92. [(t :right-side-bar/help) (onboarding/help)]
  93. :page-graph
  94. [(str (t :right-side-bar/graph-ref) (db-model/get-page-original-name block-data))
  95. (page-graph block-data)]
  96. :block-ref
  97. (when-let [block (db/entity repo [:block/uuid (:block/uuid (:block block-data))])]
  98. [(t :right-side-bar/block-ref)
  99. (let [block (:block block-data)
  100. block-id (:block/uuid block)
  101. format (:block/format block)]
  102. [[:div.ml-2.mt-1
  103. (block/block-parents {:id "block-parent"
  104. :block? true} repo block-id format)]
  105. [:div.ml-2
  106. (block-cp repo idx block)]])])
  107. :block
  108. (when-let [block (db/entity repo [:block/uuid (:block/uuid block-data)])]
  109. (let [block-id (:block/uuid block-data)
  110. format (:block/format block-data)]
  111. [(block/block-parents {:id "block-parent"
  112. :block? true} repo block-id format)
  113. [:div.ml-2
  114. (block-cp repo idx block-data)]]))
  115. :page
  116. (let [page-name (:block/name block-data)]
  117. [[:a {:href (rfe/href :page {:name page-name})
  118. :on-click (fn [e]
  119. (when (gobj/get e "shiftKey")
  120. (.preventDefault e)))}
  121. (db-model/get-page-original-name page-name)]
  122. [:div.ml-2
  123. (page-cp repo page-name)]])
  124. :page-presentation
  125. (let [page-name (get-in block-data [:page :block/name])
  126. journal? (:journal? block-data)
  127. blocks (db/get-page-blocks repo page-name)
  128. blocks (if journal?
  129. (rest blocks)
  130. blocks)
  131. sections (block/build-slide-sections blocks {:id "slide-reveal-js"
  132. :start-level 2
  133. :slide? true
  134. :sidebar? true
  135. :page-name page-name})]
  136. [[:a {:href (rfe/href :page {:name page-name})}
  137. (db-model/get-page-original-name page-name)]
  138. [:div.ml-2.slide.mt-2
  139. (slide/slide sections)]])
  140. ["" [:span]]))
  141. (defn close
  142. ([on-close]
  143. (close nil on-close))
  144. ([class on-close]
  145. [:a.close.opacity-50.hover:opacity-100.flex.items-center
  146. (cond-> {:on-click on-close}
  147. class
  148. (assoc :class class))
  149. svg/close]))
  150. (rum/defc sidebar-item < rum/reactive
  151. [repo idx db-id block-type block-data t]
  152. (let [item
  153. (if (= :page block-type)
  154. (let [page (db/query-entity-in-component db-id)]
  155. (when (seq page)
  156. (build-sidebar-item repo idx db-id block-type page t)))
  157. (build-sidebar-item repo idx db-id block-type block-data t))]
  158. (when item
  159. (let [collapse? (state/sub [:ui/sidebar-collapsed-blocks db-id])]
  160. [:div.sidebar-item.content.color-level
  161. (let [[title component] item]
  162. [:div.flex.flex-col
  163. [:div.flex.flex-row.justify-between
  164. [:div.flex.flex-row.justify-center
  165. [:a.opacity-50.hover:opacity-100.flex.items-center.pr-1
  166. {:on-click #(state/sidebar-block-toggle-collapse! db-id)}
  167. (if collapse?
  168. (svg/caret-right)
  169. (svg/caret-down))]
  170. [:div.ml-1
  171. title]]
  172. (close #(state/sidebar-remove-block! idx))]
  173. [:div {:class (if collapse? "hidden" "initial")}
  174. component]])]))))
  175. (defn- get-page
  176. [match]
  177. (let [route-name (get-in match [:data :name])
  178. page (case route-name
  179. :page
  180. (get-in match [:path-params :name])
  181. :file
  182. (get-in match [:path-params :path])
  183. (date/journal-name))]
  184. (if page
  185. (string/lower-case page))))
  186. (defn get-current-page
  187. []
  188. (let [match (:route-match @state/state)
  189. theme (:ui/theme @state/state)]
  190. (get-page match)))
  191. (rum/defc sidebar-resizer
  192. []
  193. (let [el-ref (rum/use-ref nil)]
  194. (rum/use-effect!
  195. (fn []
  196. (when-let [el (and (fn? js/window.interact) (rum/deref el-ref))]
  197. (-> (js/interact el)
  198. (.draggable
  199. (bean/->js
  200. {:listeners
  201. {:move
  202. (fn [^js/MouseEvent e]
  203. (let [width js/document.documentElement.clientWidth
  204. offset (.-left (.-rect e))
  205. to-val (- 1 (.toFixed (/ offset width) 6))
  206. to-val (cond
  207. (< to-val 0.2) 0.2
  208. (> to-val 0.7) 0.7
  209. :else to-val)]
  210. (.setProperty (.-style js/document.documentElement)
  211. "--ls-right-sidebar-width"
  212. (str (* to-val 100) "%"))))}}))
  213. (.styleCursor false)
  214. (.on "dragstart" #(.. js/document.documentElement -classList (add "is-resizing-buf")))
  215. (.on "dragend" #(.. js/document.documentElement -classList (remove "is-resizing-buf")))))
  216. #())
  217. [])
  218. [:span.resizer {:ref el-ref}]))
  219. (rum/defcs sidebar < rum/reactive
  220. [state]
  221. (let [blocks (state/sub :sidebar/blocks)
  222. blocks (if (empty? blocks)
  223. [[(state/get-current-repo) "contents" :contents nil]]
  224. blocks)
  225. sidebar-open? (state/sub :ui/sidebar-open?)
  226. repo (state/sub :git/current-repo)
  227. match (state/sub :route-match)
  228. theme (state/sub :ui/theme)
  229. t (i18n/use-tongue)]
  230. (rum/with-context [[t] i18n/*tongue-context*]
  231. [:div#right-sidebar.cp__right-sidebar
  232. {:class (if sidebar-open? "is-open")}
  233. (if sidebar-open?
  234. [:div.cp__right-sidebar-inner
  235. (sidebar-resizer)
  236. [:div.flex.flex-row.justify-between.items-center
  237. [:div.cp__right-sidebar-settings.hide-scrollbar {:key "right-sidebar-settings"}
  238. [:div.ml-4.text-sm
  239. [:a.cp__right-sidebar-settings-btn {:on-click (fn [e]
  240. (state/sidebar-add-block! repo "contents" :contents nil))}
  241. (t :right-side-bar/contents)]]
  242. [:div.ml-4.text-sm
  243. [:a.cp__right-sidebar-settings-btn {:on-click (fn [_e]
  244. (state/sidebar-add-block! repo "recent" :recent nil))}
  245. (t :right-side-bar/recent)]]
  246. [:div.ml-4.text-sm
  247. [:a.cp__right-sidebar-settings-btn {:on-click (fn []
  248. (when-let [page (get-current-page)]
  249. (state/sidebar-add-block!
  250. repo
  251. (str "page-graph-" page)
  252. :page-graph
  253. page)))}
  254. (t :right-side-bar/page)]]
  255. [:div.ml-4.text-sm
  256. [:a.cp__right-sidebar-settings-btn {:on-click (fn [_e]
  257. (state/sidebar-add-block! repo "help" :help nil))}
  258. (t :right-side-bar/help)]]]
  259. [:a.close-arrow.opacity-50.hover:opacity-100 {:on-click state/toggle-sidebar-open?!}
  260. (svg/big-arrow-right)]]
  261. (for [[idx [repo db-id block-type block-data]] (medley/indexed blocks)]
  262. (rum/with-key
  263. (sidebar-item repo idx db-id block-type block-data t)
  264. (str "sidebar-block-" idx)))])])))