datetime.cljs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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.graph-parser.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 {:style {:height 32}}
  46. [:input#repeater-num.form-input.mt-1.w-8.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 [value]
  63. (swap! *timestamp assoc-in [:repeater :duration] value))
  64. nil)
  65. [:a.ml-1.self-center {:on-click (fn []
  66. (reset! *show-repeater? false)
  67. (swap! *timestamp assoc :repeater {}))}
  68. svg/close]]
  69. [:a.text-sm {:on-click (fn []
  70. (reset! *show-repeater? true)
  71. (swap! *timestamp assoc :repeater
  72. {:kind ".+"
  73. :num 1
  74. :duration "d"}))}
  75. "Add repeater"])))
  76. (defn clear-timestamp!
  77. []
  78. (reset! *timestamp default-timestamp-value)
  79. (reset! *show-time? false)
  80. (reset! *show-repeater? false)
  81. (state/set-timestamp-block! nil)
  82. (state/set-state! :date-picker/date nil))
  83. (defn- on-submit
  84. [e]
  85. (when e (util/stop e))
  86. (let [{:keys [repeater] :as timestamp} @*timestamp
  87. date (:date-picker/date @state/state)
  88. timestamp (assoc timestamp :date (or date (t/today)))
  89. kind (if (= "w" (:duration repeater)) "++" ".+")
  90. timestamp (assoc-in timestamp [:repeater :kind] kind)
  91. text (repeated/timestamp-map->text timestamp)
  92. block-data (state/get-timestamp-block)
  93. {:keys [block typ show?]} block-data
  94. block-id (or (:block/uuid block)
  95. (:block/uuid (state/get-edit-block)))
  96. typ (or @commands/*current-command typ)]
  97. (editor-handler/set-block-timestamp! block-id
  98. typ
  99. text)
  100. (when show?
  101. (reset! show? false)))
  102. (clear-timestamp!)
  103. (commands/restore-state))
  104. (rum/defc time-repeater < rum/reactive
  105. (mixins/event-mixin
  106. (fn [state]
  107. (when-let [input (state/get-input)]
  108. (js/setTimeout #(mixins/on-enter state
  109. :node input
  110. :on-enter on-submit) 100))))
  111. []
  112. (let [{:keys [time repeater]} (rum/react *timestamp)]
  113. [:div#time-repeater.py-1.px-4
  114. [:p.text-sm.opacity-50.font-medium.mt-4 "Time:"]
  115. (time-input time)
  116. [:p.text-sm.opacity-50.font-medium.mt-4 "Repeater:"]
  117. (repeater-cp repeater)
  118. [:p.mt-4
  119. (ui/button "Submit"
  120. :on-click on-submit)]]))
  121. (rum/defc date-picker < rum/reactive
  122. {:init (fn [state]
  123. (let [ts (last (:rum/args state))]
  124. (if ts
  125. (reset! *timestamp ts)
  126. (reset! *timestamp {:time ""
  127. :repeater {}}))
  128. (when-not (:date-picker/date @state/state)
  129. (state/set-state! :date-picker/date (t/today))))
  130. state)
  131. :will-unmount (fn [state]
  132. (clear-timestamp!)
  133. state)}
  134. [id format _ts]
  135. (let [current-command @commands/*current-command
  136. deadline-or-schedule? (and current-command
  137. (contains? #{"deadline" "scheduled"}
  138. (string/lower-case current-command)))
  139. date (state/sub :date-picker/date)]
  140. (when (= :datepicker (state/sub :editor/action))
  141. [:div#date-time-picker.flex.flex-row {:on-click (fn [e] (util/stop e))
  142. :on-mouse-down (fn [e] (.stopPropagation e))}
  143. (ui/datepicker
  144. date
  145. {:deadline-or-schedule? deadline-or-schedule?
  146. :on-change
  147. (fn [e date]
  148. (util/stop e)
  149. (let [date (t/to-default-time-zone date)
  150. journal (date/journal-name date)]
  151. (when-not deadline-or-schedule?
  152. ;; similar to page reference
  153. (editor-handler/insert-command! id
  154. (page-ref/->page-ref journal)
  155. format
  156. nil)
  157. (state/clear-editor-action!)
  158. (reset! commands/*current-command nil))))})
  159. (when deadline-or-schedule?
  160. (time-repeater))])))