diff --git a/src/main/frontend/components/property.cljs b/src/main/frontend/components/property.cljs index 0a88fd637e..398ecbd98b 100644 --- a/src/main/frontend/components/property.cljs +++ b/src/main/frontend/components/property.cljs @@ -106,11 +106,8 @@ text (if value' (str value') "Pick a date")] - (ui/button - text - :icon "calendar" - :intent "border-link" - :on-click (fn [] + [:a + {:on-click (fn [] (state/set-modal! #(ui/datepicker value' {:on-change (fn [_e date] (let [repo (state/get-current-repo)] @@ -118,32 +115,84 @@ (:block/name property) date) (exit-edit-property nil nil) - (state/close-modal!)))})))))) + (state/close-modal!)))})))} + [:span.inline-flex.items-center + (ui/icon "calendar") + [:span.ml-1 text]]])) -(rum/defc property-scalar-value - [block property value {:keys [editor-on-click inline-text]}] - (let [property (when property - (if (map? property) - property - (db/entity [:block/name (util/page-name-sanity-lc property)])))] +(defn- set-editing! + [property editor-id dom-id v] + (let [v (str v) + cursor-range (if dom-id + (some-> (gdom/getElement dom-id) util/caret-range) + "")] + (state/set-editing! editor-id v property cursor-range))) + +(rum/defc property-scalar-value < rum/reactive + [block property value {:keys [inline-text + editor-id dom-id + editor-box editor-args]}] + (let [multiple-values? (= :many (:cardinality (:block/schema property))) + editing? (state/sub [:editor/editing? editor-id])] (case (:type (:block/schema property)) - :date - (date-picker block property value) + :date + (date-picker block property value) - :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))) - (exit-edit-property nil nil)))}) - ;; :object - ;; default and others - [:div.flex.flex-1 - (when editor-on-click {:on-click editor-on-click}) - (when-not (string/blank? (str value)) - (inline-text {} :markdown (str value)))]))) + :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))) + (exit-edit-property nil nil)))}) + + ;; :others + (if editing? + [:div.flex.flex-1 (cond-> {} + multiple-values? + (assoc :class "property-value-content")) + (editor-box editor-args editor-id {})] + [:div.flex.flex-1 + (cond-> + {:id (or dom-id (random-uuid)) + :style {:min-height 24} + :on-click (fn [] + (set-editing! property editor-id dom-id value))} + multiple-values? + (assoc :class "property-value-content")) + (when-not (string/blank? value) + (inline-text {} :markdown (str value)))])))) + +(rum/defc property-key-input + [block *property-key *property-value *search?] + [:input#add-property.form-input.simple-input.block.col-span-1.focus:outline-none + {:placeholder "Property key" + :value @*property-key + :auto-focus true + :on-change (fn [e] + (reset! *property-key (util/evalue e)) + (reset! *search? true)) + :on-key-down (fn [e] + (case (util/ekey e) + "Escape" + (exit-edit-property *property-key *property-value) + + (list "Tab" "Enter") + (let [k (util/evalue e)] + (when (= (util/ekey e) "Tab") + (util/stop e)) + (reset! *property-key k) + (reset! *search? false) + (when (and @*property-key + (nil? (db/entity [:block/name (util/page-name-sanity-lc @*property-key)]))) + ;; new property + (add-property! block *property-key *property-value) + (when-let [property (db/entity [:block/name (util/page-name-sanity-lc k)])] + (let [editor-id (str "ls-property-" (:db/id property) "-" (:block/uuid property))] + (set-editing! property editor-id "" ""))))) + + nil))}]) (rum/defcs property-input < rum/reactive (rum/local true ::search?) @@ -155,44 +204,14 @@ (set)) result (when-not (string/blank? @*property-key) (->> (search/property-search @*property-key) - (remove entity-properties)))] + (remove entity-properties))) + property (when @*property-key + (db/entity [:block/name (util/page-name-sanity-lc @*property-key)]))] [:div [:div.ls-property-add.grid.grid-cols-4.gap-1.flex.flex-row.items-center - [:input#add-property.form-input.simple-input.block.col-span-1.focus:outline-none - {:placeholder "Property key" - :value (rum/react *property-key) - :auto-focus true - :on-change (fn [e] - (reset! *property-key (util/evalue e)) - (reset! *search? true)) - :on-key-down (fn [e] - (case (util/ekey e) - "Escape" - (exit-edit-property *property-key *property-value) - - (list "Tab" "Enter") - (do - (when (= (util/ekey e) "Tab") - (util/stop e)) - (reset! *property-key (util/evalue e)) - (reset! *search? false) - (.focus (js/document.getElementById "add-property-value"))) - - nil))}] - - (property-scalar-value entity @*property-key @*property-value {:editor-on-click (fn [e] - (case (util/ekey e) - "Enter" - (do - (add-property! entity *property-key *property-value) - (reset! *search? false)) - - nil)) - :inline-text (:inline-text block-components-m)}) - ;; [:input#add-property-value.form-input.simple-input.block.col-span-1.focus:outline-none - ;; {:placeholder "Value" - ;; :on-change #(reset! *property-value (util/evalue %)) - ;; :on-key-down }] + (property-key-input entity *property-key *property-value *search?) + (when property + (property-scalar-value entity property @*property-value block-components-m)) [:a.close {:on-mouse-down #(exit-edit-property *property-key *property-value)} svg/close]] @@ -202,8 +221,7 @@ {:class "search-results" :on-chosen (fn [chosen] (reset! *property-key chosen) - (reset! *search? false) - (.focus (js/document.getElementById "add-property-value"))) + (reset! *search? false)) :item-render #(search-item-render @*property-key %)}))])) (rum/defcs new-property < rum/reactive @@ -256,14 +274,15 @@ (ui/icon "x")]])])) (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]}] + [state entity property item {:keys [dom-id editor-id + page-cp inline-text] + :as opts}] (let [*show-close? (::show-close? state) object? (= :object (:type (:block/schema property))) block (when object? (db/pull [:block/uuid item]))] [:div.flex.flex-1.flex-row {:on-mouse-over #(reset! *show-close? true) :on-mouse-out #(reset! *show-close? false)} - (property-scalar-value entity property item {:editor-on-click edit-fn - :inline-text inline-text}) + (property-scalar-value entity property item opts) (when @*show-close? [:a.close.fade-in {:title "Delete this value" @@ -284,12 +303,8 @@ (get (:block/properties block) k)) dom-id (str "ls-property-" k) editor-id (str "ls-property-" (:db/id property) "-" k) - editing? (state/sub [:editor/editing? editor-id]) + schema (:block/schema property) - edit-fn (fn [editor-id id v] - (let [v (str v) - cursor-range (util/caret-range (gdom/getElement (or id dom-id)))] - (state/set-editing! editor-id v property cursor-range))) multiple-values? (= :many (:cardinality schema)) type (:type schema) editor-args {:block property @@ -299,46 +314,41 @@ multiple-values? (let [v' (if (coll? v) v (when v [v])) v' (if (seq v') v' [""]) - editor-id' (str editor-id (count v')) - new-editing? (state/sub [:editor/editing? editor-id'])] - [:div.flex.flex-1.flex-col.pl-1 + editor-id' (str editor-id (count v'))] + [:div.flex.flex-1.flex-col [:div.flex.flex-1.flex-col (for [[idx item] (medley/indexed v')] (let [dom-id' (str dom-id "-" idx) - editor-id' (str editor-id idx) - editing? (state/sub [:editor/editing? editor-id'])] - (if editing? - (editor-box editor-args editor-id' {}) - (multiple-value-item block property item dom-id' editor-id' {:page-cp page-cp - :edit-fn edit-fn - :inline-text inline-text})))) + editor-id' (str editor-id idx)] + (multiple-value-item block property item {:dom-id dom-id' + :editor-id editor-id' + :editor-box editor-box + :editor-args editor-args + :page-cp page-cp + :inline-text inline-text}))) (let [fv (first v')] - (when (and (not new-editing?) - fv + (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 [] - (edit-fn (str editor-id (count v')) nil ""))} + (set-editing! property (str editor-id (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 -8}} - (ui/icon "circle-plus")]]]]))] - (when new-editing? - (editor-box editor-args editor-id' {}))]) - - editing? - (editor-box editor-args editor-id {}) + :style {:margin-left -4}} + (ui/icon "circle-plus")]]]]))]]) :else [: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})]))) + {:editor-box editor-box + :editor-args editor-args + :inline-text inline-text + :editor-id editor-id + :dom-id dom-id})]))) (rum/defcs properties-area < rum/reactive [state block properties properties-text-values edit-input-id block-components-m] @@ -351,7 +361,7 @@ (for [[prop-uuid-or-built-in-prop v] properties] (if (uuid? prop-uuid-or-built-in-prop) (when-let [property (db/sub-block (:db/id (db/entity [:block/uuid prop-uuid-or-built-in-prop])))] - [:div.grid.grid-cols-4.gap-1.items-center + [:div.grid.grid-cols-4.gap-1 [:div.property-key.col-span-1 (property-key block property)] [:div.property-value.col-span-3 diff --git a/src/main/frontend/components/property.css b/src/main/frontend/components/property.css index 45cd7075fe..4d45080390 100644 --- a/src/main/frontend/components/property.css +++ b/src/main/frontend/components/property.css @@ -18,7 +18,7 @@ } .editor-inner { - @apply px-1; + padding: 0; } } diff --git a/src/main/frontend/handler/property.cljs b/src/main/frontend/handler/property.cljs index 34e9b11571..89f9546879 100644 --- a/src/main/frontend/handler/property.cljs +++ b/src/main/frontend/handler/property.cljs @@ -95,59 +95,62 @@ (defn add-property! [repo block k-name v] - (when (some? 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 (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))) - (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 [property (db/pull repo '[*] [:block/name (gp-util/page-name-sanity-lc k-name)]) + v (if property v (or v ""))] + (when (some? v) + (prn :debug " add-property! " {:k k-name + :v v}) + (let [property-uuid (or (:block/uuid property) (random-uuid)) + {:keys [type cardinality]} (:block/schema property) + multiple-values? (= cardinality :many) + 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))) + (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'}]))))))))))) (defn remove-property! [repo block k-uuid-or-builtin-k-name]