Browse Source

feat: specify multple classes for object type

Tienson Qin 2 years ago
parent
commit
93643dafd5

+ 1 - 0
src/main/frontend/components/page.cljs

@@ -10,6 +10,7 @@
             [frontend.components.reference :as reference]
             [frontend.components.svg :as svg]
             [frontend.components.scheduled-deadlines :as scheduled]
+            [frontend.components.select :as select]
             [frontend.config :as config]
             [frontend.context.i18n :refer [t]]
             [frontend.date :as date]

+ 53 - 37
src/main/frontend/components/property.cljs

@@ -2,10 +2,11 @@
   "Block properties management."
   (:require [clojure.set :as set]
             [clojure.string :as string]
-            [frontend.config :as config]
             [frontend.components.property.value :as pv]
             [frontend.components.select :as select]
+            [frontend.config :as config]
             [frontend.db :as db]
+            [frontend.db-mixins :as db-mixins]
             [frontend.db.model :as db-model]
             [frontend.handler.db-based.property :as db-property]
             [frontend.handler.notification :as notification]
@@ -18,8 +19,8 @@
             [frontend.ui :as ui]
             [frontend.util :as util]
             [logseq.graph-parser.property :as gp-property]
-            [rum.core :as rum]
-            [frontend.db-mixins :as db-mixins]))
+            [reitit.frontend.easy :as rfe]
+            [rum.core :as rum]))
 
 (rum/defc icon
   [block {:keys [_type id]}]            ; only :emoji supported yet
@@ -42,27 +43,41 @@
                                                                                                                           :id id}}}))
                             (toggle-fn))})))))
 
-(rum/defc class-select
-  [*property-schema class]
-  (let [classes (db-model/get-all-classes (state/get-current-repo))
-        options (map (fn [[name id]] {:label name
-                                      :value id
-                                      :selected (= class id)})
-                     classes)
-        options' (cons
-                  (if class
-                    {:label "Choose a class"
-                     :value ""}
-                    {:label "Choose a class"
-                     :disabled true
-                     :selected true
-                     :value ""})
-                  options)]
-    (ui/select options'
-               (fn [_e value]
-                 (if (seq value)
-                   (swap! *property-schema assoc :class (uuid value))
-                   (swap! *property-schema dissoc :class))))))
+(rum/defcs class-select < (rum/local false ::open?)
+  [state *property-schema schema-classes _opts]
+  (let [*open? (::open? state)]
+    (if @*open?
+      (let [classes (db-model/get-all-classes (state/get-current-repo))
+            options (map (fn [[name id]] {:label name
+                                          :value id})
+                         classes)
+            opts {:items options
+                  :input-default-placeholder "Choose classes"
+                  :dropdown? true
+                  :multiple-choices? true
+                  :selected-choices schema-classes
+                  :on-apply (fn [choices]
+                              (swap! *property-schema assoc :classes choices)
+                              (reset! *open? false))
+                  :input-opts {:on-blur (fn [] (reset! *open? false))
+                               :on-key-down
+                               (fn [e]
+                                 (case (util/ekey e)
+                                   "Escape"
+                                   (do
+                                     (util/stop e)
+                                     (reset! *open? false))
+                                   nil))}}]
+        (select/select opts))
+      [:div.flex.flex-1.flex-row.cursor.items-center.flex-wrap.gap-2.col-span-3
+       {:on-click #(reset! *open? true)}
+       (if (seq schema-classes)
+         (for [class schema-classes]
+           (when-let [page (db/entity [:block/uuid class])]
+             (let [page-name (:block/original-name page)]
+               [:a.text-sm (str "#" page-name)])))
+         [:div.text-sm
+          "Click to add classes"])])))
 
 (rum/defcs property-config <
   rum/reactive
@@ -73,7 +88,7 @@
                    (reset! (::property-name state) (:block/original-name property))
                    (reset! (::property-schema state) (:block/schema property))
                    state))}
-  [state repo property {:keys [toggle-fn block]}]
+  [state repo property {:keys [toggle-fn block] :as opts}]
   (let [*property-name (::property-name state)
         *property-schema (::property-schema state)
         built-in-property? (contains? gp-property/db-built-in-properties-keys-str (:block/original-name property))
@@ -117,8 +132,8 @@
 
       (when (= :object (:type @*property-schema))
         [:div.grid.grid-cols-4.gap-1.leading-8
-         [:label "Choose class:"]
-         (class-select *property-schema (:class @*property-schema))])
+         [:label "Specify classes:"]
+         (class-select *property-schema (:classes @*property-schema) opts)])
 
       (when-not (= (:type @*property-schema) :checkbox)
         [:div.grid.grid-cols-4.gap-1.items-center.leading-8
@@ -129,6 +144,14 @@
                          :on-change (fn []
                                       (swap! *property-schema assoc :cardinality (if many? :one :many)))}))])
 
