浏览代码

refactor: remove i18n tongue context

Tienson Qin 3 年之前
父节点
当前提交
982eba9396
共有 36 个文件被更改,包括 2557 次插入2766 次删除
  1. 0 0
      docs/mobile.md
  2. 10 10
      package.json
  3. 0 8
      shadow-cljs.edn
  4. 72 73
      src/main/frontend/components/block.cljs
  5. 28 30
      src/main/frontend/components/command_palette.cljs
  6. 99 100
      src/main/frontend/components/content.cljs
  7. 119 123
      src/main/frontend/components/encryption.cljs
  8. 30 31
      src/main/frontend/components/export.cljs
  9. 74 76
      src/main/frontend/components/file.cljs
  10. 99 101
      src/main/frontend/components/header.cljs
  11. 7 8
      src/main/frontend/components/journal.cljs
  12. 192 194
      src/main/frontend/components/onboarding.cljs
  13. 401 408
      src/main/frontend/components/page.cljs
  14. 23 25
      src/main/frontend/components/page_menu.cljs
  15. 222 237
      src/main/frontend/components/plugins.cljs
  16. 187 190
      src/main/frontend/components/repo.cljs
  17. 5 6
      src/main/frontend/components/right_sidebar.cljs
  18. 173 176
      src/main/frontend/components/search.cljs
  19. 19 20
      src/main/frontend/components/select.cljs
  20. 159 165
      src/main/frontend/components/settings.cljs
  21. 98 102
      src/main/frontend/components/shortcut.cljs
  22. 186 194
      src/main/frontend/components/sidebar.cljs
  23. 123 129
      src/main/frontend/components/widgets.cljs
  24. 11 21
      src/main/frontend/context/i18n.cljs
  25. 123 129
      src/main/frontend/extensions/pdf/highlights.cljs
  26. 1 26
      src/main/frontend/format/mldoc.cljs
  27. 0 2
      src/main/frontend/handler.cljs
  28. 26 18
      src/main/frontend/handler/repo.cljs
  29. 8 10
      src/main/frontend/page.cljs
  30. 4 3
      src/main/frontend/state.cljs
  31. 50 52
      src/main/frontend/ui.cljs
  32. 0 78
      src/main/frontend/util/pool.cljs
  33. 3 2
      src/main/frontend/util/property.cljs
  34. 0 14
      src/main/frontend/worker/parser.cljs
  35. 1 1
      src/main/logseq/api.cljs
  36. 4 4
      yarn.lock

+ 0 - 0
mobile.md → docs/mobile.md


+ 10 - 10
package.json

@@ -48,18 +48,18 @@
         "gulp:build": "cross-env NODE_ENV=production gulp build",
         "gulp:build": "cross-env NODE_ENV=production gulp build",
         "css:build": "postcss tailwind.all.css -o static/css/style.css --verbose --env production",
         "css:build": "postcss tailwind.all.css -o static/css/style.css --verbose --env production",
         "css:watch": "cross-env TAILWIND_MODE=watch postcss tailwind.all.css -o static/css/style.css --verbose --watch",
         "css:watch": "cross-env TAILWIND_MODE=watch postcss tailwind.all.css -o static/css/style.css --verbose --watch",
-        "cljs:watch": "clojure -M:cljs watch parser-worker app electron",
-        "cljs:app-watch": "clojure -M:cljs watch parser-worker app",
-        "cljs:electron-watch": "clojure -M:cljs watch parser-worker app electron",
-        "cljs:release": "clojure -M:cljs release parser-worker app publishing electron",
-        "cljs:release-electron": "clojure -M:cljs release parser-worker app publishing electron --debug",
-        "cljs:release-app": "clojure -M:cljs release parser-worker app",
+        "cljs:watch": "clojure -M:cljs watch app electron",
+        "cljs:app-watch": "clojure -M:cljs watch app",
+        "cljs:electron-watch": "clojure -M:cljs watch app electron",
+        "cljs:release": "clojure -M:cljs release app publishing electron",
+        "cljs:release-electron": "clojure -M:cljs release app publishing electron --debug",
+        "cljs:release-app": "clojure -M:cljs release app",
         "cljs:test": "clojure -M:test compile test",
         "cljs:test": "clojure -M:test compile test",
         "cljs:run-test": "node static/tests.js",
         "cljs:run-test": "node static/tests.js",
         "cljs:dev-release-app": "clojure -M:cljs release app --config-merge '{:closure-defines {frontend.config/DEV-RELEASE true}}'",
         "cljs:dev-release-app": "clojure -M:cljs release app --config-merge '{:closure-defines {frontend.config/DEV-RELEASE true}}'",
-        "cljs:debug": "clojure -M:cljs release parser-worker app --debug",
-        "cljs:report": "clojure -M:cljs run shadow.cljs.build-report parser-worker app report.html",
-        "cljs:build-electron": "clojure -A:cljs compile parser-worker app electron",
+        "cljs:debug": "clojure -M:cljs release app --debug",
+        "cljs:report": "clojure -M:cljs run shadow.cljs.build-report app report.html",
+        "cljs:build-electron": "clojure -A:cljs compile app electron",
         "cljs:lint": "clojure -M:clj-kondo --parallel --lint src"
         "cljs:lint": "clojure -M:clj-kondo --parallel --lint src"
     },
     },
     "dependencies": {
     "dependencies": {
@@ -94,7 +94,7 @@
         "ignore": "5.1.8",
         "ignore": "5.1.8",
         "is-svg": "4.3.0",
         "is-svg": "4.3.0",
         "jszip": "3.5.0",
         "jszip": "3.5.0",
-        "mldoc": "1.2.9",
+        "mldoc": "1.3.0",
         "remove-accents": "0.4.2",
         "remove-accents": "0.4.2",
         "path": "0.12.7",
         "path": "0.12.7",
         "pixi-graph-fork": "0.2.0",
         "pixi-graph-fork": "0.2.0",

+ 0 - 8
shadow-cljs.edn

@@ -58,14 +58,6 @@
                                            "externs.js"]
                                            "externs.js"]
                                 :warnings {:fn-deprecated false}}}
                                 :warnings {:fn-deprecated false}}}
 
 
-  :parser-worker {:target           :browser
-                  :output-dir       "./static/js"
-                  :asset-path       "./js"
-                  :compiler-options {:source-map false}
-                  :modules          {:parser-worker {:entries    [frontend.worker.parser]
-                                                     :web-worker true}}
-                  :release          {:compiler-options {:infer-externs :auto}}}
-
   :test {:target          :node-test
   :test {:target          :node-test
          :output-to       "static/tests.js"
          :output-to       "static/tests.js"
          :closure-defines {frontend.util/NODETEST true}
          :closure-defines {frontend.util/NODETEST true}

+ 72 - 73
src/main/frontend/components/block.cljs

@@ -14,7 +14,7 @@
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
             [frontend.components.macro :as macro]
             [frontend.components.macro :as macro]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.date :as date]
             [frontend.date :as date]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.db.utils :as db-utils]
             [frontend.db.utils :as db-utils]
