mirror of
https://github.com/logseq/logseq.git
synced 2026-05-28 14:39:48 +00:00
fix: checkbox type UX
This commit is contained in:
@@ -54,12 +54,13 @@
|
||||
(let [type (keyword (string/lower-case v))]
|
||||
(swap! *property-schema assoc :type type)))))]
|
||||
|
||||
[:div.grid.grid-cols-4.gap-1.items-center.leading-8
|
||||
[:label.cols-1 "Multiple values:"]
|
||||
(let [many? (boolean (= :many (:cardinality @*property-schema)))]
|
||||
(ui/checkbox {:checked many?
|
||||
:on-change (fn []
|
||||
(swap! *property-schema assoc :cardinality (if many? :one :many)))}))]
|
||||
(when-not (= (:type @*property-schema) :checkbox)
|
||||
[:div.grid.grid-cols-4.gap-1.items-center.leading-8
|
||||
[:label.cols-1 "Multiple values:"]
|
||||
(let [many? (boolean (= :many (:cardinality @*property-schema)))]
|
||||
(ui/checkbox {:checked many?
|
||||
:on-change (fn []
|
||||
(swap! *property-schema assoc :cardinality (if many? :one :many)))}))])
|
||||
|
||||
[:div
|
||||
(ui/button
|
||||
@@ -167,21 +168,21 @@
|
||||
(let [*property-key (::property-key state)
|
||||
*property-value (::property-value state)]
|
||||
(cond
|
||||
new-property?
|
||||
[:div#edit-new-property
|
||||
(property-key-input block *property-key *property-value)]
|
||||
new-property?
|
||||
[:div#edit-new-property
|
||||
(property-key-input block *property-key *property-value)]
|
||||
|
||||
(seq properties)
|
||||
[:a {:title "Add another property"
|
||||
:on-click (fn []
|
||||
(property-handler/set-editing-new-property! edit-input-id)
|
||||
(reset! *property-key nil)
|
||||
(reset! *property-value nil))}
|
||||
[:div.block {:style {:height 20
|
||||
:width 20}}
|
||||
[:a.add-button-link.block {:title "Add another value"
|
||||
:style {:margin-left -4}}
|
||||
(ui/icon "circle-plus")]]])))
|
||||
(seq properties)
|
||||
[:a {:title "Add another property"
|
||||
:on-click (fn []
|
||||
(property-handler/set-editing-new-property! edit-input-id)
|
||||
(reset! *property-key nil)
|
||||
(reset! *property-value nil))}
|
||||
[:div.block {:style {:height 20
|
||||
:width 20}}
|
||||
[:a.add-button-link.block {:title "Add another value"
|
||||
:style {:margin-left -4}}
|
||||
(ui/icon "circle-plus")]]])))
|
||||
|
||||
(rum/defcs property-key < (rum/local false ::show-close?)
|
||||
[state block property]
|
||||
@@ -202,6 +203,27 @@
|
||||
(property-handler/remove-property! repo block (:block/uuid property)))}
|
||||
(ui/icon "x")]])]))
|
||||
|
||||
(rum/defc property-scalar-value
|
||||
[block property value {:keys [editor-on-click inline-text]}]
|
||||
(case (:type (:block/schema property))
|
||||
:date
|
||||
(ui/button
|
||||
(or value "Empty")
|
||||
:icon :calendar)
|
||||
|
||||
:checkbox
|
||||
(ui/checkbox {:checked value
|
||||
:on-change (fn [_e]
|
||||
(let [repo (state/get-current-repo)]
|
||||
(property-handler/add-property! repo block
|
||||
(:block/name property)
|
||||
(boolean (not value)))))})
|
||||
;; :object
|
||||
;; default and others
|
||||
[:div (when editor-on-click {:on-click editor-on-click})
|
||||
(when-not (string/blank? (str value))
|
||||
(inline-text {} :markdown (str value)))]))
|
||||
|
||||
(rum/defcs multiple-value-item < (rum/local false ::show-close?)
|
||||
[state entity property item dom-id' editor-id' {:keys [edit-fn page-cp inline-text]}]
|
||||
(let [*show-close? (::show-close? state)
|
||||
@@ -229,9 +251,9 @@
|
||||
item))}
|
||||
svg/close])]))
|
||||
|
||||
;; (add-property! block *property-key *property-value)
|
||||
(rum/defcs property-value < rum/reactive
|
||||
[state block property {:keys [inline-text editor-box page-cp]}]
|
||||
[state block property value
|
||||
{:keys [inline-text editor-box page-cp]}]
|
||||
(let [k (:block/uuid property)
|
||||
v (get (:block/properties-text-values block)
|
||||
k
|
||||
@@ -288,20 +310,15 @@
|
||||
(editor-box editor-args editor-id {})
|
||||
|
||||
:else
|
||||
[:div.flex.flex-1.property-value-content
|
||||
{:id dom-id
|
||||
:on-click (fn []
|
||||
(edit-fn editor-id nil v))}
|
||||
(cond
|
||||
(and (= type :date) (string/blank? v))
|
||||
[:div "TBD (date icon)"]
|
||||
[:div.flex.flex-1.items-center.property-value-content
|
||||
{:id dom-id}
|
||||
(property-scalar-value block property value
|
||||
{:editor-on-click (fn []
|
||||
(edit-fn editor-id nil v))
|
||||
:inline-text inline-text})])))
|
||||
|
||||
:else
|
||||
(when-not (string/blank? (str v))
|
||||
(inline-text {} :markdown (str v))))])))
|
||||
|
||||
(rum/defc properties-area < rum/reactive
|
||||
[block properties properties-text-values edit-input-id block-components-m]
|
||||
(rum/defcs properties-area < rum/reactive
|
||||
[state block properties properties-text-values edit-input-id block-components-m]
|
||||
(let [repo (state/get-current-repo)
|
||||
new-property? (= edit-input-id (state/sub :ui/new-property-input-id))]
|
||||
(when (or (seq properties) new-property?)
|
||||
@@ -315,7 +332,7 @@
|
||||
[:div.property-key.col-span-1
|
||||
(property-key block property)]
|
||||
[:div.property-value.col-span-3
|
||||
(property-value block property block-components-m)]])
|
||||
(property-value block property v block-components-m)]])
|
||||
;; TODO: built in properties should have UUID and corresponding schema
|
||||
;; builtin
|
||||
[:div
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
(not= (str d) "Invalid Date")))
|
||||
|
||||
(def builtin-schema-types
|
||||
{:default string? ; default, might be mixed with refs, tags
|
||||
:number number?
|
||||
:date inst?
|
||||
:boolean boolean?
|
||||
:url [:fn
|
||||
{:error/message "should be a URL"}
|
||||
gp-util/url?]
|
||||
:object uuid?}) ; TODO: make sure block exists
|
||||
{:default string? ; default, might be mixed with refs, tags
|
||||
:number number?
|
||||
:date inst?
|
||||
:checkbox boolean?
|
||||
:url [:fn
|
||||
{:error/message "should be a URL"}
|
||||
gp-util/url?]
|
||||
:object uuid?}) ; TODO: make sure block exists
|
||||
|
||||
;; schema -> type, cardinality, object's class
|
||||
;; min, max -> string length, number range, cardinality size limit
|
||||
@@ -56,90 +56,98 @@
|
||||
|
||||
(defn- infer-schema-from-input-string
|
||||
[v-str]
|
||||
(cond
|
||||
(parse-long v-str) :number
|
||||
(parse-double v-str) :number
|
||||
(util/uuid-string? v-str) :object
|
||||
(gp-util/url? v-str) :url
|
||||
(date-str? v-str) :date
|
||||
(contains? #{"true" "false"} (string/lower-case v-str)) :boolean
|
||||
:else :default))
|
||||
(try
|
||||
(cond
|
||||
(parse-long v-str) :number
|
||||
(parse-double v-str) :number
|
||||
(util/uuid-string? v-str) :object
|
||||
(gp-util/url? v-str) :url
|
||||
(date-str? v-str) :date
|
||||
(contains? #{"true" "false"} (string/lower-case v-str)) :boolean
|
||||
:else :default)
|
||||
(catch :default _e
|
||||
:default)))
|
||||
|
||||
(defn convert-property-input-string
|
||||
[schema-type v-str]
|
||||
(case schema-type
|
||||
:default
|
||||
v-str
|
||||
(if (string? v-str)
|
||||
(case schema-type
|
||||
:default
|
||||
v-str
|
||||
|
||||
:number
|
||||
(edn/read-string v-str)
|
||||
:number
|
||||
(edn/read-string v-str)
|
||||
|
||||
:boolean
|
||||
(edn/read-string (string/lower-case v-str))
|
||||
:boolean
|
||||
(edn/read-string (string/lower-case v-str))
|
||||
|
||||
:object
|
||||
(uuid v-str)
|
||||
:object
|
||||
(uuid v-str)
|
||||
|
||||
:date
|
||||
(js/Date. v-str)
|
||||
:date
|
||||
(js/Date. v-str)
|
||||
|
||||
:url
|
||||
:url
|
||||
v-str)
|
||||
v-str))
|
||||
|
||||
(defn add-property!
|
||||
[repo block k-name v]
|
||||
(let [property (db/pull repo '[*] [:block/name k-name])
|
||||
(prn :debug " add-property! " {:k k-name
|
||||
:v v})
|
||||
(let [property (db/pull repo '[*] [:block/name (gp-util/page-name-sanity-lc k-name)])
|
||||
property-uuid (or (:block/uuid property) (random-uuid))
|
||||
{:keys [type cardinality]} (:block/schema property)
|
||||
multiple-values? (= cardinality :many)
|
||||
infer-schema (infer-schema-from-input-string v)
|
||||
infer-schema (when-not type (infer-schema-from-input-string v))
|
||||
property-type (or type infer-schema :default)
|
||||
schema (get builtin-schema-types property-type)
|
||||
properties (:block/properties block)
|
||||
value (get properties property-uuid)]
|
||||
(when-not (and multiple-values? (string/blank? (str v)))
|
||||
(when-let [v* (try
|
||||
(convert-property-input-string property-type v)
|
||||
(catch :default e
|
||||
(notification/show! (str e) :error false)
|
||||
nil))]
|
||||
(when-not (contains? (if (set? value) value #{value}) v*)
|
||||
(if-let [msg (me/humanize (mu/explain-data schema v))]
|
||||
(let [msg' (str "\"" k-name "\"" " " (if (coll? msg) (first msg) msg))]
|
||||
(notification/show! msg' :warning))
|
||||
(do
|
||||
;; FIXME: what if the block already have a block/type, e.g. whiteboard?
|
||||
(when (and property (nil? (:block/type property)))
|
||||
(db/transact! repo [(outliner-core/block-with-updated-at
|
||||
{:block/schema {:type property-type}
|
||||
:block/uuid property-uuid
|
||||
:block/type "property"})]))
|
||||
(when (nil? property) ;if property not exists yet
|
||||
(db/transact! repo [(outliner-core/block-with-timestamps
|
||||
{:block/schema {:type property-type}
|
||||
:block/original-name k-name
|
||||
:block/name (util/page-name-sanity-lc k-name)
|
||||
:block/uuid property-uuid
|
||||
:block/type "property"})]))
|
||||
(let [refs (when (= property-type :default) (extract-page-refs-from-prop-str-value v*))
|
||||
refs' (when (seq refs)
|
||||
(concat (:block/refs (db/pull [:block/uuid (:block/uuid block)]))
|
||||
refs))
|
||||
v' (if (= property-type :default)
|
||||
(if (seq refs) refs v*)
|
||||
v*)
|
||||
new-value (if multiple-values? (vec (distinct (conj value v'))) v')
|
||||
block-properties (assoc properties property-uuid new-value)
|
||||
block-properties-text-values
|
||||
(if (and (not multiple-values?) (= property-type :default))
|
||||
(assoc (:block/properties-text-values block) property-uuid v*)
|
||||
(dissoc (:block/properties-text-values block) property-uuid))]
|
||||
;; TODO: fix block/properties-order
|
||||
(db/transact! repo
|
||||
[{:block/uuid (:block/uuid block)
|
||||
:block/properties block-properties
|
||||
:block/properties-text-values block-properties-text-values
|
||||
:block/refs refs'}])))))))))
|
||||
(let [v* (try
|
||||
(convert-property-input-string property-type v)
|
||||
(catch :default e
|
||||
(notification/show! (str e) :error false)
|
||||
nil))]
|
||||
(when (some? v*)
|
||||
(when-not (contains? (if (set? value) value #{value}) v*)
|
||||
(if-let [msg (me/humanize (mu/explain-data schema v))]
|
||||
(let [msg' (str "\"" k-name "\"" " " (if (coll? msg) (first msg) msg))]
|
||||
(notification/show! msg' :warning))
|
||||
(do
|
||||
;; FIXME: what if the block already have a block/type, e.g. whiteboard?
|
||||
(when (and property (nil? (:block/type property)))
|
||||
(db/transact! repo [(outliner-core/block-with-updated-at
|
||||
{:block/schema {:type property-type}
|
||||
:block/uuid property-uuid
|
||||
:block/type "property"})]))
|
||||
(when (nil? property) ;if property not exists yet
|
||||
(db/transact! repo [(outliner-core/block-with-timestamps
|
||||
{:block/schema {:type property-type}
|
||||
:block/original-name k-name
|
||||
:block/name (util/page-name-sanity-lc k-name)
|
||||
:block/uuid property-uuid
|
||||
:block/type "property"})]))
|
||||
(let [refs (when (= property-type :default) (extract-page-refs-from-prop-str-value v*))
|
||||
refs' (when (seq refs)
|
||||
(concat (:block/refs (db/pull [:block/uuid (:block/uuid block)]))
|
||||
refs))
|
||||
v' (if (= property-type :default)
|
||||
(if (seq refs) refs v*)
|
||||
v*)
|
||||
new-value (if multiple-values? (vec (distinct (conj value v'))) v')
|
||||
block-properties (assoc properties property-uuid new-value)
|
||||
block-properties-text-values
|
||||
(if (and (not multiple-values?) (= property-type :default))
|
||||
(assoc (:block/properties-text-values block) property-uuid v*)
|
||||
(dissoc (:block/properties-text-values block) property-uuid))]
|
||||
;; TODO: fix block/properties-order
|
||||
(db/transact! repo
|
||||
[{:block/uuid (:block/uuid block)
|
||||
:block/properties block-properties
|
||||
:block/properties-text-values block-properties-text-values
|
||||
:block/refs refs'}]))))))))))
|
||||
|
||||
(defn remove-property!
|
||||
[repo block k-uuid-or-builtin-k-name]
|
||||
|
||||
Reference in New Issue
Block a user