+      (when-not built-in-property?
+        (let [hide? (:hide? @*property-schema)]
+          [:div.grid.grid-cols-4.gap-1.items-center.leading-8
+           [:label "Hide by default:"]
+           (ui/checkbox {:checked hide?
+                         :on-change (fn []
+                                      (swap! *property-schema assoc :hide? (not hide?)))})]))
+
       [:div.grid.grid-cols-4.gap-1.items-center.leading-8
        [:label "Description:"]
        [:div.col-span-3
@@ -138,14 +161,6 @@
           :disabled built-in-property?
           :value (:description @*property-schema)})]]
 
-      (when-not built-in-property?
-        (let [hide? (:hide? @*property-schema)]
-          [:div.grid.grid-cols-4.gap-1.items-center.leading-8
-           [:label "Hide by default:"]
-           (ui/checkbox {:checked hide?
-                         :on-change (fn []
-                                      (swap! *property-schema assoc :hide? (not hide?)))})]))
-
       [:div
        (when-not built-in-property?
          (ui/button
@@ -227,8 +242,9 @@
                  (pv/property-scalar-value entity property @*property-value (assoc opts :editing? true)))
                (fn [{:keys [toggle-fn]}]
                  [:div.p-6
-                  (property-config repo property {:toggle-fn toggle-fn
-                                                  :block entity})])
+                  (property-config repo property (merge opts
+                                                        {:toggle-fn toggle-fn
+                                                         :block entity}))])
                {:initial-open? true
                 :modal-class (util/hiccup->class
                               "origin-top-right.absolute.left-0.rounded-md.shadow-lg.mt-2")})

+ 6 - 2
src/main/frontend/components/property/value.cljs