@@ -178,78 +178,77 @@
                    (reset! *resizing-image? false)
                    (reset! *resizing-image? false)
                    state)}
                    state)}
   [state config title src metadata full_text local?]
   [state config title src metadata full_text local?]
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (let [size (get state ::size)]
-      (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?
-                          ;; 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)))}
-          (and (:width metadata) (not (util/mobile?)))
-          (assoc :style {:width (:width metadata)}))
-        [:div.asset-container
-         [:img.rounded-sm.shadow-xl.relative
-          (merge
-           {:loading "lazy"
-            :src     src
-            :title   title}
-           metadata)]
-         [:span.ctl
-          [:a.delete
-           {:title "Delete this image"
-            :on-click
-            (fn [e]
-              (when-let [block-id (:block/uuid config)]
-                (let [confirm-fn (ui/make-confirm-modal
-                                  {:title         (t :asset/confirm-delete (.toLocaleLowerCase (t :text/image)))
-                                   :sub-title     (if local? :asset/physical-delete "")
-                                   :sub-checkbox? local?
-                                   :on-confirm    (fn [_e {:keys [close-fn sub-selected]}]
-                                                    (close-fn)
-                                                    (editor-handler/delete-asset-of-block!
-                                                     {:block-id    block-id
-                                                      :local?      local?
-                                                      :delete-local? (first sub-selected)
-                                                      :repo        (state/get-current-repo)
-                                                      :href        src
-                                                      :title       title
-                                                      :full-text   full_text}))})]
-                  (state/set-modal! confirm-fn)
-                  (util/stop e))))}
-           svg/trash-sm]
-
-          [:a.delete.ml-1
-           {:title    "maximize image"
-            :on-click (fn [^js e] (let [images (js/document.querySelectorAll ".asset-container img")
-                                        images (to-array images)
-                                        images (if-not (= (count images) 1)
-                                                 (let [^js _image (.closest (.-target e) ".asset-container")
-                                                       image (. _image querySelector "img")]
-                                                   (cons image (remove #(= image %) images)))
-                                                 images)
-                                        images (for [^js it images] {:src (.-src it)
-                                                                     :w (.-naturalWidth it)
-                                                                     :h (.-naturalHeight it)})]
-
-                                    (when (seq images)
-                                      (lightbox/preview-images! images))))}
-
-           (svg/maximize)]]])))))
+  (let [size (get state ::size)]
+    (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?
+                        ;; 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)))}
+        (and (:width metadata) (not (util/mobile?)))
+        (assoc :style {:width (:width metadata)}))
+      [:div.asset-container
+       [:img.rounded-sm.shadow-xl.relative
+        (merge
+         {:loading "lazy"
+          :src     src
+          :title   title}
+         metadata)]
+       [:span.ctl
+        [:a.delete
+         {:title "Delete this image"
+          :on-click
+          (fn [e]
+            (when-let [block-id (:block/uuid config)]
+              (let [confirm-fn (ui/make-confirm-modal
+                                {:title         (t :asset/confirm-delete (.toLocaleLowerCase (t :text/image)))
+                                 :sub-title     (if local? :asset/physical-delete "")
+                                 :sub-checkbox? local?
+                                 :on-confirm    (fn [_e {:keys [close-fn sub-selected]}]
+                                                  (close-fn)
+                                                  (editor-handler/delete-asset-of-block!
+                                                   {:block-id    block-id
+                                                    :local?      local?
+                                                    :delete-local? (first sub-selected)
+                                                    :repo        (state/get-current-repo)
+                                                    :href        src
+                                                    :title       title
+                                                    :full-text   full_text}))})]
+                (state/set-modal! confirm-fn)
+                (util/stop e))))}
+         svg/trash-sm]
+
+        [:a.delete.ml-1
+         {:title    "maximize image"
+          :on-click (fn [^js e] (let [images (js/document.querySelectorAll ".asset-container img")
+                                      images (to-array images)
+                                      images (if-not (= (count images) 1)
+                                               (let [^js _image (.closest (.-target e) ".asset-container")
+                                                     image (. _image querySelector "img")]
+                                                 (cons image (remove #(= image %) images)))
+                                               images)
+                                      images (for [^js it images] {:src (.-src it)
+                                                                   :w (.-naturalWidth it)
+                                                                   :h (.-naturalHeight it)})]
+
+                                  (when (seq images)
+                                    (lightbox/preview-images! images))))}
+
+         (svg/maximize)]]]))))
 
 
 (rum/defcs asset-link < rum/reactive
 (rum/defcs asset-link < rum/reactive
   (rum/local nil ::src)
   (rum/local nil ::src)

+ 28 - 30
src/main/frontend/components/command_palette.cljs

@@ -2,7 +2,7 @@
   (:require [frontend.handler.command-palette :as cp]
   (:require [frontend.handler.command-palette :as cp]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.data-helper :as shortcut-helper]
             [frontend.modules.shortcut.data-helper :as shortcut-helper]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.search :as search]
             [frontend.search :as search]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
@@ -22,17 +22,16 @@
 
 
 (rum/defc render-command
 (rum/defc render-command
   [{:keys [id shortcut] :as cmd} chosen?]
   [{:keys [id shortcut] :as cmd} chosen?]
-  (let [first-shortcut (first (string/split shortcut #" \| "))]
-    (rum/with-context [[t] i18n/*tongue-context*]
-                      (let [desc (translate t cmd)]
-                        [:div.inline-grid.grid-cols-4.gap-x-4.w-full
-        {:class (when chosen? "chosen")}
-        [:span.col-span-3 desc]
-        [:div.col-span-1.justify-end.tip.flex
-         (when (and (keyword? id) (namespace id))
-           [:code.opacity-20.bg-transparent (namespace id)])
-         (when-not (string/blank? first-shortcut)
-           [:code.ml-1 first-shortcut])]]))))
+  (let [first-shortcut (first (string/split shortcut #" \| "))
+        desc (translate t cmd)]
+    [:div.inline-grid.grid-cols-4.gap-x-4.w-full
+     {:class (when chosen? "chosen")}
+     [:span.col-span-3 desc]
+     [:div.col-span-1.justify-end.tip.flex
+      (when (and (keyword? id) (namespace id))
+        [:code.opacity-20.bg-transparent (namespace id)])
+      (when-not (string/blank? first-shortcut)
+        [:code.ml-1 first-shortcut])]]))
 
 
 (rum/defcs command-palette <
 (rum/defcs command-palette <
   (shortcut/disable-all-shortcuts)
   (shortcut/disable-all-shortcuts)
@@ -42,25 +41,24 @@
                    state)}
                    state)}
   [state {:keys [commands limit]
   [state {:keys [commands limit]
           :or {limit 100}}]
           :or {limit 100}}]
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (let [input (::input state)]
-      [:div.cp__palette.cp__palette-main
-       [:div.input-wrap
-        [:input.cp__palette-input.w-full
-         {:type        "text"
-          :placeholder (t :command-palette/prompt)
-          :auto-focus  true
-          :value       @input
-          :on-change   (fn [e] (reset! input (util/evalue e)))}]]
+  (let [input (::input state)]
+    [:div.cp__palette.cp__palette-main
+     [:div.input-wrap
+      [:input.cp__palette-input.w-full
+       {:type        "text"
+        :placeholder (t :command-palette/prompt)
+        :auto-focus  true
+        :value       @input
+        :on-change   (fn [e] (reset! input (util/evalue e)))}]]
 
 
-       [:div.command-results-wrap
-        (ui/auto-complete
-         (if (string/blank? @input)
-           (cp/top-commands limit)
-           (get-matched-commands commands @input limit t))
-         {:item-render render-command
-          :class       "cp__palette-results"
-          :on-chosen   (fn [cmd] (cp/invoke-command cmd))})]])))
+     [:div.command-results-wrap
+      (ui/auto-complete
+       (if (string/blank? @input)
+         (cp/top-commands limit)
+         (get-matched-commands commands @input limit t))
+       {:item-render render-command
+        :class       "cp__palette-results"
+        :on-chosen   (fn [cmd] (cp/invoke-command cmd))})]]))
 
 
 (rum/defc command-palette-modal < rum/reactive
 (rum/defc command-palette-modal < rum/reactive
   []
   []

+ 99 - 100
src/main/frontend/components/content.cljs

@@ -7,7 +7,7 @@
             [frontend.components.page-menu :as page-menu]
             [frontend.components.page-menu :as page-menu]
             [frontend.components.export :as export]
             [frontend.components.export :as export]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.extensions.srs :as srs]
             [frontend.extensions.srs :as srs]
             [frontend.format :as format]
             [frontend.format :as format]
@@ -160,116 +160,115 @@
        #())
        #())
      [])
      [])
 
 
-    (rum/with-context [[t] i18n/*tongue-context*]
-      (when-let [block (db/entity [:block/uuid block-id])]
-        (let [properties (:block/properties block)
-              heading? (true? (:heading properties))]
-          [:div#custom-context-menu
-           {:ref *el-ref}
-           [:div.py-1.rounded-md.bg-base-3.shadow-xs
-            [:div.flex-row.flex.justify-between.py-4.pl-2
-             [:div.flex-row.flex.justify-between
-              (for [color block-background-colors]
-                [:a.m-2.shadow-sm
-                 {:on-click (fn [_e]
-                              (editor-handler/set-block-property! block-id "background-color" color))}
-                 [:div.heading-bg {:style {:background-color color}}]])]
-             [:a.text-sm
-              {:title    (t :remove-background)
-               :style    {:margin-right 14
-                          :margin-top   4}
-               :on-click (fn [_e]
-                           (editor-handler/remove-block-property! block-id "background-color"))}
-              "Clear"]]
+    (when-let [block (db/entity [:block/uuid block-id])]
+      (let [properties (:block/properties block)
+            heading? (true? (:heading properties))]
+        [:div#custom-context-menu
+         {:ref *el-ref}
+         [:div.py-1.rounded-md.bg-base-3.shadow-xs
+          [:div.flex-row.flex.justify-between.py-4.pl-2
+           [:div.flex-row.flex.justify-between
+            (for [color block-background-colors]
+              [:a.m-2.shadow-sm
+               {:on-click (fn [_e]
+                            (editor-handler/set-block-property! block-id "background-color" color))}
+               [:div.heading-bg {:style {:background-color color}}]])]
+           [:a.text-sm
+            {:title    (t :remove-background)
+             :style    {:margin-right 14
+                        :margin-top   4}
+             :on-click (fn [_e]
+                         (editor-handler/remove-block-property! block-id "background-color"))}
+            "Clear"]]
 
 
-            (ui/menu-link
-             {:key      "Convert heading"
-              :on-click (fn [_e]
-                          (if heading?
-                            (editor-handler/remove-block-property! block-id :heading)
-                            (editor-handler/set-block-property! block-id :heading true)))}
-             (if heading?
-               "Convert back to a block"
-               "Convert to a heading"))
+          (ui/menu-link
+           {:key      "Convert heading"
+            :on-click (fn [_e]
+                        (if heading?
+                          (editor-handler/remove-block-property! block-id :heading)
+                          (editor-handler/set-block-property! block-id :heading true)))}
+           (if heading?
+             "Convert back to a block"
+             "Convert to a heading"))
 
 
-            (ui/menu-link
-             {:key      "Open in sidebar"
-              :on-click (fn [_e]
-                          (editor-handler/open-block-in-sidebar! block-id))}
-             "Open in sidebar")
+          (ui/menu-link
+           {:key      "Open in sidebar"
+            :on-click (fn [_e]
+                        (editor-handler/open-block-in-sidebar! block-id))}
+           "Open in sidebar")
 
 
-            (ui/menu-link
-             {:key      "Copy block ref"
-              :on-click (fn [_e]
-                          (editor-handler/copy-block-ref! block-id #(str "((" % "))")))}
-             "Copy block ref")
+          (ui/menu-link
+           {:key      "Copy block ref"
+            :on-click (fn [_e]
+                        (editor-handler/copy-block-ref! block-id #(str "((" % "))")))}
+           "Copy block ref")
 
 
-            (ui/menu-link
-             {:key      "Copy block embed"
-              :on-click (fn [_e]
-                          (editor-handler/copy-block-ref! block-id #(util/format "{{embed ((%s))}}" %)))}
-             "Copy block embed")
+          (ui/menu-link
+           {:key      "Copy block embed"
+            :on-click (fn [_e]
+                        (editor-handler/copy-block-ref! block-id #(util/format "{{embed ((%s))}}" %)))}
+           "Copy block embed")
 
 
-            (block-template block-id)
+          (block-template block-id)
 
 
-            (ui/menu-link
-             {:key      "Copy as"
-              :on-click (fn [_]
-                          (state/set-modal! #(export/export-blocks [block-id])))}
-             "Copy as")
-
-            (if (srs/card-block? block)
-              (ui/menu-link
-               {:key      "Preview Card"
-                :on-click #(srs/preview [(db/pull [:block/uuid block-id])])}
-               "Preview Card")
-              (ui/menu-link
-               {:key      "Make a Card"
-                :on-click #(srs/make-block-a-card! block-id)}
-               "Make a Card"))
+          (ui/menu-link
+           {:key      "Copy as"
+            :on-click (fn [_]
+                        (state/set-modal! #(export/export-blocks [block-id])))}
+           "Copy as")
 
 
+          (if (srs/card-block? block)
             (ui/menu-link
             (ui/menu-link
-             {:key      "Cut"
-              :on-click (fn [_e]
-                          (editor-handler/cut-block! block-id))}
-             "Cut")
-
+             {:key      "Preview Card"
+              :on-click #(srs/preview [(db/pull [:block/uuid block-id])])}
+             "Preview Card")
             (ui/menu-link
             (ui/menu-link
-             {:key      "Expand all"
-              :on-click (fn [_e]
-                          (editor-handler/expand-all! block-id))}
-             "Expand all")
+             {:key      "Make a Card"
+              :on-click #(srs/make-block-a-card! block-id)}
+             "Make a Card"))
+
+          (ui/menu-link
+           {:key      "Cut"
+            :on-click (fn [_e]
+                        (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")
 
 
+          (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)]
+              (for [[_ {:keys [key label] :as cmd} action pid] cmds]
+                (ui/menu-link
+                 {:key      key
+                  :on-click #(commands/exec-plugin-simple-command!
+                              pid (assoc cmd :uuid block-id) action)}
+                 label))))
+
+          (when (state/sub [:ui/developer-mode?])
             (ui/menu-link
             (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)]
-                (for [[_ {:keys [key label] :as cmd} action pid] cmds]
-                  (ui/menu-link
-                   {:key      key
-                    :on-click #(commands/exec-plugin-simple-command!
-                                pid (assoc cmd :uuid block-id) action)}
-                   label))))
-
-            (when (state/sub [:ui/developer-mode?])
-              (ui/menu-link
-               {:key      "(Dev) Show block data"
-                :on-click (fn []
-                            (let [block-data (with-out-str (pprint/pprint (db/pull [:block/uuid block-id])))]
-                              (println block-data)
-                              (notification/show!
-                               [:div
-                                [:pre.code block-data]
-                                [:br]
-                                (ui/button "Copy to clipboard"
-                                           :on-click #(.writeText js/navigator.clipboard block-data))]
-                               :success
-                               false)))}
-               "(Dev) Show block data"))]])))))
+             {:key      "(Dev) Show block data"
+              :on-click (fn []
+                          (let [block-data (with-out-str (pprint/pprint (db/pull [:block/uuid block-id])))]
+                            (println block-data)
+                            (notification/show!
+                             [:div
+                              [:pre.code block-data]
+                              [:br]
+                              (ui/button "Copy to clipboard"
+                                :on-click #(.writeText js/navigator.clipboard block-data))]
+                             :success
+                             false)))}
+             "(Dev) Show block data"))]]))))
 
 
 (rum/defc block-ref-custom-context-menu-content
 (rum/defc block-ref-custom-context-menu-content
   [block block-ref-id]
   [block block-ref-id]

+ 119 - 123
src/main/frontend/components/encryption.cljs

@@ -1,6 +1,6 @@
 (ns frontend.components.encryption
 (ns frontend.components.encryption
   (:require [clojure.string :as string]
   (:require [clojure.string :as string]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.encrypt :as e]
             [frontend.encrypt :as e]
             [frontend.handler.metadata :as metadata-handler]
             [frontend.handler.metadata :as metadata-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
@@ -16,33 +16,32 @@
   (let [reveal-secret-phrase? (get state ::reveal-secret-phrase?)
   (let [reveal-secret-phrase? (get state ::reveal-secret-phrase?)
         public-key (e/get-public-key repo-url)
         public-key (e/get-public-key repo-url)
         private-key (e/get-secret-key repo-url)]
         private-key (e/get-secret-key repo-url)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div
-       [:div.sm:flex.sm:items-start
-        [:div.mt-3.text-center.sm:mt-0.sm:text-left
-         [:h3#modal-headline.text-lg.leading-6.font-medium
-          "This graph is encrypted with " [:a {:href "https://age-encryption.org/" :target "_blank" :rel "noopener"} "age-encryption.org/v1"]]]]
-
-       [:div.mt-1
-        [:div.max-w-2xl.rounded-md.shadow-sm.sm:max-w-xl
-         [:div.cursor-pointer.block.w-full.rounded-sm.p-2
-          {:on-click (fn []
-                       (when (not @reveal-secret-phrase?)
-                         (reset! reveal-secret-phrase? true)))}
-          [:div.font-medium "Public Key:"]
-          [:div.font-mono.select-all.break-all public-key]
-          (if @reveal-secret-phrase?
-            [:div
-             [:div.mt-1.font-medium "Private Key:"]
-             [:div.font-mono.select-all.break-all private-key]]
-            [:div.underline "click to view the private key"])]]]
-
-       [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
-        [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
-         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-          {:type "button"
-           :on-click close-fn}
-          (t :close)]]]])))
+    [:div
+     [:div.sm:flex.sm:items-start
+      [:div.mt-3.text-center.sm:mt-0.sm:text-left
+       [:h3#modal-headline.text-lg.leading-6.font-medium
+        "This graph is encrypted with " [:a {:href "https://age-encryption.org/" :target "_blank" :rel "noopener"} "age-encryption.org/v1"]]]]
+
+     [:div.mt-1
+      [:div.max-w-2xl.rounded-md.shadow-sm.sm:max-w-xl
+       [:div.cursor-pointer.block.w-full.rounded-sm.p-2
+        {:on-click (fn []
+                     (when (not @reveal-secret-phrase?)
+                       (reset! reveal-secret-phrase? true)))}
+        [:div.font-medium "Public Key:"]
+        [:div.font-mono.select-all.break-all public-key]
+        (if @reveal-secret-phrase?
+          [:div
+           [:div.mt-1.font-medium "Private Key:"]
+           [:div.font-mono.select-all.break-all private-key]]
+          [:div.underline "click to view the private key"])]]]
+
+     [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
+      [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
+       [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+        {:type "button"
+         :on-click close-fn}
+        (t :close)]]]]))
 
 
 (defn encryption-dialog
 (defn encryption-dialog
   [repo-url]
   [repo-url]
@@ -53,77 +52,75 @@
   (rum/local "" ::password)
   (rum/local "" ::password)
   (rum/local "" ::password-confirm)
   (rum/local "" ::password-confirm)
   [state repo-url close-fn]
   [state repo-url close-fn]
-  (rum/with-context [[_t] i18n/*tongue-context*]
-    (let [password (get state ::password)
-          password-confirm (get state ::password-confirm)]
-      [:div
-       [:div.sm:flex.sm:items-start
-        [:div.mt-3.text-center.sm:mt-0.sm:text-left
-         [:h3#modal-headline.text-lg.leading-6.font-medium.font-bold
-          "Enter a password"]]]
-
-       (ui/admonition
-        :warning
-        [:div.opacity-70
-         "Choose a strong and hard to guess password.\nIf you lose your password, all the data can't be decrypted!! Please make sure you remember the password you have set, or you can keep a secure backup of the password."])
-       [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
-        {:type "password"
-         :placeholder "Password"
-         :auto-focus true
-         :on-change (fn [e]
-                      (reset! password (util/evalue e)))}]
-       [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
-        {:type "password"
-         :placeholder "Re-enter the password"
-         :on-change (fn [e]
-                      (reset! password-confirm (util/evalue e)))}]
-
-       [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
-        [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
-         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-          {:type "button"
-           :on-click (fn []
-                       (let [value @password]
-                         (cond
-                           (string/blank? value)
-                           nil
-
-                           (not= @password @password-confirm)
-                           (notification/show! "The passwords are not matched." :error)
-
-                           :else
-                           (p/let [keys (e/generate-key-pair-and-save! repo-url)
-                                   db-encrypted-secret (e/encrypt-with-passphrase value keys)]
-                             (metadata-handler/set-db-encrypted-secret! db-encrypted-secret)
-                             (close-fn true)))))}
-          "Submit"]]]])))
-
-(defn input-password
-  [repo-url close-fn]
-  (fn [_close-fn]
-    (input-password-inner repo-url close-fn)))
-
-(rum/defcs encryption-setup-dialog-inner
-  [state repo-url close-fn]
-  (rum/with-context [[t] i18n/*tongue-context*]
+  (let [password (get state ::password)
+        password-confirm (get state ::password-confirm)]
     [:div
     [:div
      [:div.sm:flex.sm:items-start
      [:div.sm:flex.sm:items-start
       [:div.mt-3.text-center.sm:mt-0.sm:text-left
       [:div.mt-3.text-center.sm:mt-0.sm:text-left
-       [:h3#modal-headline.text-lg.leading-6.font-medium
-        "Do you want to create an encrypted graph?"]]]
+       [:h3#modal-headline.text-lg.leading-6.font-medium.font-bold
+        "Enter a password"]]]
+
+     (ui/admonition
+      :warning
+      [:div.opacity-70
+       "Choose a strong and hard to guess password.\nIf you lose your password, all the data can't be decrypted!! Please make sure you remember the password you have set, or you can keep a secure backup of the password."])
+     [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
+      {:type "password"
+       :placeholder "Password"
+       :auto-focus true
+       :on-change (fn [e]
+                    (reset! password (util/evalue e)))}]
+     [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
+      {:type "password"
+       :placeholder "Re-enter the password"
+       :on-change (fn [e]
+                    (reset! password-confirm (util/evalue e)))}]
 
 
      [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
      [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
       [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
       [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
        [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
        [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
         {:type "button"
         {:type "button"
          :on-click (fn []
          :on-click (fn []
-                     (state/set-modal! (input-password repo-url close-fn)))}
-        (t :yes)]]
-      [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
-       [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-        {:type "button"
-         :on-click (fn [] (close-fn false))}
-        (t :no)]]]]))
+                     (let [value @password]
+                       (cond
+                         (string/blank? value)
+                         nil
+
+                         (not= @password @password-confirm)
+                         (notification/show! "The passwords are not matched." :error)
+
+                         :else
+                         (p/let [keys (e/generate-key-pair-and-save! repo-url)
+                                 db-encrypted-secret (e/encrypt-with-passphrase value keys)]
+                           (metadata-handler/set-db-encrypted-secret! db-encrypted-secret)
+                           (close-fn true)))))}
+        "Submit"]]]]))
+
+(defn input-password
+  [repo-url close-fn]
+  (fn [_close-fn]
+    (input-password-inner repo-url close-fn)))
+
+(rum/defcs encryption-setup-dialog-inner
+  [state repo-url close-fn]
+  [:div
+   [:div.sm:flex.sm:items-start
+    [:div.mt-3.text-center.sm:mt-0.sm:text-left
+     [:h3#modal-headline.text-lg.leading-6.font-medium
+      "Do you want to create an encrypted graph?"]]]
+
+   [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
+    [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
+     [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+      {:type "button"
+       :on-click (fn []
+                   (state/set-modal! (input-password repo-url close-fn)))}
+      (t :yes)]]
+    [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
+     [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+      {:type "button"
+       :on-click (fn [] (close-fn false))}
+      (t :no)]]]])
 
 
 (defn encryption-setup-dialog
 (defn encryption-setup-dialog
   [repo-url close-fn]
   [repo-url close-fn]
@@ -137,39 +134,38 @@
   (rum/local "" ::secret)
   (rum/local "" ::secret)
   (rum/local false ::loading)
   (rum/local false ::loading)
   [state _repo-url db-encrypted-secret close-fn]
   [state _repo-url db-encrypted-secret close-fn]
-  (rum/with-context [[_t] i18n/*tongue-context*]
-    (let [secret (::secret state)
-          loading (::loading state)]
-      [:div
-       [:div.sm:flex.sm:items-start
-        [:div.mt-3.text-center.sm:mt-0.sm:text-left
-         [:h3#modal-headline.text-lg.leading-6.font-medium
-          "Enter your password"]]]
-
-       [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
-        {:type "password"
-         :auto-focus true
-         :on-change (fn [e]
-                      (reset! secret (util/evalue e)))}]
-
-       [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
-        [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
-         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-          {:type "button"
-           :on-click (fn []
-                       (reset! loading true)
-                       (let [value @secret]
-                         (when-not (string/blank? value) ; TODO: length or other checks
-                           (let [repo (state/get-current-repo)]
-                             (p/do!
-                              (-> (e/decrypt-with-passphrase value db-encrypted-secret)
-                                  (p/then (fn [keys]
-                                            (e/save-key-pair! repo keys)
-                                            (close-fn true)
-                                            (state/set-state! :encryption/graph-parsing? false)))
-                                  (p/catch #(notification/show! "The password is not matched." :warning true))
-                                  (p/finally #(reset! loading false))))))))}
-          (if @loading (ui/loading "Decrypting") "Decrypt")]]]])))
+  (let [secret (::secret state)
+        loading (::loading state)]
+    [:div
+     [:div.sm:flex.sm:items-start
+      [:div.mt-3.text-center.sm:mt-0.sm:text-left
+       [:h3#modal-headline.text-lg.leading-6.font-medium
+        "Enter your password"]]]
+
+     [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
+      {:type "password"
+       :auto-focus true
+       :on-change (fn [e]
+                    (reset! secret (util/evalue e)))}]
+
+     [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
+      [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
+       [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+        {:type "button"
+         :on-click (fn []
+                     (reset! loading true)
+                     (let [value @secret]
+                       (when-not (string/blank? value) ; TODO: length or other checks
+                         (let [repo (state/get-current-repo)]
+                           (p/do!
+                            (-> (e/decrypt-with-passphrase value db-encrypted-secret)
+                                (p/then (fn [keys]
+                                          (e/save-key-pair! repo keys)
+                                          (close-fn true)
+                                          (state/set-state! :encryption/graph-parsing? false)))
+                                (p/catch #(notification/show! "The password is not matched." :warning true))
+                                (p/finally #(reset! loading false))))))))}
+        (if @loading (ui/loading "Decrypting") "Decrypt")]]]]))
 
 
 (defn encryption-input-secret-dialog
 (defn encryption-input-secret-dialog
   [repo-url db-encrypted-secret close-fn]
   [repo-url db-encrypted-secret close-fn]

+ 30 - 31
src/main/frontend/components/export.cljs

@@ -4,43 +4,42 @@
             [frontend.util :as util]
             [frontend.util :as util]
             [frontend.handler.export :as export]
             [frontend.handler.export :as export]
             [frontend.state :as state]
             [frontend.state :as state]
-            [frontend.context.i18n :as i18n]))
+            [frontend.context.i18n :refer [t]]))
 
 
 (rum/defc export
 (rum/defc export
   []
   []
   (when-let [current-repo (state/get-current-repo)]
   (when-let [current-repo (state/get-current-repo)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div.export
-       [:h1.title "Export"]
+    [:div.export
+     [:h1.title "Export"]
 
 
-       [:ul.mr-1
-        (when (util/electron?)
-          [:li.mb-4
-           [:a.font-medium {:on-click #(export/export-repo-as-html! current-repo)}
-            (t :export-public-pages)]])
+     [:ul.mr-1
+      (when (util/electron?)
         [:li.mb-4
         [:li.mb-4
-         [:a.font-medium {:on-click #(export/export-repo-as-markdown! current-repo)}
-          (t :export-markdown)]]
-        [:li.mb-4
-         [:a.font-medium {:on-click #(export/export-repo-as-opml! current-repo)}
-          (t :export-opml)]]
-        [:li.mb-4
-         [:a.font-medium {:on-click #(export/export-repo-as-edn-v2! current-repo)}
-          (t :export-edn)]]
-        [:li.mb-4
-         [:a.font-medium {:on-click #(export/export-repo-as-json-v2! current-repo)}
-          (t :export-json)]]
-        [:li.mb-4
-         [:a.font-medium {:on-click #(export/export-repo-as-roam-json! current-repo)}
-          (t :export-roam-json)]]]
-       [:a#download-as-edn-v2.hidden]
-       [:a#download-as-json-v2.hidden]
-       [:a#download-as-roam-json.hidden]
-       [:a#download-as-html.hidden]
-       [:a#download-as-zip.hidden]
-       [:a#export-as-markdown.hidden]
-       [:a#export-as-opml.hidden]
-       [:a#convert-markdown-to-unordered-list-or-heading.hidden]])))
+         [:a.font-medium {:on-click #(export/export-repo-as-html! current-repo)}
+          (t :export-public-pages)]])
+      [:li.mb-4
+       [:a.font-medium {:on-click #(export/export-repo-as-markdown! current-repo)}
+        (t :export-markdown)]]
+      [:li.mb-4
+       [:a.font-medium {:on-click #(export/export-repo-as-opml! current-repo)}
+        (t :export-opml)]]
+      [:li.mb-4
+       [:a.font-medium {:on-click #(export/export-repo-as-edn-v2! current-repo)}
+        (t :export-edn)]]
+      [:li.mb-4
+       [:a.font-medium {:on-click #(export/export-repo-as-json-v2! current-repo)}
+        (t :export-json)]]
+      [:li.mb-4
+       [:a.font-medium {:on-click #(export/export-repo-as-roam-json! current-repo)}
+        (t :export-roam-json)]]]
+     [:a#download-as-edn-v2.hidden]
+     [:a#download-as-json-v2.hidden]
+     [:a#download-as-roam-json.hidden]
+     [:a#download-as-html.hidden]
+     [:a#download-as-zip.hidden]
+     [:a#export-as-markdown.hidden]
+     [:a#export-as-opml.hidden]
+     [:a#convert-markdown-to-unordered-list-or-heading.hidden]]))
 
 
 
 
 (def *export-block-type (atom :text))
 (def *export-block-type (atom :text))

+ 74 - 76
src/main/frontend/components/file.cljs

@@ -6,7 +6,7 @@
             [frontend.components.lazy-editor :as lazy-editor]
             [frontend.components.lazy-editor :as lazy-editor]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.date :as date]
             [frontend.date :as date]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.format :as format]
             [frontend.format :as format]
@@ -24,43 +24,42 @@
 
 
 (rum/defc files < rum/reactive
 (rum/defc files < rum/reactive
   []
   []
-  (rum/with-context [[tongue] i18n/*tongue-context*]
-    [:div.flex-1.overflow-hidden
-     [:h1.title
-      (tongue :all-files)]
-     (when-let [current-repo (state/sub :git/current-repo)]
-       (let [files (db/get-files current-repo)
-             mobile? (util/mobile?)]
-         [:table.table-auto
-          [:thead
-           [:tr
-            [:th (tongue :file/name)]
-            (when-not mobile?
-              [:th (tongue :file/last-modified-at)])
-            (when-not mobile?
-              [:th ""])]]
-          [:tbody
-           (for [[file modified-at] files]
-             (let [file-id file]
-               [:tr {:key file-id}
-                [:td
-                 (let [href (if (config/draw? file)
-                              (rfe/href :draw nil {:file (string/replace file (str config/default-draw-directory "/") "")})
-                              (rfe/href :file {:path file-id}))]
-                   [:a {:href href}
-                    file])]
-                (when-not mobile?
-                  [:td [:span.text-gray-500.text-sm
-                       (if (zero? modified-at)
-                         (tongue :file/no-data)
-                         (date/get-date-time-string
-                          (t/to-default-time-zone (tc/to-date-time modified-at))))]])
+  [:div.flex-1.overflow-hidden
+   [:h1.title
+    (t :all-files)]
+   (when-let [current-repo (state/sub :git/current-repo)]
+     (let [files (db/get-files current-repo)
+           mobile? (util/mobile?)]
+       [:table.table-auto
+        [:thead
+         [:tr
+          [:th (t :file/name)]
+          (when-not mobile?
+            [:th (t :file/last-modified-at)])
+          (when-not mobile?
+            [:th ""])]]
+        [:tbody
+         (for [[file modified-at] files]
+           (let [file-id file]
+             [:tr {:key file-id}
+              [:td
+               (let [href (if (config/draw? file)
+                            (rfe/href :draw nil {:file (string/replace file (str config/default-draw-directory "/") "")})
+                            (rfe/href :file {:path file-id}))]
+                 [:a {:href href}
+                  file])]
+              (when-not mobile?
+                [:td [:span.text-gray-500.text-sm
+                      (if (zero? modified-at)
+                        (t :file/no-data)
+                        (date/get-date-time-string
+                         (t/to-default-time-zone (tc/to-date-time modified-at))))]])
 
 
-                (when-not mobile?
-                  [:td [:a.text-sm
-                       {:on-click (fn [_e]
-                                    (export-handler/download-file! file))}
-                       [:span (tongue :download)]]])]))]]))]))
+              (when-not mobile?
+                [:td [:a.text-sm
+                      {:on-click (fn [_e]
+                                   (export-handler/download-file! file))}
+                      [:span (t :download)]]])]))]]))])
 
 
 (rum/defcs file < rum/reactive
 (rum/defcs file < rum/reactive
   {:did-mount (fn [state]
   {:did-mount (fn [state]
@@ -74,46 +73,45 @@
         format (format/get-format path)
         format (format/get-format path)
         original-name (db/get-file-page path)
         original-name (db/get-file-page path)
         random-id (str (d/squuid))]
         random-id (str (d/squuid))]
-    (rum/with-context [[tongue] i18n/*tongue-context*]
-      [:div.file {:id (str "file-edit-wrapper-" random-id)}
-       [:h1.title
-        [:bdi (js/decodeURI path)]]
-       (when original-name
-         [:div.text-sm.mb-4.ml-1 "Page: "
-          [:a.bg-base-2.p-1.ml-1 {:style {:border-radius 4}
-                                  :href (rfe/href :page {:name original-name})
-                                  :on-click (fn [e]
-                                              (when (gobj/get e "shiftKey")
-                                                (when-let [page (db/entity [:block/name (util/page-name-sanity-lc original-name)])]
-                                                  (state/sidebar-add-block!
-                                                   (state/get-current-repo)
-                                                   (:db/id page)
-                                                   :page
-                                                   {:page page}))
-                                                (util/stop e)))}
-           original-name]])
+    [:div.file {:id (str "file-edit-wrapper-" random-id)}
+     [:h1.title
+      [:bdi (js/decodeURI path)]]
+     (when original-name
+       [:div.text-sm.mb-4.ml-1 "Page: "
+        [:a.bg-base-2.p-1.ml-1 {:style {:border-radius 4}
+                                :href (rfe/href :page {:name original-name})
+                                :on-click (fn [e]
+                                            (when (gobj/get e "shiftKey")
+                                              (when-let [page (db/entity [:block/name (util/page-name-sanity-lc original-name)])]
+                                                (state/sidebar-add-block!
+                                                 (state/get-current-repo)
+                                                 (:db/id page)
+                                                 :page
+                                                 {:page page}))
+                                              (util/stop e)))}
+         original-name]])
 
 
-       (when (and original-name (not (string/starts-with? original-name "logseq/")))
-         [:p.text-sm.ml-1.mb-4
-          (svg/warning {:style {:width "1em"
-                                :display "inline-block"}})
-          [:span.ml-1 "Please don't remove the page's title property (you can still modify it)."]])
+     (when (and original-name (not (string/starts-with? original-name "logseq/")))
+       [:p.text-sm.ml-1.mb-4
+        (svg/warning {:style {:width "1em"
+                              :display "inline-block"}})
+        [:span.ml-1 "Please don't remove the page's title property (you can still modify it)."]])
 
 
-       (cond
-         ;; image type
-         (and format (contains? (config/img-formats) format))
-         [:img {:src path}]
+     (cond
+       ;; image type
+       (and format (contains? (config/img-formats) format))
+       [:img {:src path}]
 
 
-         (and format (contains? (config/text-formats) format))
-         (when-let [file-content (db/get-file path)]
-           (let [content (string/trim file-content)
-                 mode (util/get-file-ext path)]
-             (lazy-editor/editor {:file? true
-                                  :file-path path}
-                                 (str "file-edit-" random-id)
-                                 {:data-lang mode}
-                                 content
-                                 {})))
+       (and format (contains? (config/text-formats) format))
+       (when-let [file-content (db/get-file path)]
+         (let [content (string/trim file-content)
+               mode (util/get-file-ext path)]
+           (lazy-editor/editor {:file? true
+                                :file-path path}
+                               (str "file-edit-" random-id)
+                               {:data-lang mode}
+                               content
+                               {})))
 
 
-         :else
-         [:div (tongue :file/format-not-supported (name format))])])))
+       :else
+       [:div (t :file/format-not-supported (name format))])]))

+ 99 - 101
src/main/frontend/components/header.cljs

@@ -6,7 +6,7 @@
             [frontend.components.right-sidebar :as sidebar]
             [frontend.components.right-sidebar :as sidebar]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.handler :as handler]
             [frontend.handler :as handler]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
             [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.plugin :as plugin-handler]
@@ -34,24 +34,23 @@
 
 
 (rum/defc login
 (rum/defc login
   [logged?]
   [logged?]
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (when (and (not logged?)
-               (not config/publishing?))
-
-      (ui/dropdown-with-links
-       (fn [{:keys [toggle-fn]}]
-         [:a.button.text-sm.font-medium.block {:on-click toggle-fn}
-          [:span (t :login)]])
-       (let [list [{:title (t :login-github)
-                    :url (str config/website "/login/github")}]]
-         (mapv
-          (fn [{:keys [title url]}]
-            {:title title
-             :options
-             {:on-click
-              (fn [_] (set! (.-href js/window.location) url))}})
-          list))
-       nil))))
+  (when (and (not logged?)
+             (not config/publishing?))
+
+    (ui/dropdown-with-links
+     (fn [{:keys [toggle-fn]}]
+       [:a.button.text-sm.font-medium.block {:on-click toggle-fn}
+        [:span (t :login)]])
+     (let [list [{:title (t :login-github)
+                  :url (str config/website "/login/github")}]]
+       (mapv
+        (fn [{:keys [title url]}]
+          {:title title
+           :options
+           {:on-click
+            (fn [_] (set! (.-href js/window.location) url))}})
+        list))
+     nil)))
 
 
 (rum/defc left-menu-button < rum/reactive
 (rum/defc left-menu-button < rum/reactive
   [{:keys [on-click]}]
   [{:keys [on-click]}]
@@ -164,90 +163,89 @@
                                (not (mobile-util/is-native-platform?))
                                (not (mobile-util/is-native-platform?))
                                (not config/publishing?))
                                (not config/publishing?))
         refreshing? (state/sub :nfs/refreshing?)]
         refreshing? (state/sub :nfs/refreshing?)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div.cp__header#head
-       {:class           (util/classnames [{:electron-mac   electron-mac?
-                                            :native-ios     (mobile-util/native-ios?)
-                                            :native-android (mobile-util/native-android?)}])
-        :on-double-click (fn [^js e]
-                           (when-let [target (.-target e)]
-                             (when (and (util/electron?)
-                                        (.. target -classList (contains "cp__header")))
-                               (js/window.apis.toggleMaxOrMinActiveWindow))))
-        :style           {:fontSize  50
-                          :transform (str "translateY(" (or (:offset-top vw-state) 0) "px)")}}
-       [:div.l.flex
-        (left-menu-button {:on-click (fn []
-                                       (open-fn)
-                                       (state/set-left-sidebar-open!
-                                        (not (:ui/left-sidebar-open? @state/state))))})
-
-        (when current-repo ;; this is for the Search button
-          (ui/with-shortcut :go/search "right"
-            [:a.button#search-button
-             {:on-click #(do (when (or (mobile-util/native-android?)
-                                       (mobile-util/native-iphone?))
-                               (state/set-left-sidebar-open! false))
-                             (state/pub-event! [:go/search]))}
-             (ui/icon "search" {:style {:fontSize ui/icon-size}})]))]
-
-       [:div.r.flex
-        (when (and (not (mobile-util/is-native-platform?))
-                   (not (util/electron?)))
-          (login logged?))
-
-        (when plugin-handler/lsp-enabled?
-          (plugins/hook-ui-items :toolbar))
-
-        (when (not= (state/get-current-route) :home)
-          (home-button))
-
-        (when (or (util/electron?)
-                  (mobile-util/native-ios?))
-          (back-and-forward))
-
-        (new-block-mode)
-
-        (when (and (mobile-util/is-native-platform?) (seq repos))
-          [:a.text-sm.font-medium.button
-           {:on-click
-            (fn []
-              (state/pub-event!
-               [:modal/show
-                [:div {:style {:max-width 700}}
-                 [:p "Refresh detects and processes files modified on your disk and diverged from the actual Logseq page content. Continue?"]
-                 (ui/button
-                  "Yes"
-                  :on-click (fn []
-                              (state/close-modal!)
-                              (nfs/refresh! (state/get-current-repo) repo/refresh-cb)))]]))}
-           (if refreshing?
-             [:div {:class "animate-spin-reverse"}
-              svg/refresh]
-             [:div.flex.flex-row.text-center.open-button__inner.items-center
-              (ui/icon "refresh" {:style {:fontSize ui/icon-size}})])])
-
-        (repo/sync-status current-repo)
-
-        (when show-open-folder?
-          [:a.text-sm.font-medium.button
-           {:on-click #(page-handler/ls-dir-files! shortcut/refresh!)}
+    [:div.cp__header#head
+     {:class           (util/classnames [{:electron-mac   electron-mac?
+                                          :native-ios     (mobile-util/native-ios?)
+                                          :native-android (mobile-util/native-android?)}])
+      :on-double-click (fn [^js e]
+                         (when-let [target (.-target e)]
+                           (when (and (util/electron?)
+                                      (.. target -classList (contains "cp__header")))
+                             (js/window.apis.toggleMaxOrMinActiveWindow))))
+      :style           {:fontSize  50
+                        :transform (str "translateY(" (or (:offset-top vw-state) 0) "px)")}}
+     [:div.l.flex
+      (left-menu-button {:on-click (fn []
+                                     (open-fn)
+                                     (state/set-left-sidebar-open!
+                                      (not (:ui/left-sidebar-open? @state/state))))})
+
+      (when current-repo ;; this is for the Search button
+        (ui/with-shortcut :go/search "right"
+          [:a.button#search-button
+           {:on-click #(do (when (or (mobile-util/native-android?)
+                                     (mobile-util/native-iphone?))
+                             (state/set-left-sidebar-open! false))
+                           (state/pub-event! [:go/search]))}
+           (ui/icon "search" {:style {:fontSize ui/icon-size}})]))]
+
+     [:div.r.flex
+      (when (and (not (mobile-util/is-native-platform?))
+                 (not (util/electron?)))
+        (login logged?))
+
+      (when plugin-handler/lsp-enabled?
+        (plugins/hook-ui-items :toolbar))
+
+      (when (not= (state/get-current-route) :home)
+        (home-button))
+
+      (when (or (util/electron?)
+                (mobile-util/native-ios?))
+        (back-and-forward))
+
+      (new-block-mode)
+
+      (when (and (mobile-util/is-native-platform?) (seq repos))
+        [:a.text-sm.font-medium.button
+         {:on-click
+          (fn []
+            (state/pub-event!
+             [:modal/show
+              [:div {:style {:max-width 700}}
+               [:p "Refresh detects and processes files modified on your disk and diverged from the actual Logseq page content. Continue?"]
+               (ui/button
+                 "Yes"
+                 :on-click (fn []
+                             (state/close-modal!)
+                             (nfs/refresh! (state/get-current-repo) repo/refresh-cb)))]]))}
+         (if refreshing?
+           [:div {:class "animate-spin-reverse"}
+            svg/refresh]
            [:div.flex.flex-row.text-center.open-button__inner.items-center
            [:div.flex.flex-row.text-center.open-button__inner.items-center
-            (ui/icon "folder-plus")
-            (when-not config/mobile?
-              [:span.ml-1 {:style {:margin-top (if electron-mac? 0 2)}}
-               (t :open)])]])
+            (ui/icon "refresh" {:style {:fontSize ui/icon-size}})])])
+
+      (repo/sync-status current-repo)
+
+      (when show-open-folder?
+        [:a.text-sm.font-medium.button
+         {:on-click #(page-handler/ls-dir-files! shortcut/refresh!)}
+         [:div.flex.flex-row.text-center.open-button__inner.items-center
+          (ui/icon "folder-plus")
+          (when-not config/mobile?
+            [:span.ml-1 {:style {:margin-top (if electron-mac? 0 2)}}
+             (t :open)])]])
 
 
-        (when config/publishing?
-          [:a.text-sm.font-medium.button {:href (rfe/href :graph)}
-           (t :graph)])
+      (when config/publishing?
+        [:a.text-sm.font-medium.button {:href (rfe/href :graph)}
+         (t :graph)])
 
 
-        (dropdown-menu {:me           me
-                        :t            t
-                        :current-repo current-repo
-                        :default-home default-home})
+      (dropdown-menu {:me           me
+                      :t            t
+                      :current-repo current-repo
+                      :default-home default-home})
 
 
-        (when (not (state/sub :ui/sidebar-open?))
-          (sidebar/toggle))
+      (when (not (state/sub :ui/sidebar-open?))
+        (sidebar/toggle))
 
 
-        (updater-tips-new-version t)]])))
+      (updater-tips-new-version t)]]))

+ 7 - 8
src/main/frontend/components/journal.cljs

@@ -19,7 +19,7 @@
             [rum.core :as rum]
             [rum.core :as rum]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.core :as shortcut]
-            [frontend.context.i18n :as i18n]))
+            [frontend.context.i18n :refer [t]]))
 
 
 (rum/defc blocks-cp < rum/reactive db-mixins/query
 (rum/defc blocks-cp < rum/reactive db-mixins/query
   {}
   {}
@@ -43,14 +43,13 @@
                          (let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
                          (let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
                            (text/build-data-value page-names)))]
                            (text/build-data-value page-names)))]
     (if (and (mobile-util/is-native-platform?) intro?)
     (if (and (mobile-util/is-native-platform?) intro?)
-      (rum/with-context [[t] i18n/*tongue-context*]
-        [:div
-         [:h1.title
-          (t :new-graph)]
+      [:div
+       [:h1.title
+        (t :new-graph)]
 
 
-         (ui/button
-           (t :open-a-directory)
-           :on-click #(page-handler/ls-dir-files! shortcut/refresh!))])
+       (ui/button
+         (t :open-a-directory)
+         :on-click #(page-handler/ls-dir-files! shortcut/refresh!))]
       [:div.flex-1.journal.page (cond->
       [:div.flex-1.journal.page (cond->
                                   {:class (if intro? "logseq-intro" "")}
                                   {:class (if intro? "logseq-intro" "")}
                                   data-page-tags
                                   data-page-tags

+ 192 - 194
src/main/frontend/components/onboarding.cljs

@@ -1,217 +1,215 @@
 (ns frontend.components.onboarding
 (ns frontend.components.onboarding
   (:require [frontend.components.svg :as svg]
   (:require [frontend.components.svg :as svg]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.handler.route :as route-handler]
             [frontend.handler.route :as route-handler]
             [rum.core :as rum]
             [rum.core :as rum]
             [frontend.ui :as ui]))
             [frontend.ui :as ui]))
 
 
 (rum/defc intro
 (rum/defc intro
   []
   []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    [:div#logseq-intro.pl-1
-     [:div.flex-1
-      [:div.flex.flex-col.pl-1.ls-block
-       [:hr {:style {:margin-top 200}}]
-       [:div.flex.flex-row.admonitionblock.align-items {:class "important"}
-        [:div.pr-4.admonition-icon.flex.flex-col.justify-center
-         {:title "Important"} (svg/tip)]
-        [:div.ml-4.text-lg
-         (t :on-boarding/notice)]]
-       [:p
-        {}
-        (t :on-boarding/features-desc)]
-       [:p
-        {}
-        (t :on-boarding/privacy)]
-       [:p
-        {}
-        [:strong {} "Logseq"]
-        (t :on-boarding/inspired-by)
-        [:a {:href "https://roamresearch.com/"
-             :target "_blank"} "Roam Research"]
-        ", "
-        [:a {:href "https://orgmode.org/"
-             :target "_blank"} "Org Mode"]
-        ", "
-        [:a {:href "https://tiddlywiki.com/"
-             :target "_blank"} "Tiddlywiki"]
-        " and "
-        [:a {:href "https://workflowy.com/"
-             :target "_blank"} "Workflowy"]
-        ", hats off to all of them!"]]
+  [:div#logseq-intro.pl-1
+   [:div.flex-1
+    [:div.flex.flex-col.pl-1.ls-block
+     [:hr {:style {:margin-top 200}}]
+     [:div.flex.flex-row.admonitionblock.align-items {:class "important"}
+      [:div.pr-4.admonition-icon.flex.flex-col.justify-center
+       {:title "Important"} (svg/tip)]
+      [:div.ml-4.text-lg
+       (t :on-boarding/notice)]]
+     [:p
+      {}
+      (t :on-boarding/features-desc)]
+     [:p
+      {}
+      (t :on-boarding/privacy)]
+     [:p
+      {}
+      [:strong {} "Logseq"]
+      (t :on-boarding/inspired-by)
+      [:a {:href "https://roamresearch.com/"
+           :target "_blank"} "Roam Research"]
+      ", "
+      [:a {:href "https://orgmode.org/"
+           :target "_blank"} "Org Mode"]
+      ", "
+      [:a {:href "https://tiddlywiki.com/"
+           :target "_blank"} "Tiddlywiki"]
+      " and "
+      [:a {:href "https://workflowy.com/"
+           :target "_blank"} "Workflowy"]
+      ", hats off to all of them!"]]
 
 
-      [:img.shadow-2xl
-       {:src
-        "https://asset.logseq.com/static/img/screenshot.png"
-        :alt "screenshot"}]
+    [:img.shadow-2xl
+     {:src
+      "https://asset.logseq.com/static/img/screenshot.png"
+      :alt "screenshot"}]
 
 
-      [:div.flex.flex-col.ls-block.intro-docs
-       [:h2 {} (t :on-boarding/features)]
-       [:ul
-        {}
-        [:li {} (t :on-boarding/features-backlinks)]
-        [:li {} (t :on-boarding/features-block-embed)]
-        [:li {} (t :on-boarding/features-page-embed)]
-        [:li {} (t :on-boarding/features-graph-vis)]
-        [:li {} "PDF annotations"]
-        [:li {} "Zotero integration"]
-        [:li {} "Spaced repetition cards"]
-        [:li {} (t :on-boarding/features-heading-properties)]
-        [:li
-         {}
-         (t :on-boarding/features-datalog)
-         [:a {:href "https://github.com/tonsky/datascript"
-              :target "_blank"} "Datascript"]]
-        [:li {} (t :on-boarding/features-custom-view-component)]
-        [:li
-         {}
-         [:a {:href "https://excalidraw.com/"
-              :target "_blank"} "Excalidraw"]
-         (t :on-boarding/integration)]
-        [:li
-         {}
-         [:a {:href "https://revealjs.com/"
-              :target "_blank"} "reveal.js"]
-         (t :on-boarding/slide-support)]
-        [:li
-         {}
-         (t :on-boarding/built-in-supports)
-         [:ul
-          {}
-          [:li {} (t :on-boarding/supports-code-highlights)]
-          [:li {} (t :on-boarding/supports-katex-latex)]
-          [:li
-           {}
-           (t :on-boarding/raw)
-           [:a {:href "https://github.com/weavejester/hiccup"
-                :target "_blank"} "hiccup"]]
-          [:li {} (t :on-boarding/raw-html)]]]]
-       [:h2 {} (t :on-boarding/learn-more)]
+    [:div.flex.flex-col.ls-block.intro-docs
+     [:h2 {} (t :on-boarding/features)]
+     [:ul
+      {}
+      [:li {} (t :on-boarding/features-backlinks)]
+      [:li {} (t :on-boarding/features-block-embed)]
+      [:li {} (t :on-boarding/features-page-embed)]
+      [:li {} (t :on-boarding/features-graph-vis)]
+      [:li {} "PDF annotations"]
+      [:li {} "Zotero integration"]
+      [:li {} "Spaced repetition cards"]
+      [:li {} (t :on-boarding/features-heading-properties)]
+      [:li
+       {}
+       (t :on-boarding/features-datalog)
+       [:a {:href "https://github.com/tonsky/datascript"
+            :target "_blank"} "Datascript"]]
+      [:li {} (t :on-boarding/features-custom-view-component)]
+      [:li
+       {}
+       [:a {:href "https://excalidraw.com/"
+            :target "_blank"} "Excalidraw"]
+       (t :on-boarding/integration)]
+      [:li
+       {}
+       [:a {:href "https://revealjs.com/"
+            :target "_blank"} "reveal.js"]
+       (t :on-boarding/slide-support)]
+      [:li
+       {}
+       (t :on-boarding/built-in-supports)
        [:ul
        [:ul
         {}
         {}
+        [:li {} (t :on-boarding/supports-code-highlights)]
+        [:li {} (t :on-boarding/supports-katex-latex)]
         [:li
         [:li
          {}
          {}
-         "Twitter: "
-         [:a
-          {:href "https://twitter.com/logseq"
-           :target "_blank"}
-          "https://twitter.com/logseq"]]
-        [:li
-         {}
-         "Discord: "
-         [:a
-          {:href "https://discord.gg/KpN4eHY"
-           :target "_blank"}
-          "https://discord.gg/KpN4eHY"]
-         (t :on-boarding/discord-desc)]
-        [:li
-         {}
-         "GitHub: "
-         [:a
-          {:href "https://github.com/logseq/logseq"
-           :target "_blank"}
-          "https://github.com/logseq/logseq"]
-         (t :on-boarding/github-desc)]
-        [:li
-         {}
-         (t :on-boarding/our-blog)
-         [:a
-          {:href "https://docs.logseq.com/"
-           :target "_blank"}
-          "https://docs.logseq.com/"]]]
-       [:h2 (t :on-boarding/credits-to)]
-       [:ul
-        {}
-        [:li [:a {:href "https://roamresearch.com/"
-                  :target "_blank"} "Roam Research"]]
-        [:li [:a {:href "https://orgmode.org/"
-                  :target "_blank"} "Org Mode"]]
-        [:li [:a {:href "https://tiddlywiki.com/"
-                  :target "_blank"} "Tiddlywiki"]]
-        [:li
-         [:a {:href "https://workflowy.com/"
-              :target "_blank"} "Workflowy"]]
-        [:li
-         [:a
-          {:href "https://clojure.org"
-           :target "_blank"}
-          "Clojure && Clojurescript"]
-         (t :on-boarding/clojure-desc)]
-        [:li
-         [:a {:href "https://github.com/tonsky/datascript"
-              :target "_blank"} "Datascript"]
-         (t :on-boarding/datascript-desc)]
-        [:li
-         [:a {:href "https://ocaml.org/"
-              :target "_blank"} "OCaml"]
-         " && "
-         [:a
-          {:href "https://github.com/inhabitedtype/angstrom"
-           :target "_blank"}
-          "Angstrom"]
-         (t :on-boarding/angstrom-desc-1)
-         [:a {:href "https://github.com/mldoc/mldoc"
-              :target "_blank"} (t :on-boarding/angstrom-desc-2)]
-         (t :on-boarding/angstrom-desc-3)]
-        [:li
-         [:a {:href "https://github.com/talex5/cuekeeper"
-              :target "_blank"} "Cuekeeper"]
-         (t :on-boarding/cuekeeper-desc)]
-        [:li
-         [:a {:href "https://github.com/borkdude/sci"
-              :target "_blank"} "sci"]
-         (t :on-boarding/sci-desc)]
-        [:li
-         [:a {:href "https://isomorphic-git.org/"
-              :target "_blank"} "isomorphic-git"]
-         (t :on-boarding/isomorphic-git-desc)]]
+         (t :on-boarding/raw)
+         [:a {:href "https://github.com/weavejester/hiccup"
+              :target "_blank"} "hiccup"]]
+        [:li {} (t :on-boarding/raw-html)]]]]
+     [:h2 {} (t :on-boarding/learn-more)]
+     [:ul
+      {}
+      [:li
+       {}
+       "Twitter: "
+       [:a
+        {:href "https://twitter.com/logseq"
+         :target "_blank"}
+        "https://twitter.com/logseq"]]
+      [:li
+       {}
+       "Discord: "
+       [:a
+        {:href "https://discord.gg/KpN4eHY"
+         :target "_blank"}
+        "https://discord.gg/KpN4eHY"]
+       (t :on-boarding/discord-desc)]
+      [:li
+       {}
+       "GitHub: "
+       [:a
+        {:href "https://github.com/logseq/logseq"
+         :target "_blank"}
+        "https://github.com/logseq/logseq"]
+       (t :on-boarding/github-desc)]
+      [:li
+       {}
+       (t :on-boarding/our-blog)
+       [:a
+        {:href "https://docs.logseq.com/"
+         :target "_blank"}
+        "https://docs.logseq.com/"]]]
+     [:h2 (t :on-boarding/credits-to)]
+     [:ul
+      {}
+      [:li [:a {:href "https://roamresearch.com/"
+                :target "_blank"} "Roam Research"]]
+      [:li [:a {:href "https://orgmode.org/"
+                :target "_blank"} "Org Mode"]]
+      [:li [:a {:href "https://tiddlywiki.com/"
+                :target "_blank"} "Tiddlywiki"]]
+      [:li
+       [:a {:href "https://workflowy.com/"
+            :target "_blank"} "Workflowy"]]
+      [:li
+       [:a
+        {:href "https://clojure.org"
+         :target "_blank"}
+        "Clojure && Clojurescript"]
+       (t :on-boarding/clojure-desc)]
+      [:li
+       [:a {:href "https://github.com/tonsky/datascript"
+            :target "_blank"} "Datascript"]
+       (t :on-boarding/datascript-desc)]
+      [:li
+       [:a {:href "https://ocaml.org/"
+            :target "_blank"} "OCaml"]
+       " && "
+       [:a
+        {:href "https://github.com/inhabitedtype/angstrom"
+         :target "_blank"}
+        "Angstrom"]
+       (t :on-boarding/angstrom-desc-1)
+       [:a {:href "https://github.com/mldoc/mldoc"
+            :target "_blank"} (t :on-boarding/angstrom-desc-2)]
+       (t :on-boarding/angstrom-desc-3)]
+      [:li
+       [:a {:href "https://github.com/talex5/cuekeeper"
+            :target "_blank"} "Cuekeeper"]
+       (t :on-boarding/cuekeeper-desc)]
+      [:li
+       [:a {:href "https://github.com/borkdude/sci"
+            :target "_blank"} "sci"]
+       (t :on-boarding/sci-desc)]
+      [:li
+       [:a {:href "https://isomorphic-git.org/"
+            :target "_blank"} "isomorphic-git"]
+       (t :on-boarding/isomorphic-git-desc)]]
 
 
-       [:img {:src
-              "https://asset.logseq.com/static/img/credits.png"
-              :style {:margin "12px 0 0 0"}}]]]]))
+     [:img {:src
+            "https://asset.logseq.com/static/img/credits.png"
+            :style {:margin "12px 0 0 0"}}]]]])
 
 
 (defn help
 (defn help
   []
   []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    [:div.help.cp__sidebar-help-docs
-     (let [discord-with-icon [:div.flex-row.inline-flex.items-center
-                              [:span.mr-1 (t :help/community)]
-                              (ui/icon "brand-discord" {:style {:font-size 20}})]
-           list
-           [{:title "Usage"
-             :children [[[:a
-                          {:on-click (fn [] (route-handler/redirect! {:to :shortcut-setting}))}
-                          [:div.flex-row.inline-flex.items-center
-                           [:span.mr-1 (t :help/shortcuts)]
-                           (ui/icon "command" {:style {:font-size 20}})]]]
-                        [(t :help/docs) "https://docs.logseq.com/"]
-                        ["FAQ" "https://docs.logseq.com/#/page/faq"]]}
+  [:div.help.cp__sidebar-help-docs
+   (let [discord-with-icon [:div.flex-row.inline-flex.items-center
+                            [:span.mr-1 (t :help/community)]
+                            (ui/icon "brand-discord" {:style {:font-size 20}})]
+         list
+         [{:title "Usage"
+           :children [[[:a
+                        {:on-click (fn [] (route-handler/redirect! {:to :shortcut-setting}))}
+                        [:div.flex-row.inline-flex.items-center
+                         [:span.mr-1 (t :help/shortcuts)]
+                         (ui/icon "command" {:style {:font-size 20}})]]]
+                      [(t :help/docs) "https://docs.logseq.com/"]
+                      ["FAQ" "https://docs.logseq.com/#/page/faq"]]}
 
 
-            {:title "About"
-             :children [[(t :help/start) "https://docs.logseq.com/#/page/getting%20started"]
-                        [(t :help/about) "https://logseq.com/blog/about"]]}
+          {:title "About"
+           :children [[(t :help/start) "https://docs.logseq.com/#/page/getting%20started"]
+                      [(t :help/about) "https://logseq.com/blog/about"]]}
 
 
-            {:title "Development"
-             :children [[(t :help/roadmap) "https://trello.com/b/8txSM12G/roadmap"]
-                        [(t :help/bug) "https://github.com/logseq/logseq/issues/new?assignees=&labels=&template=bug_report.md&title="]
-                        [(t :help/feature) "https://github.com/logseq/logseq/issues/new?assignees=&labels=&template=feature_request.md&title="]
-                        [(t :help/changelog) "https://docs.logseq.com/#/page/changelog"]]}
+          {:title "Development"
+           :children [[(t :help/roadmap) "https://trello.com/b/8txSM12G/roadmap"]
+                      [(t :help/bug) "https://github.com/logseq/logseq/issues/new?assignees=&labels=&template=bug_report.md&title="]
+                      [(t :help/feature) "https://github.com/logseq/logseq/issues/new?assignees=&labels=&template=feature_request.md&title="]
+                      [(t :help/changelog) "https://docs.logseq.com/#/page/changelog"]]}
 
 
-            {:title "Terms"
-             :children [[(t :help/privacy) "https://logseq.com/blog/privacy-policy"]
-                        [(t :help/terms) "https://logseq.com/blog/terms"]]}
+          {:title "Terms"
+           :children [[(t :help/privacy) "https://logseq.com/blog/privacy-policy"]
+                      [(t :help/terms) "https://logseq.com/blog/terms"]]}
 
 
-            {:title "Community"
-             :children [[(t :help/awesome-logseq) "https://github.com/logseq/awesome-logseq"]
-                        [discord-with-icon "https://discord.gg/KpN4eHY"]]}]]
+          {:title "Community"
+           :children [[(t :help/awesome-logseq) "https://github.com/logseq/awesome-logseq"]
+                      [discord-with-icon "https://discord.gg/KpN4eHY"]]}]]
 
 
-       (map (fn [sublist]
-              [[:p.mt-4.mb-1 [:b (:title sublist)]]
-              [:ul
-               (map (fn [[title href]]
-                      [:li
-                       (if href
-                         [:a {:href href :target "_blank"} title]
-                         title)])
-                    (:children sublist))]])
-            list))]))
+     (map (fn [sublist]
+            [[:p.mt-4.mb-1 [:b (:title sublist)]]
+             [:ul
+              (map (fn [[title href]]
+                     [:li
+                      (if href
+                        [:a {:href href :target "_blank"} title]
+                        title)])
+                (:children sublist))]])
+       list))])

+ 401 - 408
src/main/frontend/components/page.cljs

@@ -8,7 +8,7 @@
             [frontend.components.reference :as reference]
             [frontend.components.reference :as reference]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.date :as date]
             [frontend.date :as date]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.db-mixins :as db-mixins]
             [frontend.db-mixins :as db-mixins]
@@ -257,78 +257,77 @@
           journal? (db/journal-page? page-name)
           journal? (db/journal-page? page-name)
           fmt-journal? (boolean (date/journal-title->int page-name))
           fmt-journal? (boolean (date/journal-title->int page-name))
           sidebar? (:sidebar? option)]
           sidebar? (:sidebar? option)]
-      (rum/with-context [[_t] i18n/*tongue-context*]
-        (let [route-page-name path-page-name
-              page (if block?
-                     (->> (:db/id (:block/page (db/entity repo [:block/uuid block-id])))
-                          (db/entity repo))
-                     (do
-                       (when-not (db/entity repo [:block/name page-name])
-                         (let [m (format-block/page-name->map path-page-name true)]
-                           (db/transact! repo [m])))
-                       (db/pull [:block/name page-name])))
-              {:keys [icon]} (:block/properties page)
-              page-name (:block/name page)
-              page-original-name (:block/original-name page)
-              title (or page-original-name page-name)
-              icon (or icon "")
-              today? (and
-                      journal?
-                      (= page-name (util/page-name-sanity-lc (date/journal-name))))]
-          [:div.flex-1.page.relative
-           (merge (if (seq (:block/tags page))
-                    (let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
-                      {:data-page-tags (text/build-data-value page-names)})
-                    {})
-
-                  {:key path-page-name
-                   :class (util/classnames [{:is-journals (or journal? fmt-journal?)}])})
-
-           [:div.relative
-            (when (and (not sidebar?)
-                       (not block?))
-              [:div.flex.flex-row.space-between
-               [:div.flex-1.flex-row
-                (page-title page-name icon title format fmt-journal?)]
-               (when (not config/publishing?)
-                 [:div.flex.flex-row
-                  (when plugin-handler/lsp-enabled?
-                    (plugins/hook-ui-slot :page-head-actions-slotted nil)
-                    (plugins/hook-ui-items :pagebar))])])
-            [:div
-             (when (and block? (not sidebar?))
-               (let [config {:id "block-parent"
-                             :block? true}]
-                 [:div.mb-4
-                  (block/block-parents config repo block-id {:level-limit 3})]))
-
-             ;; blocks
-             (let [page (if block?
-                          (db/entity repo [:block/uuid block-id])
-                          page)]
-               (page-blocks-cp repo page {:sidebar? sidebar?}))]]
-
-           (when-not block?
-             (today-queries repo today? sidebar?))
-
-           (when-not block?
-             (tagged-pages repo page-name))
-
-           ;; referenced blocks
-           [:div {:key "page-references"}
-            (rum/with-key
-              (reference/references route-page-name false)
-              (str route-page-name "-refs"))]
-
-           (when-not block?
-             [:div
-              (when (not journal?)
-                (hierarchy/structures route-page-name))
-
-              ;; TODO: or we can lazy load them
-              (when-not sidebar?
-                [:div {:key "page-unlinked-references"}
-                 (reference/unlinked-references route-page-name)])])])))))
+      (let [route-page-name path-page-name
+            page (if block?
+                   (->> (:db/id (:block/page (db/entity repo [:block/uuid block-id])))
+                        (db/entity repo))
+                   (do
+                     (when-not (db/entity repo [:block/name page-name])
+                       (let [m (format-block/page-name->map path-page-name true)]
+                         (db/transact! repo [m])))
+                     (db/pull [:block/name page-name])))
+            {:keys [icon]} (:block/properties page)
+            page-name (:block/name page)
+            page-original-name (:block/original-name page)
+            title (or page-original-name page-name)
+            icon (or icon "")
+            today? (and
+                    journal?
+                    (= page-name (util/page-name-sanity-lc (date/journal-name))))]
+        [:div.flex-1.page.relative
+         (merge (if (seq (:block/tags page))
+                  (let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
+                    {:data-page-tags (text/build-data-value page-names)})
+                  {})
+
+                {:key path-page-name
+                 :class (util/classnames [{:is-journals (or journal? fmt-journal?)}])})
+
+         [:div.relative
+          (when (and (not sidebar?)
+                     (not block?))
+            [:div.flex.flex-row.space-between
+             [:div.flex-1.flex-row
+              (page-title page-name icon title format fmt-journal?)]
+             (when (not config/publishing?)
+               [:div.flex.flex-row
+                (when plugin-handler/lsp-enabled?
+                  (plugins/hook-ui-slot :page-head-actions-slotted nil)
+                  (plugins/hook-ui-items :pagebar))])])
+          [:div
+           (when (and block? (not sidebar?))
+             (let [config {:id "block-parent"
+                           :block? true}]
+               [:div.mb-4
+                (block/block-parents config repo block-id {:level-limit 3})]))
+
+           ;; blocks
+           (let [page (if block?
+                        (db/entity repo [:block/uuid block-id])
+                        page)]
+             (page-blocks-cp repo page {:sidebar? sidebar?}))]]
+
+         (when-not block?
+           (today-queries repo today? sidebar?))
+
+         (when-not block?
+           (tagged-pages repo page-name))
+
+         ;; referenced blocks
+         [:div {:key "page-references"}
+          (rum/with-key
+            (reference/references route-page-name false)
+            (str route-page-name "-refs"))]
+
+         (when-not block?
+           [:div
+            (when (not journal?)
+              (hierarchy/structures route-page-name))
+
+            ;; TODO: or we can lazy load them
+            (when-not sidebar?
+              [:div {:key "page-unlinked-references"}
+               (reference/unlinked-references route-page-name)])])]))))
 
 
 (defonce layout (atom [js/window.innerWidth js/window.innerHeight]))
 (defonce layout (atom [js/window.innerWidth js/window.innerHeight]))
 
 
@@ -374,103 +373,102 @@
                          (config-handler/set-config! :graph/settings new-settings)))
                          (config-handler/set-config! :graph/settings new-settings)))
         search-graph-filters (state/sub :search/graph-filters)
         search-graph-filters (state/sub :search/graph-filters)
         focus-nodes (rum/react *focus-nodes)]
         focus-nodes (rum/react *focus-nodes)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div.absolute.top-4.right-4.graph-filters
-       [:div.flex.flex-col
-        [:div.shadow-xl.rounded-sm
-         [:ul
-          (graph-filter-section
-           [:span.font-medium "Nodes"]
-           (fn [open?]
-             (filter-expand-area
-              open?
-              [:div
-               [:p.text-sm.opacity-70.px-4
-                (let [c1 (count (:nodes graph))
-                      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
-                ;; [:div.flex.items-center.justify-between.mb-2
-                ;;  [:span "Layout"]
-                ;;  (ui/select
-                ;;    (mapv
-                ;;     (fn [item]
-                ;;       (if (= (:label item) layout)
-                ;;         (assoc item :selected "selected")
-                ;;         item))
-                ;;     [{:label "gForce"}
-                ;;      {:label "dagre"}])
-                ;;    (fn [value]
-                ;;      (set-setting! :layout value))
-                ;;    "graph-layout")]
-                [:div.flex.items-center.justify-between.mb-2
-                 [:span (t :right-side-bar/journals)]
-                 ;; FIXME: why it's not aligned well?
-                 [:div.mt-1
-                  (ui/toggle journal?
-                             (fn []
-                               (let [value (not journal?)]
-                                 (reset! *journal? value)
-                                 (set-setting! :journal? value)))
-                             true)]]
-                [:div.flex.items-center.justify-between.mb-2
-                 [:span "Orphan pages"]
-                 [:div.mt-1
-                  (ui/toggle orphan-pages?
-                             (fn []
-                               (let [value (not orphan-pages?)]
-                                 (reset! *orphan-pages? value)
-                                 (set-setting! :orphan-pages? value)))
-                             true)]]
-                [:div.flex.items-center.justify-between.mb-2
-                 [:span "Built-in pages"]
-                 [:div.mt-1
-                  (ui/toggle builtin-pages?
-                             (fn []
-                               (let [value (not builtin-pages?)]
-                                 (reset! *builtin-pages? value)
-                                 (set-setting! :builtin-pages? value)))
-                             true)]]
-                (when (seq focus-nodes)
-                  [:div.flex.flex-col.mb-2
-                   [:p {:title "N hops from selected nodes"}
-                    "N hops from selected nodes"]
-                   (ui/tippy {:html [:div.pr-3 n-hops]}
-                             (ui/slider (or n-hops 10)
-                                        {:min 1
-                                         :max 10
-                                         :on-change #(reset! *n-hops (int %))}))])
-
-                [:a.opacity-70.opacity-100 {:on-click (fn []
-                                                        (swap! *graph-reset? not)
-                                                        (reset! *focus-nodes [])
-                                                        (reset! *n-hops nil)
-                                                        (state/clear-search-filters!))}
-                 "Reset Graph"]]]))
-           {})
-          (graph-filter-section
-           [:span.font-medium "Search"]
-           (fn [open?]
-             (filter-expand-area
-              open?
-              [:div.p-6
-               (if (seq search-graph-filters)
-                 [:div
-                  (for [q search-graph-filters]
-                    [:div.flex.flex-row.justify-between.items-center.mb-2
-                     [:span.font-medium q]
-                     [:a.search-filter-close.opacity-70.opacity-100 {:on-click #(state/remove-search-filter! q)}
-                      svg/close]])
-
-                  [:a.opacity-70.opacity-100 {:on-click state/clear-search-filters!}
-                   "Clear All"]]
-                 [:a.opacity-70.opacity-100 {:on-click #(route-handler/go-to-search! :graph)}
-                  "Click to search"])]))
-           {:search-filters search-graph-filters})]]]])))
+    [:div.absolute.top-4.right-4.graph-filters
+     [:div.flex.flex-col
+      [:div.shadow-xl.rounded-sm
+       [:ul
+        (graph-filter-section
+         [:span.font-medium "Nodes"]
+         (fn [open?]
+           (filter-expand-area
+            open?
+            [:div
+             [:p.text-sm.opacity-70.px-4
+              (let [c1 (count (:nodes graph))
+                    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
+              ;; [:div.flex.items-center.justify-between.mb-2
+              ;;  [:span "Layout"]
+              ;;  (ui/select
+              ;;    (mapv
+              ;;     (fn [item]
+              ;;       (if (= (:label item) layout)
+              ;;         (assoc item :selected "selected")
+              ;;         item))
+              ;;     [{:label "gForce"}
+              ;;      {:label "dagre"}])
+              ;;    (fn [value]
+              ;;      (set-setting! :layout value))
+              ;;    "graph-layout")]
+              [:div.flex.items-center.justify-between.mb-2
+               [:span (t :right-side-bar/journals)]
+               ;; FIXME: why it's not aligned well?
+               [:div.mt-1
+                (ui/toggle journal?
+                           (fn []
+                             (let [value (not journal?)]
+                               (reset! *journal? value)
+                               (set-setting! :journal? value)))
+                           true)]]
+              [:div.flex.items-center.justify-between.mb-2
+               [:span "Orphan pages"]
+               [:div.mt-1
+                (ui/toggle orphan-pages?
+                           (fn []
+                             (let [value (not orphan-pages?)]
+                               (reset! *orphan-pages? value)
+                               (set-setting! :orphan-pages? value)))
+                           true)]]
+              [:div.flex.items-center.justify-between.mb-2
+               [:span "Built-in pages"]
+               [:div.mt-1
+                (ui/toggle builtin-pages?
+                           (fn []
+                             (let [value (not builtin-pages?)]
+                               (reset! *builtin-pages? value)
+                               (set-setting! :builtin-pages? value)))
+                           true)]]
+              (when (seq focus-nodes)
+                [:div.flex.flex-col.mb-2
+                 [:p {:title "N hops from selected nodes"}
+                  "N hops from selected nodes"]
+                 (ui/tippy {:html [:div.pr-3 n-hops]}
+                           (ui/slider (or n-hops 10)
+                                      {:min 1
+                                       :max 10
+                                       :on-change #(reset! *n-hops (int %))}))])
+
+              [:a.opacity-70.opacity-100 {:on-click (fn []
+                                                      (swap! *graph-reset? not)
+                                                      (reset! *focus-nodes [])
+                                                      (reset! *n-hops nil)
+                                                      (state/clear-search-filters!))}
+               "Reset Graph"]]]))
+         {})
+        (graph-filter-section
+         [:span.font-medium "Search"]
+         (fn [open?]
+           (filter-expand-area
+            open?
+            [:div.p-6
+             (if (seq search-graph-filters)
+               [:div
+                (for [q search-graph-filters]
+                  [:div.flex.flex-row.justify-between.items-center.mb-2
+                   [:span.font-medium q]
+                   [:a.search-filter-close.opacity-70.opacity-100 {:on-click #(state/remove-search-filter! q)}
+                    svg/close]])
+
+                [:a.opacity-70.opacity-100 {:on-click state/clear-search-filters!}
+                 "Clear All"]]
+               [:a.opacity-70.opacity-100 {:on-click #(route-handler/go-to-search! :graph)}
+                "Click to search"])]))
+         {:search-filters search-graph-filters})]]]]))
 
 
 (defonce last-node-position (atom nil))
 (defonce last-node-position (atom nil))
 (defn- graph-register-handlers
 (defn- graph-register-handlers
@@ -503,18 +501,17 @@
                                                  (and (not (nodes (:source link)))
                                                  (and (not (nodes (:source link)))
                                                       (not (nodes (:target link)))))
                                                       (not (nodes (:target link)))))
                                                links))))]
                                                links))))]
-    (rum/with-context [[_t] i18n/*tongue-context*]
-      [:div.relative#global-graph
-       (graph/graph-2d {:nodes (:nodes graph)
-                        :links (:links graph)
-                        :width (- width 24)
-                        :height (- height 48)
-                        :dark? dark?
-                        :register-handlers-fn
-                        (fn [graph]
-                          (graph-register-handlers graph *focus-nodes *n-hops dark?))
-                        :reset? reset?})
-       (graph-filters graph settings n-hops)])))
+    [:div.relative#global-graph
+     (graph/graph-2d {:nodes (:nodes graph)
+                      :links (:links graph)
+                      :width (- width 24)
+                      :height (- height 48)
+                      :dark? dark?
+                      :register-handlers-fn
+                      (fn [graph]
+                        (graph-register-handlers graph *focus-nodes *n-hops dark?))
+                      :reset? reset?})
+     (graph-filters graph settings n-hops)]))
 
 
 (defn- filter-graph-nodes
 (defn- filter-graph-nodes
   [nodes filters]
   [nodes filters]
@@ -612,55 +609,52 @@
 (defn batch-delete-dialog
 (defn batch-delete-dialog
   [pages orphaned-pages? refresh-fn]
   [pages orphaned-pages? refresh-fn]
   (fn [close-fn]
   (fn [close-fn]
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
-
-      [:div
-       [:div.sm:flex.items-center
-        [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
-         [:span.text-red-600.text-xl
-          (ui/icon "alert-triangle")]]
-        [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
-         [:h3#modal-headline.text-lg.leading-6.font-medium
-          (if orphaned-pages?
-            (str (t :remove-orphaned-pages) "?")
-            (t :page/delete-confirmation))]]]
-
-       [:table.table-auto.cp__all_pages_table.mt-4
-        [:thead
-         [:tr.opacity-70
-          [:th [:span "#"]]
-          [:th [:span (t :block/name)]]
-          [:th [:span (t :page/backlinks)]]
-          (when-not orphaned-pages? [:th [:span (t :page/created-at)]])
-          (when-not orphaned-pages? [:th [:span (t :page/updated-at)]])]]
-
-        [:tbody
-         (for [[n {:block/keys [name created-at updated-at backlinks] :as page}] (medley/indexed pages)]
-           [:tr {:key name}
-            [:td.n.w-10 [:span.opacity-70 (str (inc n) ". ")]]
-            [:td.name [:a {:href     (rfe/href :page {:name (:block/name page)})}
-                       (block/page-cp {} page)]]
-            [:td.backlinks [:span (or backlinks "0")]]
-            (when-not orphaned-pages? [:td.created-at [:span (if created-at (date/int->local-time-2 created-at) "Unknown")]])
-            (when-not orphaned-pages? [:td.updated-at [:span (if updated-at (date/int->local-time-2 updated-at) "Unknown")]])])]]
-
-       [:div.pt-6.flex.justify-end
-
-        [:span.pr-2
-         (ui/button
-           (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)))]])))
+    [:div
+     [:div.sm:flex.items-center
+      [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
+       [:span.text-red-600.text-xl
+        (ui/icon "alert-triangle")]]
+      [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
+       [:h3#modal-headline.text-lg.leading-6.font-medium
+        (if orphaned-pages?
+          (str (t :remove-orphaned-pages) "?")
+          (t :page/delete-confirmation))]]]
+
+     [:table.table-auto.cp__all_pages_table.mt-4
+      [:thead
+       [:tr.opacity-70
+        [:th [:span "#"]]
+        [:th [:span (t :block/name)]]
+        [:th [:span (t :page/backlinks)]]
+        (when-not orphaned-pages? [:th [:span (t :page/created-at)]])
+        (when-not orphaned-pages? [:th [:span (t :page/updated-at)]])]]
+
+      [:tbody
+       (for [[n {:block/keys [name created-at updated-at backlinks] :as page}] (medley/indexed pages)]
+         [:tr {:key name}
+          [:td.n.w-10 [:span.opacity-70 (str (inc n) ". ")]]
+          [:td.name [:a {:href     (rfe/href :page {:name (:block/name page)})}
+                     (block/page-cp {} page)]]
+          [:td.backlinks [:span (or backlinks "0")]]
+          (when-not orphaned-pages? [:td.created-at [:span (if created-at (date/int->local-time-2 created-at) "Unknown")]])
+          (when-not orphaned-pages? [:td.updated-at [:span (if updated-at (date/int->local-time-2 updated-at) "Unknown")]])])]]
+
+     [:div.pt-6.flex.justify-end
+
+      [:span.pr-2
+       (ui/button
+         (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)))]]))
 
 
 (rum/defcs all-pages < rum/reactive
 (rum/defcs all-pages < rum/reactive
   (rum/local nil ::pages)
   (rum/local nil ::pages)
@@ -721,187 +715,186 @@
                          (reset! *pages nil)
                          (reset! *pages nil)
                          (reset! *current-page 1))]
                          (reset! *current-page 1))]
 
 
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div.flex-1.cp__all_pages
-       [:h1.title (t :all-pages)]
-
-       (when current-repo
-
-         ;; all pages
-         (when (nil? @*pages)
-           (let [pages (->> (page-handler/get-all-pages current-repo)
-                            (map-indexed (fn [idx page] (assoc page
-                                                               :block/backlinks (count (:block/_refs (db/entity (:db/id page))))
-                                                               :block/idx idx))))]
-             (reset! *filter-fn
-                     (memoize (fn [sort-by-item desc? journal?]
-                                (->> pages
-                                     (filter #(or (boolean journal?)
-                                                  (= false (boolean (:block/journal? %)))))
-                                     (sort-pages-by sort-by-item desc?)))))
-             (reset! *pages pages)))
-
-         ;; filter results
-         (when @*filter-fn
-           (let [pages (@*filter-fn @*sort-by-item @*desc? @*journal?)
-
-                 ;; search key
-                 pages (if-not (string/blank? @*search-key)
-                         (search/fuzzy-search pages (util/page-name-sanity-lc @*search-key)
-                                              :limit 20
-                                              :extract-fn :block/name)
-                         pages)
-
-                 _ (reset! *results-all pages)
-
-                 pages (take per-page-num (drop (* per-page-num (dec @*current-page)) pages))]
-
-             (reset! *checks (into {} (for [{:block/keys [idx]} pages]
-                                        [idx (boolean (get @*checks idx))])))
-             (reset! *results pages)))
-
-         [[:div.actions
-           {:class (util/classnames [{:has-selected (or (nil? @*indeterminate)
-                                                        (not= 0 @*indeterminate))}])}
-           [: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)]
-
-            [:div.search-wrap.flex.items-center.pl-2
-             (let [search-fn (fn []
-                               (let [^js input (rum/deref *search-input)]
-                                 (search-key (.-value input))
-                                 (reset! *current-page 1)))
-                   reset-fn (fn []
-                              (let [^js input (rum/deref *search-input)]
-                                (set! (.-value input) "")
-                                (reset! *search-key nil)))]
-
-               [(ui/button (ui/icon "search")
-                  :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)]
-                                                       (if (string/blank? (.-value target))
-                                                         (reset! *search-key nil)
-                                                         (cond
-                                                           (= 13 (.-keyCode e)) (search-fn)
-                                                           (= 27 (.-keyCode e)) (reset-fn)))))
-                                    :ref           *search-input
-                                    :default-value ""}]
-
-                (when (not (string/blank? @*search-key))
-                  [:a.cancel {:on-click reset-fn}
-                   (ui/icon "x")])])]]
-
-           [:div.r.flex.items-center.justify-between
-            (let [orphaned-pages (model/get-orphaned-pages {})
-                  orphaned-pages? (seq orphaned-pages)]
-              [:a.ml-1.pr-2.opacity-70.hover:opacity-100
-               {:on-click (fn []
-                            (if orphaned-pages?
-                              (state/set-modal!
-                               (batch-delete-dialog
-                                orphaned-pages  true
-                                #(do
-                                   (reset! *checks nil)
-                                   (refresh-pages))))
-                              (notification/show! "Congratulations, no orphaned pages in your graph!" :success)))}
-               [:span
-                (ui/icon "file-x")
-                [:span.ml-1 (t :remove-orphaned-pages)]]])
-
-            [:a.ml-1.pr-2.opacity-70.hover:opacity-100 {:href (rfe/href :all-files)}
+    [:div.flex-1.cp__all_pages
+     [:h1.title (t :all-pages)]
+
+     (when current-repo
+
+       ;; all pages
+       (when (nil? @*pages)
+         (let [pages (->> (page-handler/get-all-pages current-repo)
+                          (map-indexed (fn [idx page] (assoc page
+                                                             :block/backlinks (count (:block/_refs (db/entity (:db/id page))))
+                                                             :block/idx idx))))]
+           (reset! *filter-fn
+                   (memoize (fn [sort-by-item desc? journal?]
+                              (->> pages
+                                   (filter #(or (boolean journal?)
+                                                (= false (boolean (:block/journal? %)))))
+                                   (sort-pages-by sort-by-item desc?)))))
+           (reset! *pages pages)))
+
+       ;; filter results
+       (when @*filter-fn
+         (let [pages (@*filter-fn @*sort-by-item @*desc? @*journal?)
+
+               ;; search key
+               pages (if-not (string/blank? @*search-key)
+                       (search/fuzzy-search pages (util/page-name-sanity-lc @*search-key)
+                                            :limit 20
+                                            :extract-fn :block/name)
+                       pages)
+
+               _ (reset! *results-all pages)
+
+               pages (take per-page-num (drop (* per-page-num (dec @*current-page)) pages))]
+
+           (reset! *checks (into {} (for [{:block/keys [idx]} pages]
+                                      [idx (boolean (get @*checks idx))])))
+           (reset! *results pages)))
+
+       [[:div.actions
+         {:class (util/classnames [{:has-selected (or (nil? @*indeterminate)
+                                                      (not= 0 @*indeterminate))}])}
+         [: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)]
+
+          [:div.search-wrap.flex.items-center.pl-2
+           (let [search-fn (fn []
+                             (let [^js input (rum/deref *search-input)]
+                               (search-key (.-value input))
+                               (reset! *current-page 1)))
+                 reset-fn (fn []
+                            (let [^js input (rum/deref *search-input)]
+                              (set! (.-value input) "")
+                              (reset! *search-key nil)))]
+
+             [(ui/button (ui/icon "search")
+                :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)]
+                                                     (if (string/blank? (.-value target))
+                                                       (reset! *search-key nil)
+                                                       (cond
+                                                         (= 13 (.-keyCode e)) (search-fn)
+                                                         (= 27 (.-keyCode e)) (reset-fn)))))
+                                  :ref           *search-input
+                                  :default-value ""}]
+
+              (when (not (string/blank? @*search-key))
+                [:a.cancel {:on-click reset-fn}
+                 (ui/icon "x")])])]]
+
+         [:div.r.flex.items-center.justify-between
+          (let [orphaned-pages (model/get-orphaned-pages {})
+                orphaned-pages? (seq orphaned-pages)]
+            [:a.ml-1.pr-2.opacity-70.hover:opacity-100
+             {:on-click (fn []
+                          (if orphaned-pages?
+                            (state/set-modal!
+                             (batch-delete-dialog
+                              orphaned-pages  true
+                              #(do
+                                 (reset! *checks nil)
+                                 (refresh-pages))))
+                            (notification/show! "Congratulations, no orphaned pages in your graph!" :success)))}
              [:span
              [:span
-              (ui/icon "files")
-              [:span.ml-1 (t :all-files)]]]
+              (ui/icon "file-x")
+              [:span.ml-1 (t :remove-orphaned-pages)]]])
 
 
-            [:div
-             (ui/tippy
-              {:html  [:small (str (t :page/show-journals) " ?")]
-               :arrow true}
-              [:a.button.journal
-               {:class    (util/classnames [{:active (boolean @*journal?)}])
-                :on-click #(reset! *journal? (not @*journal?))}
-               (ui/icon "calendar")])]
-
-            [:div.paginates
-             [:span.flex.items-center.opacity-60.text-sm
-              [:span.pr-1 (t :paginates/pages (count @*results-all))]]
-             [:span.flex.items-center
-              {:class (util/classnames [{:is-first (= 1 @*current-page)
-                                         :is-last  (= @*current-page total-pages)}])}
-              [:a.py-4.pr-2 {:on-click #(to-page (dec @*current-page))} (ui/icon "caret-left") (str " " (t :paginates/prev))]
-              [:span.opacity-30 (str @*current-page "/" total-pages)]
-              [:a.py-4.pl-2 {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") (ui/icon "caret-right")]]]]]
-
-          [:table.table-auto.cp__all_pages_table
-           [:thead
-            [:tr
-             [:th.selector
-              (checkbox-opt "all-pages-select-all"
-                            (= 1 @*indeterminate)
-                            {:on-change     (fn []
-                                              (let [indeterminate? (= -1 @*indeterminate)
-                                                    all? (= 1 @*indeterminate)]
-                                                (doseq [{:block/keys [idx]} @*results]
-                                                  (swap! *checks assoc idx (or indeterminate? (not all?))))))
-                             :indeterminate (= -1 @*indeterminate)})]
-
-             (sortable-title (t :block/name) :block/name *sort-by-item *desc?)
-             (when-not mobile?
-               [(sortable-title (t :page/backlinks) :block/backlinks *sort-by-item *desc?)
-                (sortable-title (t :page/created-at) :block/created-at *sort-by-item *desc?)
-                (sortable-title (t :page/updated-at) :block/updated-at *sort-by-item *desc?)])]]
-
-           [:tbody
-            (for [{:block/keys [idx name created-at updated-at backlinks] :as page} @*results]
-              (when-not (string/blank? name)
-                [:tr {:key name}
-                 [:td.selector
-                  (checkbox-opt (str "label-" idx)
-                                (get @*checks idx)
-                                {:on-change (fn []
-                                              (swap! *checks update idx not))})]
-
-                 [:td.name [:a {:on-click (fn [e]
-                                            (let [repo (state/get-current-repo)]
-                                              (when (gobj/get e "shiftKey")
-                                                (state/sidebar-add-block!
-                                                 repo
-                                                 (:db/id page)
-                                                 :page
-                                                 {:page (:block/name page)}))))
-                                :href     (rfe/href :page {:name (:block/name page)})}
-                            (block/page-cp {} page)]]
-
-                 (when-not mobile?
-                   [:td.backlinks [:span backlinks]])
-
-                 (when-not mobile?
-                   [:td.created-at [:span (if created-at
-                                            (date/int->local-time-2 created-at)
-                                            "Unknown")]])
-                 (when-not mobile?
-                   [:td.updated-at [:span (if updated-at
-                                            (date/int->local-time-2 updated-at)
-                                            "Unknown")]])]))]]
+          [:a.ml-1.pr-2.opacity-70.hover:opacity-100 {:href (rfe/href :all-files)}
+           [:span
+            (ui/icon "files")
+            [:span.ml-1 (t :all-files)]]]
+
+          [:div
+           (ui/tippy
+            {:html  [:small (str (t :page/show-journals) " ?")]
+             :arrow true}
+            [:a.button.journal
+             {:class    (util/classnames [{:active (boolean @*journal?)}])
+              :on-click #(reset! *journal? (not @*journal?))}
+             (ui/icon "calendar")])]
 
 
           [:div.paginates
           [:div.paginates
-           [:span]
+           [:span.flex.items-center.opacity-60.text-sm
+            [:span.pr-1 (t :paginates/pages (count @*results-all))]]
            [:span.flex.items-center
            [:span.flex.items-center
             {:class (util/classnames [{:is-first (= 1 @*current-page)
             {:class (util/classnames [{:is-first (= 1 @*current-page)
                                        :is-last  (= @*current-page total-pages)}])}
                                        :is-last  (= @*current-page total-pages)}])}
-            [:a.py-4.text-sm {:on-click #(to-page (dec @*current-page))} (ui/icon "caret-left") (str " " (t :paginates/prev))]
-            [:a.py-4.pl-2.text-sm {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") (ui/icon "caret-right")]]]])])))
+            [:a.py-4.pr-2 {:on-click #(to-page (dec @*current-page))} (ui/icon "caret-left") (str " " (t :paginates/prev))]
+            [:span.opacity-30 (str @*current-page "/" total-pages)]
+            [:a.py-4.pl-2 {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") (ui/icon "caret-right")]]]]]
+
+        [:table.table-auto.cp__all_pages_table
+         [:thead
+          [:tr
+           [:th.selector
+            (checkbox-opt "all-pages-select-all"
+                          (= 1 @*indeterminate)
+                          {:on-change     (fn []
+                                            (let [indeterminate? (= -1 @*indeterminate)
+                                                  all? (= 1 @*indeterminate)]
+                                              (doseq [{:block/keys [idx]} @*results]
+                                                (swap! *checks assoc idx (or indeterminate? (not all?))))))
+                           :indeterminate (= -1 @*indeterminate)})]
+
+           (sortable-title (t :block/name) :block/name *sort-by-item *desc?)
+           (when-not mobile?
+             [(sortable-title (t :page/backlinks) :block/backlinks *sort-by-item *desc?)
+              (sortable-title (t :page/created-at) :block/created-at *sort-by-item *desc?)
+              (sortable-title (t :page/updated-at) :block/updated-at *sort-by-item *desc?)])]]
+
+         [:tbody
+          (for [{:block/keys [idx name created-at updated-at backlinks] :as page} @*results]
+            (when-not (string/blank? name)
+              [:tr {:key name}
+               [:td.selector
+                (checkbox-opt (str "label-" idx)
+                              (get @*checks idx)
+                              {:on-change (fn []
+                                            (swap! *checks update idx not))})]
+
+               [:td.name [:a {:on-click (fn [e]
+                                          (let [repo (state/get-current-repo)]
+                                            (when (gobj/get e "shiftKey")
+                                              (state/sidebar-add-block!
+                                               repo
+                                               (:db/id page)
+                                               :page
+                                               {:page (:block/name page)}))))
+                              :href     (rfe/href :page {:name (:block/name page)})}
+                          (block/page-cp {} page)]]
+
+               (when-not mobile?
+                 [:td.backlinks [:span backlinks]])
+
+               (when-not mobile?
+                 [:td.created-at [:span (if created-at
+                                          (date/int->local-time-2 created-at)
+                                          "Unknown")]])
+               (when-not mobile?
+                 [:td.updated-at [:span (if updated-at
+                                          (date/int->local-time-2 updated-at)
+                                          "Unknown")]])]))]]
+
+        [:div.paginates
+         [:span]
+         [:span.flex.items-center
+          {:class (util/classnames [{:is-first (= 1 @*current-page)
+                                     :is-last  (= @*current-page total-pages)}])}
+          [:a.py-4.text-sm {:on-click #(to-page (dec @*current-page))} (ui/icon "caret-left") (str " " (t :paginates/prev))]
+          [:a.py-4.pl-2.text-sm {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") (ui/icon "caret-right")]]]])]))

+ 23 - 25
src/main/frontend/components/page_menu.cljs

@@ -2,7 +2,7 @@
   (:require [cljs.pprint :as pprint]
   (:require [cljs.pprint :as pprint]
             [frontend.commands :as commands]
             [frontend.commands :as commands]
             [frontend.components.export :as export]
             [frontend.components.export :as export]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
@@ -27,37 +27,35 @@
 (defn delete-page-dialog
 (defn delete-page-dialog
   [page-name]
   [page-name]
   (fn [close-fn]
   (fn [close-fn]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div
-       [:div.sm:flex.items-center
-        [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
-         [:span.text-red-600.text-xl
-          (ui/icon "alert-triangle")]]
-        [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
-         [:h3#modal-headline.text-lg.leading-6.font-medium
-          (t :page/delete-confirmation)]]]
+    [:div
+     [:div.sm:flex.items-center
+      [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
+       [:span.text-red-600.text-xl
+        (ui/icon "alert-triangle")]]
+      [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
+       [:h3#modal-headline.text-lg.leading-6.font-medium
+        (t :page/delete-confirmation)]]]
 
 
-       [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
-        [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
-         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-          {:type "button"
-           :class "ui__modal-enter"
-           :on-click (fn []
-                       (delete-page! page-name))}
-          (t :yes)]]
-        [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
-         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-          {:type "button"
-           :on-click close-fn}
-          (t :cancel)]]]])))
+     [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
+      [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
+       [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+        {:type "button"
+         :class "ui__modal-enter"
+         :on-click (fn []
+                     (delete-page! page-name))}
+        (t :yes)]]
+      [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
+       [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+        {:type "button"
+         :on-click close-fn}
+        (t :cancel)]]]]))
 
 
 (defn page-menu
 (defn page-menu
   [page-name]
   [page-name]
   (when-let [page-name (or
   (when-let [page-name (or
                         page-name
                         page-name
                         (state/get-current-page))]
                         (state/get-current-page))]
-    (let [t i18n/t
-          page-name (util/page-name-sanity-lc page-name)
+    (let [page-name (util/page-name-sanity-lc page-name)
           repo (state/sub :git/current-repo)
           repo (state/sub :git/current-repo)
           page (db/entity repo [:block/name page-name])
           page (db/entity repo [:block/name page-name])
           page-original-name (:block/original-name page)
           page-original-name (:block/original-name page)

+ 222 - 237
src/main/frontend/components/plugins.cljs

@@ -2,7 +2,7 @@
   (:require [rum.core :as rum]
   (:require [rum.core :as rum]
             [frontend.state :as state]
             [frontend.state :as state]
             [cljs-bean.core :as bean]
             [cljs-bean.core :as bean]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.search :as search]
             [frontend.search :as search]
@@ -50,31 +50,28 @@
         themes (sort #(:selected %) (map #(assoc % :selected (= (:url %) selected)) themes))
         themes (sort #(:selected %) (map #(assoc % :selected (= (:url %) selected)) themes))
         _ (reset! *total (count themes))]
         _ (reset! *total (count themes))]
 
 
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
-
-      [:div.cp__themes-installed
-       {:tab-index -1}
-       [:h1.mb-4.text-2xl.p-1 (t :themes)]
-       (map-indexed
-         (fn [idx opt]
-           (let [current-selected (:selected opt)
-                 plg (get (:plugin/installed-plugins @state/state) (keyword (:pid opt)))]
-             [:div.it.flex.px-3.py-1.5.rounded-sm.justify-between
-              {:key      (str idx (:url opt))
-               :title    (when current-selected "Cancel selected theme")
-               :class    (util/classnames
-                           [{:is-selected current-selected
-                             :is-active   (= idx @*cursor)}])
-               :on-click #(do (js/LSPluginCore.selectTheme (if current-selected nil (clj->js opt)))
-                              (state/close-modal!))}
-              [:section
-               [:strong.block
-                [:small.opacity-60 (str (or (:name plg) "Logseq") " • ")]
-                (:name opt)]]
-              [:small.flex-shrink-0.flex.items-center.opacity-10
-               (when current-selected (ui/icon "check"))]]))
-         themes)])))
+    [:div.cp__themes-installed
+     {:tab-index -1}
+     [:h1.mb-4.text-2xl.p-1 (t :themes)]
+     (map-indexed
+      (fn [idx opt]
+        (let [current-selected (:selected opt)
+              plg (get (:plugin/installed-plugins @state/state) (keyword (:pid opt)))]
+          [:div.it.flex.px-3.py-1.5.rounded-sm.justify-between
+           {:key      (str idx (:url opt))
+            :title    (when current-selected "Cancel selected theme")
+            :class    (util/classnames
+                       [{:is-selected current-selected
+                         :is-active   (= idx @*cursor)}])
+            :on-click #(do (js/LSPluginCore.selectTheme (if current-selected nil (clj->js opt)))
+                           (state/close-modal!))}
+           [:section
+            [:strong.block
+             [:small.opacity-60 (str (or (:name plg) "Logseq") " • ")]
+             (:name opt)]]
+           [:small.flex-shrink-0.flex.items-center.opacity-10
+            (when current-selected (ui/icon "check"))]]))
+      themes)]))
 
 
 (rum/defc unpacked-plugin-loader
 (rum/defc unpacked-plugin-loader
   [unpacked-pkg-path]
   [unpacked-pkg-path]
@@ -164,136 +161,133 @@
         name (or title name "Untitled")
         name (or title name "Untitled")
         unpacked? (not iir)
         unpacked? (not iir)
         new-version (state/coming-update-new-version? coming-update)]
         new-version (state/coming-update-new-version? coming-update)]
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
-
-      [:div.cp__plugins-item-card
-       {:class (util/classnames
-                 [{:market          market?
-                   :installed       installed?
-                   :updating        installing-or-updating?
-                   :has-new-version new-version}])}
-
-       [:div.l.link-block
-        {:on-click #(plugin-handler/open-readme!
-                      url item (if repo remote-readme-display local-markdown-display))}
-        (if (and icon (not (string/blank? icon)))
-          [:img.icon {:src (if market? (plugin-handler/pkg-asset id icon) icon)}]
-          svg/folder)
-
-        (when (and (not market?) unpacked?)
-          [:span.flex.justify-center.text-xs.text-red-500.pt-2 (t :plugin/unpacked)])]
-
-       [:div.r
-        [:h3.head.text-xl.font-bold.pt-1.5
-
-         [:span name]
-         (when (not market?) [:sup.inline-block.px-1.text-xs.opacity-50 version])]
-
-        [:div.desc.text-xs.opacity-70
-         [:p description]
-         ;;[:small (js/JSON.stringify (bean/->js settings))]
-         ]
-
-        ;; Author & Identity
-        [:div.flag
-         [:p.text-xs.pr-2.flex.justify-between
-          [:small {:on-click #(when-let [^js el (js/document.querySelector ".cp__plugins-page .search-ctls input")]
-                                (reset! *search-key (str "@" author))
-                                (.select el))} author]
-          [:small {:on-click #(do
-                                (notification/show! "Copied!" :success)
-                                (util/copy-to-clipboard! id))}
-           (str "ID: " id)]]]
-
-        ;; Github repo
-        [:div.flag.is-top.opacity-50
-         (when repo
-           [:a.flex {:target "_blank"
-                     :href   (plugin-handler/gh-repo-url repo)}
-            (svg/github {:width 16 :height 16})])]
-
-        (if market?
-          ;; market ctls
-          [:div.ctl
-           [:ul.l.flex.items-center
-            ;; stars
-            [:li.flex.text-sm.items-center.pr-3
-             (svg/star 16) [:span.pl-1 (:stargazers_count stat)]]
-
-            ;; downloads
-            (when-let [downloads (and stat (:total_downloads stat))]
-              (when (and downloads (> downloads 0))
-                [:li.flex.text-sm.items-center.pr-3
-                 (svg/cloud-down 16) [:span.pl-1 downloads]]))]
-
-           [:div.r.flex.items-center
+    [:div.cp__plugins-item-card
+     {:class (util/classnames
+              [{:market          market?
+                :installed       installed?
+                :updating        installing-or-updating?
+                :has-new-version new-version}])}
+
+     [:div.l.link-block
+      {:on-click #(plugin-handler/open-readme!
+                   url item (if repo remote-readme-display local-markdown-display))}
+      (if (and icon (not (string/blank? icon)))
+        [:img.icon {:src (if market? (plugin-handler/pkg-asset id icon) icon)}]
+        svg/folder)
+
+      (when (and (not market?) unpacked?)
+        [:span.flex.justify-center.text-xs.text-red-500.pt-2 (t :plugin/unpacked)])]
+
+     [:div.r
+      [:h3.head.text-xl.font-bold.pt-1.5
+
+       [:span name]
+       (when (not market?) [:sup.inline-block.px-1.text-xs.opacity-50 version])]
+
+      [:div.desc.text-xs.opacity-70
+       [:p description]
+       ;;[:small (js/JSON.stringify (bean/->js settings))]
+       ]
+
+      ;; Author & Identity
+      [:div.flag
+       [:p.text-xs.pr-2.flex.justify-between
+        [:small {:on-click #(when-let [^js el (js/document.querySelector ".cp__plugins-page .search-ctls input")]
+                              (reset! *search-key (str "@" author))
+                              (.select el))} author]
+        [:small {:on-click #(do
+                              (notification/show! "Copied!" :success)
+                              (util/copy-to-clipboard! id))}
+         (str "ID: " id)]]]
+
+      ;; Github repo
+      [:div.flag.is-top.opacity-50
+       (when repo
+         [:a.flex {:target "_blank"
+                   :href   (plugin-handler/gh-repo-url repo)}
+          (svg/github {:width 16 :height 16})])]
+
+      (if market?
+        ;; market ctls
+        [:div.ctl
+         [:ul.l.flex.items-center
+          ;; stars
+          [:li.flex.text-sm.items-center.pr-3
+           (svg/star 16) [:span.pl-1 (:stargazers_count stat)]]
+
+          ;; downloads
+          (when-let [downloads (and stat (:total_downloads stat))]
+            (when (and downloads (> downloads 0))
+              [:li.flex.text-sm.items-center.pr-3
+               (svg/cloud-down 16) [:span.pl-1 downloads]]))]
+
+         [:div.r.flex.items-center
+
+          [:a.btn
+           {:class    (util/classnames [{:disabled   (or installed? installing-or-updating?)
+                                         :installing installing-or-updating?}])
+            :on-click #(plugin-handler/install-marketplace-plugin item)}
+           (if installed?
+             (t :plugin/installed)
+             (if installing-or-updating?
+               [:span.flex.items-center [:small svg/loading]
+                (t :plugin/installing)]
+               (t :plugin/install)))]]]
+
+        ;; installed ctls
+        [:div.ctl
+         [:div.l
+          [:div.de
+           [:strong (ui/icon "settings")]
+           [:ul.menu-list
+            [:li {:on-click #(when usf (js/apis.openPath usf))} (t :plugin/open-settings)]
+            [:li {:on-click #(js/apis.openPath url)} (t :plugin/open-package)]
+            [:li {:on-click
+                  #(let [confirm-fn
+                         (ui/make-confirm-modal
+                          {:title      (t :plugin/delete-alert name)
+                           :on-confirm (fn [_ {:keys [close-fn]}]
+                                         (close-fn)
+                                         (plugin-handler/unregister-plugin id))})]
+                     (state/set-sub-modal! confirm-fn {:center? true}))}
+             (t :plugin/uninstall)]]]
+
+          (when (seq sponsors)
+            [:div.de.sponsors
+             [:strong (ui/icon "coffee")]
+             [:ul.menu-list
+              (for [link sponsors]
+                [:li [:a {:href link :target "_blank"}
+                      [:span.flex.items-center link (ui/icon "external-link")]]])]])
+          ]
 
 
+         [:div.r.flex.items-center
+          (when (and unpacked? (not disabled))
             [:a.btn
             [:a.btn
-             {:class    (util/classnames [{:disabled   (or installed? installing-or-updating?)
-                                           :installing installing-or-updating?}])
-              :on-click #(plugin-handler/install-marketplace-plugin item)}
-             (if installed?
-               (t :plugin/installed)
-               (if installing-or-updating?
-                 [:span.flex.items-center [:small svg/loading]
-                  (t :plugin/installing)]
-                 (t :plugin/install)))]]]
-
-          ;; installed ctls
-          [:div.ctl
-           [:div.l
-            [:div.de
-             [:strong (ui/icon "settings")]
-             [:ul.menu-list
-              [:li {:on-click #(when usf (js/apis.openPath usf))} (t :plugin/open-settings)]
-              [:li {:on-click #(js/apis.openPath url)} (t :plugin/open-package)]
-              [:li {:on-click
-                    #(let [confirm-fn
-                           (ui/make-confirm-modal
-                             {:title      (t :plugin/delete-alert name)
-                              :on-confirm (fn [_ {:keys [close-fn]}]
-                                            (close-fn)
-                                            (plugin-handler/unregister-plugin id))})]
-                       (state/set-sub-modal! confirm-fn {:center? true}))}
-               (t :plugin/uninstall)]]]
-
-            (when (seq sponsors)
-              [:div.de.sponsors
-               [:strong (ui/icon "coffee")]
-               [:ul.menu-list
-                (for [link sponsors]
-                  [:li [:a {:href link :target "_blank"}
-                        [:span.flex.items-center link (ui/icon "external-link")]]])]])
-            ]
-
-           [:div.r.flex.items-center
-            (when (and unpacked? (not disabled))
-              [:a.btn
-               {:on-click #(js-invoke js/LSPluginCore "reload" id)}
-               (t :plugin/reload)])
-
-            (when (not unpacked?)
-              [:div.updates-actions
-               [:a.btn
-                {:class    (util/classnames [{:disabled installing-or-updating?}])
-                 :on-click #(when-not has-other-pending?
-                              (plugin-handler/check-or-update-marketplace-plugin
-                                (assoc item :only-check (not new-version))
-                                (fn [e] (notification/show! e :error))))}
-
-                (if installing-or-updating?
-                  (t :plugin/updating)
-                  (if new-version
-                    (str (t :plugin/update) " 👉 " new-version)
-                    (t :plugin/check-update))
-                  )]])
-
-            (ui/toggle (not disabled)
-                       (fn []
-                         (js-invoke js/LSPluginCore (if disabled "enable" "disable") id)
-                         (page-handler/init-commands!))
-                       true)]])]])))
+             {:on-click #(js-invoke js/LSPluginCore "reload" id)}
+             (t :plugin/reload)])
+
+          (when (not unpacked?)
+            [:div.updates-actions
+             [:a.btn
+              {:class    (util/classnames [{:disabled installing-or-updating?}])
+               :on-click #(when-not has-other-pending?
+                            (plugin-handler/check-or-update-marketplace-plugin
+                             (assoc item :only-check (not new-version))
+                             (fn [e] (notification/show! e :error))))}
+
+              (if installing-or-updating?
+                (t :plugin/updating)
+                (if new-version
+                  (str (t :plugin/update) " 👉 " new-version)
+                  (t :plugin/check-update))
+                )]])
+
+          (ui/toggle (not disabled)
+                     (fn []
+                       (js-invoke js/LSPluginCore (if disabled "enable" "disable") id)
+                       (page-handler/init-commands!))
+                     true)]])]]))
 
 
 (rum/defc panel-control-tabs
 (rum/defc panel-control-tabs
   < rum/static
   < rum/static
@@ -485,44 +479,41 @@
                                [@*sort-by #(compare %2 %1)])
                                [@*sort-by #(compare %2 %1)])
                              filtered-pkgs))]
                              filtered-pkgs))]
 
 
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
-
-      [:div.cp__plugins-marketplace
-
-       (panel-control-tabs
-         t
-         @*search-key *search-key
-         @*category *category
-         @*sort-by *sort-by nil true
-         develop-mode? (::reload state))
-
-       (cond
-         (not online?)
-         [:p.flex.justify-center.pt-20.opacity-50
-          (svg/offline 30)]
-
-         @*fetching
-         [:p.flex.justify-center.pt-20
-          svg/loading]
-
-         @*error
-         [:p.flex.justify-center.pt-20.opacity-50
-          "Remote error: " (.-message @*error)]
-
-         :else
-         [:div.cp__plugins-marketplace-cnt
-          {:class (util/classnames [{:has-installing (boolean installing)}])}
-          [:div.cp__plugins-item-lists.grid-cols-1.md:grid-cols-2.lg:grid-cols-3
-           (for [item sorted-pkgs]
-             (rum/with-key
-               (let [pid (keyword (:id item))
-                     stat (:stat item)]
-                 (plugin-item-card
-                   item true *search-key installing
-                   (and installing (= (keyword (:id installing)) pid))
-                   (contains? installed-plugins pid) stat nil))
-               (:id item)))]])])))
+    [:div.cp__plugins-marketplace
+
+     (panel-control-tabs
+      t
+      @*search-key *search-key
+      @*category *category
+      @*sort-by *sort-by nil true
+      develop-mode? (::reload state))
+
+     (cond
+       (not online?)
+       [:p.flex.justify-center.pt-20.opacity-50
+        (svg/offline 30)]
+
+       @*fetching
+       [:p.flex.justify-center.pt-20
+        svg/loading]
+
+       @*error
+       [:p.flex.justify-center.pt-20.opacity-50
+        "Remote error: " (.-message @*error)]
+
+       :else
+       [:div.cp__plugins-marketplace-cnt
+        {:class (util/classnames [{:has-installing (boolean installing)}])}
+        [:div.cp__plugins-item-lists.grid-cols-1.md:grid-cols-2.lg:grid-cols-3
+         (for [item sorted-pkgs]
+           (rum/with-key
+             (let [pid (keyword (:id item))
+                   stat (:stat item)]
+               (plugin-item-card
+                item true *search-key installing
+                (and installing (= (keyword (:id installing)) pid))
+                (contains? installed-plugins pid) stat nil))
+             (:id item)))]])]))
 
 
 (rum/defcs installed-plugins
 (rum/defcs installed-plugins
   < rum/static rum/reactive
   < rum/static rum/reactive
@@ -570,27 +561,24 @@
                               (#(update % 0 (fn [coll] (sort-by :iir coll))))
                               (#(update % 0 (fn [coll] (sort-by :iir coll))))
                               (flatten))
                               (flatten))
                          filtered-plugins)]
                          filtered-plugins)]
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
-
-      [:div.cp__plugins-installed
-
-       (panel-control-tabs
-         t
-         @*search-key *search-key
-         @*category *category
-         @*filter-by *filter-by
-         selected-unpacked-pkg
-         false develop-mode? nil)
-
-       [:div.cp__plugins-item-lists.grid-cols-1.md:grid-cols-2.lg:grid-cols-3
-        (for [item sorted-plugins]
-          (rum/with-key
-            (let [pid (keyword (:id item))]
-              (plugin-item-card
-                item false *search-key updating
-                (and updating (= (keyword (:id updating)) pid))
-                true nil (get coming-updates pid))) (:id item)))]])))
+    [:div.cp__plugins-installed
+
+     (panel-control-tabs
+      t
+      @*search-key *search-key
+      @*category *category
+      @*filter-by *filter-by
+      selected-unpacked-pkg
+      false develop-mode? nil)
+
+     [:div.cp__plugins-item-lists.grid-cols-1.md:grid-cols-2.lg:grid-cols-3
+      (for [item sorted-plugins]
+        (rum/with-key
+          (let [pid (keyword (:id item))]
+            (plugin-item-card
+             item false *search-key updating
+             (and updating (= (keyword (:id updating)) pid))
+             true nil (get coming-updates pid))) (:id item)))]]))
 
 
 (rum/defcs waiting-coming-updates
 (rum/defcs waiting-coming-updates
   < rum/reactive
   < rum/reactive
@@ -720,30 +708,27 @@
          (js/setTimeout (fn [] (.focus el)) 100))
          (js/setTimeout (fn [] (.focus el)) 100))
       [])
       [])
 
 
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
-
-      [:div.cp__plugins-page
-       {:ref       *el-ref
-        :tab-index "-1"}
-       [:h1 (t :plugins)]
-       (security-warning)
-       [:hr]
-
-       [:div.tabs.flex.items-center.justify-center
-        [:div.tabs-inner.flex.items-center
-         (ui/button [:span.it (t :plugin/installed)]
-                    :on-click #(set-active! :installed)
-                    :intent "logseq" :class (if-not market? "active" ""))
-
-         (ui/button [:span.mk (svg/apps 16) (t :plugin/marketplace)]
-                    :on-click #(set-active! :marketplace)
-                    :intent "logseq" :class (if market? "active" ""))]]
-
-       [:div.panels
-        (if market?
-          (marketplace-plugins)
-          (installed-plugins))]])))
+    [:div.cp__plugins-page
+     {:ref       *el-ref
+      :tab-index "-1"}
+     [:h1 (t :plugins)]
+     (security-warning)
+     [:hr]
+
+     [:div.tabs.flex.items-center.justify-center
+      [:div.tabs-inner.flex.items-center
+       (ui/button [:span.it (t :plugin/installed)]
+         :on-click #(set-active! :installed)
+         :intent "logseq" :class (if-not market? "active" ""))
+
+       (ui/button [:span.mk (svg/apps 16) (t :plugin/marketplace)]
+         :on-click #(set-active! :marketplace)
+         :intent "logseq" :class (if market? "active" ""))]]
+
+     [:div.panels
+      (if market?
+        (marketplace-plugins)
+        (installed-plugins))]]))
 
 
 (rum/defc custom-js-installer
 (rum/defc custom-js-installer
   [{:keys [t current-repo db-restoring? nfs-granted?]}]
   [{:keys [t current-repo db-restoring? nfs-granted?]}]

+ 187 - 190
src/main/frontend/components/repo.cljs

@@ -5,7 +5,7 @@
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
             [frontend.components.widgets :as widgets]
             [frontend.components.widgets :as widgets]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.encrypt :as e]
             [frontend.encrypt :as e]
             [frontend.handler.common :as common-handler]
             [frontend.handler.common :as common-handler]
@@ -40,52 +40,51 @@
   (let [repos (->> (state/sub [:me :repos])
   (let [repos (->> (state/sub [:me :repos])
                    (remove #(= (:url %) config/local-repo)))
                    (remove #(= (:url %) config/local-repo)))
         repos (util/distinct-by :url repos)]
         repos (util/distinct-by :url repos)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      (if (seq repos)
-        [:div#graphs
-         [:h1.title "All Graphs"]
-         [:p.ml-2.opacity-70
-          (if (state/github-authed?)
-            "A \"graph\" in Logseq could be either a local directory or a git repo."
-            "A \"graph\" in Logseq means a local directory.")]
+    (if (seq repos)
+      [:div#graphs
+       [:h1.title "All Graphs"]
+       [:p.ml-2.opacity-70
+        (if (state/github-authed?)
+          "A \"graph\" in Logseq could be either a local directory or a git repo."
+          "A \"graph\" in Logseq means a local directory.")]
 
 
-         [:div.pl-1.content.mt-3
-          [:div.flex.flex-row.my-4
-           (when (or (nfs-handler/supported?)
-                     (mobile-util/is-native-platform?))
-             [:div.mr-8
-              (ui/button
-                (t :open-a-directory)
-                :on-click #(page-handler/ls-dir-files! shortcut/refresh!))])
-           (when (and (state/logged?) (not (util/electron?)))
-             (ui/button
-               "Add another git repo"
-               :href (rfe/href :repo-add nil {:graph-types "github"})
-               :intent "logseq"))]
-          (for [{:keys [id url] :as repo} repos]
-            (let [local? (config/local-db? url)]
-              [:div.flex.justify-between.mb-4 {:key id}
-               (if local?
-                 (let [local-dir (config/get-local-dir url)
-                       graph-name (text/get-graph-name-from-path local-dir)]
-                   [:a {:title local-dir
-                        :on-click #(state/pub-event! [:graph/switch url])}
-                    graph-name])
-                 [:a {:target "_blank"
-                      :href url}
-                  (db/get-repo-path url)])
-               [:div.controls
-                (when (e/encrypted-db? url)
-                  [:a.control {:title "Show encryption information about this graph"
-                               :on-click (fn []
-                                           (state/set-modal! (encryption/encryption-dialog url)))}
-                   "🔐"])
-                [:a.text-gray-400.ml-4.font-medium.text-sm
-                 {:title "No worries, unlink this graph will clear its cache only, it does not remove your files on the disk."
-                  :on-click (fn []
-                              (repo-handler/remove-repo! repo))}
-                 "Unlink"]]]))]]
-        (widgets/add-graph)))))
+       [:div.pl-1.content.mt-3
+        [:div.flex.flex-row.my-4
+         (when (or (nfs-handler/supported?)
+                   (mobile-util/is-native-platform?))
+           [:div.mr-8
+            (ui/button
+              (t :open-a-directory)
+              :on-click #(page-handler/ls-dir-files! shortcut/refresh!))])
+         (when (and (state/logged?) (not (util/electron?)))
+           (ui/button
+             "Add another git repo"
+             :href (rfe/href :repo-add nil {:graph-types "github"})
+             :intent "logseq"))]
+        (for [{:keys [id url] :as repo} repos]
+          (let [local? (config/local-db? url)]
+            [:div.flex.justify-between.mb-4 {:key id}
+             (if local?
+               (let [local-dir (config/get-local-dir url)
+                     graph-name (text/get-graph-name-from-path local-dir)]
+                 [:a {:title local-dir
+                      :on-click #(state/pub-event! [:graph/switch url])}
+                  graph-name])
+               [:a {:target "_blank"
+                    :href url}
+                (db/get-repo-path url)])
+             [:div.controls
+              (when (e/encrypted-db? url)
+                [:a.control {:title "Show encryption information about this graph"
+                             :on-click (fn []
+                                         (state/set-modal! (encryption/encryption-dialog url)))}
+                 "🔐"])
+              [:a.text-gray-400.ml-4.font-medium.text-sm
+               {:title "No worries, unlink this graph will clear its cache only, it does not remove your files on the disk."
+                :on-click (fn []
+                            (repo-handler/remove-repo! repo))}
+               "Unlink"]]]))]]
+      (widgets/add-graph))))
 
 
 (defn refresh-cb []
 (defn refresh-cb []
   (page-handler/create-today-journal!)
   (page-handler/create-today-journal!)
@@ -136,48 +135,47 @@
               (toggle-fn)
               (toggle-fn)
               (js/setTimeout common-handler/check-changed-files-status 0))}])
               (js/setTimeout common-handler/check-changed-files-status 0))}])
         (fn [{:keys [toggle-fn]}]
         (fn [{:keys [toggle-fn]}]
-          (rum/with-context [[t] i18n/*tongue-context*]
-            [:div.p-2.rounded-md.shadow-xs.bg-base-3.flex.flex-col.sync-content
-             {:on-mouse-leave toggle-fn}
-             [:div
-              [:div
-               (cond
-                 push-failed?
-                 [:p (t :git/push-failed)]
-                 (and should-push? (seq changed-files))
-                 [:div.changes
-                  [:ul.overflow-y-auto {:style {:max-height 250}}
-                   (for [file changed-files]
-                     [:li {:key (str "sync-" file)}
-                      [:div.flex.flex-row.justify-between.align-items
-                       [:a {:href (rfe/href :file {:path file})}
-                        file]
-                       [:a.ml-4.text-sm.mt-1
-                        {:on-click (fn [_e]
-                                     (export-handler/download-file! file))}
-                        [:span (t :download)]]]])]]
-                 :else
-                 [:p (t :git/local-changes-synced)])]
-              ;; [:a.text-sm.font-bold {:href "/diff"} "Check diff"]
-              [:div.flex.flex-row.justify-between.align-items.mt-2
-               (ui/button (t :git/push)
-                 :on-click (fn [] (state/set-modal! commit/add-commit-message)))
-               (when pushing? svg/loading)]]
-             [:hr]
-             [:div
-              (when-not (string/blank? last-pulled-at)
-                [:p {:style {:font-size 12}} (t :git/last-pull)
-                 (str ": " last-pulled-at)])
-              [:div.flex.flex-row.justify-between.align-items
-               (ui/button (t :git/pull)
-                 :on-click (fn [] (repo-handler/pull-current-repo)))
-               (when pulling? svg/loading)]
-              [:a.mt-5.text-sm.opacity-50.block
-               {:on-click (fn []
-                            (export-handler/export-repo-as-zip! repo))}
-               (t :repo/download-zip)]
-              [:p.pt-2.text-sm.opacity-50
-               (t :git/version) (str " " version/version)]]])))])))
+          [:div.p-2.rounded-md.shadow-xs.bg-base-3.flex.flex-col.sync-content
+           {:on-mouse-leave toggle-fn}
+           [:div
+            [:div
+             (cond
+               push-failed?
+               [:p (t :git/push-failed)]
+               (and should-push? (seq changed-files))
+               [:div.changes
+                [:ul.overflow-y-auto {:style {:max-height 250}}
+                 (for [file changed-files]
+                   [:li {:key (str "sync-" file)}
+                    [:div.flex.flex-row.justify-between.align-items
+                     [:a {:href (rfe/href :file {:path file})}
+                      file]
+                     [:a.ml-4.text-sm.mt-1
+                      {:on-click (fn [_e]
+                                   (export-handler/download-file! file))}
+                      [:span (t :download)]]]])]]
+               :else
+               [:p (t :git/local-changes-synced)])]
+            ;; [:a.text-sm.font-bold {:href "/diff"} "Check diff"]
+            [:div.flex.flex-row.justify-between.align-items.mt-2
+             (ui/button (t :git/push)
+               :on-click (fn [] (state/set-modal! commit/add-commit-message)))
+             (when pushing? svg/loading)]]
+           [:hr]
+           [:div
+            (when-not (string/blank? last-pulled-at)
+              [:p {:style {:font-size 12}} (t :git/last-pull)
+               (str ": " last-pulled-at)])
+            [:div.flex.flex-row.justify-between.align-items
+             (ui/button (t :git/pull)
+               :on-click (fn [] (repo-handler/pull-current-repo)))
+             (when pulling? svg/loading)]
+            [:a.mt-5.text-sm.opacity-50.block
+             {:on-click (fn []
+                          (export-handler/export-repo-as-zip! repo))}
+             (t :repo/download-zip)]
+            [:p.pt-2.text-sm.opacity-50
+             (t :git/version) (str " " version/version)]]]))])))
 
 
 (defn- check-multiple-windows?
 (defn- check-multiple-windows?
   [state]
   [state]
@@ -190,108 +188,107 @@
   [state]
   [state]
   (let [multiple-windows? (::electron-multiple-windows? state)]
   (let [multiple-windows? (::electron-multiple-windows? state)]
     (when-let [current-repo (state/sub :git/current-repo)]
     (when-let [current-repo (state/sub :git/current-repo)]
-      (rum/with-context [[t] i18n/*tongue-context*]
-        (let [get-repo-name (fn [repo]
-                              (cond
-                                (mobile-util/is-native-platform?)
-                                (text/get-graph-name-from-path repo)
+      (let [get-repo-name (fn [repo]
+                            (cond
+                              (mobile-util/is-native-platform?)
+                              (text/get-graph-name-from-path repo)
 
 
-                                (config/local-db? repo)
-                                (config/get-local-dir repo)
+                              (config/local-db? repo)
+                              (config/get-local-dir repo)
 
 
-                                :else
-                                (db/get-repo-path repo)))
-              repos (state/sub [:me :repos])
-              repos (remove (fn [r] (= config/local-repo (:url r))) repos)
-              switch-repos (remove (fn [repo]
-                                     (= current-repo (:url repo)))
-                                   repos)
-              repo-links (mapv
-                          (fn [{:keys [url]}]
-                            (let [repo-path (get-repo-name url)
-                                  short-repo-name (text/get-graph-name-from-path repo-path)]
-                              {:title short-repo-name
-                               :hover-detail repo-path ;; show full path on hover
-                               :options {:class "ml-1"
-                                         :on-click #(state/pub-event! [:graph/switch url])}}))
-                          switch-repos)
-              links (->>
-                     (concat repo-links
-                             [(when (seq switch-repos)
-                                {:hr true})
-                              {:title (t :new-graph)
-                               :options {:href (rfe/href :repo-add)}}
-                              {:title (t :all-graphs)
-                               :options {:href (rfe/href :repos)}}
-                              (let [nfs-repo? (config/local-db? current-repo)]
-                                (when (and nfs-repo?
-                                           (not= current-repo config/local-repo)
-                                           (or (nfs-handler/supported?)
-                                               (mobile-util/is-native-platform?)))
-                                  {:title (t :sync-from-local-files)
-                                   :hover-detail (t :sync-from-local-files-detail)
-                                   :options {:on-click
-                                             (fn []
-                                               (state/pub-event!
-                                                [:modal/show
-                                                 [:div {:style {:max-width 700}}
-                                                  [:p "Refresh detects and processes files modified on your disk and diverged from the actual Logseq page content. Continue?"]
-                                                  (ui/button
-                                                    "Yes"
-                                                    :autoFocus "on"
-                                                    :large? true
-                                                    :on-click (fn []
-                                                                (state/close-modal!)
-                                                                (nfs-handler/refresh! (state/get-current-repo) refresh-cb)))]]))}}))
-                              {:title        (t :re-index)
-                               :hover-detail (t :re-index-detail)
-                               :options (cond->
-                                          {:on-click
+                              :else
+                              (db/get-repo-path repo)))
+            repos (state/sub [:me :repos])
+            repos (remove (fn [r] (= config/local-repo (:url r))) repos)
+            switch-repos (remove (fn [repo]
+                                   (= current-repo (:url repo)))
+                                 repos)
+            repo-links (mapv
+                        (fn [{:keys [url]}]
+                          (let [repo-path (get-repo-name url)
+                                short-repo-name (text/get-graph-name-from-path repo-path)]
+                            {:title short-repo-name
+                             :hover-detail repo-path ;; show full path on hover
+                             :options {:class "ml-1"
+                                       :on-click #(state/pub-event! [:graph/switch url])}}))
+                        switch-repos)
+            links (->>
+                   (concat repo-links
+                           [(when (seq switch-repos)
+                              {:hr true})
+                            {:title (t :new-graph)
+                             :options {:href (rfe/href :repo-add)}}
+                            {:title (t :all-graphs)
+                             :options {:href (rfe/href :repos)}}
+                            (let [nfs-repo? (config/local-db? current-repo)]
+                              (when (and nfs-repo?
+                                         (not= current-repo config/local-repo)
+                                         (or (nfs-handler/supported?)
+                                             (mobile-util/is-native-platform?)))
+                                {:title (t :sync-from-local-files)
+                                 :hover-detail (t :sync-from-local-files-detail)
+                                 :options {:on-click
                                            (fn []
                                            (fn []
-                                             (if @multiple-windows?
-                                               (state/pub-event!
-                                                [:modal/show
-                                                 [:div
-                                                  [:p "You need to close the other windows before re-index this graph."]]])
-                                               (state/pub-event!
-                                                [:modal/show
-                                                 [:div {:style {:max-width 700}}
-                                                  [:p "Re-index will discard the current graph, and then processes all the files again as they are currently stored on disk. You will lose unsaved changes and it might take a while. Continue?"]
-                                                  (ui/button
-                                                    "Yes"
-                                                    :autoFocus "on"
-                                                    :large? true
-                                                    :on-click (fn []
-                                                                (state/close-modal!)
-                                                                (repo-handler/re-index!
-                                                                 nfs-handler/rebuild-index!
-                                                                 page-handler/create-today-journal!)))]])))})}
-                              (when (util/electron?)
-                                {:title        (t :open-new-window)
-                                 :options {:on-click ui-handler/open-new-window!}})])
-                     (remove nil?))]
-          (when (seq repos)
-            (ui/dropdown-with-links
-             (fn [{:keys [toggle-fn]}]
-               (let [repo-path (get-repo-name current-repo)
-                     short-repo-name (if (or (util/electron?)
-                                             (mobile-util/is-native-platform?))
-                                       (text/get-file-basename repo-path)
-                                       repo-path)]
-                 [:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md
-                  {:on-click (fn []
-                               (check-multiple-windows? state)
-                               (toggle-fn))
-                   :title repo-path} ;; show full path on hover
-                  (ui/icon "database mr-3" {:style {:font-size 20} :id "database-icon"})
-                  [:div.graphs
-                   [:span#repo-switch.block.pr-2.whitespace-nowrap
-                    [:span [:span#repo-name.font-medium short-repo-name]]
-                    [:span.dropdown-caret.ml-2 {:style {:border-top-color "#6b7280"}}]]]]))
-             links
-             (cond->
-               {:modal-class (util/hiccup->class
-                              "origin-top-right.absolute.left-0.mt-2.rounded-md.shadow-lg")}
-               (seq switch-repos)
-               (assoc :links-header [:div.font-medium.text-sm.opacity-60.px-4.pt-2
-                                     "Switch to:"])))))))))
+                                             (state/pub-event!
+                                              [:modal/show
+                                               [:div {:style {:max-width 700}}
+                                                [:p "Refresh detects and processes files modified on your disk and diverged from the actual Logseq page content. Continue?"]
+                                                (ui/button
+                                                  "Yes"
+                                                  :autoFocus "on"
+                                                  :large? true
+                                                  :on-click (fn []
+                                                              (state/close-modal!)
+                                                              (nfs-handler/refresh! (state/get-current-repo) refresh-cb)))]]))}}))
+                            {:title        (t :re-index)
+                             :hover-detail (t :re-index-detail)
+                             :options (cond->
+                                        {:on-click
+                                         (fn []
+                                           (if @multiple-windows?
+                                             (state/pub-event!
+                                              [:modal/show
+                                               [:div
+                                                [:p "You need to close the other windows before re-index this graph."]]])
+                                             (state/pub-event!
+                                              [:modal/show
+                                               [:div {:style {:max-width 700}}
+                                                [:p "Re-index will discard the current graph, and then processes all the files again as they are currently stored on disk. You will lose unsaved changes and it might take a while. Continue?"]
+                                                (ui/button
+                                                  "Yes"
+                                                  :autoFocus "on"
+                                                  :large? true
+                                                  :on-click (fn []
+                                                              (state/close-modal!)
+                                                              (repo-handler/re-index!
+                                                               nfs-handler/rebuild-index!
+                                                               page-handler/create-today-journal!)))]])))})}
+                            (when (util/electron?)
+                              {:title        (t :open-new-window)
+                               :options {:on-click ui-handler/open-new-window!}})])
+                   (remove nil?))]
+        (when (seq repos)
+          (ui/dropdown-with-links
+           (fn [{:keys [toggle-fn]}]
+             (let [repo-path (get-repo-name current-repo)
+                   short-repo-name (if (or (util/electron?)
+                                           (mobile-util/is-native-platform?))
+                                     (text/get-file-basename repo-path)
+                                     repo-path)]
+               [:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md
+                {:on-click (fn []
+                             (check-multiple-windows? state)
+                             (toggle-fn))
+                 :title repo-path} ;; show full path on hover
+                (ui/icon "database mr-3" {:style {:font-size 20} :id "database-icon"})
+                [:div.graphs
+                 [:span#repo-switch.block.pr-2.whitespace-nowrap
+                  [:span [:span#repo-name.font-medium short-repo-name]]
+                  [:span.dropdown-caret.ml-2 {:style {:border-top-color "#6b7280"}}]]]]))
+           links
+           (cond->
+             {:modal-class (util/hiccup->class
+                            "origin-top-right.absolute.left-0.mt-2.rounded-md.shadow-lg")}
+             (seq switch-repos)
+             (assoc :links-header [:div.font-medium.text-sm.opacity-60.px-4.pt-2
+                                   "Switch to:"]))))))))

+ 5 - 6
src/main/frontend/components/right_sidebar.cljs

@@ -5,7 +5,7 @@
             [frontend.components.onboarding :as onboarding]
             [frontend.components.onboarding :as onboarding]
             [frontend.components.page :as page]
             [frontend.components.page :as page]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.date :as date]
             [frontend.date :as date]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.db-mixins :as db-mixins]
             [frontend.db-mixins :as db-mixins]
@@ -247,8 +247,7 @@
                  blocks)
                  blocks)
         sidebar-open? (state/sub :ui/sidebar-open?)
         sidebar-open? (state/sub :ui/sidebar-open?)
         repo (state/sub :git/current-repo)]
         repo (state/sub :git/current-repo)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div#right-sidebar.cp__right-sidebar.h-screen
-       {:class (if sidebar-open? "open" "closed")}
-       (when sidebar-open?
-         (sidebar-inner repo t blocks))])))
+    [:div#right-sidebar.cp__right-sidebar.h-screen
+     {:class (if sidebar-open? "open" "closed")}
+     (when sidebar-open?
+       (sidebar-inner repo t blocks))]))

+ 173 - 176
src/main/frontend/components/search.cljs

@@ -15,7 +15,7 @@
             [frontend.mixins :as mixins]
             [frontend.mixins :as mixins]
             [frontend.config :as config]
             [frontend.config :as config]
             [clojure.string :as string]
             [clojure.string :as string]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.date :as date]
             [frontend.date :as date]
             [reitit.frontend.easy :as rfe]
             [reitit.frontend.easy :as rfe]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.core :as shortcut]
@@ -85,146 +85,145 @@
 
 
 (rum/defc search-auto-complete
 (rum/defc search-auto-complete
   [{:keys [pages files blocks has-more?] :as result} search-q all?]
   [{:keys [pages files blocks has-more?] :as result} search-q all?]
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (let [pages (when-not all? (map (fn [page]
-                                      (let [alias (model/get-redirect-page-name page)]
-                                        (cond->
-                                          {:type :page
-                                           :data page}
-                                          (and alias
-                                               (not= (util/page-name-sanity-lc page)
-                                                     (util/page-name-sanity-lc alias)))
-                                          (assoc :alias alias))))
-                                 (remove nil? pages)))
-          files (when-not all? (map (fn [file] {:type :file :data file}) files))
-          blocks (map (fn [block] {:type :block :data block}) blocks)
-          search-mode (state/sub :search/mode)
-          new-page (if (or
-                        (and (seq pages)
-                             (= (util/safe-page-name-sanity-lc search-q)
-                                (util/safe-page-name-sanity-lc (:data (first pages)))))
-                        (nil? result)
-                        all?)
-                     []
-                     [{:type :new-page}])
-          result (if config/publishing?
-                   (concat pages files blocks)
-                   (concat new-page pages files blocks))
-          result (if (= search-mode :graph)
-                   [{:type :graph-add-filter}]
-                   result)
-          repo (state/get-current-repo)]
-      [:div
-       (ui/auto-complete
-        result
-        {:class "search-results"
-         :on-chosen (fn [{:keys [type data alias]}]
-                      (search-handler/add-search-to-recent! repo search-q)
-                      (search-handler/clear-search!)
-                      (case type
-                        :graph-add-filter
-                        (state/add-graph-search-filter! search-q)
-
-                        :new-page
-                        (page-handler/create! search-q)
+  (let [pages (when-not all? (map (fn [page]
+                                    (let [alias (model/get-redirect-page-name page)]
+                                      (cond->
+                                        {:type :page
+                                         :data page}
+                                        (and alias
+                                             (not= (util/page-name-sanity-lc page)
+                                                   (util/page-name-sanity-lc alias)))
+                                        (assoc :alias alias))))
+                               (remove nil? pages)))
+        files (when-not all? (map (fn [file] {:type :file :data file}) files))
+        blocks (map (fn [block] {:type :block :data block}) blocks)
+        search-mode (state/sub :search/mode)
+        new-page (if (or
+                      (and (seq pages)
+                           (= (util/safe-page-name-sanity-lc search-q)
+                              (util/safe-page-name-sanity-lc (:data (first pages)))))
+                      (nil? result)
+                      all?)
+                   []
+                   [{:type :new-page}])
+        result (if config/publishing?
+                 (concat pages files blocks)
+                 (concat new-page pages files blocks))
+        result (if (= search-mode :graph)
+                 [{:type :graph-add-filter}]
+                 result)
+        repo (state/get-current-repo)]
+    [:div
+     (ui/auto-complete
+      result
+      {:class "search-results"
+       :on-chosen (fn [{:keys [type data alias]}]
+                    (search-handler/add-search-to-recent! repo search-q)
+                    (search-handler/clear-search!)
+                    (case type
+                      :graph-add-filter
+                      (state/add-graph-search-filter! search-q)
 
 
-                        :page
-                        (let [data (or alias data)]
-                          (route/redirect-to-page! data))
+                      :new-page
+                      (page-handler/create! search-q)
 
 
-                        :file
-                        (route/redirect! {:to :file
-                                          :path-params {:path data}})
+                      :page
+                      (let [data (or alias data)]
+                        (route/redirect-to-page! data))
 
 
-                        :block
-                        (let [repo (state/get-current-repo)
-                              block-uuid (uuid (:block/uuid data))
-                              collapsed? (db/parents-collapsed? repo block-uuid)
-                              page (:block/page (db/entity [:block/uuid block-uuid]))
-                              long-page? (block-handler/long-page? repo (:db/id page))]
-                          (if page
-                            (if (or collapsed? long-page?)
-                             (route/redirect-to-page! block-uuid)
-                             (route/redirect-to-page! (:block/name page) (str "ls-block-" (:block/uuid data))))
-                            ;; search indice outdated
-                            (println "[Error] Block page missing: "
-                                     {:block-id block-uuid
-                                      :block (db/pull [:block/uuid block-uuid])})))
-                        nil)
-                      (state/close-modal!))
-         :on-shift-chosen (fn [{:keys [type data alias]}]
-                            (search-handler/add-search-to-recent! repo search-q)
-                            (case type
-                              :page
-                              (let [data (or alias data)
-                                    page (when data (db/entity [:block/name (util/page-name-sanity-lc data)]))]
-                                (when page
-                                  (state/sidebar-add-block!
-                                   (state/get-current-repo)
-                                   (:db/id page)
-                                   :page
-                                   {:page page})))
+                      :file
+                      (route/redirect! {:to :file
+                                        :path-params {:path data}})
 
 
-                              :block
-                              (let [block-uuid (uuid (:block/uuid data))
-                                    block (db/entity [:block/uuid block-uuid])]
+                      :block
+                      (let [repo (state/get-current-repo)
+                            block-uuid (uuid (:block/uuid data))
+                            collapsed? (db/parents-collapsed? repo block-uuid)
+                            page (:block/page (db/entity [:block/uuid block-uuid]))
+                            long-page? (block-handler/long-page? repo (:db/id page))]
+                        (if page
+                          (if (or collapsed? long-page?)
+                            (route/redirect-to-page! block-uuid)
+                            (route/redirect-to-page! (:block/name page) (str "ls-block-" (:block/uuid data))))
+                          ;; search indice outdated
+                          (println "[Error] Block page missing: "
+                                   {:block-id block-uuid
+                                    :block (db/pull [:block/uuid block-uuid])})))
+                      nil)
+                    (state/close-modal!))
+       :on-shift-chosen (fn [{:keys [type data alias]}]
+                          (search-handler/add-search-to-recent! repo search-q)
+                          (case type
+                            :page
+                            (let [data (or alias data)
+                                  page (when data (db/entity [:block/name (util/page-name-sanity-lc data)]))]
+                              (when page
                                 (state/sidebar-add-block!
                                 (state/sidebar-add-block!
                                  (state/get-current-repo)
                                  (state/get-current-repo)
-                                 (:db/id block)
-                                 :block
-                                 block))
+                                 (:db/id page)
+                                 :page
+                                 {:page page})))
 
 
-                              :new-page
-                              (page-handler/create! search-q)
+                            :block
+                            (let [block-uuid (uuid (:block/uuid data))
+                                  block (db/entity [:block/uuid block-uuid])]
+                              (state/sidebar-add-block!
+                               (state/get-current-repo)
+                               (:db/id block)
+                               :block
+                               block))
 
 
-                              :file
-                              (route/redirect! {:to :file
-                                                :path-params {:path data}})
+                            :new-page
+                            (page-handler/create! search-q)
 
 
-                              nil)
-                            (state/close-modal!))
-         :item-render (fn [{:keys [type data alias]}]
-                        (let [search-mode (state/get-search-mode)
-                              data (if (string? data) (pdf-assets/fix-local-asset-filename data) data)]
-                          [:div {:class "py-2"} (case type
-                                                  :graph-add-filter
-                                                  [:b search-q]
+                            :file
+                            (route/redirect! {:to :file
+                                              :path-params {:path data}})
+
+                            nil)
+                          (state/close-modal!))
+       :item-render (fn [{:keys [type data alias]}]
+                      (let [search-mode (state/get-search-mode)
+                            data (if (string? data) (pdf-assets/fix-local-asset-filename data) data)]
+                        [:div {:class "py-2"} (case type
+                                                :graph-add-filter
+                                                [:b search-q]
 
 
-                                                  :new-page
-                                                  [:div.text.font-bold (str (t :new-page) ": ")
-                                                   [:span.ml-1 (str "\"" search-q "\"")]]
+                                                :new-page
+                                                [:div.text.font-bold (str (t :new-page) ": ")
+                                                 [:span.ml-1 (str "\"" search-q "\"")]]
 
 
-                                                  :page
-                                                  [:span {:data-page-ref data}
-                                                   (when alias
-                                                     (let [target-original-name (model/get-page-original-name alias)]
-                                                       [:span.mr-2.text-sm.font-medium.mb-2 (str "Alias -> " target-original-name)]))
-                                                   (search-result-item "Page" (highlight-exact-query data search-q))]
+                                                :page
+                                                [:span {:data-page-ref data}
+                                                 (when alias
+                                                   (let [target-original-name (model/get-page-original-name alias)]
+                                                     [:span.mr-2.text-sm.font-medium.mb-2 (str "Alias -> " target-original-name)]))
+                                                 (search-result-item "Page" (highlight-exact-query data search-q))]
 
 
-                                                  :file
-                                                  (search-result-item "File" (highlight-exact-query data search-q))
+                                                :file
+                                                (search-result-item "File" (highlight-exact-query data search-q))
 
 
-                                                  :block
-                                                  (let [{:block/keys [page uuid]} data  ;; content here is normalized
-                                                        page (util/get-page-original-name page)
-                                                        repo (state/sub :git/current-repo)
-                                                        format (db/get-page-format page)
-                                                        block (model/query-block-by-uuid uuid)
-                                                        content (:block/content block)]
-                                                    [:span {:data-block-ref uuid}
-                                                      (search-result-item "Block"
-                                                        (block-search-result-item repo uuid format content search-q search-mode))])
+                                                :block
+                                                (let [{:block/keys [page uuid]} data  ;; content here is normalized
+                                                      page (util/get-page-original-name page)
+                                                      repo (state/sub :git/current-repo)
+                                                      format (db/get-page-format page)
+                                                      block (model/query-block-by-uuid uuid)
+                                                      content (:block/content block)]
+                                                  [:span {:data-block-ref uuid}
+                                                   (search-result-item "Block"
+                                                                       (block-search-result-item repo uuid format content search-q search-mode))])
 
 
-                                                  nil)]))})
-       (when (and has-more? (util/electron?) (not all?))
-         [:div.px-2.py-4.search-more
-          [:a.text-sm.font-medium {:href (rfe/href :search {:q search-q})
-                                   :on-click (fn []
-                                               (when-not (string/blank? search-q)
-                                                 (search-handler/search (state/get-current-repo) search-q {:limit 1000
-                                                                                                           :more? true})
-                                                 (search-handler/clear-search!)))}
-           (t :more)]])])))
+                                                nil)]))})
+     (when (and has-more? (util/electron?) (not all?))
+       [:div.px-2.py-4.search-more
+        [:a.text-sm.font-medium {:href (rfe/href :search {:q search-q})
+                                 :on-click (fn []
+                                             (when-not (string/blank? search-q)
+                                               (search-handler/search (state/get-current-repo) search-q {:limit 1000
+                                                                                                         :more? true})
+                                               (search-handler/clear-search!)))}
+         (t :more)]])]))
 
 
 (rum/defc recent-search-and-pages
 (rum/defc recent-search-and-pages
   [in-page-search?]
   [in-page-search?]
@@ -313,58 +312,56 @@
         search-mode (state/sub :search/mode)
         search-mode (state/sub :search/mode)
         timeout 300
         timeout 300
         in-page-search? (= search-mode :page)]
         in-page-search? (= search-mode :page)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div.cp__palette.cp__palette-main
-       (when (mobile-util/is-native-platform?)
-         {:style {:min-height "50vh"}})
+    [:div.cp__palette.cp__palette-main
+     (when (mobile-util/is-native-platform?)
+       {:style {:min-height "50vh"}})
 
 
-       [:div.input-wrap
-        [:input.cp__palette-input.w-full
-         {:type          "text"
-          :auto-focus    true
-          :placeholder   (case search-mode
-                           :graph
-                           (t :graph-search)
-                           :page
-                           (t :page-search)
-                           (t :search))
-          :auto-complete (if (util/chrome?) "chrome-off" "off") ; off not working here
-          :value         search-q
-          :on-change     (fn [e]
-                           (when @search-timeout
-                             (js/clearTimeout @search-timeout))
-                           (let [value (util/evalue e)
-                                 is-composing? (util/onchange-event-is-composing? e)] ;; #3199
-                             (if (and (string/blank? value) (not is-composing?))
-                               (search-handler/clear-search! false)
-                               (let [search-mode (state/get-search-mode)
-                                     opts (if (= :page search-mode)
-                                            (when-let [current-page (or (state/get-current-page)
-                                                                        (date/today))]
-                                              {:page-db-id (:db/id (db/entity [:block/name (util/page-name-sanity-lc current-page)]))})
-                                            {})]
-                                 (state/set-q! value)
-                                 (reset! search-timeout
-                                         (js/setTimeout
-                                          (fn []
-                                            (if (= :page search-mode)
-                                              (search-handler/search (state/get-current-repo) value opts)
-                                              (search-handler/search (state/get-current-repo) value)))
-                                          timeout))))))}]]
-       [:div.search-results-wrap
-        (if (seq search-result)
-          (search-auto-complete search-result search-q false)
-          (recent-search-and-pages in-page-search?))]])))
+     [:div.input-wrap
+      [:input.cp__palette-input.w-full
+       {:type          "text"
+        :auto-focus    true
+        :placeholder   (case search-mode
+                         :graph
+                         (t :graph-search)
+                         :page
+                         (t :page-search)
+                         (t :search))
+        :auto-complete (if (util/chrome?) "chrome-off" "off") ; off not working here
+        :value         search-q
+        :on-change     (fn [e]
+                         (when @search-timeout
+                           (js/clearTimeout @search-timeout))
+                         (let [value (util/evalue e)
+                               is-composing? (util/onchange-event-is-composing? e)] ;; #3199
+                           (if (and (string/blank? value) (not is-composing?))
+                             (search-handler/clear-search! false)
+                             (let [search-mode (state/get-search-mode)
+                                   opts (if (= :page search-mode)
+                                          (when-let [current-page (or (state/get-current-page)
+                                                                      (date/today))]
+                                            {:page-db-id (:db/id (db/entity [:block/name (util/page-name-sanity-lc current-page)]))})
+                                          {})]
+                               (state/set-q! value)
+                               (reset! search-timeout
+                                       (js/setTimeout
+                                        (fn []
+                                          (if (= :page search-mode)
+                                            (search-handler/search (state/get-current-repo) value opts)
+                                            (search-handler/search (state/get-current-repo) value)))
+                                        timeout))))))}]]
+     [:div.search-results-wrap
+      (if (seq search-result)
+        (search-auto-complete search-result search-q false)
+        (recent-search-and-pages in-page-search?))]]))
 
 
 (rum/defc more < rum/reactive
 (rum/defc more < rum/reactive
   [route]
   [route]
   (let [search-q (get-in route [:path-params :q])
   (let [search-q (get-in route [:path-params :q])
         search-result (state/sub :search/more-result)]
         search-result (state/sub :search/more-result)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div#search.flex-1.flex
-       [:div.inner
-        [:h1.title (t :search/result-for) [:i search-q]]
-        [:p.font-medium.tx-sm (str (count (:blocks search-result)) " " (t :search/items))]
-        [:div#search-wrapper.relative.w-full.text-gray-400.focus-within:text-gray-600
-         (when-not (string/blank? search-q)
-           (search-auto-complete search-result search-q true))]]])))
+    [:div#search.flex-1.flex
+     [:div.inner
+      [:h1.title (t :search/result-for) [:i search-q]]
+      [:p.font-medium.tx-sm (str (count (:blocks search-result)) " " (t :search/items))]
+      [:div#search-wrapper.relative.w-full.text-gray-400.focus-within:text-gray-600
+       (when-not (string/blank? search-q)
+         (search-auto-complete search-result search-q true))]]]))

+ 19 - 20
src/main/frontend/components/select.cljs

@@ -4,7 +4,7 @@
   new select-type, set :ui/open-select to the select-type. See
   new select-type, set :ui/open-select to the select-type. See
   :select-graph/open command for an example."
   :select-graph/open command for an example."
   (:require [frontend.modules.shortcut.core :as shortcut]
   (:require [frontend.modules.shortcut.core :as shortcut]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.search :as search]
             [frontend.search :as search]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
@@ -33,26 +33,25 @@
   [state {:keys [items limit on-chosen empty-placeholder prompt-key]
   [state {:keys [items limit on-chosen empty-placeholder prompt-key]
           :or {limit 100
           :or {limit 100
                prompt-key :select/default-prompt}}]
                prompt-key :select/default-prompt}}]
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (let [input (::input state)]
-      [:div.cp__select.cp__select-main
-       [:div.input-wrap
-        [:input.cp__select-input.w-full
-         {:type        "text"
-          :placeholder (t prompt-key)
-          :auto-focus  true
-          :value       @input
-          :on-change   (fn [e] (reset! input (util/evalue e)))}]]
+  (let [input (::input state)]
+    [:div.cp__select.cp__select-main
+     [:div.input-wrap
+      [:input.cp__select-input.w-full
+       {:type        "text"
+        :placeholder (t prompt-key)
+        :auto-focus  true
+        :value       @input
+        :on-change   (fn [e] (reset! input (util/evalue e)))}]]
 
 
-       [:div.item-results-wrap
-        (ui/auto-complete
-         (search/fuzzy-search items @input :limit limit :extract-fn :value)
-         {:item-render render-item
-          :class       "cp__select-results"
-          :on-chosen   (fn [x]
-                         (state/close-modal!)
-                         (on-chosen x))
-          :empty-placeholder (empty-placeholder t)})]])))
+     [:div.item-results-wrap
+      (ui/auto-complete
+       (search/fuzzy-search items @input :limit limit :extract-fn :value)
+       {:item-render render-item
+        :class       "cp__select-results"
+        :on-chosen   (fn [x]
+                       (state/close-modal!)
+                       (on-chosen x))
+        :empty-placeholder (empty-placeholder t)})]]))
 
 
 (defn select-config
 (defn select-config
   "Config that supports multiple types (uses) of this component. To add a new
   "Config that supports multiple types (uses) of this component. To add a new

+ 159 - 165
src/main/frontend/components/settings.cljs

@@ -2,7 +2,7 @@
   (:require [clojure.string :as string]
   (:require [clojure.string :as string]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.storage :as storage]
             [frontend.storage :as storage]
             [frontend.date :as date]
             [frontend.date :as date]
             [frontend.dicts :as dicts]
             [frontend.dicts :as dicts]
@@ -109,22 +109,21 @@
 
 
 (rum/defc delete-account-confirm
 (rum/defc delete-account-confirm
   [close-fn]
   [close-fn]
-  (rum/with-context [[t] i18n/*tongue-context*]
-    [:div
-     (ui/admonition
-      :important
-      [:p.text-gray-700 (t :user/delete-account-notice)])
-     [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
-      [:span.flex.w-full.rounded-md.sm:ml-3.sm:w-auto
-       [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-        {:type     "button"
-         :on-click user-handler/delete-account!}
-        (t :user/delete-account)]]
-      [:span.mt-3.flex.w-full.rounded-md.sm:mt-0.sm:w-auto
-       [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-        {:type     "button"
-         :on-click close-fn}
-        "Cancel"]]]]))
+  [:div
+   (ui/admonition
+    :important
+    [:p.text-gray-700 (t :user/delete-account-notice)])
+   [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
+    [:span.flex.w-full.rounded-md.sm:ml-3.sm:w-auto
+     [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+      {:type     "button"
+       :on-click user-handler/delete-account!}
+      (t :user/delete-account)]]
+    [:span.mt-3.flex.w-full.rounded-md.sm:mt-0.sm:w-auto
+     [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+      {:type     "button"
+       :on-click close-fn}
+      "Cancel"]]]])
 
 
 (rum/defc outdenting-hint
 (rum/defc outdenting-hint
   []
   []
@@ -163,22 +162,20 @@
 
 
 
 
 (defn edit-config-edn []
 (defn edit-config-edn []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (row-with-button-action
-     {:left-label   (t :settings-page/custom-configuration)
-      :button-label (t :settings-page/edit-config-edn)
-      :href         (rfe/href :file {:path (config/get-config-path)})
-      :on-click     #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
-      :-for         "config_edn"})))
+  (row-with-button-action
+   {:left-label   (t :settings-page/custom-configuration)
+    :button-label (t :settings-page/edit-config-edn)
+    :href         (rfe/href :file {:path (config/get-config-path)})
+    :on-click     #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
+    :-for         "config_edn"}))
 
 
 (defn edit-custom-css []
 (defn edit-custom-css []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (row-with-button-action
-     {:left-label   (t :settings-page/custom-theme)
-      :button-label (t :settings-page/edit-custom-css)
-      :href         (rfe/href :file {:path (config/get-custom-css-path)})
-      :on-click     #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
-      :-for         "customize_css"})))
+  (row-with-button-action
+   {:left-label   (t :settings-page/custom-theme)
+    :button-label (t :settings-page/edit-custom-css)
+    :href         (rfe/href :file {:path (config/get-custom-css-path)})
+    :on-click     #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
+    :-for         "customize_css"}))
 
 
 (defn show-brackets-row [t show-brackets?]
 (defn show-brackets-row [t show-brackets?]
   [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
   [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
@@ -554,137 +551,134 @@
         switch-theme (if dark? "white" "dark")
         switch-theme (if dark? "white" "dark")
         *active (::active state)]
         *active (::active state)]
 
 
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
-
-      [:div#settings.cp__settings-main
-       [:header
-        [:h1.title (t :settings)]]
-
-       [:div.cp__settings-inner.md:flex
-
-        [:aside.md:w-64 {:style {:min-width "10rem"}}
-         [:ul
-          (for [[label text icon]
-                [[:general (t :settings-page/tab-general) (ui/icon "adjustments" {:style {:font-size 20}})]
-                 [:editor (t :settings-page/tab-editor) (ui/icon "writing" {:style {:font-size 20}})]
-                 (when-not (mobile-util/is-native-platform?)
-                   [:git (t :settings-page/tab-version-control) (ui/icon "history" {:style {:font-size 20}})])
-                 [:advanced (t :settings-page/tab-advanced) (ui/icon "bulb" {:style {:font-size 20}})]]]
-
-            (when label
-              [:li
-               {:key text
-                :class    (util/classnames [{:active (= label @*active)}])
-                :on-click #(reset! *active label)}
-
-               [:a.flex.items-center
-                icon
-                [:strong text]]]))]]
-
-        [:article
-
-         (case @*active
-
-           :general
-           [:div.panel-wrap.is-general
-            (when-not (mobile-util/is-native-platform?)
-              (version-row t version))
-            (language-row t preferred-language)
-            (theme-modes-row t switch-theme system-theme? dark?)
-            (when current-repo (edit-config-edn))
-            (when current-repo (edit-custom-css))
-            (keyboard-shortcuts-row t)]
-
-           :editor
-           [:div.panel-wrap.is-editor
-            (file-format-row t preferred-format)
-            (date-format-row t preferred-date-format)
-            (workflow-row t preferred-workflow)
-            ;; (enable-block-timestamps-row t enable-block-timestamps?)
-            (show-brackets-row t show-brackets?)
-            (when (util/electron?) (switch-spell-check-row t))
-            (outdenting-row t logical-outdenting?)
-            (when-not (or (util/mobile?) (mobile-util/is-native-platform?))
-              (shortcut-tooltip-row t enable-shortcut-tooltip?)
-              (tooltip-row t enable-tooltip?))
-            (timetracking-row t enable-timetracking?)
-            (journal-row t enable-journals?)
-            (encryption-row t enable-encryption?)
-            (enable-all-pages-public-row t enable-all-pages-public?)
-            (zotero-settings-row t)
-            (auto-push-row t current-repo enable-git-auto-push?)]
-
-           :git
-           [:div.panel-wrap
-            [:div.text-sm.my-4
-             [:span.text-sm.opacity-50.my-4
-              "You can view a page's edit history by clicking the three vertical dots "
-              "in the top-right corner and selecting \"Check page's history\". "
-              "Logseq uses "]
-             [:a {:href "https://git-scm.com/" :target "_blank"}
-              "Git"]
-             [:span.text-sm.opacity-50.my-4
-              " for version control."]]
-            [:br]
-            (switch-git-auto-commit-row t)
-            (git-auto-commit-seconds t)
-
-            (ui/admonition
-             :warning
-             [:p (t :settings-page/git-confirm)])]
-
-           :advanced
-           [:div.panel-wrap.is-advanced
-            (when (and util/mac? (util/electron?)) (app-auto-update-row t))
-            (usage-diagnostics-row t instrument-disabled?)
-            (when-not (mobile-util/is-native-platform?) (developer-mode-row t developer-mode?))
-            (when (util/electron?) (plugin-system-switcher-row t))
-            (clear-cache-row t)
-
-            (ui/admonition
-             :warning
-             [:p "Clearing the cache will discard open graphs. You will lose unsaved changes."])
-
-            (when logged?
-              [:div
-               [:div.mt-6.sm:mt-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center.sm:pt-5
-                [:label.block.text-sm.font-medium.leading-5.sm:mt-px..opacity-70
-                 {:for "cors"}
-                 (t :settings-page/custom-cors-proxy-server)]
-                [:div.mt-1.sm:mt-0.sm:col-span-2
-                 [:div.max-w-lg.rounded-md.sm:max-w-xs
-                  [:input#pat.form-input.is-small.transition.duration-150.ease-in-out
-                   {:default-value cors-proxy
-                    :on-blur       (fn [event]
-                                     (when-let [server (util/evalue event)]
-                                       (user-handler/set-cors! server)
-                                       (notification/show! "Custom CORS proxy updated successfully!" :success)))
-                    :on-key-press  (fn [event]
-                                     (let [k (gobj/get event "key")]
-                                       (when (= "Enter" k)
-                                         (when-let [server (util/evalue event)]
-                                           (user-handler/set-cors! server)
-                                           (notification/show! "Custom CORS proxy updated successfully!" :success)))))}]]]]
-               (ui/admonition
-                :important
-                [:p (t :settings-page/dont-use-other-peoples-proxy-servers)
-                 [:a {:href   "https://github.com/isomorphic-git/cors-proxy"
-                      :target "_blank"}
-                  "https://github.com/isomorphic-git/cors-proxy"]])])
-
-            (when logged?
-              [:div
-               [:hr]
-               [:div.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center.sm:pt-5
-                [:label.block.text-sm.font-medium.leading-5.opacity-70.text-red-600.dark:text-red-400
-                 {:for "delete account"}
-                 (t :user/delete-account)]
-                [:div.mt-1.sm:mt-0.sm:col-span-2
-                 [:div.max-w-lg.rounded-md.sm:max-w-xs
-                  (ui/button (t :user/delete-your-account)
-                             :on-click (fn []
-                                         (ui-handler/toggle-settings-modal!)
-                                         (js/setTimeout #(state/set-modal! delete-account-confirm))))]]]])]
-
-           nil)]]])))
+    [:div#settings.cp__settings-main
+     [:header
+      [:h1.title (t :settings)]]
+
+     [:div.cp__settings-inner.md:flex
+
+      [:aside.md:w-64 {:style {:min-width "10rem"}}
+       [:ul
+        (for [[label text icon]
+              [[:general (t :settings-page/tab-general) (ui/icon "adjustments" {:style {:font-size 20}})]
+               [:editor (t :settings-page/tab-editor) (ui/icon "writing" {:style {:font-size 20}})]
+               (when-not (mobile-util/is-native-platform?)
+                 [:git (t :settings-page/tab-version-control) (ui/icon "history" {:style {:font-size 20}})])
+               [:advanced (t :settings-page/tab-advanced) (ui/icon "bulb" {:style {:font-size 20}})]]]
+
+          (when label
+            [:li
+             {:key text
+              :class    (util/classnames [{:active (= label @*active)}])
+              :on-click #(reset! *active label)}
+
+             [:a.flex.items-center
+              icon
+              [:strong text]]]))]]
+
+      [:article
+
+       (case @*active
+
+         :general
+         [:div.panel-wrap.is-general
+          (when-not (mobile-util/is-native-platform?)
+            (version-row t version))
+          (language-row t preferred-language)
+          (theme-modes-row t switch-theme system-theme? dark?)
+          (when current-repo (edit-config-edn))
+          (when current-repo (edit-custom-css))
+          (keyboard-shortcuts-row t)]
+
+         :editor
+         [:div.panel-wrap.is-editor
+          (file-format-row t preferred-format)
+          (date-format-row t preferred-date-format)
+          (workflow-row t preferred-workflow)
+          ;; (enable-block-timestamps-row t enable-block-timestamps?)
+          (show-brackets-row t show-brackets?)
+          (when (util/electron?) (switch-spell-check-row t))
+          (outdenting-row t logical-outdenting?)
+          (when-not (or (util/mobile?) (mobile-util/is-native-platform?))
+            (shortcut-tooltip-row t enable-shortcut-tooltip?)
+            (tooltip-row t enable-tooltip?))
+          (timetracking-row t enable-timetracking?)
+          (journal-row t enable-journals?)
+          (encryption-row t enable-encryption?)
+          (enable-all-pages-public-row t enable-all-pages-public?)
+          (zotero-settings-row t)
+          (auto-push-row t current-repo enable-git-auto-push?)]
+
+         :git
+         [:div.panel-wrap
+          [:div.text-sm.my-4
+           [:span.text-sm.opacity-50.my-4
+            "You can view a page's edit history by clicking the three vertical dots "
+            "in the top-right corner and selecting \"Check page's history\". "
+            "Logseq uses "]
+           [:a {:href "https://git-scm.com/" :target "_blank"}
+            "Git"]
+           [:span.text-sm.opacity-50.my-4
+            " for version control."]]
+          [:br]
+          (switch-git-auto-commit-row t)
+          (git-auto-commit-seconds t)
+
+          (ui/admonition
+           :warning
+           [:p (t :settings-page/git-confirm)])]
+
+         :advanced
+         [:div.panel-wrap.is-advanced
+          (when (and util/mac? (util/electron?)) (app-auto-update-row t))
+          (usage-diagnostics-row t instrument-disabled?)
+          (when-not (mobile-util/is-native-platform?) (developer-mode-row t developer-mode?))
+          (when (util/electron?) (plugin-system-switcher-row t))
+          (clear-cache-row t)
+
+          (ui/admonition
+           :warning
+           [:p "Clearing the cache will discard open graphs. You will lose unsaved changes."])
+
+          (when logged?
+            [:div
+             [:div.mt-6.sm:mt-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center.sm:pt-5
+              [:label.block.text-sm.font-medium.leading-5.sm:mt-px..opacity-70
+               {:for "cors"}
+               (t :settings-page/custom-cors-proxy-server)]
+              [:div.mt-1.sm:mt-0.sm:col-span-2
+               [:div.max-w-lg.rounded-md.sm:max-w-xs
+                [:input#pat.form-input.is-small.transition.duration-150.ease-in-out
+                 {:default-value cors-proxy
+                  :on-blur       (fn [event]
+                                   (when-let [server (util/evalue event)]
+                                     (user-handler/set-cors! server)
+                                     (notification/show! "Custom CORS proxy updated successfully!" :success)))
+                  :on-key-press  (fn [event]
+                                   (let [k (gobj/get event "key")]
+                                     (when (= "Enter" k)
+                                       (when-let [server (util/evalue event)]
+                                         (user-handler/set-cors! server)
+                                         (notification/show! "Custom CORS proxy updated successfully!" :success)))))}]]]]
+             (ui/admonition
+              :important
+              [:p (t :settings-page/dont-use-other-peoples-proxy-servers)
+               [:a {:href   "https://github.com/isomorphic-git/cors-proxy"
+                    :target "_blank"}
+                "https://github.com/isomorphic-git/cors-proxy"]])])
+
+          (when logged?
+            [:div
+             [:hr]
+             [:div.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center.sm:pt-5
+              [:label.block.text-sm.font-medium.leading-5.opacity-70.text-red-600.dark:text-red-400
+               {:for "delete account"}
+               (t :user/delete-account)]
+              [:div.mt-1.sm:mt-0.sm:col-span-2
+               [:div.max-w-lg.rounded-md.sm:max-w-xs
+                (ui/button (t :user/delete-your-account)
+                  :on-click (fn []
+                              (ui-handler/toggle-settings-modal!)
+                              (js/setTimeout #(state/set-modal! delete-account-confirm))))]]]])]
+
+         nil)]]]))

+ 98 - 102
src/main/frontend/components/shortcut.cljs

@@ -1,6 +1,6 @@
 (ns frontend.components.shortcut
 (ns frontend.components.shortcut
   (:require [clojure.string :as str]
   (:require [clojure.string :as str]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.data-helper :as dh]
             [frontend.modules.shortcut.data-helper :as dh]
             [frontend.state :as state]
             [frontend.state :as state]
@@ -69,117 +69,113 @@
                           state/state
                           state/state
                           [:config (state/get-current-repo) :shortcuts])
                           [:config (state/get-current-repo) :shortcuts])
          _ (rum/react shortcut-config)]
          _ (rum/react shortcut-config)]
-     (rum/with-context [[t] i18n/*tongue-context*]
-       [:div
-        [:table
-         [:thead
-          [:tr
-           [:th.text-left [:b (t name)]]
-           [:th.text-right]]]
-         [:tbody
-          (map (fn [[k {:keys [binding]}]]
-                 [:tr {:key k}
-                  [:td.text-left (t (dh/decorate-namespace k))]
-                  (shortcut-col k binding configurable? (t (dh/decorate-namespace k)))])
-               (dh/binding-by-category name))]]]))))
+     [:div
+      [:table
+       [:thead
+        [:tr
+         [:th.text-left [:b (t name)]]
+         [:th.text-right]]]
+       [:tbody
+        (map (fn [[k {:keys [binding]}]]
+               [:tr {:key k}
+                [:td.text-left (t (dh/decorate-namespace k))]
+                (shortcut-col k binding configurable? (t (dh/decorate-namespace k)))])
+          (dh/binding-by-category name))]]])))
 
 
 (rum/defc trigger-table []
 (rum/defc trigger-table []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    [:table
-     [:thead
-      [:tr
-       [:th.text-left [:b (t :help/shortcuts-triggers)]]
-       [:th.text-right [:b (t :help/shortcut)]]]]
-     [:tbody
-      [:tr
-       [:td.text-left (t :help/slash-autocomplete)]
-       [:td.text-right [:code "/"]]]
-      [:tr
-       [:td.text-left (t :help/block-content-autocomplete)]
-       [:td.text-right [:code "<"]]]
-      [:tr
-       [:td.text-left (t :help/reference-autocomplete)]
-       [:td.text-right [:code "[[]]"]]]
-      [:tr
-       [:td.text-left (t :help/block-reference)]
-       [:td.text-right [:code "(())"]]]
-      [:tr
-       [:td.text-left (t :command.editor/open-link-in-sidebar)]
-       [:td.text-right (ui/render-keyboard-shortcut ["shift" "click"])]]
-      [:tr
-       [:td.text-left (t :help/context-menu)]
-       [:td.text-right (ui/render-keyboard-shortcut ["right" "click"])]]]]))
+  [:table
+   [:thead
+    [:tr
+     [:th.text-left [:b (t :help/shortcuts-triggers)]]
+     [:th.text-right [:b (t :help/shortcut)]]]]
+   [:tbody
+    [:tr
+     [:td.text-left (t :help/slash-autocomplete)]
+     [:td.text-right [:code "/"]]]
+    [:tr
+     [:td.text-left (t :help/block-content-autocomplete)]
+     [:td.text-right [:code "<"]]]
+    [:tr
+     [:td.text-left (t :help/reference-autocomplete)]
+     [:td.text-right [:code "[[]]"]]]
+    [:tr
+     [:td.text-left (t :help/block-reference)]
+     [:td.text-right [:code "(())"]]]
+    [:tr
+     [:td.text-left (t :command.editor/open-link-in-sidebar)]
+     [:td.text-right (ui/render-keyboard-shortcut ["shift" "click"])]]
+    [:tr
+     [:td.text-left (t :help/context-menu)]
+     [:td.text-right (ui/render-keyboard-shortcut ["right" "click"])]]]])
 
 
 (defn markdown-and-orgmode-syntax []
 (defn markdown-and-orgmode-syntax []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (let [list [:bold :italics :del :mark :latex :code :link :pre :img]
+  (let [list [:bold :italics :del :mark :latex :code :link :pre :img]
 
 
-          preferred-format (state/get-preferred-format) ; markdown/org
+        preferred-format (state/get-preferred-format) ; markdown/org
 
 
-          title (case preferred-format
-                  :markdown (t :help/markdown-syntax)
-                  :org (t :help/org-mode-syntax))
+        title (case preferred-format
+                :markdown (t :help/markdown-syntax)
+                :org (t :help/org-mode-syntax))
 
 
-          learn-more (case preferred-format
-                       :markdown "https://www.markdownguide.org/basic-syntax"
-                       :org "https://orgmode.org/worg/dev/org-syntax.html")
+        learn-more (case preferred-format
+                     :markdown "https://www.markdownguide.org/basic-syntax"
+                     :org "https://orgmode.org/worg/dev/org-syntax.html")
 
 
-          raw (case preferred-format
-                :markdown {:bold (str "**" (t :bold) "**")
-                           :italics (str "_" (t :italics) "_")
-                           :link "[Link](https://www.example.com)"
-                           :del (str "~~" (t :strikethrough) "~~")
-                           :mark (str "^^" (t :highlight) "^^")
-                           :latex "$$E = mc^2$$"
-                           :code (str "`" (t :code) "`")
-                           :pre "```clojure\n  (println \"Hello world!\")\n```"
-                           :img "![image](https://asset.logseq.com/static/img/logo.png)"}
-                :org {:bold (str "*" (t :bold) "*")
-                      :italic (str "/" (t :italics) "/")
-                      :del (str "+" (t :strikethrough) "+")
-                      :pre [:pre "#+BEGIN_SRC clojure\n  (println \"Hello world!\")\n#+END_SRC"]
-                      :link "[[https://www.example.com][Link]]"
-                      :mark (str "^^" (t :highlight) "^^")
-                      :latex "$$E = mc^2$$"
-                      :code "~Code~"
-                      :img "[[https://asset.logseq.com/static/img/logo.png][image]]"})
+        raw (case preferred-format
+              :markdown {:bold (str "**" (t :bold) "**")
+                         :italics (str "_" (t :italics) "_")
+                         :link "[Link](https://www.example.com)"
+                         :del (str "~~" (t :strikethrough) "~~")
+                         :mark (str "^^" (t :highlight) "^^")
+                         :latex "$$E = mc^2$$"
+                         :code (str "`" (t :code) "`")
+                         :pre "```clojure\n  (println \"Hello world!\")\n```"
+                         :img "![image](https://asset.logseq.com/static/img/logo.png)"}
+              :org {:bold (str "*" (t :bold) "*")
+                    :italic (str "/" (t :italics) "/")
+                    :del (str "+" (t :strikethrough) "+")
+                    :pre [:pre "#+BEGIN_SRC clojure\n  (println \"Hello world!\")\n#+END_SRC"]
+                    :link "[[https://www.example.com][Link]]"
+                    :mark (str "^^" (t :highlight) "^^")
+                    :latex "$$E = mc^2$$"
+                    :code "~Code~"
+                    :img "[[https://asset.logseq.com/static/img/logo.png][image]]"})
 
 
-          rendered {:italics [:i (t :italics)]
-                    :bold [:b (t :bold)]
-                    :link [:a {:href "https://www.example.com"} "Link"]
-                    :del [:del (t :strikethrough)]
-                    :mark [:mark (t :highlight)]
-                    :latex (latex/latex "help-latex" "E = mc^2" true false)
-                    :code [:code (t :code)]
-                    :pre (highlight/highlight "help-highlight" {:data-lang "clojure"} "(println \"Hello world!\")")
-                    :img [:img {:style {:float "right" :width 32 :height 32}
-                                :src "https://asset.logseq.com/static/img/logo.png"
-                                :alt "image"}]}]
+        rendered {:italics [:i (t :italics)]
+                  :bold [:b (t :bold)]
+                  :link [:a {:href "https://www.example.com"} "Link"]
+                  :del [:del (t :strikethrough)]
+                  :mark [:mark (t :highlight)]
+                  :latex (latex/latex "help-latex" "E = mc^2" true false)
+                  :code [:code (t :code)]
+                  :pre (highlight/highlight "help-highlight" {:data-lang "clojure"} "(println \"Hello world!\")")
+                  :img [:img {:style {:float "right" :width 32 :height 32}
+                              :src "https://asset.logseq.com/static/img/logo.png"
+                              :alt "image"}]}]
 
 
-      [:table
-       [:thead
-        [:tr
-         [:th.text-left [:b title]]
-         [:th.text-right [:a {:href learn-more} "Learn more →"]]]]
-       [:tbody
-        (map (fn [name]
-               [:tr
-                [:td.text-left [(if (= :pre name) :pre :code) (get raw name)]]
-                [:td.text-right (get rendered name)]])
-             list)]])))
+    [:table
+     [:thead
+      [:tr
+       [:th.text-left [:b title]]
+       [:th.text-right [:a {:href learn-more} "Learn more →"]]]]
+     [:tbody
+      (map (fn [name]
+             [:tr
+              [:td.text-left [(if (= :pre name) :pre :code) (get raw name)]]
+              [:td.text-right (get rendered name)]])
+        list)]]))
 
 
 (rum/defc shortcut
 (rum/defc shortcut
   []
   []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    [:div
-     [:h1.title (t :help/shortcut-page-title)]
-     (trigger-table)
-     (markdown-and-orgmode-syntax)
-     (shortcut-table :shortcut.category/basics true)
-     (shortcut-table :shortcut.category/navigating true)
-     (shortcut-table :shortcut.category/block-editing true)
-     (shortcut-table :shortcut.category/block-command-editing true)
-     (shortcut-table :shortcut.category/block-selection true)
-     (shortcut-table :shortcut.category/formatting true)
-     (shortcut-table :shortcut.category/toggle true)
-     (shortcut-table :shortcut.category/others true)]))
+  [:div
+   [:h1.title (t :help/shortcut-page-title)]
+   (trigger-table)
+   (markdown-and-orgmode-syntax)
+   (shortcut-table :shortcut.category/basics true)
+   (shortcut-table :shortcut.category/navigating true)
+   (shortcut-table :shortcut.category/block-editing true)
+   (shortcut-table :shortcut.category/block-command-editing true)
+   (shortcut-table :shortcut.category/block-selection true)
+   (shortcut-table :shortcut.category/formatting true)
+   (shortcut-table :shortcut.category/toggle true)
+   (shortcut-table :shortcut.category/others true)])

+ 186 - 194
src/main/frontend/components/sidebar.cljs

@@ -12,7 +12,7 @@
             [frontend.components.plugins :as plugins]
             [frontend.components.plugins :as plugins]
             [frontend.components.select :as select]
             [frontend.components.select :as select]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.db.model :as db-model]
             [frontend.db.model :as db-model]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
@@ -168,12 +168,11 @@
                 state)}
                 state)}
   [state]
   [state]
   (let [num (state/sub :srs/cards-due-count)]
   (let [num (state/sub :srs/cards-due-count)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md {:on-click #(state/pub-event! [:modal/show-cards])}
-       (ui/icon "infinity mr-3" {:style {:font-size 20}})
-       [:span.flex-1 (t :right-side-bar/flashcards)]
-       (when (and num (not (zero? num)))
-         [:span.ml-3.inline-block.py-0.5.px-3.text-xs.font-medium.rounded-full.fade-in num])])))
+    [:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md {:on-click #(state/pub-event! [:modal/show-cards])}
+     (ui/icon "infinity mr-3" {:style {:font-size 20}})
+     [:span.flex-1 (t :right-side-bar/flashcards)]
+     (when (and num (not (zero? num)))
+       [:span.ml-3.inline-block.py-0.5.px-3.text-xs.font-medium.rounded-full.fade-in num])]))
 
 
 (defn get-default-home-if-valid
 (defn get-default-home-if-valid
   []
   []
@@ -202,61 +201,60 @@
 
 
 (rum/defc sidebar-nav
 (rum/defc sidebar-nav
   [_route-match close-modal-fn]
   [_route-match close-modal-fn]
-  (rum/with-context [[t] i18n/*tongue-context*]
-    (let [default-home (get-default-home-if-valid)]
-
-      [:div.left-sidebar-inner.flex-1.flex.flex-col.min-h-0
-       {:on-click #(when-let [^js target (and (util/sm-breakpoint?) (.-target %))]
-                     (when (some (fn [sel] (boolean (.closest target sel)))
-                                 [".favorites .bd" ".recent .bd" ".dropdown-wrapper" ".nav-header"])
-                       (close-modal-fn)))}
-       [:div.flex.flex-col.pb-4.wrap
-        [:nav.px-2.space-y-1 {:aria-label "Sidebar"}
-         (repo/repos-dropdown)
-
-         [:div.nav-header
-
-          (if (:page default-home)
-            (sidebar-item
-              {:class            "home-nav"
-               :title            (:page default-home)
-               :on-click-handler route-handler/redirect-to-home!
-               :icon             "home"})
-            (sidebar-item
-              {:class            "journals-nav"
-               :title            (t :right-side-bar/journals)
-               :on-click-handler route-handler/go-to-journals!
-               :icon             "calendar"}))
-
-          [:div.flashcards-nav
-           (flashcards)]
+  (let [default-home (get-default-home-if-valid)]
 
 
-          (sidebar-item
-            {:class "graph-view-nav"
-             :title (t :right-side-bar/graph-view)
-             :href  (rfe/href :graph)
-             :icon  "hierarchy"})
+    [:div.left-sidebar-inner.flex-1.flex.flex-col.min-h-0
+     {:on-click #(when-let [^js target (and (util/sm-breakpoint?) (.-target %))]
+                   (when (some (fn [sel] (boolean (.closest target sel)))
+                               [".favorites .bd" ".recent .bd" ".dropdown-wrapper" ".nav-header"])
+                     (close-modal-fn)))}
+     [:div.flex.flex-col.pb-4.wrap
+      [:nav.px-2.space-y-1 {:aria-label "Sidebar"}
+       (repo/repos-dropdown)
+
+       [:div.nav-header
 
 
+        (if (:page default-home)
           (sidebar-item
           (sidebar-item
-            {:class "all-pages-nav"
-             :title (t :right-side-bar/all-pages)
-             :href  (rfe/href :all-pages)
-             :icon  "files"})]]
-
-        (favorites t)
-
-        (recent-pages t)
-
-        [:nav.px-2 {:aria-label "Sidebar"
-                    :class      "new-page"}
-         (when-not config/publishing?
-           [:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md
-            {:on-click (fn []
-                         (and (util/sm-breakpoint?)
-                              (state/toggle-left-sidebar!))
-                         (state/pub-event! [:go/search]))}
-            (ui/icon "circle-plus mr-3" {:style {:font-size 20}})
-            [:span.flex-1 (t :right-side-bar/new-page)]])]]])))
+           {:class            "home-nav"
+            :title            (:page default-home)
+            :on-click-handler route-handler/redirect-to-home!
+            :icon             "home"})
+          (sidebar-item
+           {:class            "journals-nav"
+            :title            (t :right-side-bar/journals)
+            :on-click-handler route-handler/go-to-journals!
+            :icon             "calendar"}))
+
+        [:div.flashcards-nav
+         (flashcards)]
+
+        (sidebar-item
+         {:class "graph-view-nav"
+          :title (t :right-side-bar/graph-view)
+          :href  (rfe/href :graph)
+          :icon  "hierarchy"})
+
+        (sidebar-item
+         {:class "all-pages-nav"
+          :title (t :right-side-bar/all-pages)
+          :href  (rfe/href :all-pages)
+          :icon  "files"})]]
+
+      (favorites t)
+
+      (recent-pages t)
+
+      [:nav.px-2 {:aria-label "Sidebar"
+                  :class      "new-page"}
+       (when-not config/publishing?
+         [:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md
+          {:on-click (fn []
+                       (and (util/sm-breakpoint?)
+                            (state/toggle-left-sidebar!))
+                       (state/pub-event! [:go/search]))}
+          (ui/icon "circle-plus mr-3" {:style {:font-size 20}})
+          [:span.flex-1 (t :right-side-bar/new-page)]])]]]))
 
 
 (rum/defc left-sidebar < rum/reactive
 (rum/defc left-sidebar < rum/reactive
   [{:keys [left-sidebar-open? route-match]}]
   [{:keys [left-sidebar-open? route-match]}]
@@ -282,39 +280,38 @@
   [{:keys [route-match global-graph-pages? route-name indexeddb-support? db-restoring? main-content]}]
   [{:keys [route-match global-graph-pages? route-name indexeddb-support? db-restoring? main-content]}]
 
 
   (let [left-sidebar-open? (state/sub :ui/left-sidebar-open?)]
   (let [left-sidebar-open? (state/sub :ui/left-sidebar-open?)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div#main-container.cp__sidebar-main-layout.flex-1.flex
-       {:class (util/classnames [{:is-left-sidebar-open left-sidebar-open?}])}
+    [:div#main-container.cp__sidebar-main-layout.flex-1.flex
+     {:class (util/classnames [{:is-left-sidebar-open left-sidebar-open?}])}
 
 
-       ;; desktop left sidebar layout
-       (left-sidebar {:left-sidebar-open? left-sidebar-open?
-                      :route-match route-match})
+     ;; desktop left sidebar layout
+     (left-sidebar {:left-sidebar-open? left-sidebar-open?
+                    :route-match route-match})
 
 
-       [:div#main-content-container.scrollbar-spacing.w-full.flex.justify-center
-        [:div.cp__sidebar-main-content
-         {:data-is-global-graph-pages global-graph-pages?
-          :data-is-full-width         (or global-graph-pages?
-                                          (contains? #{:all-files :all-pages :my-publishing} route-name))}
+     [:div#main-content-container.scrollbar-spacing.w-full.flex.justify-center
+      [:div.cp__sidebar-main-content
+       {:data-is-global-graph-pages global-graph-pages?
+        :data-is-full-width         (or global-graph-pages?
+                                        (contains? #{:all-files :all-pages :my-publishing} route-name))}
 
 
-         (when-not (mobile-util/is-native-platform?)
-           (widgets/demo-graph-alert))
+       (when-not (mobile-util/is-native-platform?)
+         (widgets/demo-graph-alert))
 
 
-         (widgets/github-integration-soon-deprecated-alert)
+       (widgets/github-integration-soon-deprecated-alert)
 
 
-         (cond
-           (not indexeddb-support?)
-           nil
+       (cond
+         (not indexeddb-support?)
+         nil
 
 
-           db-restoring?
-           [:div.mt-20
-            [:div.ls-center
-             (ui/loading (t :loading))]]
+         db-restoring?
+         [:div.mt-20
+          [:div.ls-center
+           (ui/loading (t :loading))]]
 
 
-           :else
-           [:div {:class (if global-graph-pages? "" (util/hiccup->class "max-w-7xl.mx-auto.pb-24"))
-                  :style {:margin-bottom (if global-graph-pages? 0 120)
-                          :padding-bottom (when (mobile-util/native-iphone?) "7rem")}}
-            main-content])]]])))
+         :else
+         [:div {:class (if global-graph-pages? "" (util/hiccup->class "max-w-7xl.mx-auto.pb-24"))
+                :style {:margin-bottom (if global-graph-pages? 0 120)
+                        :padding-bottom (when (mobile-util/native-iphone?) "7rem")}}
+          main-content])]]]))
 
 
 (rum/defc footer
 (rum/defc footer
   []
   []
@@ -344,7 +341,7 @@
   []
   []
   (let [cloning? (state/sub :repo/cloning?)
   (let [cloning? (state/sub :repo/cloning?)
         default-home (get-default-home-if-valid)
         default-home (get-default-home-if-valid)
-        importing-to-db? (state/sub :repo/importing-to-db?)
+        parsing? (state/sub :repo/parsing-files?)
         current-repo (state/sub :git/current-repo)
         current-repo (state/sub :git/current-repo)
         loading-files? (when current-repo (state/sub [:repo/loading-files? current-repo]))
         loading-files? (when current-repo (state/sub [:repo/loading-files? current-repo]))
         me (state/sub :me)
         me (state/sub :me)
@@ -352,51 +349,50 @@
         latest-journals (db/get-latest-journals (state/get-current-repo) journals-length)
         latest-journals (db/get-latest-journals (state/get-current-repo) journals-length)
         preferred-format (state/sub [:me :preferred_format])
         preferred-format (state/sub [:me :preferred_format])
         logged? (:name me)]
         logged? (:name me)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div
-       (cond
-         (and default-home
-              (= :home (state/get-current-route))
-              (not (state/route-has-p?))
-              (:page default-home))
-         (route-handler/redirect-to-page! (:page default-home))
+    [:div
+     (cond
+       (and default-home
+            (= :home (state/get-current-route))
+            (not (state/route-has-p?))
+            (:page default-home))
+       (route-handler/redirect-to-page! (:page default-home))
 
 
-         (and config/publishing?
-              (not default-home)
-              (empty? latest-journals))
-         (route-handler/redirect! {:to :all-pages})
+       (and config/publishing?
+            (not default-home)
+            (empty? latest-journals))
+       (route-handler/redirect! {:to :all-pages})
 
 
-         importing-to-db?
-         (ui/loading (t :parsing-files))
+       parsing?
+       (ui/loading (t :parsing-files))
 
 
-         loading-files?
-         (ui/loading (t :loading-files))
+       loading-files?
+       (ui/loading (t :loading-files))
 
 
-         (and (not logged?) (seq latest-journals))
-         (journal/journals latest-journals)
+       (and (not logged?) latest-journals)
+       (journal/journals latest-journals)
 
 
-         (and logged? (not preferred-format))
-         (widgets/choose-preferred-format)
+       (and logged? (not preferred-format))
+       (widgets/choose-preferred-format)
 
 
-                         ;; TODO: delay this
-         (and logged? (nil? (:email me)))
-         (settings/set-email)
+       ;; TODO: delay this
+       (and logged? (nil? (:email me)))
+       (settings/set-email)
 
 
-         cloning?
-         (ui/loading (t :cloning))
+       cloning?
+       (ui/loading (t :cloning))
 
 
-         (seq latest-journals)
-         (journal/journals latest-journals)
+       (seq latest-journals)
+       (journal/journals latest-journals)
 
 
-         (or
-          (and (mobile-util/is-native-platform?)
-               (nil? (state/get-current-repo)))
-          (and logged? (empty? (:repos me))))
-         (widgets/add-graph)
+       (or
+        (and (mobile-util/is-native-platform?)
+             (nil? (state/get-current-repo)))
+        (and logged? (empty? (:repos me))))
+       (widgets/add-graph)
 
 
-                         ;; FIXME: why will this happen?
-         :else
-         [:div])])))
+       ;; FIXME: why will this happen?
+       :else
+       [:div])]))
 
 
 (rum/defc custom-context-menu < rum/reactive
 (rum/defc custom-context-menu < rum/reactive
   []
   []
@@ -406,9 +402,7 @@
        {:class-names "fade"
        {:class-names "fade"
         :timeout {:enter 500
         :timeout {:enter 500
                   :exit 300}}
                   :exit 300}}
-       links
-        ;; (custom-context-menu-content)
-       ))))
+       links))))
 
 
 (rum/defc new-block-mode < rum/reactive
 (rum/defc new-block-mode < rum/reactive
   []
   []
@@ -431,12 +425,11 @@
   []
   []
   (when-not (state/sub :ui/sidebar-open?)
   (when-not (state/sub :ui/sidebar-open?)
     ;; TODO: remove with-context usage
     ;; TODO: remove with-context usage
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div.cp__sidebar-help-btn
-       {:title (t :help-shortcut-title)
-        :on-click (fn []
-                    (state/sidebar-add-block! (state/get-current-repo) "help" :help nil))}
-       "?"])))
+    [:div.cp__sidebar-help-btn
+     {:title (t :help-shortcut-title)
+      :on-click (fn []
+                  (state/sidebar-add-block! (state/get-current-repo) "help" :help nil))}
+     "?"]))
 
 
 (defn- hide-context-menu-and-clear-selection
 (defn- hide-context-menu-and-clear-selection
   [e]
   [e]
@@ -480,67 +473,66 @@
         home? (= :home route-name)
         home? (= :home route-name)
         edit? (:editor/editing? @state/state)
         edit? (:editor/editing? @state/state)
         default-home (get-default-home-if-valid)]
         default-home (get-default-home-if-valid)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      (theme/container
-       {:t             t
-        :theme         theme
-        :route         route-match
-        :current-repo  current-repo
-        :edit?         edit?
-        :nfs-granted?  granted?
-        :db-restoring? db-restoring?
-        :sidebar-open? sidebar-open?
-        :settings-open? settings-open?
-        :sidebar-blocks-len (count right-sidebar-blocks)
-        :system-theme? system-theme?
-        :on-click      (fn [e]
-                         (editor-handler/unhighlight-blocks!)
-                         (util/fix-open-external-with-shift! e))}
-
-       [:div.theme-inner
-        {:class (util/classnames [{:ls-left-sidebar-open left-sidebar-open?
-                                   :ls-right-sidebar-open sidebar-open?}])}
-
-        [:div.#app-container
-         [:div#left-container
-          {:class (if (state/sub :ui/sidebar-open?) "overflow-hidden" "w-full")}
-          (header/header {:open-fn        open-fn
-                          :white?         white?
-                          :current-repo   current-repo
-                          :logged?        logged?
-                          :page?          page?
-                          :route-match    route-match
-                          :me             me
-                          :default-home   default-home
-                          :new-block-mode new-block-mode})
-
-          (main {:route-match         route-match
-                 :global-graph-pages? global-graph-pages?
-                 :logged?             logged?
-                 :home?               home?
-                 :route-name          route-name
-                 :indexeddb-support?  indexeddb-support?
-                 :white?              white?
-                 :db-restoring?       db-restoring?
-                 :main-content        main-content})
-
-          (footer)]
-         (right-sidebar/sidebar)
-
-         [:div#app-single-container]]
-
-        (ui/notification)
-        (ui/modal)
-        (ui/sub-modal)
-        (command-palette/command-palette-modal)
-        (select/select-modal)
-        (custom-context-menu)
-        (plugins/custom-js-installer {:t t
-                                      :current-repo current-repo
-                                      :nfs-granted? granted?
-                                      :db-restoring? db-restoring?})
-        [:a#download.hidden]
-        (when
-         (and (not config/mobile?)
-              (not config/publishing?))
-          (help-button))]))))
+    (theme/container
+     {:t             t
+      :theme         theme
+      :route         route-match
+      :current-repo  current-repo
+      :edit?         edit?
+      :nfs-granted?  granted?
+      :db-restoring? db-restoring?
+      :sidebar-open? sidebar-open?
+      :settings-open? settings-open?
+      :sidebar-blocks-len (count right-sidebar-blocks)
+      :system-theme? system-theme?
+      :on-click      (fn [e]
+                       (editor-handler/unhighlight-blocks!)
+                       (util/fix-open-external-with-shift! e))}
+
+     [:div.theme-inner
+      {:class (util/classnames [{:ls-left-sidebar-open left-sidebar-open?
+                                 :ls-right-sidebar-open sidebar-open?}])}
+
+      [:div.#app-container
+       [:div#left-container
+        {:class (if (state/sub :ui/sidebar-open?) "overflow-hidden" "w-full")}
+        (header/header {:open-fn        open-fn
+                        :white?         white?
+                        :current-repo   current-repo
+                        :logged?        logged?
+                        :page?          page?
+                        :route-match    route-match
+                        :me             me
+                        :default-home   default-home
+                        :new-block-mode new-block-mode})
+
+        (main {:route-match         route-match
+               :global-graph-pages? global-graph-pages?
+               :logged?             logged?
+               :home?               home?
+               :route-name          route-name
+               :indexeddb-support?  indexeddb-support?
+               :white?              white?
+               :db-restoring?       db-restoring?
+               :main-content        main-content})
+
+        (footer)]
+       (right-sidebar/sidebar)
+
+       [:div#app-single-container]]
+
+      (ui/notification)
+      (ui/modal)
+      (ui/sub-modal)
+      (command-palette/command-palette-modal)
+      (select/select-modal)
+      (custom-context-menu)
+      (plugins/custom-js-installer {:t t
+                                    :current-repo current-repo
+                                    :nfs-granted? granted?
+                                    :db-restoring? db-restoring?})
+      [:a#download.hidden]
+      (when
+          (and (not config/mobile?)
+               (not config/publishing?))
+        (help-button))])))

+ 123 - 129
src/main/frontend/components/widgets.cljs

@@ -1,6 +1,6 @@
 (ns frontend.components.widgets
 (ns frontend.components.widgets
   (:require [clojure.string :as string]
   (:require [clojure.string :as string]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
             [frontend.handler.repo :as repo-handler]
             [frontend.handler.repo :as repo-handler]
@@ -16,23 +16,22 @@
 
 
 (rum/defc choose-preferred-format
 (rum/defc choose-preferred-format
   []
   []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    [:div
-     [:h1.title {:style {:margin-bottom "0.25rem"}}
-      (t :format/preferred-mode)]
+  [:div
+   [:h1.title {:style {:margin-bottom "0.25rem"}}
+    (t :format/preferred-mode)]
 
 
-     [:div.mt-4.ml-1
-      (ui/button
-       "Markdown"
-       :on-click
-       #(user-handler/set-preferred-format! :markdown))
+   [:div.mt-4.ml-1
+    (ui/button
+      "Markdown"
+      :on-click
+      #(user-handler/set-preferred-format! :markdown))
 
 
-      [:span.ml-2.mr-2 "-OR-"]
+    [:span.ml-2.mr-2 "-OR-"]
 
 
-      (ui/button
-       "Org Mode"
-       :on-click
-       #(user-handler/set-preferred-format! :org))]]))
+    (ui/button
+      "Org Mode"
+      :on-click
+      #(user-handler/set-preferred-format! :org))]])
 
 
 (rum/defcs add-github-repo <
 (rum/defcs add-github-repo <
   (rum/local "" ::repo)
   (rum/local "" ::repo)
@@ -40,124 +39,121 @@
   [state]
   [state]
   (let [repo (get state ::repo)
   (let [repo (get state ::repo)
         branch (get state ::branch)]
         branch (get state ::branch)]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      [:div.flex.flex-col
-       [:div.w-full.mx-auto
-        [:div
-         [:div
-          [:h1.title
-           (t :git/add-repo-prompt)]
-          [:div.mt-4.mb-4.relative.rounded-md.shadow-sm.max-w-xs
-           [:input#repo.form-input.block.w-full.sm:text-sm.sm:leading-5
-            {:autoFocus true
-             :placeholder "https://github.com/username/repo"
-             :on-change (fn [e]
-                          (reset! repo (util/evalue e)))}]]
-          [:label.font-medium "Default Branch (make sure it's matched with your setting on GitHub): "]
-          [:div.mt-2.mb-4.relative.rounded-md.shadow-sm.max-w-xs
-           [:input#branch.form-input.block.w-full.sm:text-sm.sm:leading-5
-            {:value @branch
-             :placeholder "e.g. main"
-             :on-change (fn [e]
-                          (reset! branch (util/evalue e)))}]]]]
+    [:div.flex.flex-col
+     [:div.w-full.mx-auto
+      [:div
+       [:div
+        [:h1.title
+         (t :git/add-repo-prompt)]
+        [:div.mt-4.mb-4.relative.rounded-md.shadow-sm.max-w-xs
+         [:input#repo.form-input.block.w-full.sm:text-sm.sm:leading-5
+          {:autoFocus true
+           :placeholder "https://github.com/username/repo"
+           :on-change (fn [e]
+                        (reset! repo (util/evalue e)))}]]
+        [:label.font-medium "Default Branch (make sure it's matched with your setting on GitHub): "]
+        [:div.mt-2.mb-4.relative.rounded-md.shadow-sm.max-w-xs
+         [:input#branch.form-input.block.w-full.sm:text-sm.sm:leading-5
+          {:value @branch
+           :placeholder "e.g. main"
+           :on-change (fn [e]
+                        (reset! branch (util/evalue e)))}]]]]
 
 
-        (ui/button
-         (t :git/add-repo-prompt-confirm)
-         :on-click
-         (fn []
-           (let [branch (string/trim @branch)]
-             (if (string/blank? branch)
-               (notification/show!
-                [:p.text-gray-700.dark:text-gray-300 "Please input a branch, make sure it's matched with your setting on GitHub."]
-                :error
-                false)
-               (let [repo (util/lowercase-first @repo)]
-                 (if (util/starts-with? repo "https://github.com/")
-                   (let [repo (string/replace repo ".git" "")]
-                     (repo-handler/create-repo! repo branch))
+      (ui/button
+        (t :git/add-repo-prompt-confirm)
+        :on-click
+        (fn []
+          (let [branch (string/trim @branch)]
+            (if (string/blank? branch)
+              (notification/show!
+               [:p.text-gray-700.dark:text-gray-300 "Please input a branch, make sure it's matched with your setting on GitHub."]
+               :error
+               false)
+              (let [repo (util/lowercase-first @repo)]
+                (if (util/starts-with? repo "https://github.com/")
+                  (let [repo (string/replace repo ".git" "")]
+                    (repo-handler/create-repo! repo branch))
 
 
-                   (notification/show!
-                    [:p.text-gray-700.dark:text-gray-300 "Please input a valid repo url, e.g. https://github.com/username/repo"]
-                    :error
-                    false)))))))]])))
+                  (notification/show!
+                   [:p.text-gray-700.dark:text-gray-300 "Please input a valid repo url, e.g. https://github.com/username/repo"]
+                   :error
+                   false)))))))]]))
 
 
 (rum/defc add-local-directory
 (rum/defc add-local-directory
   []
   []
-  (rum/with-context [[t] i18n/*tongue-context*]
-    [:div.flex.flex-col
-     [:h1.title (t :on-boarding/add-graph)]
-     (let [nfs-supported? (or (nfs/supported?) (mobile-util/is-native-platform?))]
-       (if (mobile-util/is-native-platform?)
-         [:div.text-sm
-          (ui/button "Open a local directory"
-            :on-click #(page-handler/ls-dir-files! shortcut/refresh!))
-          [:hr]
-          [:ol
-           [:li
-            [:div.font-bold.mb-2 "How to sync my notes?"]
-            (if (mobile-util/native-android?)
-              [:div
-               [:p "We're developing our built-in paid Logseq Sync, but you can use any third-party sync service to keep your notes sync with other devices."]
-               [:p "If you prefer to use Dropbox to sync your notes, you can use "
-                [:a {:href "https://play.google.com/store/apps/details?id=com.ttxapps.dropsync"
-                     :target "_blank"}
-                 "Dropsync"]
-                ". Or you can use "
-                [:a {:href "https://play.google.com/store/apps/details?id=dk.tacit.android.foldersync.lite"
-                     :target "_blank"}
-                 "FolderSync"]
-                "."]]
-              [:div
-               [:p "You can sync your graphs by using iCloud. Please choose an existing graph or create a new graph in your iCloud Drive's Logseq directory."]
-               [:p "We're developing our built-in paid Logseq Sync. Stay tuned."]])]
+  [:div.flex.flex-col
+   [:h1.title (t :on-boarding/add-graph)]
+   (let [nfs-supported? (or (nfs/supported?) (mobile-util/is-native-platform?))]
+     (if (mobile-util/is-native-platform?)
+       [:div.text-sm
+        (ui/button "Open a local directory"
+          :on-click #(page-handler/ls-dir-files! shortcut/refresh!))
+        [:hr]
+        [:ol
+         [:li
+          [:div.font-bold.mb-2 "How to sync my notes?"]
+          (if (mobile-util/native-android?)
+            [:div
+             [:p "We're developing our built-in paid Logseq Sync, but you can use any third-party sync service to keep your notes sync with other devices."]
+             [:p "If you prefer to use Dropbox to sync your notes, you can use "
+              [:a {:href "https://play.google.com/store/apps/details?id=com.ttxapps.dropsync"
+                   :target "_blank"}
+               "Dropsync"]
+              ". Or you can use "
+              [:a {:href "https://play.google.com/store/apps/details?id=dk.tacit.android.foldersync.lite"
+                   :target "_blank"}
+               "FolderSync"]
+              "."]]
+            [:div
+             [:p "You can sync your graphs by using iCloud. Please choose an existing graph or create a new graph in your iCloud Drive's Logseq directory."]
+             [:p "We're developing our built-in paid Logseq Sync. Stay tuned."]])]
 
 
-           [:li.mt-8
-            [:div.font-bold.mb-2 "I need some help"]
-            [:p "👋 Join our discord group to chat with the makers and our helpful community members."]
-            (ui/button "Join the community"
-                       :href "https://discord.gg/KpN4eHY"
-                       :target "_blank")]]]
-         [:div.cp__widgets-open-local-directory
-          [:div.select-file-wrap.cursor
-           (when nfs-supported?
-             {:on-click #(page-handler/ls-dir-files! shortcut/refresh!)})
-           [:div
-            [:h1.title (t :on-boarding/open-local-dir)]
-            [:p (t :on-boarding/new-graph-desc-1)]
-            [:p (t :on-boarding/new-graph-desc-2)]
-            [:ul
-             [:li (t :on-boarding/new-graph-desc-3)]
-             [:li (t :on-boarding/new-graph-desc-4)]
-             [:li (t :on-boarding/new-graph-desc-5)]]
-            (when-not nfs-supported?
-              (ui/admonition :warning
-                             [:p "It seems that your browser doesn't support the "
-                              [:a {:href   "https://web.dev/file-system-access/"
-                                   :target "_blank"}
-                               "new native filesystem API"]
-                              [:span ", please use any Chromium 86+ based browser like Chrome, Vivaldi, Edge, etc. Notice that the API doesn't support mobile browsers at the moment."]]))]]]))]))
+         [:li.mt-8
+          [:div.font-bold.mb-2 "I need some help"]
+          [:p "👋 Join our discord group to chat with the makers and our helpful community members."]
+          (ui/button "Join the community"
+            :href "https://discord.gg/KpN4eHY"
+            :target "_blank")]]]
+       [:div.cp__widgets-open-local-directory
+        [:div.select-file-wrap.cursor
+         (when nfs-supported?
+           {:on-click #(page-handler/ls-dir-files! shortcut/refresh!)})
+         [:div
+          [:h1.title (t :on-boarding/open-local-dir)]
+          [:p (t :on-boarding/new-graph-desc-1)]
+          [:p (t :on-boarding/new-graph-desc-2)]
+          [:ul
+           [:li (t :on-boarding/new-graph-desc-3)]
+           [:li (t :on-boarding/new-graph-desc-4)]
+           [:li (t :on-boarding/new-graph-desc-5)]]
+          (when-not nfs-supported?
+            (ui/admonition :warning
+                           [:p "It seems that your browser doesn't support the "
+                            [:a {:href   "https://web.dev/file-system-access/"
+                                 :target "_blank"}
+                             "new native filesystem API"]
+                            [:span ", please use any Chromium 86+ based browser like Chrome, Vivaldi, Edge, etc. Notice that the API doesn't support mobile browsers at the moment."]]))]]]))])
 
 
 (rum/defc android-permission-alert
 (rum/defc android-permission-alert
   []
   []
   (when (mobile-util/native-android?)
   (when (mobile-util/native-android?)
-    (rum/with-context [[_t] i18n/*tongue-context*]
-      [:div.flex.flex-col
-       [:h1.title "Storage access permission"]
-       [:div.text-sm
-        [:div
-         [:p "Logseq needs the permission to access your device storage. Read "
-          [:a {:href "https://developer.android.com/about/versions/11/privacy/storage#all-files-access"
-               :target "_blank"}
-           "more"]
-          "."]
-         [:div
-          (ui/button "Grant Permission"
-                     :on-click #(page-handler/ls-dir-files! shortcut/refresh!))]
-         [:p.mb-1 "Note:"]
-         [:ol
-          [:li "We will never access files outside of your graph folders you choose."]
-          [:li "If you have granted the permission, you don't need to do it again."]]]
-        [:hr]]])))
+    [:div.flex.flex-col
+     [:h1.title "Storage access permission"]
+     [:div.text-sm
+      [:div
+       [:p "Logseq needs the permission to access your device storage. Read "
+        [:a {:href "https://developer.android.com/about/versions/11/privacy/storage#all-files-access"
+             :target "_blank"}
+         "more"]
+        "."]
+       [:div
+        (ui/button "Grant Permission"
+          :on-click #(page-handler/ls-dir-files! shortcut/refresh!))]
+       [:p.mb-1 "Note:"]
+       [:ol
+        [:li "We will never access files outside of your graph folders you choose."]
+        [:li "If you have granted the permission, you don't need to do it again."]]]
+      [:hr]]]))
 
 
 (rum/defcs add-graph <
 (rum/defcs add-graph <
   [state & {:keys [graph-types]
   [state & {:keys [graph-types]
@@ -181,17 +177,15 @@
                              (keep generate-f)
                              (keep generate-f)
                              (vec)
                              (vec)
                              (interpose [:b.mt-10.mb-5.opacity-50 "OR"]))]
                              (interpose [:b.mt-10.mb-5.opacity-50 "OR"]))]
-    (rum/with-context [[_t] i18n/*tongue-context*]
-      [:div.p-8.flex.flex-col available-graph])))
+    [:div.p-8.flex.flex-col available-graph]))
 
 
 (rum/defc demo-graph-alert
 (rum/defc demo-graph-alert
   []
   []
   (when (and (config/demo-graph?)
   (when (and (config/demo-graph?)
              (not config/publishing?))
              (not config/publishing?))
-    (rum/with-context [[t] i18n/*tongue-context*]
-      (ui/admonition
-        :warning
-        [:p (t :on-boarding/demo-graph)]))))
+    (ui/admonition
+     :warning
+     [:p (t :on-boarding/demo-graph)])))
 
 
 (rum/defc github-integration-soon-deprecated-alert
 (rum/defc github-integration-soon-deprecated-alert
   []
   []

+ 11 - 21
src/main/frontend/context/i18n.cljs

@@ -15,26 +15,16 @@
 (defn fetch-local-language []
 (defn fetch-local-language []
   (.. js/window -navigator -language))
   (.. js/window -navigator -language))
 
 
-(rum/defcontext *tongue-context*)
+(defonce translate-dicts (atom {}))
 
 
-;; FIXME: reactive
-(defonce t
+(defn t
+  [& args]
   (let [preferred-language (keyword (state/sub :preferred-language))
   (let [preferred-language (keyword (state/sub :preferred-language))
-        set-preferred-language state/set-preferred-language!
-        all-dicts (deep-merge dicts/dicts shortcut-dict/dict)
-        t (partial (dicts/translate all-dicts) preferred-language)]
-    (if (nil? preferred-language)
-      (set-preferred-language (fetch-local-language))
-      :ok)
-    t))
-
-(rum/defc tongue-provider [children]
-  (let [preferred-language (keyword (state/sub :preferred-language))
-        set-preferred-language state/set-preferred-language!
-        all-dicts (deep-merge dicts/dicts shortcut-dict/dict)
-        t (partial (dicts/translate all-dicts) preferred-language)]
-    (if (nil? preferred-language)
-      (set-preferred-language (fetch-local-language))
-      :ok)
-    (rum/bind-context [*tongue-context* [t preferred-language set-preferred-language]]
-                      children)))
+        _ (when (nil? preferred-language)
+            (state/set-preferred-language! (fetch-local-language)))
+        dicts (or (get @translate-dicts preferred-language)
+                  (let [result (some-> (deep-merge dicts/dicts shortcut-dict/dict)
+                                       dicts/translate)]
+                    (swap! translate-dicts assoc preferred-language result)
+                    result))]
+    (apply (partial dicts preferred-language) args)))

+ 123 - 129
src/main/frontend/extensions/pdf/highlights.cljs

@@ -2,7 +2,7 @@
   (:require [cljs-bean.core :as bean]
   (:require [cljs-bean.core :as bean]
             [clojure.string :as string]
             [clojure.string :as string]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.extensions.pdf.assets :as pdf-assets]
             [frontend.extensions.pdf.assets :as pdf-assets]
             [frontend.extensions.pdf.utils :as pdf-utils]
             [frontend.extensions.pdf.utils :as pdf-utils]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
@@ -117,62 +117,59 @@
         #())
         #())
       [])
       [])
 
 
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
+    [:ul.extensions__pdf-hls-ctx-menu
+     {:ref      *el
+      :style    {:top top :left left}
+      :on-click (fn [^js/MouseEvent e]
+                  (when-let [action (.. e -target -dataset -action)]
+                    (case action
+                      "ref"
+                      (pdf-assets/copy-hl-ref! highlight)
 
 
-      [:ul.extensions__pdf-hls-ctx-menu
-       {:ref      *el
-        :style    {:top top :left left}
-        :on-click (fn [^js/MouseEvent e]
-                    (when-let [action (.. e -target -dataset -action)]
-                      (case action
-                        "ref"
-                        (pdf-assets/copy-hl-ref! highlight)
-
-                        "copy"
-                        (do
-                          (front-utils/copy-to-clipboard!
-                            (or (:text content) (.toString range)))
-                          (pdf-utils/clear-all-selection))
+                      "copy"
+                      (do
+                        (front-utils/copy-to-clipboard!
+                         (or (:text content) (.toString range)))
+                        (pdf-utils/clear-all-selection))
 
 
-                        "link"
-                        (pdf-assets/goto-block-ref! highlight)
+                      "link"
+                      (pdf-assets/goto-block-ref! highlight)
 
 
-                        "del"
-                        (do
-                          (del-hl! highlight)
-                          (pdf-assets/del-ref-block! highlight)
-                          (pdf-assets/unlink-hl-area-image$ viewer (:pdf/current @state/state) highlight))
+                      "del"
+                      (do
+                        (del-hl! highlight)
+                        (pdf-assets/del-ref-block! highlight)
+                        (pdf-assets/unlink-hl-area-image$ viewer (:pdf/current @state/state) highlight))
 
 
-                        ;; colors
-                        (let [properties {:color action}]
-                          (if-not id
-                            ;; add highlight
-                            (let [highlight (merge (if (fn? highlight) (highlight) highlight)
-                                                   {:id         (pdf-utils/gen-uuid)
-                                                    :properties properties})]
-                              (add-hl! highlight)
-                              (pdf-utils/clear-all-selection)
-                              (pdf-assets/copy-hl-ref! highlight))
+                      ;; colors
+                      (let [properties {:color action}]
+                        (if-not id
+                          ;; add highlight
+                          (let [highlight (merge (if (fn? highlight) (highlight) highlight)
+                                                 {:id         (pdf-utils/gen-uuid)
+                                                  :properties properties})]
+                            (add-hl! highlight)
+                            (pdf-utils/clear-all-selection)
+                            (pdf-assets/copy-hl-ref! highlight))
 
 
-                            ;; update highlight
-                            (upd-hl! (assoc highlight :properties properties))))))
+                          ;; update highlight
+                          (upd-hl! (assoc highlight :properties properties))))))
 
 
-                    (clear-ctx-tip!))}
+                  (clear-ctx-tip!))}
 
 
-       [:li.item-colors
-        (for [it ["yellow", "blue", "green", "red", "purple"]]
-          [:a {:key it :data-color it :data-action it} it])]
+     [:li.item-colors
+      (for [it ["yellow", "blue", "green", "red", "purple"]]
+        [:a {:key it :data-color it :data-action it} it])]
 
 
 
 
-       (and id [:li.item {:data-action "ref"} (t :pdf/copy-ref)])
+     (and id [:li.item {:data-action "ref"} (t :pdf/copy-ref)])
 
 
-       (and (not (:image content)) [:li.item {:data-action "copy"} (t :pdf/copy-text)])
+     (and (not (:image content)) [:li.item {:data-action "copy"} (t :pdf/copy-text)])
 
 
-       (and id [:li.item {:data-action "link"} (t :pdf/linked-ref)])
+     (and id [:li.item {:data-action "link"} (t :pdf/linked-ref)])
 
 
-       (and id [:li.item {:data-action "del"} (t :delete)])
-       ])))
+     (and id [:li.item {:data-action "del"} (t :delete)])
+     ]))
 
 
 (rum/defc pdf-highlights-text-region
 (rum/defc pdf-highlights-text-region
   [^js viewer vw-hl hl
   [^js viewer vw-hl hl
@@ -827,90 +824,87 @@
             #(.off bus "pagechanging" page-fn))))
             #(.off bus "pagechanging" page-fn))))
       [viewer])
       [viewer])
 
 
-    (rum/with-context
-      [[t] i18n/*tongue-context*]
-
-      [:div.extensions__pdf-toolbar
-       [:div.inner
-        [:div.r.flex.buttons
-
-         ;; appearance
-         [:a.button
-          {:title    "More settings"
-           :on-click #(set-settings-visible! (not settings-visible?))}
-          (svg/adjustments 18)]
-
-         ;; selection
-         [:a.button
-          {:title    (str "Area highlight (" (if front-utils/mac? "⌘" "Shift") ")")
-           :class    (when area-mode? "is-active")
-           :on-click #(set-area-mode! (not area-mode?))}
-          (svg/icon-area 18)]
-
-         ;; zoom
-         [:a.button
-          {:title    "Zoom out"
-           :on-click (partial pdf-utils/zoom-out-viewer viewer)}
-          (svg/zoom-out 18)]
-
-         [:a.button
-          {:title    "Zoom in"
-           :on-click (partial pdf-utils/zoom-in-viewer viewer)}
-          (svg/zoom-in 18)]
-
-         [:a.button
-          {:title    "Outline"
-           :on-click #(set-outline-visible! (not outline-visible?))}
-          (svg/view-list 16)]
-
-         ;; metadata
-         [:a.button.is-info
-          {:title    "Document info"
-           :on-click #(p/let [ret (pdf-utils/get-meta-data$ viewer)]
-                        (state/set-modal! (make-docinfo-in-modal ret)))}
-          (svg/icon-info)]
-
-         ;; annotations
-         [:a.button
-          {:title    "Annotations page"
-           :on-click #(pdf-assets/goto-annotations-page! (:pdf/current @state/state))}
-          (svg/annotations 16)]
-
-         ;; pager
-         [:div.pager.flex.items-center.ml-1
-
-          [:span.nu.flex.items-center.opacity-70
-           [:input {:ref            *page-ref
-                    :type           "number"
-                    :default-value  current-page-num
-                    :on-mouse-enter #(.select ^js (.-target %))
-                    :on-key-up      (fn [^js e]
-                                      (let [^js input (.-target e)
-                                            value (front-utils/safe-parse-int (.-value input))]
-                                        (when (and (= (.-keyCode e) 13) value (> value 0))
-                                          (set! (. viewer -currentPageNumber)
-                                                (if (> value total-page-num) total-page-num value)))))}]
-           [:small "/ " total-page-num]]
-
-          [:span.ct.flex.items-center
-           [:a.button {:on-click #(. viewer previousPage)} (svg/up-narrow)]
-           [:a.button {:on-click #(. viewer nextPage)} (svg/down-narrow)]]]
-
-         [:a.button
-          {:on-click #(state/set-state! :pdf/current nil)}
-          (t :close)]]]
-
-       ;; contents outline
-       (pdf-outline viewer outline-visible? set-outline-visible!)
-
-       ;; settings
-       (and settings-visible?
-            (pdf-settings
-              viewer
-              viewer-theme
-              {:t t
-               :hide-settings! #(set-settings-visible! false)
-               :select-theme!  #(set-viewer-theme! %)}))])))
+    [:div.extensions__pdf-toolbar
+     [:div.inner
+      [:div.r.flex.buttons
+
+       ;; appearance
+       [:a.button
+        {:title    "More settings"
+         :on-click #(set-settings-visible! (not settings-visible?))}
+        (svg/adjustments 18)]
+
+       ;; selection
+       [:a.button
+        {:title    (str "Area highlight (" (if front-utils/mac? "⌘" "Shift") ")")
+         :class    (when area-mode? "is-active")
+         :on-click #(set-area-mode! (not area-mode?))}
+        (svg/icon-area 18)]
+
+       ;; zoom
+       [:a.button
+        {:title    "Zoom out"
+         :on-click (partial pdf-utils/zoom-out-viewer viewer)}
+        (svg/zoom-out 18)]
+
+       [:a.button
+        {:title    "Zoom in"
+         :on-click (partial pdf-utils/zoom-in-viewer viewer)}
+        (svg/zoom-in 18)]
+
+       [:a.button
+        {:title    "Outline"
+         :on-click #(set-outline-visible! (not outline-visible?))}
+        (svg/view-list 16)]
+
+       ;; metadata
+       [:a.button.is-info
+        {:title    "Document info"
+         :on-click #(p/let [ret (pdf-utils/get-meta-data$ viewer)]
+                      (state/set-modal! (make-docinfo-in-modal ret)))}
+        (svg/icon-info)]
+
+       ;; annotations
+       [:a.button
+        {:title    "Annotations page"
+         :on-click #(pdf-assets/goto-annotations-page! (:pdf/current @state/state))}
+        (svg/annotations 16)]
+
+       ;; pager
+       [:div.pager.flex.items-center.ml-1
+
+        [:span.nu.flex.items-center.opacity-70
+         [:input {:ref            *page-ref
+                  :type           "number"
+                  :default-value  current-page-num
+                  :on-mouse-enter #(.select ^js (.-target %))
+                  :on-key-up      (fn [^js e]
+                                    (let [^js input (.-target e)
+                                          value (front-utils/safe-parse-int (.-value input))]
+                                      (when (and (= (.-keyCode e) 13) value (> value 0))
+                                        (set! (. viewer -currentPageNumber)
+                                              (if (> value total-page-num) total-page-num value)))))}]
+         [:small "/ " total-page-num]]
+
+        [:span.ct.flex.items-center
+         [:a.button {:on-click #(. viewer previousPage)} (svg/up-narrow)]
+         [:a.button {:on-click #(. viewer nextPage)} (svg/down-narrow)]]]
+
+       [:a.button
+        {:on-click #(state/set-state! :pdf/current nil)}
+        (t :close)]]]
+
+     ;; contents outline
+     (pdf-outline viewer outline-visible? set-outline-visible!)
+
+     ;; settings
+     (and settings-visible?
+          (pdf-settings
+           viewer
+           viewer-theme
+           {:t t
+            :hide-settings! #(set-settings-visible! false)
+            :select-theme!  #(set-viewer-theme! %)}))]))
 
 
 (rum/defc pdf-viewer
 (rum/defc pdf-viewer
   [url initial-hls ^js pdf-document ops]
   [url initial-hls ^js pdf-document ops]

+ 1 - 26
src/main/frontend/format/mldoc.cljs

@@ -9,9 +9,7 @@
             [lambdaisland.glogi :as log]
             [lambdaisland.glogi :as log]
             [medley.core :as medley]
             [medley.core :as medley]
             ["mldoc" :as mldoc :refer [Mldoc]]
             ["mldoc" :as mldoc :refer [Mldoc]]
-            [linked.core :as linked]
-            ;; [frontend.util.pool :as pool]
-            ))
+            [linked.core :as linked]))
 
 
 (defonce parseJson (gobj/get Mldoc "parseJson"))
 (defonce parseJson (gobj/get Mldoc "parseJson"))
 (defonce parseInlineJson (gobj/get Mldoc "parseInlineJson"))
 (defonce parseInlineJson (gobj/get Mldoc "parseInlineJson"))
@@ -199,29 +197,6 @@
         []))
         []))
     (log/error :edn/wrong-content-type content)))
     (log/error :edn/wrong-content-type content)))
 
 
-;; (defn ->edn-async
-;;   ([content config]
-;;    (->edn-async nil content config))
-;;   ([file content config]
-;;    (if util/node-test?
-;;      (p/resolved (->edn content config))
-;;      (try
-;;        (if (string/blank? content)
-;;          (p/resolved [])
-;;          (p/let [v (pool/add-parse-job! content config)]
-;;            (try
-;;              (-> v
-;;                  (util/json->clj)
-;;                  (update-src-full-content content)
-;;                  (collect-page-properties))
-;;              (catch js/Error e
-;;                (println :parser/failed file)
-;;                (js/console.error e)
-;;                (p/resolved [])))))
-;;        (catch js/Error e
-;;          (log/error :parser/failed e)
-;;          (p/resolved []))))))
-
 (defn opml->edn
 (defn opml->edn
   [content]
   [content]
   (try
   (try

+ 0 - 2
src/main/frontend/handler.cljs

@@ -26,7 +26,6 @@
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.storage :as storage]
             [frontend.storage :as storage]
             [frontend.util :as util]
             [frontend.util :as util]
-            [frontend.util.pool :as pool]
             [cljs.reader :refer [read-string]]
             [cljs.reader :refer [read-string]]
             [goog.object :as gobj]
             [goog.object :as gobj]
             [lambdaisland.glogi :as log]
             [lambdaisland.glogi :as log]
@@ -237,7 +236,6 @@
     (reset! db/*sync-search-indice-f search/sync-search-indice!)
     (reset! db/*sync-search-indice-f search/sync-search-indice!)
     (db/run-batch-txs!)
     (db/run-batch-txs!)
     (file-handler/run-writes-chan!)
     (file-handler/run-writes-chan!)
-    (pool/init-parser-pool!)
     (when config/dev?
     (when config/dev?
       (enable-datalog-console))
       (enable-datalog-console))
     (when (util/electron?)
     (when (util/electron?)

+ 26 - 18
src/main/frontend/handler/repo.cljs

@@ -198,7 +198,7 @@
         (create-default-files! repo-url db-encrypted?)))
         (create-default-files! repo-url db-encrypted?)))
     (when re-render?
     (when re-render?
       (ui-handler/re-render-root! re-render-opts))
       (ui-handler/re-render-root! re-render-opts))
-    (state/set-importing-to-db! false)
+    (state/set-parsing-files! false)
     (state/pub-event! [:graph/added repo-url])))
     (state/pub-event! [:graph/added repo-url])))
 
 
 (defn- parse-files-and-create-default-files!
 (defn- parse-files-and-create-default-files!
@@ -212,26 +212,34 @@
       (parse-files-and-create-default-files-inner! repo-url files delete-files delete-blocks file-paths first-clone? db-encrypted? re-render? re-render-opts metadata opts))
       (parse-files-and-create-default-files-inner! repo-url files delete-files delete-blocks file-paths first-clone? db-encrypted? re-render? re-render-opts metadata opts))
     (parse-files-and-create-default-files-inner! repo-url files delete-files delete-blocks file-paths first-clone? db-encrypted? re-render? re-render-opts metadata opts)))
     (parse-files-and-create-default-files-inner! repo-url files delete-files delete-blocks file-paths first-clone? db-encrypted? re-render? re-render-opts metadata opts)))
 
 
+(defn- update-parsing-state!
+  [repo-url refresh?]
+  (state/set-loading-files! repo-url false)
+  (when-not refresh? (state/set-parsing-files! true)))
+
 (defn parse-files-and-load-to-db!
 (defn parse-files-and-load-to-db!
   [repo-url files {:keys [first-clone? delete-files delete-blocks re-render? re-render-opts refresh?] :as opts
   [repo-url files {:keys [first-clone? delete-files delete-blocks re-render? re-render-opts refresh?] :as opts
                    :or {re-render? true}}]
                    :or {re-render? true}}]
-  (state/set-loading-files! repo-url false)
-  (when-not refresh? (state/set-importing-to-db! true))
-  (let [file-paths (map :file/path files)
-        metadata-file (config/get-metadata-path)
-        metadata-content (some #(when (= (:file/path %) metadata-file)
-                                  (:file/content %)) files)
-        metadata (when metadata-content
-                   (common-handler/read-metadata! metadata-content))
-        db-encrypted? (:db/encrypted? metadata)
-        db-encrypted-secret (if db-encrypted? (:db/encrypted-secret metadata) nil)]
-    (if db-encrypted?
-      (let [close-fn #(parse-files-and-create-default-files! repo-url files delete-files delete-blocks file-paths first-clone? db-encrypted? re-render? re-render-opts metadata opts)]
-        (state/set-state! :encryption/graph-parsing? true)
-        (state/pub-event! [:modal/encryption-input-secret-dialog repo-url
-                           db-encrypted-secret
-                           close-fn]))
-      (parse-files-and-create-default-files! repo-url files delete-files delete-blocks file-paths first-clone? db-encrypted? re-render? re-render-opts metadata opts))))
+  (update-parsing-state! repo-url refresh?)
+  ;; TODO: parsing rotating ui will be not refreshed without setTimeout
+  (js/setTimeout
+   (fn []
+     (let [file-paths (map :file/path files)
+           metadata-file (config/get-metadata-path)
+           metadata-content (some #(when (= (:file/path %) metadata-file)
+                                     (:file/content %)) files)
+           metadata (when metadata-content
+                      (common-handler/read-metadata! metadata-content))
+           db-encrypted? (:db/encrypted? metadata)
+           db-encrypted-secret (if db-encrypted? (:db/encrypted-secret metadata) nil)]
+       (if db-encrypted?
+         (let [close-fn #(parse-files-and-create-default-files! repo-url files delete-files delete-blocks file-paths first-clone? db-encrypted? re-render? re-render-opts metadata opts)]
+           (state/set-state! :encryption/graph-parsing? true)
+           (state/pub-event! [:modal/encryption-input-secret-dialog repo-url
+                              db-encrypted-secret
+                              close-fn]))
+         (parse-files-and-create-default-files! repo-url files delete-files delete-blocks file-paths first-clone? db-encrypted? re-render? re-render-opts metadata opts))))
+   100))
 
 
 (defn load-repo-to-db!
 (defn load-repo-to-db!
   [repo-url {:keys [first-clone? diffs nfs-files refresh? new-graph?]}]
   [repo-url {:keys [first-clone? diffs nfs-files refresh? new-graph?]}]

+ 8 - 10
src/main/frontend/page.cljs

@@ -3,8 +3,7 @@
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.components.sidebar :as sidebar]
             [frontend.components.sidebar :as sidebar]
-            [frontend.handler.plugin :as plugin-handler]
-            [frontend.context.i18n :as i18n]))
+            [frontend.handler.plugin :as plugin-handler]))
 
 
 (rum/defc route-view
 (rum/defc route-view
   [view route-match]
   [view route-match]
@@ -32,14 +31,13 @@
                      (teardown)))}
                      (teardown)))}
   []
   []
   (when-let [route-match (state/sub :route-match)]
   (when-let [route-match (state/sub :route-match)]
-    (i18n/tongue-provider
-     (let [route-name (get-in route-match [:data :name])]
-       (when-let [view (:view (:data route-match))]
-         (if (= :draw route-name)
-           (view route-match)
-           (sidebar/sidebar
-            route-match
-            (view route-match))))))))
+    (let [route-name (get-in route-match [:data :name])]
+      (when-let [view (:view (:data route-match))]
+        (if (= :draw route-name)
+          (view route-match)
+          (sidebar/sidebar
+           route-match
+           (view route-match)))))))
 
 
         ;; FIXME: disable for now
         ;; FIXME: disable for now
         ;; (let [route-name (get-in route-match [:data :name])
         ;; (let [route-name (get-in route-match [:data :name])

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

@@ -31,8 +31,9 @@
      :notification/show?                    false
      :notification/show?                    false
      :notification/content                  nil
      :notification/content                  nil
      :repo/cloning?                         false
      :repo/cloning?                         false
+     ;; :repo/loading-files? is only for github repos
      :repo/loading-files?                   {}
      :repo/loading-files?                   {}
-     :repo/importing-to-db?                 nil
+     :repo/parsing-files?                   nil
      :repo/changed-files                    nil
      :repo/changed-files                    nil
      :nfs/user-granted?                     {}
      :nfs/user-granted?                     {}
      :nfs/refreshing?                       nil
      :nfs/refreshing?                       nil
@@ -1282,9 +1283,9 @@
   [repo]
   [repo]
   (get-in @state [:repo/loading-files? repo]))
   (get-in @state [:repo/loading-files? repo]))
 
 
-(defn set-importing-to-db!
+(defn set-parsing-files!
   [value]
   [value]
-  (set-state! :repo/importing-to-db? value))
+  (set-state! :repo/parsing-files? value))
 
 
 (defn set-editor-last-input-time!
 (defn set-editor-last-input-time!
   [repo time]
   [repo time]

+ 50 - 52
src/main/frontend/ui.cljs

@@ -1,7 +1,7 @@
 (ns frontend.ui
 (ns frontend.ui
   (:require [clojure.string :as string]
   (:require [clojure.string :as string]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
-            [frontend.context.i18n :as i18n]
+            [frontend.context.i18n :refer [t]]
             [frontend.handler.notification :as notification-handler]
             [frontend.handler.notification :as notification-handler]
             [frontend.mixins :as mixins]
             [frontend.mixins :as mixins]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.core :as shortcut]
@@ -392,15 +392,14 @@
   "Render an infinite list."
   "Render an infinite list."
   [state _list-element-id body {:keys [on-load has-more more more-class]
   [state _list-element-id body {:keys [on-load has-more more more-class]
                                :or {more-class "text-sm"}}]
                                :or {more-class "text-sm"}}]
-  (rum/with-context [[t] i18n/*tongue-context*]
-    [:div
-     body
-     (when has-more
-       [:div.w-full.p-4
-        [:a.fade-link.text-link.font-bold
-         {:on-click on-load
-          :class more-class}
-         (or more (t :page/earlier))]])]))
+  [:div
+   body
+   (when has-more
+     [:div.w-full.p-4
+      [:a.fade-link.text-link.font-bold
+       {:on-click on-load
+        :class more-class}
+       (or more (t :page/earlier))]])])
 
 
 (rum/defcs auto-complete <
 (rum/defcs auto-complete <
   (rum/local 0 ::current-idx)
   (rum/local 0 ::current-idx)
@@ -568,48 +567,47 @@
   [{:keys [tag title sub-title sub-checkbox? on-cancel on-confirm]
   [{:keys [tag title sub-title sub-checkbox? on-cancel on-confirm]
     :or {on-cancel #()}}]
     :or {on-cancel #()}}]
   (fn [close-fn]
   (fn [close-fn]
-    (rum/with-context [[t] i18n/*tongue-context*]
-      (let [*sub-checkbox-selected (and sub-checkbox? (atom []))]
-        [:div.ui__confirm-modal
-         {:class (str "is-" tag)}
-         [:div.sm:flex.sm:items-start
-          [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
-           [:svg.h-6.w-6.text-red-600
-            {:stroke "currentColor", :view-box "0 0 24 24", :fill "none"}
-            [:path
-             {:d
-              "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
-              :stroke-width    "2"
-              :stroke-linejoin "round"
-              :stroke-linecap  "round"}]]]
-          [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
-           [:h2.headline.text-lg.leading-6.font-medium
-            (if (keyword? title) (t title) title)]
-           [:label.sublabel
-            (when sub-checkbox?
-              (checkbox
-               {:default-value false
-                :on-change     (fn [e]
-                                 (let [checked (.. e -target -checked)]
-                                   (reset! *sub-checkbox-selected [checked])))}))
-            [:h3.subline.text-gray-400
-             (if (keyword? sub-title)
-               (t sub-title)
-               sub-title)]]]]
-
-         [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
-          [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
-           [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-            {:type     "button"
-             :on-click #(and (fn? on-confirm)
-                             (on-confirm % {:close-fn close-fn
-                                            :sub-selected (and *sub-checkbox-selected @*sub-checkbox-selected)}))}
-            (t :yes)]]
-          [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
-           [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
-            {:type     "button"
-             :on-click (comp on-cancel close-fn)}
-            (t :cancel)]]]]))))
+    (let [*sub-checkbox-selected (and sub-checkbox? (atom []))]
+      [:div.ui__confirm-modal
+       {:class (str "is-" tag)}
+       [:div.sm:flex.sm:items-start
+        [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
+         [:svg.h-6.w-6.text-red-600
+          {:stroke "currentColor", :view-box "0 0 24 24", :fill "none"}
+          [:path
+           {:d
+            "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
+            :stroke-width    "2"
+            :stroke-linejoin "round"
+            :stroke-linecap  "round"}]]]
+        [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
+         [:h2.headline.text-lg.leading-6.font-medium
+          (if (keyword? title) (t title) title)]
+         [:label.sublabel
+          (when sub-checkbox?
+            (checkbox
+             {:default-value false
+              :on-change     (fn [e]
+                               (let [checked (.. e -target -checked)]
+                                 (reset! *sub-checkbox-selected [checked])))}))
+          [:h3.subline.text-gray-400
+           (if (keyword? sub-title)
+             (t sub-title)
+             sub-title)]]]]
+
+       [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
+        [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
+         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+          {:type     "button"
+           :on-click #(and (fn? on-confirm)
+                           (on-confirm % {:close-fn close-fn
+                                          :sub-selected (and *sub-checkbox-selected @*sub-checkbox-selected)}))}
+          (t :yes)]]
+        [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
+         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+          {:type     "button"
+           :on-click (comp on-cancel close-fn)}
+          (t :cancel)]]]])))
 
 
 (rum/defc sub-modal < rum/reactive
 (rum/defc sub-modal < rum/reactive
   []
   []

+ 0 - 78
src/main/frontend/util/pool.cljs

@@ -1,78 +0,0 @@
-(ns frontend.util.pool
-  (:require [electron.ipc :as ipc]
-            [frontend.config :as config]
-            [frontend.util :as util]
-            [promesa.core :as p]
-            [clojure.string :as string]
-            ["threads" :refer [Pool Worker spawn]]
-            [frontend.mobile.util :as mobile-util]))
-
-(defonce parser-pool (atom nil))
-
-(defn- absolute-path-for-worker
-  "Returns the absolute path to the worker file, on Windows.
-
-   NOTE: This is a bug in threads.js.
-   See-also: https://github.com/andywer/threads.js/blob/8f94053f028b0d4e4fb1fdec535867f6d0e23946/src/master/implementation.browser.ts#L10"
-  [path]
-  (if util/win32?
-    (-> path
-        (p/then #(str "//./" (string/replace % "\\" "/"))))
-    path))
-
-(defn create-parser-pool!
-  ([]
-   (create-parser-pool! 8))
-  ([num]
-   (p/let [static-path (if (and (util/electron?)
-                                (= "file:" (.-protocol js/location)))
-                         (absolute-path-for-worker (ipc/ipc :getDirname))
-                         "/static")
-           path (str static-path "/js/parser-worker.js")
-           path (if (or (util/electron?)
-                        (mobile-util/is-native-platform?))
-                  path
-                  (config/asset-uri path))]
-     (Pool.
-      (fn []
-        (spawn (Worker. path) num))))))
-
-;; (defn finish-pool!
-;;   [{:keys [pool tasks]} ok-handler]
-;;   (-> (p/all @tasks)
-;;       (p/then (fn [result]
-;;                 (ok-handler result)
-;;                 (.completed pool)
-;;                 (.terminate pool)
-;;                 (reset! tasks nil)))))
-
-(defn terminate-pool!
-  [^js pool]
-  (p/let [_ (.completed pool)]
-    (.terminate pool)))
-
-(defn add-parse-job!
-  [content config]
-  (when-let [pool @parser-pool]
-    (.queue ^js pool
-            (fn [parser]
-              (try
-                (parser.parse content config)
-                (catch js/Error e
-                  (js/console.error e)
-                  nil)))))
-  ;; (let [task (.queue ^js pool
-  ;;                    (fn [parser]
-  ;;                      (parser.parse content config)))]
-  ;;   (swap! (:tasks m) conj task)
-  ;;   task)
-  )
-
-(defn init-parser-pool!
-  []
-  (p/let [pool (create-parser-pool!)]
-    (reset! parser-pool pool)))
-
-(comment
-  (add-parse-job! "- hello" (frontend.format.mldoc/default-config :markdown))
-  (add-parse-job! "*world*" (frontend.format.mldoc/default-config :markdown)))

+ 3 - 2
src/main/frontend/util/property.cljs

@@ -36,8 +36,9 @@
 
 
 (defn contains-properties?
 (defn contains-properties?
   [content]
   [content]
-  (and (string/includes? content properties-start)
-       (util/safe-re-find properties-end-pattern content)))
+  (when content
+    (and (string/includes? content properties-start)
+         (util/safe-re-find properties-end-pattern content))))
 
 
 (defn remove-empty-properties
 (defn remove-empty-properties
   [content]
   [content]

+ 0 - 14
src/main/frontend/worker/parser.cljs

@@ -1,14 +0,0 @@
-(ns frontend.worker.parser
-  (:require ["mldoc" :refer [Mldoc]]
-            ["threads/worker" :refer [expose]]))
-
-(def parse-json (.-parseJson Mldoc))
-
-(expose (clj->js {:parse parse-json}))
-
-(defn init
-  []
-  (println "Parser worker initialized!")
-  (js/self.addEventListener "message"
-                            (fn [^js e]
-                              (js/postMessage (.. e -data)))))

+ 1 - 1
src/main/logseq/api.cljs

@@ -507,7 +507,7 @@
                         ;; attached shallow children
                         ;; attached shallow children
                         (assoc block :block/children
                         (assoc block :block/children
                           (map #(list :uuid (get-in % [:data :block/uuid]))
                           (map #(list :uuid (get-in % [:data :block/uuid]))
-                            (outliner/get-children uuid))))]
+                            (db/get-block-immediate-children repo uuid))))]
             (bean/->js (normalize-keyword-for-json block))))))))
             (bean/->js (normalize-keyword-for-json block))))))))
 
 
 (def ^:export get_current_block
 (def ^:export get_current_block

+ 4 - 4
yarn.lock

@@ -5201,10 +5201,10 @@ mkdirp@^1.0.3:
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
   integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
   integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
 
 
-mldoc@1.2.8:
-  version "1.2.8"
-  resolved "https://registry.yarnpkg.com/mldoc/-/mldoc-1.2.8.tgz#e352471ca08c614d0cc2eab860b1b2749a791ebf"
-  integrity sha512-bzRYfeBzBSuenlwdzPb1AUohRrcmwg6t3o+y2YPXBPF2HpxuaAoBn3oMCBQ36IvVaLugyYqrq4dSrFbkK7VUPg==
+mldoc@1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/mldoc/-/mldoc-1.3.0.tgz#e72a157cc1204442ea5e90facd60837343a66338"
+  integrity sha512-qDxtIXzOheFJHq0d/4bDvMkM/VrhbDLMKw9MZurWbNPW6PxZQduC0BhXIGZyP4qT+pecZpUEMbUyMbNGn8ztsw==
   dependencies:
   dependencies:
     yargs "^12.0.2"
     yargs "^12.0.2"