Browse Source

enhance: multiple values better ux

Tienson Qin 2 years ago
parent
commit
f3e351901d
1 changed files with 141 additions and 118 deletions
  1. 141 118
      src/main/frontend/components/property.cljs

+ 141 - 118
src/main/frontend/components/property.cljs

@@ -158,7 +158,7 @@
     (state/set-editing! editor-id v property cursor-range)))
 
 (defn- select-page
-  [block property]
+  [block property opts]
   (let [repo (state/get-current-repo)
         pages (->> (model/get-all-page-original-names repo)
                    (map (fn [p] {:value p})))]
@@ -171,11 +171,19 @@
                                      (page-handler/create! page {:redirect? false
                                                                  :create-first-block? false}))
                                    (let [id' (or id (:block/uuid (db/entity [:block/name (util/page-name-sanity-lc page)])))]
-                                     (add-property! block (:block/original-name property) id'))))
-                    :show-new-when-not-exact-match? true})))
+                                     (add-property! block (:block/original-name property) id'))
+                                   (when-let [f (:on-chosen opts)] (f))))
+                    :show-new-when-not-exact-match? true
+                    :input-opts (fn [_]
+                                  {:on-key-down
+                                   (fn [e]
+                                     (case (util/ekey e)
+                                       "Escape"
+                                       (when-let [f (:on-chosen opts)] (f))
+                                       nil))})})))
 
 (defn- select-block
-  [block property]
+  [block property opts]
   (let [blocks (->> (model/get-all-block-contents)
                    (map (fn [b]
                           (assoc b :value (:block/content b)))))]
@@ -183,7 +191,8 @@
                     :dropdown? true
                     :on-chosen (fn [chosen]
                                  (let [id (:block/uuid chosen)]
-                                   (add-property! block (:block/original-name property) id)))
+                                   (add-property! block (:block/original-name property) id)
+                                   (when-let [f (:on-chosen opts)] (f))))
                     :input-opts (fn [not-matched?]
                                   {:on-key-down
                                    (fn [e]
@@ -205,13 +214,15 @@
                                                                                                      {:page property-page
                                                                                                       :replace-empty-target? false})]
                                                  (when-let [id (:block/uuid new-block)]
-                                                   (add-property! block (:block/original-name property) id)))))))
+                                                   (add-property! block (:block/original-name property) id))
+                                                 (when-let [f (:on-chosen opts)] (f)))))))
                                        "Escape"
