Quellcode durchsuchen

enhance: enum choices drag && drop support

Tienson Qin vor 2 Jahren
Ursprung
Commit
53df250cc8

+ 2 - 13
src/main/frontend/components/container.cljs

@@ -62,17 +62,6 @@
        (ui/icon "chevron-left" {:class "more"})]
       (when child [:div.bd child])]]))
 
-(defn- delta-y
-  [e]
-  (when-let [target (.. e -target)]
-    (let [rect (.. target getBoundingClientRect)]
-      (- (.. e -pageY) (.. rect -top)))))
-
-(defn- move-up?
-  [e]
-  (let [delta (delta-y e)]
-    (< delta 14)))
-
 (rum/defc page-name
   [name icon recent?]
   (let [original-name (db-model/get-page-original-name name)
@@ -127,12 +116,12 @@
                       (util/stop e)
                       (reset! dragging-over name)
                       (when-not (= name (get @state/state :favorites/dragging))
-                        (reset! up? (move-up? e))))
+                        (reset! up? (util/move-up? e))))
       :on-drag-leave (fn [_e]
                        (reset! dragging-over nil))
       :on-drop (fn [e]
                  (page-handler/reorder-favorites! {:to name
-                                                   :up? (move-up? e)})
+                                                   :up? (util/move-up? e)})
                  (reset! up? nil)
                  (reset! dragging-over nil))}
      (page-name name icon false)]))

+ 1 - 1
src/main/frontend/components/container.css

@@ -734,7 +734,7 @@ html[data-theme='dark'] {
   }
 }
 
-.favorites li.dragging-target {
+li.dragging-target {
   border-left: 5px solid green;
 }
 

+ 76 - 34
src/main/frontend/components/property.cljs

@@ -11,7 +11,9 @@
             [frontend.handler.db-based.property :as db-property-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.property :as property-handler]
+            [frontend.handler.reorder :as reorder-handler]
             [frontend.handler.property.util :as pu]
+            [frontend.handler.notification :as notification]
             [frontend.mixins :as mixins]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.search :as search]
@@ -21,7 +23,7 @@
             [logseq.db.property :as db-property]
             [rum.core :as rum]
             [frontend.handler.route :as route-handler]
