Selaa lähdekoodia

enhance(ux): property value input

Tienson Qin 1 vuosi sitten
vanhempi
sitoutus
83e4560a1a

+ 17 - 8
src/main/frontend/components/property.cljs

@@ -31,7 +31,8 @@
             [frontend.components.property.closed-value :as closed-value]
             [frontend.components.property.util :as components-pu]
             [promesa.core :as p]
-            [logseq.db :as ldb]))
+            [logseq.db :as ldb]
+            [goog.dom :as gdom]))
 
 (defn- <create-class-if-not-exists!
   [value]
@@ -127,7 +128,7 @@
 (rum/defc schema-type <
   shortcut/disable-all-shortcuts
   [property {:keys [*property-name *property-schema built-in-property? disabled?
-                    show-type-change-hints? in-block-container? *show-new-property-config?]}]
+                    show-type-change-hints? in-block-container? block *show-new-property-config?]}]
   (let [property-name (or (and *property-name @*property-name) (:block/original-name property))
         property-schema (or (and *property-schema @*property-schema) (:block/schema property))
         schema-types (->> (concat db-property-type/user-built-in-property-types
@@ -156,12 +157,19 @@
                                         [:cardinality :classes :position]))]
            (when *property-schema
              (swap! *property-schema update-schema-fn))
-           (p/do!
-            (let [schema (or (and *property-schema @*property-schema)
-                             (update-schema-fn property-schema))]
-              (components-pu/update-property! property property-name schema))
-
-            (reset! *show-new-property-config? false))))}
+           (let [schema (or (and *property-schema @*property-schema)
+                            (update-schema-fn property-schema))
+                 repo (state/get-current-repo)]
+             (p/do!
+              (when block
+                (pv/exit-edit-property))
+              (reset! *show-new-property-config? false)
+              (components-pu/update-property! property property-name schema)
+              (when block
+                (let [id (str "ls-property-" (:db/id block) "-" (:db/id property) "-editor")]
+                  (state/set-state! :editor/editing-property-value-id
+                                    {id true}))
+                (property-handler/set-block-property! repo (:block/uuid block) property-name (if (= type :default) "" :property/empty-placeholder)))))))}
       (shui/select-trigger
        {:class "!px-2 !py-0 !h-8"}
        (shui/select-value
@@ -468,6 +476,7 @@
              (when-not class-schema?
                (if @*show-new-property-config?
                  (schema-type property {:in-block-container? in-block-container?
+                                        :block entity
                                         :*show-new-property-config? *show-new-property-config?})
                  (pv/property-value entity property @*property-value (assoc opts :editing? true))))])])
 

+ 45 - 33
src/main/frontend/components/property/value.cljs

@@ -38,6 +38,7 @@
   (state/set-state! :editor/new-property-key nil)
   (state/set-state! :editor/new-property-input-id nil)
   (state/set-state! :editor/properties nil)
