Просмотр исходного кода

Feat: ordered(number) list blocks (#9141)

* fix(ui): marker of number list
* feat(ui): sub alpha marker for order block (own-property)
* fix(ui): make order list style more compatiable
* fix(ui): reactive block state for all the order list related items
* improve(ux): backspace for the empty order list block
* improve(ui): slash commands for the own number list block
* fix(ui): incorrect order list number for the root block
* fix(ui): order list not work for the custom query blocks
* fix(ui): contextmenu for the number list marker
* improve(ui): remove the property of `logseq.children-as` for the order list feature
* fix(ui): incorrect order list number for the journal pages list
---------

Co-authored-by: Gabriel Horner <[email protected]>
Charlie 2 лет назад
Родитель
Сommit
68492a5c67

+ 1 - 1
deps/graph-parser/src/logseq/graph_parser/property.cljs

@@ -64,7 +64,7 @@
      :created-at :updated-at :last-modified-at :created_at :last_modified_at
      :query-table :query-properties :query-sort-by :query-sort-desc :ls-type
      :hl-type :hl-page :hl-stamp :hl-color :logseq.macro-name :logseq.macro-arguments
-     :logseq.tldraw.page :logseq.tldraw.shape
+     :logseq.order-list-type :logseq.tldraw.page :logseq.tldraw.shape
      ; task markers
      :todo :doing :now :later :done}
    @built-in-extended-properties))

+ 17 - 1
src/main/frontend/commands.cljs

@@ -147,6 +147,7 @@
    "Tomorrow" "TIME & DATE"
    "LATER" "TASK"
    "A" "PRIORITY"
+   "Number list" "LIST TYPE"
    "Query" "ADVANCED"
    "Quote" "ORG-MODE"})
 
@@ -250,9 +251,12 @@
      ["Current time" #(date/get-current-time) "Insert current time"]
      ["Date picker" [[:editor/show-date-picker]] "Pick a date and insert here"]]
 
+    ;; order list
+    [["Number list" [[:editor/clear-current-slash]
+                     [:editor/toggle-own-number-list]] "Number list"]]
+
     ;; task management
     (get-preferred-workflow)
-
     [["DONE" (->marker "DONE")]
      ["WAITING" (->marker "WAITING")]
      ["CANCELED" (->marker "CANCELED")]
@@ -654,6 +658,18 @@
         macro (youtube/gen-youtube-ts-macro)]
     (insert! input-id macro {})))
 
