reference.cljs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. (ns frontend.components.reference
  2. (:require [clojure.string :as string]
  3. [frontend.components.block :as block]
  4. [frontend.components.content :as content]
  5. [frontend.components.editor :as editor]
  6. [frontend.date :as date]
  7. [frontend.db :as db]
  8. [frontend.db.model :as model-db]
  9. [frontend.db-mixins :as db-mixins]
  10. [frontend.handler.block :as block-handler]
  11. [frontend.handler.page :as page-handler]
  12. [frontend.state :as state]
  13. [frontend.ui :as ui]
  14. [frontend.util :as util]
  15. [medley.core :as medley]
  16. [rum.core :as rum]))
  17. (rum/defc filter-dialog-inner < rum/reactive
  18. [filters-atom _close-fn references page-name]
  19. [:div.filters
  20. [:div.sm:flex.sm:items-start
  21. [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-gray-200.text-gray-500.sm:mx-0.sm:h-10.sm:w-10
  22. (ui/icon "filter" {:style {:fontSize 20}})]
  23. [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
  24. [:h3#modal-headline.text-lg.leading-6.font-medium "Filter"]
  25. [:span.text-xs
  26. "Click to include and shift-click to exclude. Click again to remove."]]]
  27. (when (seq references)
  28. (let [filters (rum/react filters-atom)]
  29. [:div.mt-5.sm:mt-4.sm:flex.sm.gap-1.flex-wrap
  30. (for [reference references]
  31. (let [lc-reference (string/lower-case reference)
  32. filtered (get filters lc-reference)
  33. color (condp = filtered
  34. true "text-green-400"
  35. false "text-red-400"
  36. nil)]
  37. [:button.border.rounded.px-1.mb-1.mr-1 {:key reference :class color :style {:border-color "currentColor"}
  38. :on-click (fn [e]
  39. (swap! filters-atom #(if (nil? (get filters lc-reference))
  40. (assoc % lc-reference (not (.-shiftKey e)))
  41. (dissoc % lc-reference)))
  42. (page-handler/save-filter! page-name @filters-atom))}
  43. reference]))]))])
  44. (defn filter-dialog
  45. [filters-atom references page-name]
  46. (fn [close-fn]
  47. (filter-dialog-inner filters-atom close-fn references page-name)))
  48. (defn- block-with-ref-level
  49. [block level]
  50. (if (:block/children block)
  51. (-> (update block :block/children
  52. (fn [blocks]
  53. (map (fn [block]
  54. (let [level (inc level)
  55. block (assoc block :ref/level level)]
  56. (block-with-ref-level block level))) blocks)))
  57. (assoc :ref/level level))
  58. (assoc block :ref/level level)))
  59. (defn- blocks-with-ref-level
  60. [page-blocks]
  61. (map (fn [[page blocks]]
  62. [page (map #(block-with-ref-level % 1) blocks)])
  63. page-blocks))
  64. (rum/defcs references < rum/reactive db-mixins/query
  65. (rum/local nil ::n-ref)
  66. {:init (fn [state]
  67. (let [page-name (first (:rum/args state))
  68. filters (when page-name
  69. (atom (page-handler/get-filters (string/lower-case page-name))))]
  70. (assoc state ::filters filters)))}
  71. [state page-name _marker?]
  72. (when page-name
  73. (let [page-name (string/lower-case page-name)
  74. repo (state/get-current-repo)
  75. threshold (state/get-linked-references-collapsed-threshold)
  76. refed-blocks-ids (model-db/get-referenced-blocks-ids page-name)
  77. *n-ref (::n-ref state)
  78. n-ref (or (rum/react *n-ref) (count refed-blocks-ids))
  79. default-collapsed? (>= (count refed-blocks-ids) threshold)
  80. filters-atom (get state ::filters)
  81. filter-state (rum/react filters-atom)
  82. block? (util/uuid-string? page-name)
  83. block-id (and block? (uuid page-name))
  84. page-name (string/lower-case page-name)
  85. journal? (date/valid-journal-title? (string/capitalize page-name))
  86. scheduled-or-deadlines (when (and journal?
  87. (not (true? (state/scheduled-deadlines-disabled?)))
  88. (= page-name (string/lower-case (date/journal-name))))
  89. (db/get-date-scheduled-or-deadlines (string/capitalize page-name)))]
  90. (when (or (seq refed-blocks-ids)
  91. (seq scheduled-or-deadlines)
  92. (seq filter-state))
  93. [:div.references.mt-6.flex-1.flex-row
  94. [:div.content
  95. (when (seq scheduled-or-deadlines)
  96. (ui/foldable
  97. [:h2.font-bold.opacity-50 "SCHEDULED AND DEADLINE"]
  98. [:div.references-blocks.mb-6
  99. (let [ref-hiccup (block/->hiccup scheduled-or-deadlines
  100. {:id (str page-name "-agenda")
  101. :ref? true
  102. :group-by-page? true
  103. :editor-box editor/box}
  104. {})]
  105. (content/content page-name {:hiccup ref-hiccup}))]
  106. {:title-trigger? true}))
  107. (when (seq refed-blocks-ids)
  108. (ui/foldable
  109. [:div.flex.flex-row.flex-1.justify-between.items-center
  110. [:h2.font-bold.opacity-50 (str n-ref " Linked Reference"
  111. (when (> n-ref 1) "s"))]
  112. [:a.filter.fade-link
  113. {:title "Filter"
  114. :on-mouse-down (fn [e] (util/stop-propagation e))
  115. :on-click (fn []
  116. (let [ref-blocks (if block-id
  117. (db/get-block-referenced-blocks block-id)
  118. (db/get-page-referenced-blocks page-name))
  119. ref-pages (map (comp :block/original-name first) ref-blocks)
  120. references (db/get-page-linked-refs-refed-pages repo page-name)
  121. references (->> (concat ref-pages references)
  122. (remove nil?)
  123. (distinct))]
  124. (state/set-modal! (filter-dialog filters-atom references page-name))))}
  125. (ui/icon "filter" {:class (cond
  126. (empty? filter-state)
  127. ""
  128. (every? true? (vals filter-state))
  129. "text-green-400"
  130. (every? false? (vals filter-state))
  131. "text-red-400"
  132. :else
  133. "text-yellow-400")
  134. :style {:fontSize 24}})]]
  135. (fn []
  136. (let [ref-blocks (if block-id
  137. (db/get-block-referenced-blocks block-id)
  138. (db/get-page-referenced-blocks page-name))
  139. filters (when (seq filter-state)
  140. (->> (group-by second filter-state)
  141. (medley/map-vals #(map first %))))
  142. filtered-ref-blocks (->> (block-handler/filter-blocks repo ref-blocks filters true)
  143. blocks-with-ref-level)
  144. n-ref (apply +
  145. (for [[_ rfs] filtered-ref-blocks]
  146. (count rfs)))]
  147. (reset! *n-ref n-ref)
  148. [:div.references-blocks
  149. (let [ref-hiccup (block/->hiccup filtered-ref-blocks
  150. {:id page-name
  151. :ref? true
  152. :breadcrumb-show? true
  153. :group-by-page? true
  154. :editor-box editor/box
  155. :filters filters}
  156. {})]
  157. (content/content page-name
  158. {:hiccup ref-hiccup}))]))
  159. {:default-collapsed? default-collapsed?
  160. :title-trigger? true}))]]))))
  161. (rum/defcs unlinked-references-aux
  162. < rum/reactive db-mixins/query
  163. {:wrap-render
  164. (fn [render-fn]
  165. (fn [state]
  166. (reset! (second (:rum/args state))
  167. (apply +
  168. (for [[_ rfs]
  169. (db/get-page-unlinked-references
  170. (first (:rum/args state)))]
  171. (count rfs))))
  172. (render-fn state)))}
  173. [state page-name _n-ref]
  174. (let [ref-blocks (db/get-page-unlinked-references page-name)]
  175. [:div.references-blocks
  176. (let [ref-hiccup (block/->hiccup ref-blocks
  177. {:id (str page-name "-unlinked-")
  178. :ref? true
  179. :group-by-page? true
  180. :editor-box editor/box}
  181. {})]
  182. (content/content page-name
  183. {:hiccup ref-hiccup}))]))
  184. (rum/defcs unlinked-references < rum/reactive
  185. (rum/local nil ::n-ref)
  186. [state page-name]
  187. (let [n-ref (get state ::n-ref)]
  188. (when page-name
  189. (let [page-name (string/lower-case page-name)]
  190. [:div.references.mt-6.flex-1.flex-row
  191. [:div.content.flex-1
  192. (ui/foldable
  193. [:h2.font-bold {:style {:opacity "0.3"}}
  194. (if @n-ref
  195. (str @n-ref " Unlinked Reference" (when (> @n-ref 1)
  196. "s"))
  197. "Unlinked References")]
  198. (fn [] (unlinked-references-aux page-name n-ref))
  199. {:default-collapsed? true
  200. :title-trigger? true})]]))))