enhance: better UX for enum values

This commit is contained in:
Tienson Qin
2023-09-28 05:14:33 +08:00
parent fee8ff393e
commit 023ffbed10
2 changed files with 145 additions and 33 deletions

View File

@@ -20,7 +20,16 @@
[frontend.util :as util]
[logseq.db.property :as db-property]
[rum.core :as rum]
[frontend.handler.route :as route-handler]))
[frontend.handler.route :as route-handler]
[frontend.handler.notification :as notification]))
(defn- update-property!
[property property-name property-schema]
(property-handler/update-property!
(state/get-current-repo)
(:block/uuid property)
{:property-name property-name
:property-schema property-schema}))
(rum/defc icon
[block {:keys [_type id]} {:keys [disabled?]}] ; only :emoji supported yet
@@ -92,33 +101,135 @@
"Click to add classes"
"Click to select a class")])])))
(rum/defcs enum-select < (rum/local false ::open?)
[state *property-schema values]
(let [items (map (fn [value] {:label value
:value value})
values)
opts {:items items
:input-default-placeholder "Update choices"
:dropdown? false
:close-modal? false
:multiple-choices? true
:selected-choices values
:extract-chosen-fn :value
:show-new-when-not-exact-match? true
:on-apply (fn [choices]
(swap! *property-schema assoc :enum-values choices))}]
(ui/dropdown
(fn [{:keys [toggle-fn]}]
[:div.enum-values.cursor-pointer.flex.flex-col {:on-click toggle-fn}
(if (seq values)
(for [value values]
[:div.enum-value value])
[:div.text-sm
"Add choices"])])
(fn [{:keys [_toggle-fn]}]
(select/select opts))
{:modal-class (util/hiccup->class
"origin-top-right.absolute.left-0.rounded-md.shadow-lg.mt-2")})))
(rum/defcs enum-item-config <
{:init (fn [state]
(let [{:keys [name description]} (first (:rum/args state))]
(assoc state
::name (atom (or name ""))
::description (atom (or description "")))))}
[state {:keys [id name description]} {:keys [toggle-fn on-save]}]
(let [*name (::name state)
*description (::description state)]
[:div.flex.flex-col.gap-4.p-4.whitespace-nowrap.w-96
[:div.grid.grid-cols-5.gap-1.items-center.leading-8
[:label.col-span-2 "Name:"]
[:input.form-input.col-span-3
{:default-value @*name
:on-change #(reset! *name (util/evalue %))}]]
[:div.grid.grid-cols-5.gap-1.items-start.leading-8
[:label.col-span-2 "Description:"]
[:div.col-span-3
(ui/ls-textarea
{:on-change #(reset! *description (util/evalue %))
:value @*description})]]
[:div
(ui/button
"Save"
:on-click (fn [e]
(util/stop e)
(when-not (string/blank? @*name)
(let [result (when on-save (on-save (string/trim @*name) @*description))]
(if (= :value-exists result)
(notification/show! (str "Choice already exist") :warning)
(when toggle-fn (toggle-fn)))))))]]))
(rum/defcs enum-new-item <
(rum/local "" ::name)
(rum/local "" ::description)
[state {:keys [toggle-fn on-save]}]
(let [*name (::name state)
*description (::description state)]
[:div.flex.flex-col.gap-4.p-4.whitespace-nowrap.w-96
[:div.grid.grid-cols-5.gap-1.items-center.leading-8
[:label.col-span-2 "Name:"]
[:input.form-input.col-span-3
{:default-value ""
:on-change #(reset! *name (util/evalue %))}]]
[:div.grid.grid-cols-5.gap-1.items-start.leading-8
[:label.col-span-2 "Description:"]
[:div.col-span-3
(ui/ls-textarea
{:on-change #(reset! *description (util/evalue %))
:value @*description})]]
[:div
(ui/button
"Save"
:on-click (fn [e]
(util/stop e)
(when-not (string/blank? @*name)
(let [result (when on-save (on-save (string/trim @*name) @*description))]
(if (= :value-exists result)
(notification/show! (str "Choice already exist") :warning)
(when toggle-fn (toggle-fn)))))))]]))
(rum/defcs choice-with-close <
(rum/local false ::hover?)
[state name {:keys [toggle-fn delete-choice]}]
(let [*hover? (::hover? state)]
[:div.flex.flex-1.flex-row.items-center.gap-2
{:on-mouse-over #(reset! *hover? true)
:on-mouse-out #(reset! *hover? false)}
[:a {:on-click toggle-fn}
name]
(when @*hover?
[:a.fade-link.flex {:on-click delete-choice
:title "Delete this choice"}
(ui/icon "X")])]))
(rum/defc enum-choices
[property *property-name *property-schema {:keys [values order] :as _config}]
(let [dropdown-opts {:modal-class (util/hiccup->class
"origin-top-right.absolute.left-0.rounded-md.shadow-lg")}]
[:div.enum-choices.flex.flex-col
(for [id order]
(let [{:keys [name] :as item} (get values id)]
(ui/dropdown
(fn [opts]
(choice-with-close
name
(assoc opts :delete-choice
(fn []
(let [new-values (dissoc values id)
new-order (vec (remove #{id} order))]
(swap! *property-schema assoc :enum-config {:values new-values
:order new-order})
;; FIXME: how to handle block properties with this value?
;; 1. delete the blocks' property that has this value
;; 2. update exist values to the default value if exists
;; 3. soft delete, users can still see it in some existing blocks,
;; but they will not see it when adding or updating this property
(update-property! property @*property-name @*property-schema))))))
(fn [opts]
(enum-item-config
item
(assoc opts :on-save
(fn [name description]
(if (some (fn [[vid m]] (and (not= vid id) (= name (:name m)))) values)
:value-exists
(let [new-values (assoc values id {:name name
:description description})]
(swap! *property-schema assoc :enum-config {:values new-values
:order order})
(update-property! property @*property-name @*property-schema)))))))
dropdown-opts)))
(ui/dropdown
(fn [{:keys [toggle-fn]}]
[:a.flex.flex-row.items-center.gap-1.text-sm.leading-8 {:on-click toggle-fn}
(ui/icon "plus" {:size 16})
"Add choice"])
(fn [opts]
(enum-new-item (assoc opts :on-save
(fn [name description]
(if (contains? (set (map :name (vals values))) name)
:value-exists
(let [id (random-uuid)
new-values (assoc values id {:name name
:description description})
new-order (vec (conj order id))]
(swap! *property-schema assoc :enum-config {:values new-values
:order new-order})
(update-property! property @*property-name @*property-schema)))))))
dropdown-opts)]))
(rum/defcs property-config <
rum/reactive
@@ -188,7 +299,7 @@
:enum
[:div.grid.grid-cols-4.gap-1.items-start.leading-8
[:label "Enum choices:"]
(enum-select *property-schema (:enum-values @*property-schema))]
(enum-choices property *property-name *property-schema (:enum-config @*property-schema))]
nil)
@@ -224,10 +335,7 @@
"Save"
:on-click (fn [e]
(util/stop e)
(property-handler/update-property!
repo (:block/uuid property)
{:property-name @*property-name
:property-schema @*property-schema})
(update-property! property @*property-name @*property-schema)
(when toggle-fn (toggle-fn)))))]]]))
(defn- get-property-from-db [name]

View File

@@ -38,6 +38,10 @@
margin-left: 7px;
}
.grid-auto-fit {
grid-template-columns: repeat(auto-fit, 120px);
}
.ls-properties-area {
@apply grid gap-2 pt-1;