Files
logseq/src/main/frontend/components/datetime.cljs
Gabriel Horner f1d15b0e05 Lint components and address comments in review
Start using :clj-kondo/ignore as lint violations that need to be
revisited. They may side effect and should be removed with better
understanding of their context
2022-01-12 15:32:47 -05:00

170 lines
6.6 KiB
Clojure

(ns frontend.components.datetime
(:require [cljs-time.core :as t]
[clojure.string :as string]
[frontend.commands :as commands]
[frontend.components.svg :as svg]
[frontend.date :as date]
[frontend.handler.editor :as editor-handler]
[frontend.handler.repeated :as repeated]
[frontend.state :as state]
[frontend.ui :as ui]
[frontend.util :as util]
[frontend.mixins :as mixins]
[rum.core :as rum]))
(defonce default-timestamp-value {:time ""
:repeater {}})
(defonce *timestamp (atom default-timestamp-value))
(defonce *show-time? (atom false))
(rum/defc time-input < rum/reactive
[default-value]
(let [show? (rum/react *show-time?)]
(if (or show? (not (string/blank? default-value)))
[:div.flex.flex-row {:style {:height 32}}
[:input#time.form-input.w-20.ms:w-60
{:default-value default-value
:on-change (fn [event]
(util/stop event)
(let [value (util/evalue event)]
(swap! *timestamp assoc :time value)))}]
[:a.ml-2.self-center {:on-click (fn []
(reset! *show-time? false)
(swap! *timestamp assoc :time nil))}
svg/close]]
[:a.text-sm {:on-click (fn []
(reset! *show-time? true)
(let [{:keys [hour minute]} (date/get-local-date)
result (str hour ":" (util/zero-pad minute))]
(swap! *timestamp assoc :time result)))}
"Add time"])))
(defonce *show-repeater? (atom false))
(rum/defc repeater-cp < rum/reactive
[{:keys [num duration kind]}]
(let [show? (rum/react *show-repeater?)]
(if (or show? (and num duration kind))
[:div.w.full.flex.flex-row.justify-left {:style {:height 32}}
[:input#repeater-num.form-input.mt-1.w-8.px-1.sm:w-20.sm:px-2.text-center
{:default-value num
:on-change (fn [event]
(let [value (util/evalue event)]
(swap! *timestamp assoc-in [:repeater :num] value)))}]
(ui/select
(mapv
(fn [item]
(if (= (:label item) duration)
(assoc item :selected "selected")
item))
[{:label "h"}
{:label "d"}
{:label "w"}
{:label "m"}
{:label "y"}])
(fn [value]
(swap! *timestamp assoc-in [:repeater :duration] value))
nil)
[:a.ml-1.self-center {:on-click (fn []
(reset! *show-repeater? false)
(swap! *timestamp assoc :repeater {}))}
svg/close]]
[:a.text-sm {:on-click (fn []
(reset! *show-repeater? true)
(swap! *timestamp assoc :repeater
{:kind ".+"
:num 1
:duration "d"}))}
"Add repeater"])))
(defn clear-timestamp!
[]
(reset! *timestamp default-timestamp-value)
(reset! *show-time? false)
(reset! *show-repeater? false)
(state/set-state! :date-picker/date nil))
(defn- on-submit
[e]
(when e (util/stop e))
(let [{:keys [repeater] :as timestamp} @*timestamp
date (:date-picker/date @state/state)
timestamp (assoc timestamp :date (or date (t/today)))
kind (if (= "w" (:duration repeater)) "++" ".+")
timestamp (assoc-in timestamp [:repeater :kind] kind)
text (repeated/timestamp-map->text timestamp)
block-data (state/get-timestamp-block)
{:keys [block typ show?]} block-data
block-id (or (:block/uuid (state/get-edit-block))
(:block/uuid block))]
typ (or @commands/*current-command typ)
(editor-handler/set-block-timestamp! block-id
typ
text)
(when show?
(reset! show? false)))
(clear-timestamp!)
(state/set-editor-show-date-picker! false)
(commands/restore-state false))
(rum/defc time-repeater < rum/reactive
(mixins/event-mixin
(fn [state]
(when-let [input (state/get-input)]
(js/setTimeout #(mixins/on-enter state
:node input
:on-enter on-submit) 100))))
[]
(let [{:keys [time repeater]} (rum/react *timestamp)]
[:div#time-repeater.py-1.px-4 {:style {:min-width 300}}
[:p.text-sm.opacity-50.font-medium.mt-4 "Time:"]
(time-input time)
[:p.text-sm.opacity-50.font-medium.mt-4 "Repeater:"]
(repeater-cp repeater)
[:p.mt-4
(ui/button "Submit"
:on-click on-submit)]]))
(rum/defc date-picker < rum/reactive
{:init (fn [state]
(let [ts (last (:rum/args state))]
(if ts
(reset! *timestamp ts)
(reset! *timestamp {:time ""
:repeater {}}))
(when-not (:date-picker/date @state/state)
(state/set-state! :date-picker/date (t/today))))
state)
:will-unmount (fn [state]
(clear-timestamp!)
state)}
[id format _ts]
(let [current-command @commands/*current-command
deadline-or-schedule? (and current-command
(contains? #{"deadline" "scheduled"}
(string/lower-case current-command)))
date (state/sub :date-picker/date)]
(when (state/sub :editor/show-date-picker?)
[:div#date-time-picker.flex.flex-row {:on-click (fn [e] (util/stop e))
:on-mouse-down (fn [e] (.stopPropagation e))}
(ui/datepicker
date
{:deadline-or-schedule? deadline-or-schedule?
:on-change
(fn [e date]
(util/stop e)
(let [date (t/to-default-time-zone date)
journal (date/journal-name date)]
(when-not deadline-or-schedule?
;; similar to page reference
(editor-handler/insert-command! id
(util/format "[[%s]]" journal)
format
nil)
(state/set-editor-show-date-picker! false)
(reset! commands/*current-command nil))))})
(when deadline-or-schedule?
(time-repeater))])))