+  (state/set-state! :editor/editing-property-value-id {})
   (state/clear-edit!))
 
 (defn set-editing!
@@ -160,13 +161,17 @@
 
 (defn- select-aux
   [block property {:keys [items selected-choices multiple-choices?] :as opts}]
-  (let [selected-choices (remove nil? selected-choices)
+  (let [selected-choices (->> selected-choices
+                              (remove nil?)
+                              (remove #(= :property/empty-placeholder %)))
         clear-value (str "No " (:block/original-name property))
-        items' (if (and (seq selected-choices) (not multiple-choices?))
-                 (cons {:value clear-value
-                        :label clear-value}
-                       items)
-                 items)
+        items' (->>
+                (if (and (seq selected-choices) (not multiple-choices?))
+                  (cons {:value clear-value
+                         :label clear-value}
+                        items)
+                  items)
+                (remove #(= :property/empty-placeholder (:value %))))
         k (if multiple-choices? :on-apply :on-chosen)
         f (get opts k)
         f' (fn [chosen]
@@ -176,6 +181,7 @@
                                                         (:block/original-name property))
                (f chosen)))]
     (select/select (assoc opts
+                          :selected-choices selected-choices
                           :items items'
                           k f'))))
 
@@ -359,7 +365,8 @@
          (cond
            (or esc?
                (and enter? (util/tag? new-value))
-               (and enter? new-property?))
+               (and enter? new-property?)
+               (string/blank? value))
            (save-text! repo block property value editor-id e)
 
            enter?
@@ -564,32 +571,35 @@
 
 (rum/defc single-value-select
   [block property value value-f select-opts {:keys [editing?] :as opts}]
-  (let [schema (:block/schema property)
+  (let [[open? set-open!] (rum/use-state editing?)
+        schema (:block/schema property)
         type (get schema :type :default)
         select-opts' (cond-> (assoc select-opts
                                     :multiple-choices? false
-                                    :dropdown? (if editing? true false))
+                                    :on-chosen #(set-open! false))
                        (= type :page)
-                       (assoc :classes (:classes schema)))
-        select-f (fn []
-                   [:div.property-select (cond-> {} editing? (assoc :class "h-6"))
-                    (case type
-                      (:number :url :date :default)
-                      (select block property select-opts' opts)
-
-                      :page
-                      (property-value-select-page block property select-opts' opts))])]
-    (if editing?
-      (select-f)
-      [:a.control-link.jtrigger
-       {:tabIndex 0
-        :on-click (if config/publishing?
-                    (constantly nil)
-                    #(shui/popup-show! (.-target %) select-f {:as-menu? true}))
-        :class "flex flex-1"}
-       (if (and (string/blank? value) (not editing?))
-         [:div.opacity-50.pointer.text-sm "Empty"]
-         (value-f))])))
+                       (assoc :classes (:classes schema)))]
+    (shui/dropdown-menu
+     {:open open?}
+     (shui/dropdown-menu-trigger
+      {:class "jtrigger flex flex-1"
+       :on-click #(set-open! (not open?))
+       :on-key-down (fn [e]
+                      (when (= " " (util/ekey e))
+                        (set-open! true)))}
+      (if (string/blank? value)
+        [:div.opacity-50.pointer.text-sm "Empty"]
+        (value-f)))
+     (shui/dropdown-menu-content
+      {:align "start"
+       :on-interact-outside #(set-open! false)}
+      [:div.property-select
+       (case type
+         (:number :url :date :default)
+         (select block property select-opts' opts)
+
+         :page
+         (property-value-select-page block property select-opts' opts))]))))
 
 (rum/defcs property-scalar-value < rum/reactive db-mixins/query
   (rum/local nil ::ref)
@@ -604,18 +614,20 @@
         schema (:block/schema property)
         type (get schema :type :default)
         multiple-values? (= :many (:cardinality schema))
-        editor-id (or editor-id (str "ls-property-" (:db/id block) "-" (:db/id property)))
-        editing? (or editing? (and @*ref (state/sub-editing? @*ref)))
+        editing? (or editing?
+                     (state/sub-property-value-editing? editor-id)
+                     (and @*ref (state/sub-editing? @*ref)))
         select-type? (select-type? property type)
         closed-values? (seq (:values schema))
-        select-opts {:on-chosen on-chosen}]
+        select-opts {:on-chosen on-chosen}
+        value (if (= value :property/empty-placeholder) nil value)]
     (if (and select-type?
              (not (and (not closed-values?) (= type :date))))
       (single-value-select block property value
                            (fn []
                              (select-item property type value opts))
                            select-opts
-                           opts)
+                           (assoc opts :editing? editing?))
       (case type
         :date
         (property-value-date-picker block property value nil)

+ 1 - 1
src/main/frontend/components/select.cljs

@@ -60,7 +60,7 @@
                  prompt-key input-default-placeholder close-modal?
                  extract-fn extract-chosen-fn host-opts on-input input-opts
                  item-cp transform-fn tap-*input-val
-                 multiple-choices? on-apply _selected-choices
+                 multiple-choices? on-apply selected-choices
                  dropdown? show-new-when-not-exact-match? exact-match-exclude-items
                  input-container initial-open?]
           :or {limit 100

+ 4 - 2
src/main/frontend/db/async.cljs

@@ -92,7 +92,8 @@
                          [?prop-b :block/uuid ?prop-uuid]
                          [?prop-b :block/schema ?prop-schema]
                          [(get ?prop-schema :type) ?prop-type]
-                         [(get ?bp ?prop-uuid) ?v]]
+                         [(get ?bp ?prop-uuid) ?v]
+                         [(not= ?v :property/empty-placeholder)]]
                        property-name)]
       (->> result
            (map (fn [[prop-type v]] [prop-type (if (coll? v) v [v])]))
@@ -131,7 +132,8 @@
         :where
         [?b :block/properties ?p]
         [(get ?p ?property-uuid) ?v]
-        [(some? ?v)]]
+        [(some? ?v)]
+        [(not= ?v :property/empty-placeholder)]]
       property-uuid))
 
 ;; TODO: batch queries for better performance and UX

+ 9 - 7
src/main/frontend/handler/db_based/property.cljs

@@ -208,12 +208,14 @@
                 schema (get (built-in-validation-schemas property) property-type)
                 properties (:block/properties block)
                 value (get properties property-uuid)
-                v* (try
-                     (convert-property-input-string property-type v)
-                     (catch :default e
-                       (js/console.error e)
-                       (notification/show! (str e) :error false)
-                       nil))
+                v* (if (= v :property/empty-placeholder)
+                     v
+                     (try
+                       (convert-property-input-string property-type v)
+                       (catch :default e
+                         (js/console.error e)
+                         (notification/show! (str e) :error false)
+                         nil)))
                 tags-or-alias? (and (contains? #{"tags" "alias"} (string/lower-case k-name)) (uuid? v*))]
             (if tags-or-alias?
               (let [property-value-id (:db/id (db/entity [:block/uuid v*]))
@@ -226,7 +228,7 @@
                               [[:db/add (:db/id block) attribute property-value-id]]
                               {:outliner-op :save-block}))
               (when-not (contains? (if (set? value) value #{value}) v*)
-                (if-let [msg (validate-property-value schema v*)]
+                (if-let [msg (when-not (= v* :property/empty-placeholder) (validate-property-value schema v*))]
                   (let [msg' (str "\"" k-name "\"" " " (if (coll? msg) (first msg) msg))]
                     (notification/show! msg' :warning))
                   (do

+ 12 - 0
src/main/frontend/state.cljs

@@ -136,6 +136,8 @@
       :editor/block                          (atom nil)
       :editor/new-property-input-id          (atom nil)
       :editor/new-property-key               (atom nil)
+      ;; id -> bool
+      :editor/editing-property-value-id      (atom {})
       :editor/properties-container           (atom nil)
       :editor/block-dom-id                   (atom nil)
       :editor/set-timestamp-block            (atom nil) ;; click rendered block timestamp-cp to set timestamp
@@ -608,6 +610,16 @@ Similar to re-frame subscriptions"
     (rum/react
      (get @(:editor/ref->editing? @state) block-ref))))
 
+(defn sub-property-value-editing?
+  [property-value-id]
+  (when property-value-id
+    (rum/react
+     (r/cached-derived-atom
+      (:editor/editing-property-value-id @state)
+      [(get-current-repo) ::editing-property-value property-value-id]
+      (fn [s]
+        (get s property-value-id))))))
+
 (defn sub-config
   "Sub equivalent to get-config which should handle all sub user-config access"
   ([] (sub-config (get-current-repo)))