瀏覽代碼

feat: code/quote/math block (#11545)

Add code, quote and math block
Tienson Qin 1 年之前
父節點
當前提交
54f191c6c6

+ 12 - 1
deps/db/src/logseq/db/frontend/property.cljs

@@ -38,6 +38,16 @@
                                    :cardinality :many
                                    :public? true
                                    :classes #{:logseq.class/Root}}}
+   :logseq.property.node/type {:title "Node type"
+                               :schema {:type :keyword
+                                        :public? false
+                                        :hide? true
+                                        :view-context :block}}
+   :logseq.property.code/mode {:title "Code mode"
+                               :schema {:type :string
+                                        :public? false
+                                        :hide? true
+                                        :view-context :block}}
    :logseq.property/parent {:title "Parent"
                             :schema {:type :node
                                      :public? true
@@ -264,7 +274,8 @@
 
 (def logseq-property-namespaces
   #{"logseq.property" "logseq.property.tldraw" "logseq.property.pdf" "logseq.property.fsrs" "logseq.task"
-    "logseq.property.linked-references" "logseq.property.asset" "logseq.property.table"
+    "logseq.property.linked-references" "logseq.property.asset" "logseq.property.table" "logseq.property.node"
+    "logseq.property.code"
     "logseq.property.journal" "logseq.property.class" "logseq.property.view"})
 
 (defn logseq-property?

+ 1 - 1
deps/db/src/logseq/db/frontend/schema.cljs

@@ -2,7 +2,7 @@
   "Main datascript schemas for the Logseq app"
   (:require [clojure.set :as set]))
 
-(def version 25)
+(def version 27)
 ;; A page is a special block, a page can corresponds to multiple files with the same ":block/name".
 (def ^:large-vars/data-var schema
   {:db/ident        {:db/unique :db.unique/identity}

+ 1 - 1
deps/outliner/src/logseq/outliner/property.cljs

@@ -32,7 +32,7 @@
                     {:type :notification
                      :payload {:message "Can't set a tag as a parent for non-tag page"
                                :type :warning}
-                     :blocks (remove ldb/class? blocks)}))))
+                     :blocks (map #(select-keys % [:db/id :block/title]) (remove ldb/class? blocks))}))))
 
 (defn- build-property-value-tx-data
   ([block property-id value]

+ 47 - 11
src/main/frontend/commands.cljs

@@ -154,6 +154,40 @@
     (db-based-query)
     (file-based-query)))
 
+(defn db-based-code-block
+  []
+  [[:editor/input "" {:last-pattern command-trigger}]
+   [:editor/set-property :logseq.property.node/type :code]
+   [:codemirror/focus]])
+
+(defn file-based-code-block
+  []
+  [[:editor/input "```\n```\n" {:type "block"
+                                :backward-pos 5
+                                :only-breakline? true}]
+   [:editor/select-code-block-mode]])
+
+(defn code-block-steps
+  []
+  (if (config/db-based-graph? (state/get-current-repo))
+    (db-based-code-block)
+    (file-based-code-block)))
+
+(declare ->block)
+(defn quote-block-steps
+  []
+  (if (config/db-based-graph? (state/get-current-repo))
+    [[:editor/input "" {:last-pattern command-trigger}]
+     [:editor/set-property :logseq.property.node/type :quote]]
+    (->block "quote")))
+
+(defn math-block-steps
+  []
+  (if (config/db-based-graph? (state/get-current-repo))
+    [[:editor/input "" {:last-pattern command-trigger}]
+     [:editor/set-property :logseq.property.node/type :math]]
+    (->block "export" "latex")))
+
 (defn get-statuses
   []
   (let [db-based? (config/db-based-graph? (state/get-current-repo))
@@ -288,11 +322,17 @@
                         {:last-pattern command-trigger
                          :backward-pos 6}]] "Create a underline text decoration"
           :icon/underline])
-       ["Code block" [[:editor/input "```\n```\n" {:type "block"
-                                                   :backward-pos 5
-                                                   :only-breakline? true}]
-                      [:editor/select-code-block-mode]] "Insert code block"
-        :icon/code]]
+       ["Code block"
+        (code-block-steps)
+        "Insert code block"
+        :icon/code]
+       ["Quote"
+        (quote-block-steps)
+        "Create a quote block"
+        :icon/quote-block]
+       ["Math block"
+        (math-block-steps)
+        "Create a latex block"]]
 
       (headings)
 
