datetime.cljs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. (ns frontend.components.datetime
  2. (:require [cljs-time.core :as t]
  3. [clojure.string :as string]
  4. [frontend.commands :as commands]
  5. [frontend.components.svg :as svg]
  6. [frontend.date :as date]
  7. [frontend.handler.editor :as editor-handler]
  8. [frontend.handler.repeated :as repeated]
  9. [frontend.state :as state]
  10. [frontend.ui :as ui]
  11. [frontend.util :as util]
  12. [frontend.mixins :as mixins]
  13. [rum.core :as rum]
  14. [logseq.common.util.page-ref :as page-ref]))
  15. (defonce default-timestamp-value {:time ""
  16. :repeater {}})
  17. (defonce *timestamp (atom default-timestamp-value))
  18. (defonce *show-time? (atom false))
  19. (rum/defc time-input < rum/reactive
  20. [default-value]
  21. (let [show? (rum/react *show-time?)]
  22. (if (or show? (not (string/blank? default-value)))
  23. [:div.flex.flex-row {:style {:height 32}}
  24. [:input#time.form-input.w-20.ms:w-60
  25. {:default-value default-value
  26. :on-change (fn [event]
  27. (util/stop event)
  28. (let [value (util/evalue event)]
  29. (swap! *timestamp assoc :time value)))}]
  30. [:a.ml-2.self-center {:on-click (fn []
  31. (reset! *show-time? false)
  32. (swap! *timestamp assoc :time nil))}
  33. svg/close]]
  34. [:a.text-sm {:on-click (fn []
  35. (reset! *show-time? true)
  36. (let [{:keys [hour minute]} (date/get-local-date)
  37. result (str hour ":" (util/zero-pad minute))]
  38. (swap! *timestamp assoc :time result)))}
  39. "Add time"])))
  40. (defonce *show-repeater? (atom false))
  41. (rum/defc repeater-cp < rum/reactive
  42. [{:keys [num duration kind]}]
  43. (let [show? (rum/react *show-repeater?)]
  44. (if (or show? (and num duration kind))
  45. [:div.w.full.flex.flex-row.justify-left
  46. [:input#repeater-num.form-input.w-8.mr-2.px-1.sm:w-20.sm:px-2.text-center
  47. {:default-value num
  48. :on-change (fn [event]
  49. (let [value (util/evalue event)]
  50. (swap! *timestamp assoc-in [:repeater :num] value)))}]
  51. (ui/select
  52. (mapv
  53. (fn [item]
  54. (if (= (:label item) duration)
  55. (assoc item :selected "selected")
  56. item))
  57. [{:label "h"}
  58. {:label "d"}
  59. {:label "w"}
  60. {:label "m"}
  61. {:label "y"}])
  62. (fn [_e value]
  63. (swap! *timestamp assoc-in [:repeater :duration] value)))
  64. [:a.ml-2.self-center {:on-click (fn []
  65. (reset! *show-repeater? false)
  66. (swap! *timestamp assoc :repeater {}))}
  67. svg/close]]
  68. [:a.text-sm {:on-click (fn []
  69. (reset! *show-repeater? true)
  70. (swap! *timestamp assoc :repeater
  71. {:kind ".+"
  72. :num 1
  73. :duration "d"}))}
  74. "Add repeater"])))
  75. (defn- clear-timestamp!
  76. []
  77. (reset! *timestamp default-timestamp-value)
  78. (reset! *show-time? false)
  79. (reset! *show-repeater? false)
  80. (state/set-state! :date-picker/date nil))
  81. (defn- on-submit
  82. "Submit handler of date picker"
  83. [e]
  84. (when e (util/stop e))
  85. (let [{:keys [repeater] :as timestamp} @*timestamp
  86. date (:date-picker/date @state/state)
  87. timestamp (assoc timestamp :date (or date (t/today)))
  88. kind (if (= "w" (:duration repeater)) "++" ".+")
  89. timestamp (assoc-in timestamp [:repeater :kind] kind)
  90. text (repeated/timestamp-map->text timestamp)
  91. block-data (state/get-timestamp-block)
  92. {:keys [block typ show?]} block-data
  93. editing-block-id (:block/uuid (state/get-edit-block))
  94. block-id (or (:block/uuid block)
  95. editing-block-id)
  96. typ (or @commands/*current-command typ)]
  97. (if (and (state/editing?) (= editing-block-id block-id))
  98. (editor-handler/set-editing-block-timestamp! typ
  99. text)
  100. (editor-handler/set-block-timestamp! block-id
  101. typ
  102. text))
  103. (when show?
  104. (reset! show? false)))
  105. (clear-timestamp!)
  106. (state/set-timestamp-block! nil)
  107. (commands/restore-state))
  108. (rum/defc time-repeater < rum/reactive
  109. (mixins/event-mixin
  110. (fn [state]
  111. (when-let [input (state/get-input)]
  112. (js/setTimeout #(mixins/on-enter state
  113. :node input
  114. :on-enter on-submit) 100))))
  115. []
  116. (let [{:keys [time repeater]} (rum/react *timestamp)]
  117. [:div#time-repeater.py-1.px-4
  118. [:p.text-sm.opacity-50.font-medium.mt-4 "Time:"]
  119. (time-input time)
  120. [:p.text-sm.opacity-50.font-medium.mt-4 "Repeater:"]
  121. (repeater-cp repeater)
  122. [:p.mt-4
  123. (ui/button "Submit"
  124. :on-click on-submit)]]))
  125. (rum/defc date-picker < rum/reactive
  126. {:init (fn [state]
  127. (let [ts (last (:rum/args state))]
  128. (clear-timestamp!)
  129. (if ts
  130. (reset! *timestamp ts)
  131. (reset! *timestamp {:time ""
  132. :repeater {}}))
  133. (when-not (:date-picker/date @state/state)
  134. (state/set-state! :date-picker/date (get ts :date (t/today)))))
  135. state)}
  136. [dom-id format _ts]
  137. (let [current-command @commands/*current-command
  138. deadline-or-schedule? (and current-command
  139. (contains? #{"deadline" "scheduled"}
  140. (string/lower-case current-command)))
  141. date (state/sub :date-picker/date)]
  142. [:div#date-time-picker.flex.flex-col.sm:flex-row {:on-click (fn [e] (util/stop e))
  143. :on-pointer-down (fn [e] (.stopPropagation e))}
  144. (ui/datepicker
  145. date
  146. {:deadline-or-schedule? deadline-or-schedule?
  147. :on-change
  148. (fn [e date]
  149. (util/stop e)
  150. (let [date (t/to-default-time-zone date)
  151. journal (date/journal-name date)]
  152. ;; deadline-or-schedule? is handled in on-submit, not here
  153. (when-not deadline-or-schedule?
  154. ;; similar to page reference
  155. (editor-handler/insert-command! dom-id
  156. (page-ref/->page-ref journal)
  157. format
  158. {:command :page-ref})
  159. (state/clear-editor-action!)
  160. (reset! commands/*current-command nil))))})
  161. (when deadline-or-schedule?
  162. (time-repeater))]))