+(defmethod handle-step :editor/toggle-children-number-list [[_]]
+  (when-let [block (state/get-edit-block)]
+    (state/pub-event! [:editor/toggle-children-number-list block])))
+
+(defmethod handle-step :editor/toggle-own-number-list [[_]]
+  (when-let [block (state/get-edit-block)]
+    (state/pub-event! [:editor/toggle-own-number-list block])))
+
+(defmethod handle-step :editor/remove-own-number-list [[_]]
+  (when-let [block (state/get-edit-block)]
+    (state/pub-event! [:editor/remove-own-number-list block])))
+
 (defmethod handle-step :editor/show-date-picker [[_ type]]
   (if (and
        (contains? #{:scheduled :deadline} type)

+ 66 - 43
src/main/frontend/components/block.cljs

@@ -1691,10 +1691,10 @@
 
 (rum/defc block-children < rum/reactive
   [config block children collapsed?]
-  (let [ref? (:ref? config)
-        query? (:custom-query? config)
-        children (when (coll? children)
-                   (remove nil? children))]
+  (let [ref?        (:ref? config)
+        query?      (:custom-query? config)
+        children    (when (coll? children)
+                      (remove nil? children))]
     (when (and (coll? children)
                (seq children)
                (not collapsed?))
@@ -1728,12 +1728,17 @@
 
 (rum/defcs block-control < rum/reactive
   [state config block uuid block-id collapsed? *control-show? edit? has-child?]
-  (let [doc-mode? (state/sub :document/mode?)
-        control-show? (util/react *control-show?)
-        ref? (:ref? config)
-        empty-content? (block-content-empty? block)
-        fold-button-right? (state/enable-fold-button-right?)]
+  (let [doc-mode?          (state/sub :document/mode?)
+        control-show?      (util/react *control-show?)
+        ref?               (:ref? config)
+        empty-content?     (block-content-empty? block)
+        fold-button-right? (state/enable-fold-button-right?)
+        own-number-list?   (:own-order-number-list? config)
+        order-list?        (boolean own-number-list?)
+        order-list-idx     (:own-order-list-index config)]
     [:div.block-control-wrap.mr-1.flex.flex-row.items-center.sm:mr-2
+     {:class (util/classnames [{:is-order-list order-list?
+                                :bullet-closed collapsed?}])}
      (when (or (not fold-button-right?) has-child?)
        [:a.block-control
         {:id       (str "control-" uuid)
@@ -1745,13 +1750,15 @@
                        (if collapsed?
                          (editor-handler/expand-block! uuid)
                          (editor-handler/collapse-block! uuid))))}
-        [:span {:class (if (and control-show?
-                                (or collapsed?
-                                    (editor-handler/collapsable? uuid {:semantic? true}))) "control-show cursor-pointer" "control-hide")}
+        [:span {:class (if (or (and control-show?
+                                    (or collapsed?
+                                        (editor-handler/collapsable? uuid {:semantic? true})))
+                               (and collapsed? order-list?))
+                         "control-show cursor-pointer"
+                         "control-hide")}
          (ui/rotating-arrow collapsed?)]])
 
-     (let [bullet [:a {:on-click (fn [event]
-                                   (bullet-on-click event block uuid))}
+     (let [bullet [:a.bullet-link-wrap {:on-click #(bullet-on-click % block uuid)}
                    [:span.bullet-container.cursor
                     {:id (str "dot-" uuid)
                      :draggable true
@@ -1759,11 +1766,14 @@
                                       (bullet-drag-start event block uuid block-id))
                      :blockid (str uuid)
                      :class (str (when collapsed? "bullet-closed")
-                                 " "
                                  (when (and (:document/mode? config)
                                             (not collapsed?))
-                                   "hide-inner-bullet"))}
-                    [:span.bullet {:blockid (str uuid)}]]]]
+                                   " hide-inner-bullet")
+                                 (when order-list? " as-order-list typed-list"))}
+
+                    [:span.bullet {:blockid (str uuid)}
+                     (when order-list?
+                       [:label (str order-list-idx ".")])]]]]
        (cond
          (and (or (mobile-util/native-platform?)
                   (:ui/show-empty-bullets? (state/get-config)))
@@ -1771,14 +1781,14 @@
          bullet
 
          (or
-          (and empty-content?
-               (not edit?)
-               (not (:block/top? block))
-               (not (:block/bottom? block))
-               (not (util/react *control-show?)))
-          (and doc-mode?
-               (not collapsed?)
-               (not (util/react *control-show?))))
+           (and empty-content?
+                (not edit?)
+                (not (:block/top? block))
+                (not (:block/bottom? block))
+                (not (util/react *control-show?)))
+           (and doc-mode?
+                (not collapsed?)
+                (not (util/react *control-show?))))
          ;; hidden
          [:span.bullet-container]
 
@@ -2765,6 +2775,7 @@
         config (if (nil? (:query-result config))
                  (assoc config :query-result (atom nil))
                  config)
+        config (if ref? (block-handler/attach-order-list-state config block) config)
         heading? (:heading properties)
         *control-show? (get state ::control-show?)
         db-collapsed? (util/collapsed? block)
@@ -2865,6 +2876,12 @@
 
      (dnd-separator-wrapper block block-id slide? false false)]))
 
+(defn- attach-order-list-state!
+  [cp-state]
+  (let [args (:rum/args cp-state)]
+    (assoc cp-state
+      :rum/args (assoc (vec args) 0 (block-handler/attach-order-list-state (first args) (second args))))))
+
 (rum/defcs block-container < rum/reactive
   (rum/local false ::show-block-left-menu?)
   (rum/local false ::show-block-right-menu?)
@@ -2881,20 +2898,26 @@
 
                :else
                nil)
-             (assoc state
-                    ::control-show? (atom false)
-                    ::navigating-block (atom (:block/uuid block)))))
+             (-> (assoc state
+                   ::control-show? (atom false)
+                   ::navigating-block (atom (:block/uuid block)))
+                 (attach-order-list-state!))))
+
+   :will-remount (fn [_old-state new-state]
+                   (-> new-state
+                       (attach-order-list-state!)))
+
    :should-update (fn [old-state new-state]
-                    (let [compare-keys [:block/uuid :block/content :block/parent :block/collapsed?
-                                        :block/properties :block/left :block/children :block/_refs :block/bottom? :block/top?]
-                          config-compare-keys [:show-cloze?]
-                          b1 (second (:rum/args old-state))
-                          b2 (second (:rum/args new-state))
-                          result (or
-                                  (not= (select-keys b1 compare-keys)
-                                        (select-keys b2 compare-keys))
-                                  (not= (select-keys (first (:rum/args old-state)) config-compare-keys)
-                                        (select-keys (first (:rum/args new-state)) config-compare-keys)))]
+                    (let [compare-keys        [:block/uuid :block/content :block/parent :block/collapsed?
+                                               :block/properties :block/left :block/children :block/_refs :block/bottom? :block/top?]
+                          config-compare-keys [:show-cloze? :own-order-list-type :own-order-list-index]
+                          b1                  (second (:rum/args old-state))
+                          b2                  (second (:rum/args new-state))
+                          result              (or
+                                                (not= (select-keys b1 compare-keys)
+                                                      (select-keys b2 compare-keys))
+                                                (not= (select-keys (first (:rum/args old-state)) config-compare-keys)
+                                                      (select-keys (first (:rum/args new-state)) config-compare-keys)))]
                       (boolean result)))
    :will-unmount (fn [state]
                    ;; restore root block's collapsed state
@@ -2904,8 +2927,8 @@
                        (state/set-collapsed-block! block-id nil)))
                    state)}
   [state config block]
-  (let [repo (state/get-current-repo)
-        ref? (:ref? config)
+  (let [repo          (state/get-current-repo)
+        ref?          (:ref? config)
         custom-query? (boolean (:custom-query? config))]
     (if (and (or ref? custom-query?) (not (:ref-query-child? config)))
       (ui/lazy-visible
@@ -2915,11 +2938,11 @@
 
 (defn divide-lists
   [[f & l]]
-  (loop [l l
+  (loop [l        l
          ordered? (:ordered f)
-         result [[f]]]
+         result   [[f]]]
     (if (seq l)
-      (let [cur (first l)
+      (let [cur          (first l)
             cur-ordered? (:ordered cur)]
         (if (= ordered? cur-ordered?)
           (recur

+ 34 - 7
src/main/frontend/components/block.css

@@ -116,6 +116,7 @@
       position: relative;
       top: 4px;
     }
+
     a {
       color: var(--ls-primary-text-color);
 
@@ -202,6 +203,10 @@
 .block-control-wrap {
   height: 24px;
   margin-top: 0;
+
+  &.is-order-list {
+    @apply relative right-0;
+  }
 }
 
 .block-control, .block-control:hover {
@@ -525,6 +530,13 @@
     background-color: var(--ls-block-bullet-color, #8fbc8f);
   }
 
+  &.as-order-list {
+    min-width: 16px;
+    width: auto;
+    white-space: nowrap;
+    justify-content: end;
+  }
+
   .bullet {
     border-radius: 50%;
     width: 6px;
@@ -533,17 +545,32 @@
     transition: transform 0.2s;
   }
 
-  &.bullet-closed {
-    background-color: var(--ls-block-bullet-border-color, #ced9e0);
+  &:not(.typed-list) {
+    &.bullet-closed {
+      background-color: var(--ls-block-bullet-border-color, #ced9e0);
+    }
   }
-}
 
-a:hover > .bullet-container .bullet {
-  transform: scale(1.4);
+  &.typed-list:not(:focus-within) {
+    .bullet {
+      background-color: unset;
+      height: unset;
+      width: unset;
+      box-shadow: none;
+    }
+  }
 }
 
-a:hover > .bullet-container {
-  background-color: var(--ls-block-bullet-border-color, #ced9e0);
+.bullet-link-wrap {
+  color: var(--ls-primary-text-color);
+
+  &:hover > .bullet-container .bullet {
+    transform: scale(1.4);
+  }
+
+  &:hover > .bullet-container:not(.typed-list) {
+    background-color: var(--ls-block-bullet-border-color, #ced9e0);
+  }
 }
 
 .content.doc-mode {

+ 2 - 1
src/main/frontend/components/content.cljs

@@ -353,7 +353,8 @@
      (mixins/listen state js/window "contextmenu"
                     (fn [e]
                       (let [target (gobj/get e "target")
-                            block-id (d/attr target "blockid")
+                            block-el (.closest target ".bullet-container[blockid]")
+                            block-id (some-> block-el (.getAttribute "blockid"))
                             {:keys [block block-ref]} (state/sub :block-ref/context)
                             {:keys [page]} (state/sub :page-title/context)]
                         (cond

+ 29 - 0
src/main/frontend/handler/block.cljs

@@ -291,3 +291,32 @@
                               (recur parent (conj result parent))
                               result))))]
       (distinct (mapcat get-parents filtered-ref-blocks)))))
+
+(defn get-idx-of-order-list-block
+  [block order-list-type]
+  (let [order-block-fn? #(some-> % :block/properties :logseq.order-list-type (= order-list-type))
+        prev-block-fn   #(some->> (:db/id %) (db-model/get-prev-sibling (state/get-current-repo)))
+        prev-block      (prev-block-fn block)]
+    (letfn [(page-fn? [b] (some-> b :block/name some?))
+            (order-sibling-list [b]
+              (lazy-seq
+                (when (and (not (page-fn? b)) (order-block-fn? b))
+                  (cons b (order-sibling-list (prev-block-fn b))))))
+            (order-parent-list [b]
+              (lazy-seq
+                (when (and (not (page-fn? b)) (order-block-fn? b))
+                  (cons b (order-parent-list (db-model/get-block-parent (:block/uuid b)))))))]
+      (let [idx           (if prev-block
+                            (count (order-sibling-list block)) 1)
+            order-parents-count (count (order-parent-list block))]
+        (if (or (zero? order-parents-count)
+                (odd? order-parents-count))
+          idx (nth (seq "abcdefghijklmnopqrstuvwxyz") (mod (dec idx) 26)))))))
+
+(defn attach-order-list-state
+  [config block]
+  (let [own-order-list-type  (some-> block :block/properties :logseq.order-list-type str string/lower-case)
+        own-order-list-index (some->> own-order-list-type (get-idx-of-order-list-block block))]
+    (assoc config :own-order-list-type own-order-list-type
+                  :own-order-list-index own-order-list-index
+                  :own-order-number-list? (= own-order-list-type "number"))))

+ 42 - 2
src/main/frontend/handler/editor.cljs

@@ -62,6 +62,35 @@
 (defonce *asset-uploading? (atom false))
 (defonce *asset-uploading-process (atom 0))
 
+(declare set-block-property!)
+(declare remove-block-property!)
+
+(defn get-block-own-order-list-type
+  [block]
+  (some-> block :block/properties :logseq.order-list-type))
+
+(defn set-block-own-order-list-type!
+  [block type]
+  (when-let [uuid (:block/uuid block)]
+    (set-block-property! uuid :logseq.order-list-type (name type))))
+
+(defn remove-block-own-order-list-type!
+  [block]
+  (when-let [uuid (:block/uuid block)]
+    (remove-block-property! uuid :logseq.order-list-type)))
+
+(defn own-order-list?
+  [block]
+  (not (string/blank? (get-block-own-order-list-type block))))
+
+(defn own-order-number-list?
+  [block]
+  (= (get-block-own-order-list-type block) "number"))
+
+(defn make-block-as-own-order-list!
+  [block]
+  (some-> block (set-block-own-order-list-type! "number")))
+
 (defn get-selection-and-format
   []
   (when-let [block (state/get-edit-block)]
@@ -558,7 +587,9 @@
                     {:ok-handler
                      (fn [last-block]
                        (clear-when-saved!)
-                       (edit-block! last-block 0 id))}))))
+                       (edit-block! last-block 0 id)
+                       (when-let [order-list-type (and (own-order-list? block) (get-block-own-order-list-type block))]
+                         (set-block-own-order-list-type! last-block order-list-type)))}))))
    (state/set-editor-op! nil)))
 
 (defn api-insert-new-block!
@@ -2450,6 +2481,7 @@
     (let [{:keys [block config]} (get-state)]
       (when block
         (let [input (state/get-input)
+              config (assoc config :keydown-new-block true)
               content (gobj/get input "value")
               pos (cursor/pos input)
               current-node (outliner-core/block block)
@@ -2492,6 +2524,12 @@
               "list-item" (dwim-in-list)
               "properties-drawer" (dwim-in-properties state))
 
+            (and (string/blank? content)
+                 (own-order-number-list? block)
+                 (not (some-> (db-model/get-block-parent (:block/uuid block))
+                              (own-order-number-list?))))
+            (remove-block-own-order-list-type! block)
+
             (and
              (string/blank? content)
              (not has-right?)
@@ -2739,7 +2777,9 @@
                    (not root-block?)
                    (not single-block?)
                    (not custom-query?))
-          (delete-block! repo false)))
+          (if (own-order-number-list? block)
+            (remove-block-own-order-list-type! block)
+            (delete-block! repo false))))
 
       (and (> current-pos 1)
            (= (util/nth-safe value (dec current-pos)) (state/get-editor-command-trigger)))

+ 10 - 0
src/main/frontend/handler/events.cljs

@@ -948,6 +948,16 @@
 (defmethod handle :editor/quick-capture [[_ args]]
   (quick-capture/quick-capture args))
 
+(defmethod handle :editor/toggle-own-number-list [[_ block]]
+  (when block
+    (if (editor-handler/own-order-number-list? block)
+      (editor-handler/remove-block-own-order-list-type! block)
+      (editor-handler/make-block-as-own-order-list! block))))
+
+(defmethod handle :editor/remove-own-number-list [[_ block]]
+  (when (some-> block (editor-handler/own-order-number-list?))
+    (editor-handler/remove-block-own-order-list-type! block)))
+
 (defn run!
   []
   (let [chan (state/get-events-chan)]