@@ -333,14 +373,10 @@
       ;; https://orgmode.org/manual/Structure-Templates.html
       (when-not db?
         (cond->
-         [["Quote" (->block "quote")
-           "Create a quote block"
-           :icon/quote-block
-           "BLOCK TYPE"]
-        ;; Should this be replaced by "Code block"?
+         [;; Should this be replaced by "Code block"?
           ["Src" (->block "src") "Create a code block"]
           ["Advanced Query" (->block "query") "Create an advanced query block"]
-          ["Latex export" (->block "export" "latex") "Create a latex block"]
+          ["Math block" (->block "export" "latex") "Create a latex block"]
           ["Note" (->block "note") "Create a note block"]
           ["Tip" (->block "tip") "Create a tip block"]
           ["Important" (->block "important") "Create an important block"]

+ 6 - 2
src/main/frontend/common.css

@@ -111,7 +111,7 @@ body {
     font-weight: bold;
   }
 
-  blockquote {
+  blockquote, .block-content-or-editor-wrap[data-node-type='quote'] {
     display: block;
     text-indent: 0;
     padding: 8px 20px;
@@ -122,10 +122,14 @@ body {
     font-size: 1rem;
   }
 
-  html blockquote {
+  html blockquote, .block-content-or-editor-wrap[data-node-type='quote']  {
     border-left-color: var(--ls-page-blockquote-border-color, var(--lx-gray-05-alpha, hsl(var(--primary)/.4)));
   }
 
+  .block-content-or-editor-wrap[data-node-type='quote'] {
+    margin: 0.5rem 0;
+  }
+
   summary {
     outline: none;
   }

+ 41 - 22
src/main/frontend/components/block.cljs

@@ -2036,7 +2036,9 @@
 
 (declare block-content)
 
-(defn build-block-title
+(declare src-cp)
+
+(defn- text-block-title
   [config {:block/keys [marker pre-block? properties] :as block}]
   (let [block-title (:block.temp/ast-title block)
         config (assoc config :block block)
@@ -2134,6 +2136,20 @@
                           (state/pub-event! [:modal/show-cards (:db/id block)]))}
              "Practice")])))))))
 
+(defn build-block-title
+  [config block]
+  (let [node-type (:logseq.property.node/type block)]
+    (case node-type
+      :code
+      [:div.flex.flex-1.w-full
+       (src-cp (assoc config :block block) {:language (:logseq.property.code/mode block)})]
+
+      ;; TODO: switched to https://cortexjs.io/mathlive/ for editing
+      :math
+      (latex/latex (str (:container-id config) "-" (:db/id block)) (:block/title block) true false)
+
+      (text-block-title config block))))
+
 (rum/defc span-comma
   []
   [:span ", "])
@@ -2395,20 +2411,21 @@
       :block-content-slotted
       (-> block (dissoc :block/children :block/page)))]
 
