Browse Source

Merge branch 'master' into fix-toggling-config-in-settings

Tienson Qin 3 years ago
parent
commit
7256451367

+ 12 - 4
gulpfile.js

@@ -49,18 +49,25 @@ const common = {
     return gulp.watch(resourceFilePath, { ignoreInitial: true }, common.syncResourceFile)
   },
 
-  syncStatic () {
+  syncAllStatic () {
     return gulp.src([
       outputFilePath,
       '!' + path.join(outputPath, 'node_modules/**')
     ]).pipe(gulp.dest(publicStaticPath))
   },
 
-  keepSyncStatic () {
+  syncJS_CSSinRt () {
+    return gulp.src([
+      path.join(outputPath, 'js/**'),
+      path.join(outputPath, 'css/**')
+    ], { base: outputPath }).pipe(gulp.dest(publicStaticPath))
+  },
+
+  keepSyncStaticInRt () {
     return gulp.watch([
       path.join(outputPath, 'js/**'),
       path.join(outputPath, 'css/**')
-    ], { ignoreInitial: true }, common.syncStatic)
+    ], { ignoreInitial: true }, common.syncJS_CSSinRt)
   }
 }
 
@@ -109,5 +116,6 @@ exports.electronMaker = async () => {
 }
 
 exports.clean = common.clean
-exports.watch = gulp.series(common.syncResourceFile, common.syncStatic, gulp.parallel(common.keepSyncResourceFile, css.watchCSS, common.keepSyncStatic))
+exports.watch = gulp.series(common.syncResourceFile, common.syncAllStatic,
+  gulp.parallel(common.keepSyncResourceFile, css.watchCSS, common.keepSyncStaticInRt))
 exports.build = gulp.series(common.clean, common.syncResourceFile, css.buildCSS)

+ 1 - 1
package.json

@@ -93,7 +93,7 @@
         "ignore": "5.1.8",
         "is-svg": "4.2.2",
         "jszip": "3.5.0",
-        "mldoc": "1.2.5",
+        "mldoc": "1.2.6",
         "path": "0.12.7",
         "pixi-graph-fork": "0.2.0",
         "pixi.js": "6.2.0",

+ 29 - 28
src/electron/electron/search.cljs

@@ -159,41 +159,42 @@
 ;;                          "select id, uuid, content from blocks_fts where content match ? ORDER BY rank")]
 ;;       (js->clj (.all ^object stmt q) :keywordize-keys true))))
 
+(defn- search-blocks-aux
+  [database sql input page limit]
+  (let [stmt (prepare database sql)]
+    (js->clj
+     (if page
+       (.all ^object stmt (int page) input limit)
+       (.all ^object stmt  input limit))
+     :keywordize-keys true)))
+
 (defn search-blocks
   [repo q {:keys [limit page]}]
   (when-let [database (get-db repo)]
     (when-not (string/blank? q)
-      (let [match? (or
-                    (string/includes? q " and ")
-                    (string/includes? q " & ")
-                    (string/includes? q " or ")
-                    (string/includes? q " | ")
-                    ;; (string/includes? q " not ")
-                    )
-            input  (if match?
-                         (-> q
-                             (string/replace " and " " AND ")
-                             (string/replace " & " " AND ")
-                             (string/replace " or " " OR ")
-                             (string/replace " | " " OR ")
-                             (string/replace " not " " NOT "))
-                         (str "%" (string/replace q #"\s+" "%") "%"))
+      (let [match-input (-> q
+                            (string/replace " and " " AND ")
+                            (string/replace " & " " AND ")
+                            (string/replace " or " " OR ")
+                            (string/replace " | " " OR ")
+                            (string/replace " not " " NOT "))
+            non-match-input (str "%" (string/replace q #"\s+" "%") "%")
             limit  (or limit 20)
             select "select rowid, uuid, content, page from blocks_fts where "
             pg-sql (if page "page = ? and" "")
-            sql    (if match?
-                     (str select
-                          pg-sql
-                          " content match ? order by rank limit ?")
-                     (str select
-                          pg-sql
-                          " content like ? limit ?"))
-            stmt   (prepare database sql)]
-        (js->clj
-         (if page
-           (.all ^object stmt (int page) input limit)
-           (.all ^object stmt  input limit))
-          :keywordize-keys true)))))
+            match-sql (str select
+                           pg-sql
+                           " content match ? order by rank limit ?")
+            non-match-sql (str select
+                               pg-sql
+                               " content like ? limit ?")]
+        (->>
+         (concat
+          (search-blocks-aux database match-sql match-input page limit)
+          (search-blocks-aux database non-match-sql non-match-input page limit))
+         (distinct)
+         (take limit)
+         (vec))))))
 
 (defn truncate-blocks-table!
   [repo]

+ 8 - 7
src/electron/electron/window.cljs

@@ -50,13 +50,13 @@
                                    origin (.-origin urlObj)
                                    requestHeaders (.-requestHeaders details)]
                                (if (and
-                                    (.hasOwnProperty requestHeaders "referer")
-                                    (not-empty (.-referer requestHeaders)))
-                                 (callback #js {:cancel false
+                                     (.hasOwnProperty requestHeaders "referer")
+                                     (not-empty (.-referer requestHeaders)))
+                                 (callback #js {:cancel         false
                                                 :requestHeaders requestHeaders})
                                  (do
                                    (set! (.-referer requestHeaders) origin)
-                                   (callback #js {:cancel false
+                                   (callback #js {:cancel         false
                                                   :requestHeaders requestHeaders}))))))
      (.loadURL win url)
      ;;(when dev? (.. win -webContents (openDevTools)))
@@ -115,9 +115,10 @@
                          (js/decodeURIComponent url) url)
                    url (if-not win32? (string/replace url "file://" "") url)]
                (.. logger (info "new-window" url))
-               (if (string/includes?
-                    (.normalize path url)
-                    (.join path (. app getAppPath) "index.html"))
+               (if (some #(string/includes?
+                            (.normalize path url)
+                            (.join path (. app getAppPath) %))
+                         ["index.html" "electron.html"])
                  (.info logger "pass-window" url)
                  (open url)))
              (.preventDefault e)))

+ 87 - 104
src/main/frontend/components/block.cljs