@@ -115,12 +115,16 @@
                                    (when-let [f (:on-chosen opts)] (f))))
                     :show-new-when-not-exact-match? true
                     :input-opts (fn [_]
-                                  {:on-blur (or (:on-chosen opts) identity)
+                                  {:on-blur (fn []
+                                              (exit-edit-property)
+                                              (when-let [f (:on-chosen opts)] (f)))
                                    :on-key-down
                                    (fn [e]
                                      (case (util/ekey e)
                                        "Escape"
-                                       (when-let [f (:on-chosen opts)] (f))
+                                       (do
+                                         (exit-edit-property)
+                                         (when-let [f (:on-chosen opts)] (f)))
                                        nil))})})))
 
 (defn- move-cursor

+ 44 - 30
src/main/frontend/components/select.cljs

@@ -23,10 +23,10 @@
         selected-choices (rum/react *selected-choices)]
     [:div.flex.flex-row.justify-between.w-full {:class (when chosen? "chosen")}
      [:span
-      (when multiple-choices? (ui/checkbox {:checked (selected-choices value)
-                                            :style {:margin-right 4}
-                                            :on-click (fn [e]
-                                                        (.preventDefault e))}))
+      (when multiple-choices?
+        (ui/checkbox {:checked (boolean (selected-choices (:value result)))
+                      :style {:margin-right 4}
+                      :on-click (fn [e] (.preventDefault e))}))
       value]
      (when (and (map? result) (:id result))
        [:div.tip.flex
@@ -43,6 +43,7 @@
   < rum/reactive
   shortcut/disable-all-shortcuts
   (rum/local "" ::input)
+  (rum/local nil ::toggle)
   {:init (fn [state]
            (assoc state ::selected-choices
                   (atom (set (:selected-choices (first (:rum/args state)))))))
@@ -57,14 +58,17 @@
                  extract-fn host-opts on-input input-opts
                  item-cp transform-fn tap-*input-val
                  multiple-choices? on-apply _selected-choices
-                 dropdown? show-new-when-not-exact-match? exact-match-exclude-items]
+                 dropdown? show-new-when-not-exact-match? exact-match-exclude-items
+                 input-container initial-open?]
           :or {limit 100
                prompt-key :select/default-prompt
                empty-placeholder (fn [_t] [:div])
                close-modal? true
                extract-fn :value
-               exact-match-exclude-items #{}}}]
+               exact-match-exclude-items #{}
+               initial-open? true}}]
   (let [input (::input state)
+        *toggle (::toggle state)
         *selected-choices (::selected-choices state)
         search-result' (->>
                         (cond-> (search/fuzzy-search items @input :limit limit :extract-fn extract-fn)
@@ -86,17 +90,19 @@
                          (remove nil?))
                         search-result')
         input-opts' (if (fn? input-opts) (input-opts (empty? search-result)) input-opts)
-        input-container [:div.input-wrap
-                         [:input.cp__select-input.w-full
-                          (merge {:type        "text"
-                                  :placeholder (or input-default-placeholder (t prompt-key))
-                                  :auto-focus  true
-                                  :value       @input
-                                  :on-change   (fn [e]
-                                                 (let [v (util/evalue e)]
-                                                   (reset! input v)
-                                                   (and (fn? on-input) (on-input v))))}
-                                 input-opts')]]
+        input-container (or
+                         input-container
+                         [:div.input-wrap
+                          [:input.cp__select-input.w-full
+                           (merge {:type        "text"
+                                   :placeholder (or input-default-placeholder (t prompt-key))
+                                   :auto-focus  true
+                                   :value       @input
+                                   :on-change   (fn [e]
+                                                  (let [v (util/evalue e)]
+                                                    (reset! input v)
+                                                    (and (fn? on-input) (on-input v))))}
+                                  input-opts')]])
         results-container [:div
                            [:div.item-results-wrap
                             (ui/auto-complete
@@ -104,20 +110,27 @@
                              {:item-render       (or item-cp (fn [result chosen?]
                                                                (render-item result chosen? multiple-choices? *selected-choices)))
                               :class             "cp__select-results"
-                              :on-chosen         (fn [x]
+                              :on-chosen         (fn [matched]
                                                    (reset! input "")
-                                                   (if multiple-choices?
-                                                     (if (@*selected-choices x)
-                                                       (swap! *selected-choices disj x)
-                                                       (swap! *selected-choices conj x))
-                                                     (do
-                                                       (when close-modal? (state/close-modal!))
-                                                       (when on-chosen
-                                                         (on-chosen (if multiple-choices? @*selected-choices x))))))
+                                                   (let [x (extract-fn matched)]
+                                                     (if multiple-choices?
+                                                       (if (@*selected-choices x)
+                                                         (swap! *selected-choices disj x)
+                                                         (swap! *selected-choices conj x))
+                                                       (do
+                                                         (when close-modal? (state/close-modal!))
+                                                         (when on-chosen
+                                                           (on-chosen (if multiple-choices? @*selected-choices x)))))))
                               :empty-placeholder (empty-placeholder t)})]
 
                            (when multiple-choices?
-                             [:div.p-4 (ui/button "Apply updates" :on-click on-apply)])]]
+                             [:div.p-4 (ui/button "Apply updates"
+                                                  {:small? true
+                                                   :on-mouse-down (fn [e]
+                                                                    (util/stop e)
+                                                                    (when @*toggle (@*toggle))
+                                                                    (when (fn? on-apply)
+                                                                      (on-apply @*selected-choices)))})])]]
     (when (fn? tap-*input-val)
       (tap-*input-val input))
     [:div.cp__select
@@ -125,11 +138,12 @@
 
      (if dropdown?
        (ui/dropdown
-        (fn [] input-container)
+        (if (fn? input-container) input-container (fn [] input-container))
         (fn [] results-container)
-        :initial-open? true)
+        {:initial-open? initial-open?
+         :*toggle-fn *toggle})
        [:<>
-        input-container
+        (if (fn? input-container) (input-container) input-container)
         results-container])]))
 
 (defn select-config

+ 5 - 1
src/main/frontend/ui.cljs

@@ -161,9 +161,13 @@
                (reset! (:open? state) true)))
            state)}
   [state content-fn modal-content-fn
-   & [{:keys [modal-class z-index trigger-class _initial-open?]
+   & [{:keys [modal-class z-index trigger-class _initial-open? *toggle-fn]
        :or   {z-index 999}}]]
   (let [{:keys [open?]} state
+        _ (when (and (util/atom? *toggle-fn)
+                     (nil? @*toggle-fn)
+                     (:toggle-fn state))
+            (reset! *toggle-fn (:toggle-fn state)))
         modal-content (modal-content-fn state)
         close-fn (:close-fn state)]
     [:div.relative.ui__dropdown-trigger {:class trigger-class}