-                                       (exit-edit-property)
+                                       (do (exit-edit-property)
+                                           (when-let [f (:on-chosen opts)] (f)))
                                        nil))})})))
 
 (defn- select
-  [block property]
+  [block property opts]
   (let [items (->> (model/get-block-property-values (:block/uuid property))
                    (mapcat (fn [[_id value]]
                              (if (coll? value)
@@ -221,103 +232,113 @@
         add-property-f #(add-property! block (:block/original-name property) %)]
     (select/select {:items items
                     :dropdown? true
-                    :on-chosen (fn [chosen] (add-property-f (:value chosen)))
-                    :show-new-when-not-exact-match? true})))
+                    :on-chosen (fn [chosen]
+                                 (add-property-f (:value chosen))
+                                 (when-let [f (:on-chosen opts)] (f)))
+                    :show-new-when-not-exact-match? true
+                    :input-opts (fn [_]
+                                  {:on-key-down
+                                   (fn [e]
+                                     (case (util/ekey e)
+                                       "Escape"
+                                       (when-let [f (:on-chosen opts)] (f))
+                                       nil))})})))
 
 (rum/defc property-scalar-value < rum/reactive db-mixins/query
   [block property value {:keys [inline-text page-cp block-cp
                                 editor-id dom-id row?
                                 editor-box editor-args
-                                new-item? editing?
-                                blocks-container-id]}]
+                                editing? editing-atom
+                                blocks-container-id]
+                         :as opts}]
   (let [property (model/sub-block (:db/id property))
         multiple-values? (= :many (:cardinality (:block/schema property)))
         editor-id (or editor-id (str "ls-property-" blocks-container-id "-" (:db/id block) "-" (:db/id property)))
         editing? (or editing? (state/sub [:editor/editing? editor-id]))
         repo (state/get-current-repo)
-        type (:type (:block/schema property))]
-    (when (or (not new-item?) editing?)
-      (case type
-       :date
-       (date-picker block property value)
-
-       :checkbox
-       (let [add-property! (fn []
-                             (add-property! block (:block/original-name property) (boolean (not value))))]
-         (ui/checkbox {:tabIndex "0"
-                       :checked value
-                       :on-change (fn [_e] (add-property!))
-                       :on-key-down (fn [e]
-                                      (when (= (util/ekey e) "Enter")
-                                        (add-property!)))}))
-       ;; :others
-       (if editing?
-         [:div.flex.flex-1
-          (case type
-            (list :number :url)
-            (select block property)
-
-            :page
-            (select-page block property)
-
-            :block
-            (select-block block property)
-
-            (let [config {:editor-opts
-                          {:on-key-down
-                           (fn [e]
-                             (let [enter? (= (util/ekey e) "Enter")]
-                               (when (and (contains? #{"Enter" "Escape"} (util/ekey e))
-                                          (not (state/get-editor-action)))
-                                 (util/stop e)
-                                 (property-handler/set-block-property! repo (:block/uuid block)
-                                                                       (:block/original-name property)
-                                                                       (util/evalue e)
-                                                                       :old-value value)
-                                 (exit-edit-property)
-
-                                 (when (and enter? multiple-values?)
-                                   (let [values-count (-> (:block/properties (db/entity (:db/id block)))
-                                                          (get (:block/uuid property))
-                                                          (count))
-                                         editor-id (str "ls-property-" blocks-container-id "-" (:db/id block) "-" (:db/id property) "-" values-count)]
-                                     (set-editing! property editor-id nil ""))))))}}]
+        type (:type (:block/schema property))
+        select-opts {:on-chosen (fn [] (when editing-atom (reset! editing-atom false)))}]
+    (case type
+      :date
+      (date-picker block property value)
+
+      :checkbox
+      (let [add-property! (fn []
+                            (add-property! block (:block/original-name property) (boolean (not value))))]
+        (ui/checkbox {:tabIndex "0"
+                      :checked value
+                      :on-change (fn [_e] (add-property!))
+                      :on-key-down (fn [e]
+                                     (when (= (util/ekey e) "Enter")
+                                       (add-property!)))}))
+      ;; :others
+      (if editing?
+        [:div.flex.flex-1
+         (case type
+           (list :number :url)
+           [:div.h-8 (select block property select-opts)]
+
+           :page
+           [:div.h-8 (select-page block property select-opts)]
+
+           :block
+           [:div.h-8 (select-block block property select-opts)]
+
+           (let [config {:editor-opts
+                         {:on-key-down
+                          (fn [e]
+                            (let [enter? (= (util/ekey e) "Enter")]
+                              (when (and (contains? #{"Enter" "Escape"} (util/ekey e))
+                                         (not (state/get-editor-action)))
+                                (util/stop e)
+                                (property-handler/set-block-property! repo (:block/uuid block)
+                                                                      (:block/original-name property)
+                                                                      (util/evalue e)
+                                                                      :old-value value)
+                                (exit-edit-property)
+
+                                (when (and enter? multiple-values?)
+                                  (let [values-count (-> (:block/properties (db/entity (:db/id block)))
+                                                         (get (:block/uuid property))
+                                                         (count))
+                                        editor-id (str "ls-property-" blocks-container-id "-" (:db/id block) "-" (:db/id property) "-" values-count)]
+                                    (set-editing! property editor-id nil ""))))))}}]
              (editor-box editor-args editor-id (cond-> config
                                                  multiple-values?
                                                  (assoc :property-value value)))))]
-         (let [class (str (when-not row? "flex flex-1 ")
-                          (when multiple-values? "property-value-content"))]
-           [:div {:id (or dom-id (random-uuid))
-                  :class class
-                  :style {:min-height 24}
-                  :on-click (fn []
-                              (let [page-or-block? (contains? #{:page :block} type)]
-                                (when (or (not page-or-block?)
-                                          (and (string/blank? value) page-or-block?))
-                                  (set-editing! property editor-id dom-id value))))}
-            (let [type (if (and (= type :default) (uuid? value))
-                         (if-let [e (db/entity [:block/uuid value])]
-                           (if (:block/name e) :page :block)
-                           type)
-                         type)]
-              (when-not (string/blank? value)
-                (case type
-                  :page
-                  (when-let [page (db/entity [:block/uuid value])]
-                    (page-cp {} page))
-
-                  :block
-                  (if-let [block (db/entity [:block/uuid value])]
-                    [:div.property-block-container.w-full
-                     (block-cp [block] {:id (str value)
-                                        :editor-box editor-box})]
-                    (if multiple-values?
-                      (property-handler/delete-property-value! repo block (:block/uuid property) value)
-                      (property-handler/remove-block-property! repo
-                                                               (:block/uuid block)
-                                                               (:block/uuid property))))
-
-                  (inline-text {} :markdown (str value)))))]))))))
+        (let [class (str (when-not row? "flex flex-1 ")
+                         (when multiple-values? "property-value-content"))]
+          [:div {:id (or dom-id (random-uuid))
+                 :class class
+                 :style {:min-height 24}
+                 :on-click (fn []
+                             (let [page-or-block? (contains? #{:page :block} type)]
+                               (when (or (not page-or-block?)
+                                         (and (string/blank? value) page-or-block?))
+                                 (set-editing! property editor-id dom-id value))))}
+           (let [type (if (and (= type :default) (uuid? value))
+                        (if-let [e (db/entity [:block/uuid value])]
+                          (if (:block/name e) :page :block)
+                          type)
+                        type)]
+             (when-not (string/blank? value)
+               (case type
+                 :page
+                 (when-let [page (db/entity [:block/uuid value])]
+                   (page-cp {} page))
+
+                 :block
+                 (if-let [block (db/entity [:block/uuid value])]
+                   [:div.property-block-container.w-full
+                    (block-cp [block] {:id (str value)
+                                       :editor-box editor-box})]
+                   (if multiple-values?
+                     (property-handler/delete-property-value! repo block (:block/uuid property) value)
+                     (property-handler/remove-block-property! repo
+                                                              (:block/uuid block)
+                                                              (:block/uuid property))))
+
+                 (inline-text {} :markdown (str value)))))])))))
 
 (defn- get-property-from-db [name]
   (when-not (string/blank? name)
@@ -429,8 +450,8 @@
      (:block/original-name property)]))
 
 (rum/defcs multiple-value-item < (rum/local false ::show-close?)
-  [state entity property items item {:keys [editor-id new-item? row?]
-                                     :as opts}]
+  [state entity property item {:keys [editor-id row?]
+                               :as opts}]
   (let [*show-close? (::show-close? state)
         editing? (state/sub [:editor/editing? editor-id])]
     [:div (cond->
@@ -441,9 +462,7 @@
             row?
             (assoc :class "relative pr-4"))
      (property-scalar-value entity property item (assoc opts :editing? editing?))
-     (when (and (or (not new-item?) editing?)
-                @*show-close?
-                (seq items))
+     (when @*show-close?
        [:a.close.fade-in
         {:class "absolute top-0 right-0"
          :title "Delete this value"
@@ -456,8 +475,10 @@
         (ui/icon "x")])]))
 
 (rum/defcs property-value < rum/reactive
+  (rum/local false ::editing?)
   [state block property v opts]
-  (let [k (:block/uuid property)
+  (let [*editing? (::editing? state)
+        k (:block/uuid property)
         dom-id (str "ls-property-" (:blocks-container-id opts) "-" k)
         editor-id (str "ls-property-" (:blocks-container-id opts) "-" (:db/id block) "-" (:db/id property))
         schema (:block/schema property)
@@ -468,38 +489,40 @@
                      :format :markdown}]
     (cond
       multiple-values?
-      (let [items (if (coll? v) v (when v [v]))
-            v' (if (seq items) items [""])
-            v' (conj v' ::new-value-placeholder) ; new one
-            ]
+      (let [items (if (coll? v) v (when v [v]))]
         [:div {:class (if row? "flex flex-1 flex-row items-center flex-wrap" "grid gap-1")}
-         (for [[idx item] (medley/indexed v')]
+         (for [[idx item] (medley/indexed v)]
            (let [dom-id' (str dom-id "-" idx)
                  editor-id' (str editor-id idx)]
              (rum/with-key
-               (multiple-value-item block property items item
+               (multiple-value-item block property item
                                     (merge
                                      opts
                                      {:dom-id dom-id'
                                       :editor-id editor-id'
                                       :editor-args editor-args
-                                      :new-item? (= item ::new-value-placeholder)
                                       :row? row?}))
                dom-id')))
 
-         (let [fv (first v')]
-           (when (and fv
-                      (or (and (string? fv) (not (string/blank? fv)))
-                          (and (not (string? fv)) (some? fv))))
-             [:div.rounded-sm.ml-1
-              {:on-click (fn []
-                           (set-editing! property (str editor-id (dec (count v'))) nil ""))}
-              [:div.flex.flex-row
-               [:div.block {:style {:height      20
-                                    :width       20}}
-                [:a.add-button-link.block {:title "Add another value"
-                                           :style {:margin-left -4}}
-                 (ui/icon "circle-plus")]]]]))])
+         (cond
+           @*editing?
+           (property-scalar-value block property v
+                                  (merge
+                                   opts
+                                   {:editor-args editor-args
+                                    :editor-id editor-id
+                                    :dom-id dom-id
+                                    :editing? @*editing?
+                                    :editing-atom *editing?}))
+
+           :else
+           [:div.rounded-sm.ml-1 {:on-click (fn [] (reset! *editing? true))}
+            [:div.flex.flex-row
+             [:div.block {:style {:height      20
+                                  :width       20}}
+              [:a.add-button-link.block {:title "Add another value"
+                                         :style {:margin-left -4}}
+               (ui/icon "circle-plus")]]]])])
 
       :else
       [:div.flex.flex-1.items-center.property-value-content