@@ -185,23 +185,23 @@
       (ui/resize-provider
        (ui/resize-consumer
         (cond->
-         {:className "resize image-resize"
-          :onSizeChanged (fn [value]
-                           (when (and (not @*resizing-image?)
-                                      (some? @size)
-                                      (not= value @size))
-                             (reset! *resizing-image? true))
-                           (reset! size value))
-          :onMouseUp (fn []
-                       (when (and @size @*resizing-image?)
-                         (when-let [block-id (:block/uuid config)]
-                           (let [size (bean/->clj @size)]
-                             (editor-handler/resize-image! block-id metadata full_text size))))
-                       (when @*resizing-image?
+          {:className "resize image-resize"
+           :onSizeChanged (fn [value]
+                            (when (and (not @*resizing-image?)
+                                       (some? @size)
+                                       (not= value @size))
+                              (reset! *resizing-image? true))
+                            (reset! size value))
+           :onMouseUp (fn []
+                        (when (and @size @*resizing-image?)
+                          (when-let [block-id (:block/uuid config)]
+                            (let [size (bean/->clj @size)]
+                              (editor-handler/resize-image! block-id metadata full_text size))))
+                        (when @*resizing-image?
                           ;; TODO: need a better way to prevent the clicking to edit current block
-                         (js/setTimeout #(reset! *resizing-image? false) 200)))
-          :onClick (fn [e]
-                     (when @*resizing-image? (util/stop e)))}
+                          (js/setTimeout #(reset! *resizing-image? false) 200)))
+           :onClick (fn [e]
+                      (when @*resizing-image? (util/stop e)))}
           (and (:width metadata) (not (util/mobile?)))
           (assoc :style {:width (:width metadata)}))
         [:div.asset-container
@@ -476,7 +476,7 @@
           redirect-page-name (or (and (= :org (state/get-preferred-format))
                                       (:org-mode/insert-file-link? (state/get-config))
                                       redirect-page-name)
-                              (model/get-redirect-page-name page-name (:block/alias? config)))
+                                 (model/get-redirect-page-name page-name (:block/alias? config)))
           inner (page-inner config
                             page-name-in-block
                             page-name
@@ -717,8 +717,10 @@
   (if macro-content
     (let [ast (->> (mldoc/->edn macro-content (mldoc/default-config format))
                    (map first))
-          block? (mldoc/block-with-title? (ffirst ast))]
-      (if block?
+          paragraph? (and (= 1 (count ast))
+                          (= "Paragraph" (ffirst ast)))]
+      (if (and (not paragraph?)
+               (mldoc/block-with-title? (ffirst ast)))
         [:div
          (markup-elements-cp (assoc config :block/format format) ast)]
         (inline-text format macro-content)))
@@ -922,9 +924,9 @@
             (->elem
              :a
              (cond->
-              {:href      (str "file://" path)
-               :data-href path
-               :target    "_blank"}
+               {:href      (str "file://" path)
+                :data-href path
+                :target    "_blank"}
                title
                (assoc :title title))
              (map-inline config label)))
@@ -981,9 +983,9 @@
                     (->elem
                      :a
                      (cond->
-                      {:href      (str "file://" href*)
-                       :data-href href*
-                       :target    "_blank"}
+                       {:href      (str "file://" href*)
+                        :data-href href*
+                        :target    "_blank"}
                        title
                        (assoc :title title))
                      (map-inline config label))))))
@@ -1007,20 +1009,20 @@
 
             (= protocol "ar")
             (->elem
-              :a.external-link
-              (cond->
-                {:href (ar-url->http-url href)
-                 :target "_blank"}
-                title
-                (assoc :title title))
-              (map-inline config label))
+             :a.external-link
+             (cond->
+               {:href (ar-url->http-url href)
+                :target "_blank"}
+               title
+               (assoc :title title))
+             (map-inline config label))
 
             :else
             (->elem
              :a.external-link
              (cond->
-              {:href href
-               :target "_blank"}
+               {:href href
+                :target "_blank"}
                title
                (assoc :title title))
              (map-inline config label))))))
