block.cljs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. (ns frontend.components.file-based.block
  2. (:require [clojure.string :as string]
  3. [frontend.commands :as commands]
  4. [frontend.components.file-based.datetime :as datetime-comp]
  5. [frontend.handler.editor :as editor-handler]
  6. [frontend.handler.file-based.repeated :as repeated]
  7. [frontend.state :as state]
  8. [frontend.ui :as ui]
  9. [frontend.util :as util]
  10. [frontend.util.file-based.clock :as clock]
  11. [frontend.util.file-based.drawer :as drawer]
  12. [logseq.shui.hooks :as hooks]
  13. [logseq.shui.ui :as shui]
  14. [reitit.frontend.easy :as rfe]
  15. [rum.core :as rum]))
  16. (defn marker-switch
  17. [{:block/keys [marker] :as block}]
  18. (when (contains? #{"NOW" "LATER" "TODO" "DOING"} marker)
  19. (let [set-marker-fn (fn [new-marker]
  20. (fn [e]
  21. (util/stop e)
  22. (editor-handler/set-marker block new-marker)))
  23. next-marker (case marker
  24. "NOW" "LATER"
  25. "LATER" "NOW"
  26. "TODO" "DOING"
  27. "DOING" "TODO")]
  28. [:a
  29. {:class (str "marker-switch block-marker " marker)
  30. :title (util/format "Change from %s to %s" marker next-marker)
  31. :on-pointer-down (set-marker-fn next-marker)}
  32. marker])))
  33. (defn block-checkbox
  34. [block class]
  35. (let [marker (:block/marker block)
  36. [class checked?] (cond
  37. (nil? marker)
  38. nil
  39. (contains? #{"NOW" "LATER" "DOING" "IN-PROGRESS" "TODO" "WAIT" "WAITING"} marker)
  40. [class false]
  41. (= "DONE" marker)
  42. [(str class " checked") true])]
  43. (when class
  44. (ui/checkbox {:class class
  45. :style {:margin-right 5}
  46. :checked checked?
  47. :on-pointer-down (fn [e]
  48. (util/stop-propagation e))
  49. :on-change (fn [_e]
  50. (if checked?
  51. (editor-handler/uncheck block)
  52. (editor-handler/check block)))}))))
  53. (defn marker-cp
  54. [{:block/keys [pre-block? marker] :as _block}]
  55. (when-not pre-block?
  56. (when (contains? #{"IN-PROGRESS" "WAIT" "WAITING"} marker)
  57. [:span {:class (str "task-status block-marker " (string/lower-case marker))
  58. :style {:margin-right 3.5}}
  59. (string/upper-case marker)])))
  60. (rum/defc set-priority
  61. [block priority]
  62. [:div
  63. (let [priorities (sort (remove #(= priority %) ["A" "B" "C"]))]
  64. (for [p priorities]
  65. [:a.mr-2.text-base.tooltip-priority {:key (str (random-uuid))
  66. :priority p
  67. :on-click (fn [] (editor-handler/set-priority block p))}]))])
  68. (rum/defc priority-text
  69. [priority]
  70. [:a.opacity-50.hover:opacity-100
  71. {:class "priority"
  72. :href (rfe/href :page {:name priority})
  73. :style {:margin-right 3.5}}
  74. (util/format "[#%s]" (str priority))])
  75. (defn priority-cp
  76. [{:block/keys [pre-block? priority] :as block}]
  77. (when (and (not pre-block?) priority)
  78. (ui/tooltip
  79. (priority-text priority)
  80. (set-priority block priority))))
  81. (defn clock-summary-cp
  82. [block body]
  83. (when (and (state/enable-timetracking?)
  84. (or (= (:block/marker block) "DONE")
  85. (contains? #{"TODO" "LATER"} (:block/marker block))))
  86. (let [summary (clock/clock-summary body true)]
  87. (when (and summary
  88. (not= summary "0m")
  89. (not (string/blank? summary)))
  90. [:div {:style {:max-width 100}}
  91. (ui/tooltip
  92. [:div.text-sm.time-spent.ml-1 {:style {:padding-top 3}}
  93. [:a.fade-link
  94. summary]]
  95. (when-let [logbook (drawer/get-logbook body)]
  96. (let [clocks (->> (last logbook)
  97. (filter #(string/starts-with? % "CLOCK:"))
  98. (remove string/blank?))]
  99. [:div.p-4
  100. [:div.font-bold.mb-2 "LOGBOOK:"]
  101. [:ul
  102. (for [clock (take 10 (reverse clocks))]
  103. [:li clock])]])))]))))
  104. (rum/defc timestamp-editor
  105. [ast *show-datapicker?]
  106. (let [*trigger-ref (rum/use-ref nil)]
  107. (hooks/use-effect!
  108. (fn []
  109. (let [pid (shui/popup-show!
  110. (.closest (rum/deref *trigger-ref) "a")
  111. (datetime-comp/date-picker nil nil (repeated/timestamp->map ast))
  112. {:id :timestamp-editor
  113. :align :start
  114. :root-props {:onOpenChange #(reset! *show-datapicker? %)}
  115. :content-props {:onEscapeKeyDown #(reset! *show-datapicker? false)}})]
  116. #(do (shui/popup-hide! pid)
  117. (reset! *show-datapicker? false))))
  118. [])
  119. [:i {:ref *trigger-ref}]))
  120. (rum/defcs timestamp-cp
  121. < rum/reactive
  122. (rum/local false ::show-datepicker?)
  123. [state block typ ast]
  124. (let [ts-block-id (get-in (state/sub [:editor/set-timestamp-block]) [:block :block/uuid])
  125. _active? (= (get block :block/uuid) ts-block-id)
  126. *show-datapicker? (get state ::show-datepicker?)]
  127. [:div.flex.flex-col.gap-4.timestamp
  128. [:div.text-sm.flex.flex-row
  129. [:div.opacity-50.font-medium.timestamp-label
  130. (str typ ": ")]
  131. [:a.opacity-80.hover:opacity-100
  132. {:on-pointer-down (fn [e]
  133. (util/stop e)
  134. (state/clear-editor-action!)
  135. (editor-handler/escape-editing)
  136. (reset! *show-datapicker? true)
  137. (reset! commands/*current-command typ)
  138. (state/set-timestamp-block! {:block block
  139. :typ typ}))}
  140. [:span.time-start "<"] [:time (repeated/timestamp->text ast)] [:span.time-stop ">"]
  141. (when (and _active? @*show-datapicker?)
  142. (timestamp-editor ast *show-datapicker?))]]]))