-            [frontend.handler.notification :as notification]))
+            ))
 
 (defn- update-property!
   [property property-name property-schema]
@@ -166,7 +168,7 @@
   (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
+    [:div.flex.flex-1.flex-row.items-center.gap-2.justify-between
      {:on-mouse-over #(reset! *hover? true)
       :on-mouse-out #(reset! *hover? false)}
      [:a {:on-click toggle-fn}
@@ -176,45 +178,85 @@
                            :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})
+(rum/defcs choice-item <
+  (rum/local nil ::up?)
+  (rum/local nil ::dragging-over)
+  [state property item values order *property-schema *property-name dropdown-opts]
+  (let [up? (get state ::up?)
+        dragging-over (get state ::dragging-over)
+        {:keys [id name]} item]
+    [:li
+     {:key name
+      :title name
+      :data-ref name
+      :draggable true
+      :on-drag-start (fn [event]
+                       (.setData (.-dataTransfer event) "id" (str id)))
+      :on-drag-over (fn [e]
+                      (util/stop e)
+                      (reset! dragging-over id)
+                      (when-not (= (str id) (.getData (.-dataTransfer e) "id"))
+                        (reset! up? (util/move-up? e))))
+      :on-drag-leave (fn [_e]
+                       (reset! dragging-over nil))
+      :on-drop (fn [e]
+                 (when-let [target (some-> (.getData (.-dataTransfer e) "id") uuid)]
+                   (let [up? (util/move-up? e)
+                         new-order (reorder-handler/reorder-items order
+                                                                  {:target target
+                                                                   :to id
+                                                                   :up? up?})]
+                     (when (seq new-order)
+                       (swap! *property-schema assoc :enum-config {:values values
+                                                                 :order new-order})
+                       (update-property! property @*property-name @*property-schema))))
+                 (reset! up? nil)
+                 (reset! dragging-over nil))}
+     (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)))
+                    (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)]))
+
+(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")}
+        order (if (not= (count order) (count values))
+                (vec (concat order (remove (set order) (keys values))))
+                order)]
+    [:div.enum-choices.flex.flex-col
+     [:ol
+      (for [id order]
+        (let [item (assoc (get values id) :id id)]
+          (choice-item property item values order *property-schema *property-name dropdown-opts)))]
      (ui/dropdown
       (fn [{:keys [toggle-fn]}]
-        [:a.flex.flex-row.items-center.gap-1.text-sm.leading-8 {:on-click toggle-fn}
+        [:a.fade-link.flex.flex-row.items-center.gap-1.leading-8 {:on-click toggle-fn}
          (ui/icon "plus" {:size 16})
          "Add choice"])
       (fn [opts]

+ 8 - 21
src/main/frontend/handler/page.cljs

@@ -14,6 +14,7 @@
             [frontend.format.block :as block]
             [frontend.fs :as fs]
             [frontend.handler.common :as common-handler]
+            [frontend.handler.reorder :as reorder-handler]
             [frontend.handler.config :as config-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.plugin :as plugin-handler]
@@ -889,29 +890,15 @@
      (db-based-rename! old-name new-name redirect? persist-op?)
      (file-based-rename! old-name new-name redirect?))))
 
-(defn- split-col-by-element
-  [col element]
-  (let [col (vec col)
-        idx (.indexOf col element)]
-    [(subvec col 0 (inc idx))
-     (subvec col (inc idx))]))
-
 (defn reorder-favorites!
   [{:keys [to up?]}]
-  (let [favorites (:favorites (state/get-config))
-        from (get @state/state :favorites/dragging)]
-    (when (and from to (not= from to))
-      (let [[prev next] (split-col-by-element favorites to)
-            [prev next] (mapv #(remove (fn [e] (= from e)) %) [prev next])
-            favorites (->>
-                       (if up?
-                         (concat (drop-last prev) [from (last prev)] next)
-                         (concat prev [from] next))
-                       (remove nil?)
-                       (mapv util/safe-page-name-sanity-lc)
-                       distinct
-                       vec)]
-        (config-handler/set-config! :favorites favorites)))))
+  (let [target (get @state/state :favorites/dragging)
+        favorites (->> (reorder-handler/reorder-items (:favorites (state/get-config))
+                                                      {:target target
+                                                       :to to
+                                                       :up? up?})
+                       (mapv util/safe-page-name-sanity-lc))]
+    (config-handler/set-config! :favorites favorites)))
 
 (defn has-more-journals?
   []

+ 22 - 0
src/main/frontend/handler/reorder.cljs

@@ -0,0 +1,22 @@
+(ns frontend.handler.reorder
+  "Reorder items")
+
+(defn- split-col-by-element
+  [col element]
+  (let [col (vec col)
+        idx (.indexOf col element)]
+    [(subvec col 0 (inc idx))
+     (subvec col (inc idx))]))
+
+(defn reorder-items
+  [items {:keys [target to up?]}]
+  (when (and target to (not= target to))
+    (let [[prev next] (split-col-by-element items to)
+          [prev next] (mapv #(remove (fn [e] (= target e)) %) [prev next])]
+      (->>
+       (if up?
+         (concat (drop-last prev) [target (last prev)] next)
+         (concat prev [target] next))
+       (remove nil?)
+       distinct
+       vec))))

+ 9 - 0
src/main/frontend/util.cljc

@@ -1535,3 +1535,12 @@ Arg *stop: atom, reset to true to stop the loop"
                   js/window.mozRequestAnimationFrame
                   js/window.msRequestAnimationFrame))
          #(js/setTimeout % 16))))
+
+#?(:cljs
+   (defn move-up?
+     "Whether move upwards when dragging."
+     [e]
+     (let [delta (when-let [target (.. e -target)]
+                   (let [rect (.. target getBoundingClientRect)]
+                     (- (.. e -pageY) (.. rect -top))))]
+       (< delta 14))))