@@ -1349,14 +1351,15 @@
 (defn- toggle-block-children
   [e children]
   (let [block-ids (map :block/uuid children)]
-    (if (some editor-handler/collapsable? block-ids)
-      (dorun (map editor-handler/collapse-block! block-ids))
-      (dorun (map editor-handler/expand-block! block-ids)))))
+    (dorun
+     (if (some editor-handler/collapsable? block-ids)
+       (map editor-handler/collapse-block! block-ids)
+       (map editor-handler/expand-block! block-ids)))))
 
 (rum/defc block-children < rum/reactive
-  [config children collapsed? *ref-collapsed?]
+  [config children collapsed? *default-collapsed?]
   (let [ref? (:ref? config)
-        collapsed? (if ref? (rum/react *ref-collapsed?) collapsed?)
+        collapsed? (if ref? (rum/react *default-collapsed?) collapsed?)
         children (and (coll? children) (filter map? children))]
     (when (and (coll? children)
                (seq children)
@@ -1393,7 +1396,7 @@
    (every? #(= % ["Horizontal_Rule"]) body)))
 
 (rum/defcs block-control < rum/reactive
-  [state config block uuid block-id body children collapsed? *ref-collapsed? *control-show? edit?]
+  [state config block uuid block-id body children collapsed? *control-show? edit?]
   (let [doc-mode? (state/sub :document/mode?)
         has-children-blocks? (and (coll? children) (seq children))
         has-child? (and
@@ -1405,9 +1408,7 @@
                                 (seq body))
                            has-children-blocks?)
                        (util/react *control-show?))
-        ref-collapsed? (util/react *ref-collapsed?)
         ref? (:ref? config)
-        collapsed? (if ref? ref-collapsed? collapsed?)
         empty-content? (block-content-empty? block)]
     [:div.mr-1.flex.flex-row.items-center.sm:mr-2
      {:style {:height 24
@@ -1419,11 +1420,9 @@
        :on-click (fn [event]
                    (util/stop event)
                    (when-not (and (not collapsed?) (not has-child?))
-                     (if ref?
-                       (swap! *ref-collapsed? not)
-                       (if collapsed?
-                         (editor-handler/expand-block! uuid)
-                         (editor-handler/collapse-block! uuid)))))}
+                     (if collapsed?
+                       (editor-handler/expand-block! uuid)
+                       (editor-handler/collapse-block! uuid))))}
       [:span {:class (if control-show? "control-show" "control-hide")}
        (ui/rotating-arrow collapsed?)]]
      (let [bullet [:a {:on-click (fn [event]
@@ -1567,7 +1566,7 @@
 
 (defn build-block-title
   [config {:block/keys [title marker pre-block? properties level heading-level]
-                                :as t}]
+           :as t}]
   (let [config (assoc config :block t)
         slide? (boolean (:slide? config))
         block-ref? (:block-ref? config)
@@ -1619,7 +1618,7 @@
           (when (and (util/electron?) (not= block-type :default))
             [:a.prefix-link
              {:on-click #(case block-type
-                            ;; pdf annotation
+                           ;; pdf annotation
                            :annotation (pdf-assets/open-block-ref! t)
                            (.preventDefault %))}
 
@@ -1792,12 +1791,12 @@
            (not (:block/pre-block? block)))
       (let [move-to (rum/react *move-to)]
         (when-not
-         (or (and top? (not= move-to :top))
-             (and (not top?) (= move-to :top))
-             (and block-content? (not= move-to :nested))
-             (and (not block-content?)
-                  (seq (:block/children block))
-                  (= move-to :nested)))
+            (or (and top? (not= move-to :top))
+                (and (not top?) (= move-to :top))
+                (and block-content? (not= move-to :nested))
+                (and (not block-content?)
+                     (seq (:block/children block))
+                     (= move-to :nested)))
           (dnd-separator move-to block-content?))))))
 
 (defn clock-summary-cp
@@ -1840,12 +1839,12 @@
                          :on-mouse-down ; TODO: it seems that Safari doesn't work well with on-mouse-down
                          )
         attrs (cond->
-                  {:blockid       (str uuid)
-                   :data-type (name block-type)
-                   :style {:width "100%"}}
-                  (not block-ref?)
-                  (assoc mouse-down-key (fn [e]
-                                          (block-content-on-mouse-down e block block-id content edit-input-id))))]
+                {:blockid       (str uuid)
+                 :data-type (name block-type)
+                 :style {:width "100%"}}
+                (not block-ref?)
+                (assoc mouse-down-key (fn [e]
+                                        (block-content-on-mouse-down e block block-id content edit-input-id))))]
     [:div.block-content.inline
      (cond-> {:id (str "block-content-" uuid)
               :on-mouse-up (fn [_e]
@@ -2020,16 +2019,16 @@
                                                                  (:block/pre-block? block)
                                                                  content)]
                                  [block
-                                 (if (seq title)
-                                   (->elem :span (map-inline config title))
-                                   (->elem :div (markup-elements-cp config body)))]))))
+                                  (if (seq title)
+                                    (->elem :span (map-inline config title))
+                                    (->elem :div (markup-elements-cp config body)))]))))
             breadcrumb (->> (into [] parents-props)
                             (concat [page-name-props] (when more? [:more]))
                             (filterv identity)
                             (map (fn [x] (if (vector? x)
-                                          (let [[block label] x]
-                                            (breadcrumb-fragment config block label))
-                                          [:span.opacity-70 "⋯"])))
+                                           (let [[block label] x]
+                                             (breadcrumb-fragment config block label))
+                                           [:span.opacity-70 "⋯"])))
                             (interpose (breadcrumb-separator)))]
         [:div.block-parents.flex-row.flex-1
          {:class (when (seq breadcrumb)
@@ -2141,31 +2140,13 @@
      children)
     (distinct @refs)))
 
-;; (rum/defc block-immediate-children < rum/reactive
-;;   [repo config uuid ref? collapsed?]
-;;   (when (and ref? (not collapsed?))
-;;     (let [children (db/get-block-immediate-children repo uuid)
-;;           children (block-handler/filter-blocks repo children (:filters config) false)]
-;;       (when (seq children)
-;;         [:div.ref-children {:style {:margin-left "1.8rem"}}
-;;          (blocks-container children (assoc config
-;;                                            :breadcrumb-show? false
-;;                                            :ref? true
-;;                                            :ref-child? true))]))))
-
 (rum/defcs block-container < rum/reactive
   {:init (fn [state]
-           (let [[config block] (:rum/args state)
-                 ref-collpased? (boolean
-                                 (and
-                                  (seq (:block/children block))
-                                  (or (:custom-query? config)
-                                      (and (:ref? config)
-                                           (>= (:ref/level block)
-                                               (state/get-ref-open-blocks-level))))))]
+           (let [[config block] (:rum/args state)]
              (assoc state
+                    ::init-collapsed? (get-in block [:block/properties :collapsed])
                     ::control-show? (atom false)
-                    ::ref-collapsed? (atom ref-collpased?))))
+                    ::default-collapsed? (atom (editor-handler/block-default-collapsed? block config)))))
    :should-update (fn [old-state new-state]
                     (let [compare-keys [:block/uuid :block/properties
                                         :block/parent :block/left
@@ -2178,7 +2159,8 @@
                        (not= (select-keys (first (:rum/args old-state)) config-compare-keys)
                              (select-keys (first (:rum/args new-state)) config-compare-keys)))))}
   [state config {:block/keys [uuid repo children pre-block? top? properties refs heading-level level type format content] :as block}]