-    (let [title-collapse-enabled? (:outliner/block-title-collapse-enabled? (state/get-config))]
-      (when (and (not block-ref-with-title?)
-                 (seq body)
-                 (or (not title-collapse-enabled?)
-                     (and title-collapse-enabled?
-                          (or (not collapsed?)
-                              (some? (mldoc/extract-first-query-from-ast body))))))
-        [:div.block-body
-         (let [body (block/trim-break-lines! (:block.temp/ast-body block))
-               uuid (:block/uuid block)]
-           (for [[idx child] (medley/indexed body)]
-             (when-let [block (markup-element-cp config child)]
-               (rum/with-key (block-child block)
-                 (str uuid "-" idx)))))]))))
+    (when-not (contains? #{:code :math} (:logseq.property.node/type block))
+      (let [title-collapse-enabled? (:outliner/block-title-collapse-enabled? (state/get-config))]
+        (when (and (not block-ref-with-title?)
+                   (seq body)
+                   (or (not title-collapse-enabled?)
+                       (and title-collapse-enabled?
+                            (or (not collapsed?)
+                                (some? (mldoc/extract-first-query-from-ast body))))))
+          [:div.block-body
+           (let [body (block/trim-break-lines! (:block.temp/ast-body block))
+                 uuid (:block/uuid block)]
+             (for [[idx child] (medley/indexed body)]
+               (when-let [block (markup-element-cp config child)]
+                 (rum/with-key (block-child block)
+                   (str uuid "-" idx)))))])))))
 
 (rum/defcs block-tag <
   (rum/local false ::hover?)
@@ -2707,7 +2724,8 @@
                      (rum/react *refs-count))
         table? (:table? config)]
     [:div.block-content-or-editor-wrap
-     {:class (when (:page-title? config) "ls-page-title-container")}
+     {:class (when (:page-title? config) "ls-page-title-container")
+      :data-node-type (some-> (:logseq.property.node/type block) name)}
      (when (and db-based? (not table?)) (block-positioned-properties config block :block-left))
      [:div.block-content-or-editor-inner
       [:div.flex.flex-1.flex-row.gap-1.items-center
@@ -3509,12 +3527,13 @@
 (declare ->hiccup)
 
 (rum/defc src-cp < rum/static
-  [config options html-export?]
+  [config options]
   (when options
-    (let [{:keys [lines language]} options
+    (let [html-export? (:html-export? config)
+          {:keys [lines language]} options
           attr (when language
                  {:data-lang language})
-          code (apply str lines)
+          code (if lines (apply str lines) (:block/title (:block config)))
           [inside-portal? set-inside-portal?] (rum/use-state nil)]
       (cond
         html-export?
@@ -3522,7 +3541,7 @@
 
         :else
         (let [language (if (contains? #{"edn" "clj" "cljc" "cljs"} language) "clojure" language)]
-          [:div.ui-fenced-code-editor
+          [:div.ui-fenced-code-editor.flex.flex-1
            {:ref (fn [el]
                    (set-inside-portal? (and el (whiteboard-handler/inside-portal? el))))}
            (cond
@@ -3704,9 +3723,9 @@
          {:data-lang lang}
          (if-let [opts (plugin-handler/hook-fenced-code-by-lang lang)]
            [:div.ui-fenced-code-wrap
-            (src-cp config options html-export?)
+            (src-cp config options)
             (plugins/hook-ui-fenced-code (:block config) (string/join "" (:lines options)) opts)]
-           (src-cp config options html-export?))])
+           (src-cp config options))])
 
       :else
       "")

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

@@ -36,7 +36,8 @@
             [logseq.db.frontend.property.type :as db-property-type]
             [logseq.shui.ui :as shui]
             [promesa.core :as p]
-            [rum.core :as rum]))
+            [rum.core :as rum]
+            [frontend.modules.outliner.op :as outliner-op]))
 
 (rum/defc property-empty-btn-value
   [property & opts]
@@ -732,11 +733,29 @@
                      (shui/popup-show!
                       (.-target e)
                       (fn []
-                        [:div.p-4.h-64 {:style {:width "42rem"}}
-                         (let [block (db/entity (:db/id v-block))
-                               query (:block/title block)]
-                           (query-builder-component/builder query {:property property
-                                                                   :block block}))])
+                        (let [block (db/entity (:db/id v-block))
+                              query (:block/title block)]
+                          [:div.p-4.h-64.flex.flex-col.gap-4 {:style {:width "42rem"}}
+                           [:div.flex.flex-1
+                            (query-builder-component/builder query {:property property
+                                                                    :block block})]
+
+                           [:div
+                            (shui/button
+                             {:variant :ghost
+                              :size :sm
+                              :class "text-muted-foreground"
+                              :on-click (fn []
+                                          (p/do!
+                                           (ui-outliner-tx/transact!
+                                            {:outliner-op :save-block}
+                                            (db-property-handler/set-block-properties! (:db/id block)
+                                                                                       {:logseq.property.node/type :code
+                                                                                        :logseq.property.code/mode "clojure"})
+                                            (outliner-op/save-block! {:db/id (:db/id block) :block/title ""}))
+
+                                           (shui/popup-hide!)))}
+                             "Switch to advanced query")]]))
                       {:align :end}))}
         (ui/icon "settings" {:size 18})))]))
 

+ 10 - 10
src/main/frontend/extensions/code.cljs

@@ -153,7 +153,6 @@
 ;; export CodeMirror to global scope
 (set! js/window -CodeMirror CodeMirror)
 