-  (let [block (merge block (block/parse-title-and-body uuid format pre-block? content))
+  (let [init-collapsed? (::init-collapsed? state)
+        block (merge block (block/parse-title-and-body uuid format pre-block? content))
         body (:block/body block)
         blocks-container-id (:blocks-container-id config)
         config (update config :block merge block)
@@ -2188,9 +2170,10 @@
                  config)
         heading? (and (= type :heading) heading-level (<= heading-level 6))
         *control-show? (get state ::control-show?)
-        *ref-collapsed? (get state ::ref-collapsed?)
-        collapsed? (or @*ref-collapsed?
-                       (get properties :collapsed))
+        *default-collapsed? (get state ::default-collapsed?)
+        collapsed? (if (not= init-collapsed? (:collapsed properties))
+                     (:collapsed properties)
+                     @*default-collapsed?)
         ref? (boolean (:ref? config))
         breadcrumb-show? (:breadcrumb-show? config)
         slide? (boolean (:slide? config))
@@ -2214,15 +2197,15 @@
         review-cards? (:review-cards? config)]
     [:div.ls-block
      (cond->
-      {:id block-id
-       :data-refs data-refs
-       :data-refs-self data-refs-self
-       :data-collapsed (and collapsed? has-child?)
-       :class (str uuid
-                   (when pre-block? " pre-block")
-                   (when (and card? (not review-cards?)) " shadow-xl"))
-       :blockid (str uuid)
-       :haschild (str has-child?)}
+       {:id block-id
+        :data-refs data-refs
+        :data-refs-self data-refs-self
+        :data-collapsed (and collapsed? has-child?)
+        :class (str uuid
+                    (when pre-block? " pre-block")
+                    (when (and card? (not review-cards?)) " shadow-xl"))
+        :blockid (str uuid)
+        :haschild (str has-child?)}
 
        level
        (assoc :level level)
@@ -2254,11 +2237,11 @@
        :on-mouse-leave (fn [e]
                          (block-mouse-leave e *control-show? block-id doc-mode?))}
       (when (not slide?)
-        (block-control config block uuid block-id body children collapsed? *ref-collapsed? *control-show? edit?))
+        (block-control config block uuid block-id body children collapsed? *control-show? edit?))
 
       (block-content-or-editor config block edit-input-id block-id heading-level edit?)]
 
-     (block-children config children collapsed? *ref-collapsed?)
+     (block-children config children collapsed? *default-collapsed?)
 
      (dnd-separator-wrapper block block-id slide? false false)]))
 
@@ -2325,7 +2308,7 @@
         (->elem
          :li
          (cond->
-          {:checked checked?}
+           {:checked checked?}
            number
            (assoc :value number))
          (vec-cat

+ 5 - 0
src/main/frontend/components/block.css

@@ -141,6 +141,11 @@
   background-color: var(--ls-guideline-color, #ddd);
 }
 
+.block-children-left-border:hover {
+  padding-right: 0px;
+  background-color: var(--ls-primary-text-color);
+}
+
 .block-children {
   padding-top: 2px;
   padding-bottom: 3px;

+ 13 - 10
src/main/frontend/components/content.cljs

@@ -234,17 +234,20 @@
                           (editor-handler/cut-block! block-id))}
              "Cut")
 
-            (ui/menu-link
-              {:key      "Expand all"
-               :on-click (fn [_e]
-                           (editor-handler/expand-all! block-id))}
-              "Expand all")
+            (when (editor-handler/expand-all? block-id)
+              (ui/menu-link
+               {:key      "Expand all"
+                :on-click (fn [_e]
+                            (editor-handler/expand-all! block-id))}
+               "Expand all"))
 
-            (ui/menu-link
-              {:key      "Collapse all"
-               :on-click (fn [_e]
-                           (editor-handler/collapse-all! block-id))}
-              "Collapse all")
+            (when (editor-handler/collapse-all? block-id)
+
+              (ui/menu-link
+               {:key      "Collapse all"
+                :on-click (fn [_e]
+                            (editor-handler/collapse-all! block-id))}
+               "Collapse all"))
 
             (when (state/sub [:plugin/simple-commands])
               (when-let [cmds (state/get-plugins-commands-with-type :block-context-menu-item)]

+ 45 - 35
src/main/frontend/components/datetime.cljs

@@ -9,10 +9,12 @@
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.util :as util]
-            [rum.core :as rum]))
+            [frontend.mixins :as mixins]
+            [rum.core :as rum]
+            [goog.dom :as gdom]
+            [frontend.commands :as commands]))
 
-(defonce default-timestamp-value {:date nil
-                                  :time ""
+(defonce default-timestamp-value {:time ""
                                   :repeater {}})
 (defonce *timestamp (atom default-timestamp-value))
 
@@ -81,18 +83,42 @@
   []
   (reset! *timestamp default-timestamp-value)
   (reset! *show-time? false)
-  (reset! *show-repeater? false))
+  (reset! *show-repeater? false)
+  (state/set-state! :date-picker/date nil))
 
-(rum/defc time-repeater < rum/reactive
-  []
-  (let [{:keys [date time repeater] :as timestamp} (rum/react *timestamp)
-        timestamp (if date
-                    timestamp
-                    (assoc timestamp :date (t/today)))
+(defn- on-submit
+  [e]
+  (when e (util/stop e))
+  (let [{:keys [time repeater] :as timestamp} @*timestamp
+        date (:date-picker/date @state/state)
+        timestamp (assoc timestamp :date (or date (t/today)))
         kind (if (= "w" (:duration repeater)) "++" ".+")
         timestamp (assoc-in timestamp [:repeater :kind] kind)
-        text (repeated/timestamp-map->text timestamp)]
-    [:div.py-1.px-4 {:style {:min-width 300}}
+        text (repeated/timestamp-map->text timestamp)
+        block-data (state/get-timestamp-block)]
+    (let [{:keys [block typ show?]} block-data
+          block-id (or (:block/uuid (state/get-edit-block))
+                       (:block/uuid block))
+          typ (or @commands/*current-command typ)]
+      (editor-handler/set-block-timestamp! block-id
+                                           typ
+                                           text)
+      (when show?
+        (reset! show? false))))
+  (clear-timestamp!)
+  (state/set-editor-show-date-picker! false)
+  (commands/restore-state false))
+
+(rum/defc time-repeater < rum/reactive
+  (mixins/event-mixin
+   (fn [state]
+     (when-let [input (state/get-input)]
+       (js/setTimeout #(mixins/on-enter state
+                                        :node input
+                                        :on-enter on-submit) 100))))
+  []
+  (let [{:keys [time repeater] :as timestamp} (rum/react *timestamp)]
+    [:div#time-repeater.py-1.px-4 {:style {:min-width 300}}
      [:p.text-sm.opacity-50.font-medium.mt-4 "Time:"]
      (time-input time)
 
@@ -101,32 +127,17 @@
 
      [:p.mt-4
       (ui/button "Submit"
-                 :on-click (fn [e]
-                             (util/stop e)
-                             (let [block-data (state/get-timestamp-block)]
-                               (let [{:keys [block typ show?]} block-data
-                                     block-id (or (:block/uuid (state/get-edit-block))
-                                                  (:block/uuid block))
-                                     typ (or @commands/*current-command typ)]
-                                 (editor-handler/set-block-timestamp! block-id
-                                                                      typ
-                                                                      text)
-                                 (state/clear-edit!)
-                                 (when show?
-                                   (reset! show? false))))
-                             (clear-timestamp!)
-                             (state/set-editor-show-date-picker! false)))]]))
+        :on-click on-submit)]]))
 
 (rum/defc date-picker < rum/reactive
   {:init (fn [state]
            (let [ts (last (:rum/args state))]
              (if ts
                (reset! *timestamp ts)
-               (reset! *timestamp {:date (if (and ts (:date ts))
-                                           (:date ts)
-                                           (t/today))
-                                   :time ""
-                                   :repeater {}})))
+               (reset! *timestamp {:time ""
+                                   :repeater {}}))
+             (when-not (:date-picker/date @state/state)
+               (state/set-state! :date-picker/date (t/today))))
            state)
    :will-unmount (fn [state]
                    (clear-timestamp!)
@@ -136,7 +147,7 @@
         deadline-or-schedule? (and current-command
                                    (contains? #{"deadline" "scheduled"}
                                               (string/lower-case current-command)))
-        date (get @*timestamp :date)]
+        date (state/sub :date-picker/date)]
     (when (state/sub :editor/show-date-picker?)
       [:div#date-time-picker.flex.flex-row {:on-click (fn [e] (util/stop e))
                                             :on-mouse-down (fn [e] (.stopPropagation e))}
@@ -155,7 +166,6 @@
                                                format
                                                nil)
                (state/set-editor-show-date-picker! false)
-               (reset! commands/*current-command nil))
-             (swap! *timestamp assoc :date date)))})
+               (reset! commands/*current-command nil))))})
        (when deadline-or-schedule?
          (time-repeater))])))

+ 2 - 3
src/main/frontend/components/file.cljs

@@ -74,12 +74,11 @@
   (let [path (get-path state)
         format (format/get-format path)
         page (db/get-file-page path)
-        random-id (str (dc/squuid))
-        config? (= path (config/get-config-path))]
+        random-id (str (dc/squuid))]
     (rum/with-context [[tongue] i18n/*tongue-context*]
       [:div.file {:id (str "file-edit-wrapper-" random-id)}
        [:h1.title
-        [:bdi path]]
+        [:bdi (js/decodeURI path)]]
        (when page
          [:div.text-sm.mb-4.ml-1 "Page: "
           [:a.bg-base-2.p-1.ml-1 {:style {:border-radius 4}

+ 31 - 50
src/main/frontend/components/page.cljs

@@ -67,29 +67,10 @@
           (editor-handler/edit-block! block :max (:block/uuid block))))))
   state)
 
-(defn- expand-top-block!
-  [state]
-  (let [[_ blocks _ _ _] (:rum/args state)]
-    (letfn [(one-top-block? [blocks]
-              (= 1 (->> blocks
-                        (mapcat (juxt :db/id #(-> % :block/parent :db/id)))
-                        (apply hash-map)
-                        (#(remove (reduce
-                                    (fn [acc [id parent]] (if (contains? % parent) (conj acc id) acc))
-                                    #{}
-                                    %)
-                                  (keys %)))
-                        count
-                        )))]
-      (if (and (one-top-block? blocks)
-               (-> blocks first :block/properties :collapsed))
-        (editor-handler/expand-block! (-> blocks first :block/uuid)))))
-  state)
-
 (rum/defc page-blocks-inner <
-  {:did-mount  #(-> % open-first-block! expand-top-block!)
+  {:did-mount  open-first-block!
    :did-update open-first-block!}
-  [page-name page-blocks hiccup sidebar? preview?]
+  [page-name page-blocks hiccup sidebar? preview? block-uuid]
   [:div.page-blocks-inner {:style {:margin-left (if sidebar? 0 -20)}}
    (rum/with-key
      (content/content page-name
@@ -163,7 +144,7 @@
               hiccup-config (common-handler/config-with-document-mode hiccup-config)
               hiccup (block/->hiccup page-blocks hiccup-config {})]
           [:div
-           (page-blocks-inner page-name page-blocks hiccup sidebar? preview?)
+           (page-blocks-inner page-name page-blocks hiccup sidebar? preview? block-id)
            (when-not config/publishing?
              (let [args (if block-id
                           {:block-uuid block-id}
@@ -444,7 +425,7 @@
                       s1 (if (> c1 1) "s" "")
                       ;; c2 (count (:links graph))
                       ;; s2 (if (> c2 1) "s" "")
-]
+                      ]
                   ;; (util/format "%d page%s, %d link%s" c1 s1 c2 s2)
                   (util/format "%d page%s" c1 s1))]
                [:div.p-6
@@ -704,18 +685,18 @@
 
         [:span.pr-2
          (ui/button
-          (t :cancel)
-          :intent "logseq"
-          :on-click close-fn)]
+           (t :cancel)
+           :intent "logseq"
+           :on-click close-fn)]
 
         (ui/button
-         (t :yes)
-         :on-click (fn []
-                     (close-fn)
-                     (doseq [page-name (map :block/name pages)]
-                       (page-handler/delete! page-name #()))
-                     (notification/show! (str (t :tips/all-done) "!") :success)
-                     (js/setTimeout #(refresh-fn) 200)))]])))
+          (t :yes)
+          :on-click (fn []
+                      (close-fn)
+                      (doseq [page-name (map :block/name pages)]
+                        (page-handler/delete! page-name #()))
+                      (notification/show! (str (t :tips/all-done) "!") :success)
+                      (js/setTimeout #(refresh-fn) 200)))]])))
 
 (rum/defcs all-pages < rum/reactive
   (rum/local nil ::pages)
@@ -748,11 +729,11 @@
         *search-input (rum/create-ref)
 
         *indeterminate (rum/derived-atom
-                        [*checks] ::indeterminate
-                        (fn [checks]
-                          (when-let [checks (vals checks)]
-                            (if (every? true? checks)
-                              1 (if (some true? checks) -1 0)))))
+                           [*checks] ::indeterminate
+                         (fn [checks]
+                           (when-let [checks (vals checks)]
+                             (if (every? true? checks)
+                               1 (if (some true? checks) -1 0)))))
 
         mobile? (util/mobile?)
         total-pages (if-not @*results-all 0
@@ -821,16 +802,16 @@
            [:div.l.flex.items-center
             [:div.actions-wrap
              (ui/button
-              [(ui/icon "trash") (t :delete)]
-              :on-click (fn []
-                          (let [selected (filter (fn [[_ v]] v) @*checks)
-                                selected (and (seq selected)
-                                              (into #{} (for [[k _] selected] k)))]
-                            (when-let [pages (and selected (filter #(contains? selected (:block/idx %)) @*results))]
-                              (state/set-modal! (batch-delete-dialog pages false #(do
-                                                                                    (reset! *checks nil)
-                                                                                    (refresh-pages)))))))
-              :small? true)]
+               [(ui/icon "trash") (t :delete)]
+               :on-click (fn []
+                           (let [selected (filter (fn [[_ v]] v) @*checks)
+                                 selected (and (seq selected)
+                                               (into #{} (for [[k _] selected] k)))]
+                             (when-let [pages (and selected (filter #(contains? selected (:block/idx %)) @*results))]
+                               (state/set-modal! (batch-delete-dialog pages false #(do
+                                                                                     (reset! *checks nil)
+                                                                                     (refresh-pages)))))))
+               :small? true)]
 
             [:div.search-wrap.flex.items-center.pl-2
              (let [search-fn (fn []
@@ -843,8 +824,8 @@
                                 (reset! *search-key nil)))]
 
                [(ui/button (ui/icon "search")
-                           :on-click search-fn
-                           :small? true)
+                  :on-click search-fn
+                  :small? true)
                 [:input.form-input {:placeholder   (t :search/page-names)
                                     :on-key-up     (fn [^js e]
                                                      (let [^js target (.-target e)]

+ 2 - 0
src/main/frontend/components/sidebar.css

@@ -35,6 +35,8 @@
 }
 
 #main-content {
+  transition: padding-left .3s;
+
   &.is-left-sidebar-open {
     padding-left: 0;
 

+ 6 - 3
src/main/frontend/config.cljs

@@ -383,9 +383,12 @@
 
       (and (mobile-util/native-ios?) (local-db? repo-url))
       (let [dir (-> (get-repo-dir repo-url)
-                    (string/replace "file:///" "file:/"))]
-        (str dir relative-path))
-
+                    (string/replace "file:///" "file:/")
+                    (string/replace "%20" " "))]
+        (if (string/starts-with? relative-path dir)
+          relative-path
+          (str dir relative-path)))
+      
       (= "/" (first relative-path))
       (subs relative-path 1)
 

+ 7 - 0
src/main/frontend/db/model.cljs

@@ -573,6 +573,13 @@
          (map (comp :collapsed :block/properties))
          (some true?))))
 
+(defn block-collapsed?
+  ([block-id]
+   (block-collapsed? (state/get-current-repo) block-id))
+  ([repo block-id]
+   (when-let [block (db-utils/entity repo [:block/uuid block-id])]
+     (get-in block [:block/properties :collapsed]))))
+
 (defn get-block-page
   [repo block-id]
   (when-let [block (db-utils/entity repo [:block/uuid block-id])]

+ 80 - 34
src/main/frontend/handler/editor.cljs

@@ -3306,13 +3306,14 @@
     (state/set-edit-content! (state/get-edit-input-id) (.-value input))))
 
 (defn collapsable? [block-id]
-  (if-let [block (db-model/query-block-by-uuid block-id)]
-    (let [block (block/parse-title-and-body block)]
-      (and
-        (nil? (-> block :block/properties :collapsed))
-        (or (not-empty (:block/body block))
-            (db-model/has-children? block-id))))
-    false))
+  (when block-id
+    (if-let [block (db-model/query-block-by-uuid block-id)]
+      (let [block (block/parse-title-and-body block)]
+        (and
+         (nil? (-> block :block/properties :collapsed))
+         (or (not-empty (:block/body block))
+             (db-model/has-children? block-id))))
+      false)))
 
 (defn all-blocks-with-level
   "Return all blocks associated with correct level
@@ -3333,29 +3334,30 @@
   [{:keys [collapse? expanded? root-block] :or {collapse? false expanded? false root-block nil}}]
   (when-let [page (or (state/get-current-page)
                       (date/today))]
-    (->>
-     (-> page
-         (db/get-page-blocks-no-cache)
-         (tree/blocks->vec-tree page))
-
-     (#(cond->> %
-         root-block (map (fn find [root]
-                       (if (= root-block (:block/uuid root))
-                         root
-                         (first (filter find (:block/children root []))))))))
-
-     (#(cond->> %
-         collapse? (w/postwalk
-                     (fn [x]
-                      (if (and (map? x) (-> x :block/properties :collapsed))
-                        (assoc x :block/children []) x)))))
-
-     (mapcat (fn [x] (tree-seq map? :block/children x)))
-
-     (#(cond->> %
-         expanded? (filter (fn [b] (collapsable? (:block/uuid b))))))
-
-     (map (fn [x] (dissoc x :block/children))))))
+    (let [blocks (-> page
+                     (db/get-page-blocks-no-cache)
+                     (tree/blocks->vec-tree page))]
+      (cond->> blocks
+        root-block
+        (map (fn find [root]
+               (if (= root-block (:block/uuid root))
+                 root
+                 (first (filter find (:block/children root []))))))
+
+        collapse?
+        (w/postwalk
+         (fn [b]
+           (if (and (map? b) (-> b :block/properties :collapsed))
+             (assoc b :block/children []) b)))
+
+        true
+        (mapcat (fn [x] (tree-seq map? :block/children x)))
+
+        expanded?
+        (filter (fn [b] (collapsable? (:block/uuid b))))
+
+        true
+        (map (fn [x] (dissoc x :block/children)))))))
 
 (defn collapse-block! [block-id]
   (when (collapsable? block-id)
@@ -3440,9 +3442,8 @@
    (collapse-all! nil))
   ([block-id]
    (let [blocks-to-collapse (all-blocks-with-level {:expanded? true :root-block block-id})]
-     (when (seq blocks-to-collapse)
-       (doseq [{:block/keys [uuid]} blocks-to-collapse]
-         (collapse-block! uuid))))))
+     (doseq [{:block/keys [uuid]} blocks-to-collapse]
+       (collapse-block! uuid)))))
 
 (defn expand-all!
   ([]
@@ -3451,7 +3452,24 @@
    (->> (all-blocks-with-level {:root-block block-id})
         (filter (fn [b] (-> b :block/properties :collapsed)))
         (map (comp expand-block! :block/uuid))
-        doall)))
+        dorun)))
+
+(defn- get-block-with-its-children
+  [block-uuid]
+  (let [repo (state/get-current-repo)
+        children (db/get-block-children repo block-uuid)
+        block (db/pull [:block/uuid block-uuid])]
+    (cons block (seq children))))
+
+(defn expand-all?
+  [block-uuid]
+  (let [blocks (get-block-with-its-children block-uuid)]
+    (some #(get-in % [:block/properties :collapsed]) blocks)))
+
+(defn collapse-all?
+  [block-uuid]
+  (let [blocks (get-block-with-its-children block-uuid)]
+    (some #(collapsable? (:block/uuid %)) blocks)))
 
 (defn toggle-open! []
   (let [all-collapsed?
@@ -3548,3 +3566,31 @@
       (save-block! (state/get-current-repo)
                    (:block/uuid block)
                    content))))
+
+(defn block-default-collapsed?
+  "Whether a block should be collapsed by default.
+  Currently, this handles several cases:
+  1. Zoom in mode, it will open the current block if it's collapsed.
+  2. Queries.
+  3. References."
+  [block config]
+  (let [collapsed? (cond
+                     (and (:block? config)
+                          (= (:id config) (str (:block/uuid block))))
+                     false
+
+                     (and (:block? config)
+                          (get-in block [:block/properties :collapsed]))
+                     true
+
+                     :else
+                     (boolean
+                      (and
+                       (seq (:block/children block))
+                       (or (:custom-query? config)
+                           (and (:ref? config)
+                                (>= (:ref/level block)
+                                    (state/get-ref-open-blocks-level)))))))]
+    (if (or (:ref? config) (:block? config))
+      collapsed?
+      (get-in block [:block/properties :collapsed]))))

+ 2 - 6
src/main/frontend/handler/journal.cljs

@@ -1,7 +1,5 @@
 (ns frontend.handler.journal
-  (:require [clojure.string :as string]
-            [frontend.date :as date]
-            [frontend.handler.editor :as editor-handler]
+  (:require [frontend.date :as date]
             [frontend.handler.route :as route-handler]
             [frontend.state :as state]
             [frontend.util :as util]
@@ -11,10 +9,8 @@
 (defn- redirect-to-journal!
   [page]
   (when (and page (state/enable-journals? (state/get-current-repo)))
-    (prn {:page page})
     (route-handler/redirect! {:to          :page
-                              :path-params {:name page}})
-    (editor-handler/insert-first-page-block-if-not-exists! page)))
+                              :path-params {:name page}})))
 
 (defn go-to-tomorrow!
   []

+ 13 - 1
src/main/frontend/modules/outliner/core.cljs

@@ -229,6 +229,15 @@
                       (throw (js/Error. "Number of children and sorted-children are not equal."))))
                   sorted-children)))))))))
 
+(defn set-block-collapsed! [txs-state id collapsed?]
+  (let [e (db/entity id)
+        properties (:block/properties e)
+        properties (if collapsed?
+                     (assoc properties :collapsed true)
+                     (dissoc properties :collapsed))]
+    (swap! txs-state concat [{:db/id id
+                              :block/properties properties}])))
+
 (defn save-node
   ([node]
    (save-node node nil))
@@ -577,7 +586,10 @@
                  (tree/-save txs-state)))
            (some-> last-node-right
                    (tree/-set-left-id first-node-left-id)
-                   (tree/-save txs-state))))
+                   (tree/-save txs-state))
+           (when-let [parent (get-block-by-id first-node-left-id)]
+             (when (db-model/block-collapsed? first-node-left-id)
+               (set-block-collapsed! txs-state (:db/id (get-data parent)) false)))))
        (when-not (first-level? first-node)
          (let [parent (tree/-get-parent first-node)
                parent-parent-id (tree/-get-parent-id parent)

+ 4 - 3
src/main/frontend/text.cljs

@@ -341,6 +341,7 @@
   (when (string? path)
     (let [parts (->> (string/split path #"/")
                      (take-last 2))]
-      (if (not= (first parts) "0")
-        (string/join "/" parts)
-        (last parts)))))
+      (-> (if (not= (first parts) "0")
+            (string/join "/" parts)
+            (last parts))
+          js/decodeURI))))

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

@@ -171,7 +171,7 @@
       (dissoc option :background :class :small?)
       (when href
         {:on-click (fn []
-                     (set! (.-href js/window.location) href)
+                     (util/open-url href)
                      (when (fn? on-click) (on-click)))}))
      text]))
 

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

@@ -1546,3 +1546,13 @@
        Always ignore the IME process."
      [e]
      (gobj/getValueByKeys e "nativeEvent" "isComposing"))) ;; No keycode available
+
+#?(:cljs
+   (defn open-url
+     [url]
+     (let [route? (or (string/starts-with? url
+                        (string/replace js/location.href js/location.hash ""))
+                      (string/starts-with? url "#"))]
+       (if (and (not route?) (electron?))
+         (js/window.apis.openExternal url)
+         (set! (.-href js/window.location) url)))))

+ 18 - 26
src/main/frontend/util/page_property.cljs

@@ -11,32 +11,24 @@
 
 (defn insert-property
   [format content key value]
-  (when (string? content)
-    (let [ast (mldoc/->edn content (mldoc/default-config format))
-          key-exists? (fn [k] (boolean (k (last (ffirst ast)))))
-          key (if (string? key) (keyword key) key)
-          old-value (key (last (ffirst ast)))
-          new-value (case key
-                      :title value
-                      (-> (if (coll? old-value)
-                            (concat old-value [value])
-                            (conj [old-value] value))
-                          (distinct)))
-          build-property-fn (fn [value]
-                              (util/format (case format
-                                             :org "#+%s: %s"
-                                             "%s:: %s")
-                                           (name key)
-                                           (if (coll? value)
-                                             (->> (remove nil? value)
-                                                  (string/join ", "))
-                                             value)))
-          old-property-str (when old-value (build-property-fn old-value))
-          new-property-str (build-property-fn new-value)]
-      (if (key-exists? key)
-        (string/replace content old-property-str new-property-str)
-        (string/join "\n" (remove #(= "" %)
-                                  [new-property-str content]))))))
+  (when (and (string? content) (not (string/blank? (name key))))
+    (let [key (if (string? key) (keyword key) key)
+          key-part (util/format (case format
+                                  :org "#+%s: "
+                                  "%s:: ") (name key))
+          new-property-line (str key-part value)
+          lines (string/split-lines content)
+          key-exists? (atom false)
+          lines (doall
+                 (map (fn [line]
+                        (if (and (string/starts-with? line key-part) (not @key-exists?)) ; only replace the first match
+                          (do
+                            (reset! key-exists? true)
+                            new-property-line)
+                          line)) lines))
+          lines (if (= lines [""]) nil lines)
+          lines (if @key-exists? lines (cons new-property-line lines))]
+      (string/join "\n" lines))))
 
 (defn insert-properties
   [format content kvs]

+ 14 - 20
src/test/frontend/util/page_property_test.cljs

@@ -15,19 +15,13 @@
       "#+title: new title\nhello"
 
       (property/insert-property :org "#+title: title\nhello" :alias "alias1")
-      "#+title: title\n#+alias: alias1\nhello"
+      "#+alias: alias1\n#+title: title\nhello"
 
       (property/insert-property :org "#+title: title\n#+alias: alias1\nhello" :alias "alias2")
-      "#+title: title\n#+alias: alias1, alias2\nhello"
+      "#+title: title\n#+alias: alias2\nhello"
 
       (property/insert-property :org "#+title: title\n#+alias: alias1, alias2\nhello" :alias "alias3")
-      "#+title: title\n#+alias: alias1, alias2, alias3\nhello"
-
-      (property/insert-property :org "#+title: title\n#+alias: alias1, alias2\nhello" :aliases "aliases1")
-      "#+title: title\n#+alias: alias1, alias2\n#+aliases: aliases1\nhello"
-
-      (property/insert-property :org "#+title: title\n#+alias: alias1, alias2\n#+aliases: aliases1\nhello" :aliases "aliases2")
-      "#+title: title\n#+alias: alias1, alias2\n#+aliases: aliases1, aliases2\nhello"))
+      "#+title: title\n#+alias: alias3\nhello"))
 
   (testing "add markdown page property"
     (are [x y] (= x y)
@@ -41,19 +35,19 @@
       "title:: new title\nhello"
 
       (property/insert-property :markdown "title:: title\nhello" :alias "alias1")
-      "title:: title\nalias:: alias1\nhello"
+      "alias:: alias1\ntitle:: title\nhello"
 
       (property/insert-property :markdown "title:: title\nalias:: alias1\nhello" :alias "alias2")
-      "title:: title\nalias:: alias1, alias2\nhello"
+      "title:: title\nalias:: alias2\nhello"
 
       (property/insert-property :markdown "title:: title\nalias:: alias1, alias2\nhello" :alias "alias3")
-      "title:: title\nalias:: alias1, alias2, alias3\nhello"
+      "title:: title\nalias:: alias3\nhello"
 
       (property/insert-property :markdown "title:: title\nalias:: alias1, alias2\nhello" :aliases "aliases1")
-      "title:: title\nalias:: alias1, alias2\naliases:: aliases1\nhello"
+      "aliases:: aliases1\ntitle:: title\nalias:: alias1, alias2\nhello"
 
       (property/insert-property :markdown "title:: title\nalias:: alias1, alias2\naliases:: aliases1\nhello" :aliases "aliases2")
-      "title:: title\nalias:: alias1, alias2\naliases:: aliases1, aliases2\nhello")))
+      "title:: title\nalias:: alias1, alias2\naliases:: aliases2\nhello")))
 
 (deftest test-insert-properties
   (testing "add org page properties"
@@ -68,19 +62,19 @@
       (property/insert-properties :org "#+title: title\nhello"
                                   {:title "new title"
                                    :alias "alias1"})
-      "#+title: new title\n#+alias: alias1\nhello"
+      "#+alias: alias1\n#+title: new title\nhello"
 
       (property/insert-properties :org "#+title: title\n#+alias: alias1\nhello"
                                   {:title "new title"
                                    :alias "alias2"
                                    :aliases "aliases1"})
-      "#+title: new title\n#+alias: alias1, alias2\n#+aliases: aliases1\nhello"
+      "#+aliases: aliases1\n#+title: new title\n#+alias: alias2\nhello"
 
       (property/insert-properties :org "#+title: title\n#+alias: alias1, alias2\n#+aliases: aliases1\nhello"
                                   {:title "new title"
                                    :alias "alias2"
                                    :aliases "aliases1"})
-      "#+title: new title\n#+alias: alias1, alias2\n#+aliases: aliases1\nhello"))
+      "#+title: new title\n#+alias: alias2\n#+aliases: aliases1\nhello"))
 
   (testing "add markdown page properties"
     (are [x y] (= x y)
@@ -93,18 +87,18 @@
       (property/insert-properties :markdown "title:: title\nhello"
                                   {:title "new title"
                                    :alias "alias1"})
-      "title:: new title\nalias:: alias1\nhello"
+      "alias:: alias1\ntitle:: new title\nhello"
 
       (property/insert-properties :markdown "title:: title\nalias:: alias1\nhello"
                                   {:title "new title"
                                    :alias "alias2"
                                    :aliases "aliases1"})
-      "title:: new title\nalias:: alias1, alias2\naliases:: aliases1\nhello"
+      "aliases:: aliases1\ntitle:: new title\nalias:: alias2\nhello"
 
       (property/insert-properties :markdown "title:: title\nalias:: alias1, alias2\naliases:: aliases1\nhello"
                                   {:title "new title"
                                    :alias "alias2"
                                    :aliases "aliases1"})
-      "title:: new title\nalias:: alias1, alias2\naliases:: aliases1\nhello")))
+      "title:: new title\nalias:: alias2\naliases:: aliases1\nhello")))
 
 #_(cljs.test/run-tests)