-
 (defn- all-tokens-by-cursor
   "All tokens from the beginning of the document to the cursor(inclusive)."
   [cm]
@@ -163,7 +162,6 @@
     (concat (mapcat #(.getLineTokens cm %) (range line))
             (filter #(<= (.-end %) pos) (.getLineTokens cm line)))))
 
-
 (defn- tokens->doc-state
   "Parse tokens into document state of the last token."
   [tokens]
@@ -392,7 +390,7 @@
   (p/do!
    (code-handler/save-code-editor!)
    (when-let [block-id (:block/uuid config)]
-     (let [block (db/pull [:block/uuid block-id])]
+     (let [block (db/entity [:block/uuid block-id])]
        (editor-handler/edit-block! block :max)))))
 
 (defn ^:large-vars/cleanup-todo render!
@@ -481,12 +479,14 @@
                                                    shifted?
                                                    (case key-code
                                                      "Enter"
-                                                     (when-let [blockid (some-> (.-target e) (.closest "[blockid]") (.getAttribute "blockid"))]
-                                                       (code-handler/save-code-editor!)
-                                                       (js/setTimeout
-                                                        #(editor-handler/api-insert-new-block! ""
-                                                                                               {:block-uuid (uuid blockid)
-                                                                                                :sibling? true}) 32))
+                                                     (do
+                                                       (util/stop e)
+                                                       (when-let [blockid (some-> (.-target e) (.closest "[blockid]") (.getAttribute "blockid"))]
+                                                         (code-handler/save-code-editor!)
+                                                         (js/setTimeout
+                                                          #(editor-handler/api-insert-new-block! ""
+                                                                                                 {:block-uuid (uuid blockid)
+                                                                                                  :sibling? true}) 32)))
                                                      nil)))))
         (.addEventListener element "pointerdown"
                            (fn [e]
@@ -539,7 +539,7 @@
                        (.setValue editor' code))))
                  state)}
   [state _config id attr code _theme _options]
-  [:div.extensions__code
+  [:div.extensions__code.flex.flex-1
    (when-let [mode (:data-lang attr)]
      (when-not (= mode "calc")
        [:div.extensions__code-lang

+ 6 - 6
src/main/frontend/extensions/latex.cljs

@@ -16,7 +16,7 @@
 
 (defn render!
   [state]
-  (let [[id s display?] (:rum/args state)]
+  (let [[id s _ display?] (:rum/args state)]
     (try
       (when-let [elem (gdom/getElement id)]
         (js/katex.render s elem
@@ -42,13 +42,13 @@
           (config/asset-uri "/static/js/mhchem.min.js")
           (fn []
             (some-> (when-let [enhancers (and config/lsp-enabled?
-                                           (seq (hook-extensions-enhancers-by-key :katex)))]
+                                              (seq (hook-extensions-enhancers-by-key :katex)))]
                       (for [{f :enhancer} enhancers]
                         (when (fn? f) (f js/window.katex))))
-              (p/all)
-              (p/finally (fn []
-                           (reset! *loading? false)
-                           (render! state)))))))
+                    (p/all)
+                    (p/finally (fn []
+                                 (reset! *loading? false)
+                                 (render! state)))))))
        state))))
 
 (defn- state-&-load-and-render!

+ 5 - 1
src/main/frontend/handler/code.cljs

@@ -21,11 +21,15 @@
             ds (.-dataset textarea)
             value (gobj/get textarea "value")
             default-value (or (.-v ds) (gobj/get textarea "defaultValue"))
-            repo (state/get-current-repo)]
+            repo (state/get-current-repo)
+            block (:block config)]
         (when (not= value default-value)
           ;; update default value for the editor initial state
           (set! ds -v value)
           (cond
+            (= :code (:logseq.property.node/type block))
+            (editor-handler/save-block-if-changed! block value)
+
             ;; save block content
             (:block/uuid config)
             (let [block (db/entity [:block/uuid (:block/uuid config)])

+ 1 - 0
src/main/frontend/handler/editor.cljs

@@ -845,6 +845,7 @@
                           db-based? (config/db-based-graph? repo)
                           delete-prev-block? (and db-based?
                                                   (empty? (:block/tags block))
+                                                  (not (:logseq.property.node/type block))
                                                   (seq (:block/properties block))
                                                   (empty? (:block/properties prev-block))
                                                   (not (:logseq.property/created-from-property block)))]

+ 3 - 1
src/main/frontend/worker/db/migrate.cljs

@@ -274,7 +274,9 @@
    [23 {:fix add-card-properties}]
    [24 {:classes [:logseq.class/Cards]}]
    [25 {:properties [:logseq.property/query]
-        :fix add-query-property-to-query-tag}]])
+        :fix add-query-property-to-query-tag}]
+   [26 {:properties [:logseq.property.node/type]}]
+   [27 {:properties [:logseq.property.code/mode]}]])
 
 (let [max-schema-version (apply max (map first schema-version->updates))]
   (assert (<= db-schema/version max-schema-version))

+ 1 - 1
src/main/frontend/worker/rtc/db_listener.cljs

@@ -27,7 +27,7 @@
 
 (def ^:private watched-attr-ns
   #{"logseq.property" "logseq.property.tldraw" "logseq.property.pdf" "logseq.property.fsrs"
-    "logseq.property.linked-references" "logseq.task"
+    "logseq.property.linked-references" "logseq.task" "logseq.property.node" "logseq.property.code"
     "logseq.class" "logseq.kv"})
 
 (defn- watched-attr?

+ 0 - 0
validate.cljs