Browse Source

Merge github-bendyorke:logseq/logseq into feat/cmdk

Ben Yorke 2 years ago
parent
commit
0f7f9adf9b
100 changed files with 558 additions and 2535 deletions
  1. 1 1
      .github/workflows/build.yml
  2. 1 1
      .github/workflows/stale-issues.yml
  3. 1 1
      .projectile
  4. 2 2
      android/app/build.gradle
  5. 2 1
      android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  6. 1 0
      android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  7. BIN
      android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png
  8. BIN
      android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png
  9. BIN
      android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png
  10. BIN
      android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png
  11. BIN
      android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png
  12. 1 0
      capacitor.config.ts
  13. 6 7
      deps/graph-parser/src/logseq/graph_parser/block.cljs
  14. 1 1
      deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs
  15. 2 5
      deps/graph-parser/src/logseq/graph_parser/whiteboard.cljs
  16. 3 3
      deps/graph-parser/test/logseq/graph_parser/block_test.cljs
  17. 3 3
      deps/shui/src/logseq/shui/context.cljs
  18. 18 5
      docs/dev-practices.md
  19. 3 3
      docs/develop-logseq-on-mobile.md
  20. 15 10
      docs/develop-logseq-on-windows.md
  21. 9 4
      docs/docker-web-app-guide.md
  22. 42 1
      e2e-tests/editor.spec.ts
  23. 30 8
      gulpfile.js
  24. 4 4
      ios/App/App.xcodeproj/project.pbxproj
  25. 1 0
      libs/package.json
  26. 10 5
      libs/src/LSPlugin.caller.ts
  27. 41 32
      libs/src/LSPlugin.core.ts
  28. 55 33
      libs/src/LSPlugin.ts
  29. 115 100
      libs/src/LSPlugin.user.ts
  30. 47 39
      libs/src/helpers.ts
  31. 2 1
      libs/src/modules/LSPlugin.Experiments.ts
  32. 34 36
      libs/src/modules/LSPlugin.Request.ts
  33. 48 51
      libs/src/modules/LSPlugin.Search.ts
  34. 1 1
      libs/src/modules/LSPlugin.Storage.ts
  35. 20 3
      libs/src/postmate/index.ts
  36. 11 6
      libs/yarn.lock
  37. 16 6
      package.json
  38. 2 1
      packages/amplify/package.json
  39. 6 0
      packages/amplify/src/LSAuthenticator.tsx
  40. 1 2
      packages/amplify/src/amplify.ts
  41. 3 3
      packages/amplify/yarn.lock
  42. 0 0
      resources/css/amplify.css
  43. 0 349
      resources/css/codemirror.min.css
  44. 0 160
      resources/css/codemirror.solarized.css
  45. 0 230
      resources/css/datepicker.css
  46. 0 0
      resources/css/excalidraw.min.css
  47. 0 13
      resources/css/fonts.css
  48. 0 200
      resources/css/inter.css
  49. 0 441
      resources/css/photoswipe.css
  50. 0 6
      resources/css/reveal.min.css
  51. 0 0
      resources/css/reveal_black.min.css
  52. 0 9
      resources/css/shepherd.css
  53. 0 36
      resources/css/show-hint.css
  54. 0 47
      resources/css/table.css
  55. 0 665
      resources/css/tooltip.css
  56. BIN
      resources/fonts/Cascadia.woff2
  57. BIN
      resources/fonts/FG_Virgil.woff2
  58. BIN
      resources/fonts/IBMPlexMono-Text-Latin1.woff
  59. BIN
      resources/fonts/IBMPlexSans-Bold.woff
  60. BIN
      resources/fonts/IBMPlexSans-Text.woff
  61. BIN
      resources/fonts/IBMPlexSans-TextItalic.woff
  62. BIN
      resources/fonts/Virgil.woff2
  63. BIN
      resources/fonts/inter/Inter-Black.woff
  64. BIN
      resources/fonts/inter/Inter-Black.woff2
  65. BIN
      resources/fonts/inter/Inter-BlackItalic.woff
  66. BIN
      resources/fonts/inter/Inter-BlackItalic.woff2
  67. BIN
      resources/fonts/inter/Inter-Bold.woff
  68. BIN
      resources/fonts/inter/Inter-Bold.woff2
  69. BIN
      resources/fonts/inter/Inter-BoldItalic.woff
  70. BIN
      resources/fonts/inter/Inter-BoldItalic.woff2
  71. BIN
      resources/fonts/inter/Inter-ExtraBold.woff
  72. BIN
      resources/fonts/inter/Inter-ExtraBold.woff2
  73. BIN
      resources/fonts/inter/Inter-ExtraBoldItalic.woff
  74. BIN
      resources/fonts/inter/Inter-ExtraBoldItalic.woff2
  75. BIN
      resources/fonts/inter/Inter-ExtraLight.woff
  76. BIN
      resources/fonts/inter/Inter-ExtraLight.woff2
  77. BIN
      resources/fonts/inter/Inter-ExtraLightItalic.woff
  78. BIN
      resources/fonts/inter/Inter-ExtraLightItalic.woff2
  79. BIN
      resources/fonts/inter/Inter-Italic.woff
  80. BIN
      resources/fonts/inter/Inter-Italic.woff2
  81. BIN
      resources/fonts/inter/Inter-Light.woff
  82. BIN
      resources/fonts/inter/Inter-Light.woff2
  83. BIN
      resources/fonts/inter/Inter-LightItalic.woff
  84. BIN
      resources/fonts/inter/Inter-LightItalic.woff2
  85. BIN
      resources/fonts/inter/Inter-Medium.woff
  86. BIN
      resources/fonts/inter/Inter-Medium.woff2
  87. BIN
      resources/fonts/inter/Inter-MediumItalic.woff
  88. BIN
      resources/fonts/inter/Inter-MediumItalic.woff2
  89. BIN
      resources/fonts/inter/Inter-Regular.woff
  90. BIN
      resources/fonts/inter/Inter-Regular.woff2
  91. BIN
      resources/fonts/inter/Inter-SemiBold.woff
  92. BIN
      resources/fonts/inter/Inter-SemiBold.woff2
  93. BIN
      resources/fonts/inter/Inter-SemiBoldItalic.woff
  94. BIN
      resources/fonts/inter/Inter-SemiBoldItalic.woff2
  95. BIN
      resources/fonts/inter/Inter-Thin.woff
  96. BIN
      resources/fonts/inter/Inter-Thin.woff2
  97. BIN
      resources/fonts/inter/Inter-ThinItalic.woff
  98. BIN
      resources/fonts/inter/Inter-ThinItalic.woff2
  99. BIN
      resources/fonts/inter/Inter-italic.var.woff2
  100. BIN
      resources/fonts/inter/Inter-roman.var.woff2

+ 1 - 1
.github/workflows/build.yml

@@ -25,7 +25,7 @@ jobs:
       - name: Checkout Actions Repository
         uses: actions/checkout@v3
       - name: Check spelling with custom config file
-        uses: crate-ci/[email protected]3.10
+        uses: crate-ci/[email protected]6.8
         with:
           config: ./typos.toml
 

+ 1 - 1
.github/workflows/stale-issues.yml

@@ -30,7 +30,7 @@ jobs:
           stale-issue-label: ':status/automatic-stale'
           close-issue-label: ':status/automatic-closing'
           # trunk-ignore(yamllint/line-length)
-          exempt-issue-labels: ':status/hold, :status/WIP, :type/enhancement, type/can-be-reproduced, priority-A'
+          exempt-issue-labels: 'hold, WIP, :type/enhancement, can-be-reproduced, priority-A, :type/bug, :type/feature-request'
           remove-stale-when-updated: true
           stale-issue-message: |
             Hi There! 👋

+ 1 - 1
.projectile

@@ -11,7 +11,7 @@
 -/resources/static/js/katex.min.js
 -/resources/static/js/mhchem.min.js
 -/resources/static/js/mldoc.min.js
--/resources/static/js/reveal.min.js
+-/resources/static/js/reveal.js
 -/resources/static/js/sci.min.js
 -/resources/static/js/excalidraw.min.js
 -/resources/static/js/react-force-graph.min.js

+ 2 - 2
android/app/build.gradle

@@ -6,8 +6,8 @@ android {
         applicationId "com.logseq.app"
         minSdkVersion rootProject.ext.minSdkVersion
         targetSdkVersion rootProject.ext.targetSdkVersion
-        versionCode 63
-        versionName "0.9.10"
+        versionCode 68
+        versionName "0.9.15"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         aaptOptions {
              // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.

+ 2 - 1
android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -2,4 +2,5 @@
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
     <background android:drawable="@color/ic_launcher_background"/>
     <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
-</adaptive-icon>
+    <monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
+</adaptive-icon>

+ 1 - 0
android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -2,4 +2,5 @@
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
     <background android:drawable="@color/ic_launcher_background"/>
     <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+    <monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
 </adaptive-icon>

BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png


BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png


BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png


BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png


BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png


+ 1 - 0
capacitor.config.ts

@@ -8,6 +8,7 @@ const config: CapacitorConfig = {
   appName: 'Logseq',
   bundledWebRuntime: false,
   webDir: 'public',
+  loggingBehavior: 'debug',
   plugins: {
     SplashScreen: {
       launchShowDuration: 500,

+ 6 - 7
deps/graph-parser/src/logseq/graph_parser/block.cljs

@@ -527,7 +527,6 @@
                                 :block/properties-text-values properties-text-values
                                 :block/invalid-properties invalid-properties
                                 :block/pre-block? true
-                                :block/unordered true
                                 :block/macros (extract-macros-from-ast body)
                                 :block/body body}
                          {:keys [tags refs]}
@@ -561,12 +560,12 @@
                        :level (if unordered? (:level block) 1))
                 block)
         block (cond->
-                (-> (assoc block
-                           :uuid id
-                           :refs ref-pages-in-properties
-                           :format format
-                           :meta pos-meta)
-                    (dissoc :size))
+               (-> (assoc block
+                          :uuid id
+                          :refs ref-pages-in-properties
+                          :format format
+                          :meta pos-meta)
+                   (dissoc :size :unordered))
                 (or (seq (:properties properties)) markdown-heading?)
                 (assoc :properties (with-heading-property (:properties properties) markdown-heading? (:size block))
                        :properties-text-values (:properties-text-values properties)

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

@@ -153,7 +153,7 @@
   ;; only increase over time as the docs graph rarely has deletions
   (testing "Counts"
     (is (= 303 (count files)) "Correct file count")
-    (is (= 69499 (count (d/datoms db :eavt))) "Correct datoms count")
+    (is (= 63632 (count (d/datoms db :eavt))) "Correct datoms count")
 
     (is (= 5866
            (ffirst

+ 2 - 5
deps/graph-parser/src/logseq/graph_parser/whiteboard.cljs

@@ -78,14 +78,11 @@
   (let [shape? (shape-block? block)
         shape (block->shape block)
         default-page-ref {:block/name (gp-util/page-name-sanity-lc page-name)}]
-    (merge (if shape?
+    (merge (when shape?
              (merge
               {:block/uuid (uuid (:id shape))}
               (with-whiteboard-block-refs shape page-name)
-              (with-whiteboard-content shape))
-
-             ;; TODO: remove?
-             {:block/unordered true})
+              (with-whiteboard-content shape)))
            (when (nil? (:block/parent block)) {:block/parent default-page-ref})
            (when (nil? (:block/format block)) {:block/format :markdown}) ;; TODO: read from config
            {:block/page default-page-ref})))

+ 3 - 3
deps/graph-parser/test/logseq/graph_parser/block_test.cljs

@@ -24,19 +24,19 @@
              (not= (:uuid x) (:block/uuid result))
              (= (select-keys result
                              [:block/properties :block/content :block/properties-text-values :block/properties-order]) (gp-block/block-keywordize y))))
-    {:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :markdown, :meta {:start_pos 51, :end_pos 101}, :macros [], :unordered true, :content "bar\nid:: 63f199bc-c737-459f-983d-84acfcda14fe", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
+    {:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :markdown, :meta {:start_pos 51, :end_pos 101}, :macros [], :content "bar\nid:: 63f199bc-c737-459f-983d-84acfcda14fe", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
     {:properties {},
      :content "bar",
      :properties-text-values {},
      :properties-order []}
 
-    {:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :org, :meta {:start_pos 51, :end_pos 101}, :macros [], :unordered true, :content "bar\n:id: 63f199bc-c737-459f-983d-84acfcda14fe", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
+    {:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :org, :meta {:start_pos 51, :end_pos 101}, :macros [], :content "bar\n:id: 63f199bc-c737-459f-983d-84acfcda14fe", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
     {:properties {},
      :content "bar",
      :properties-text-values {},
      :properties-order []}
 
-    {:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :markdown, :meta {:start_pos 51, :end_pos 101}, :macros [], :unordered true, :content "bar\n  \n  id:: 63f199bc-c737-459f-983d-84acfcda14fe\nblock body", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
+    {:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :markdown, :meta {:start_pos 51, :end_pos 101}, :macros [], :content "bar\n  \n  id:: 63f199bc-c737-459f-983d-84acfcda14fe\nblock body", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
     {:properties {},
      :content "bar\nblock body",
      :properties-text-values {},

+ 3 - 3
deps/shui/src/logseq/shui/context.cljs

@@ -20,9 +20,9 @@
    :config app-config
    ;; Until components are converted over, they need to fallback to the old inline function 
    ;; Wrap the old inline function to allow for interception, but fallback to the old inline function
-   :inline-block (inline->inline-block inline block-config) 
+   :inline-block (inline->inline-block inline block-config)
    :map-inline-block (inline->map-inline-block inline block-config)
-   ;; Currently frontend component are provided an object map containin at least the following keys:
+   ;; Currently frontend component are provided an object map containing at least the following keys:
    ;; These will be passed through in a whitelisted fashion so as to be able to track the dependencies  
    ;; back to the core application
    ;; TODO: document the following
@@ -30,7 +30,7 @@
    :block? (:block? block-config)
    :blocks-container-id (:blocks-container-id block-config)
    :editor-box (:editor-box block-config)
-   :id (:id block-config) 
+   :id (:id block-config)
    :mode? (:mode? block-config)
    :query-result (:query-result block-config)
    :sidebar? (:sidebar? block-config)

+ 18 - 5
docs/dev-practices.md

@@ -74,11 +74,24 @@ error if it detects an invalid query.
 
 ### Translations
 
-Our translations can be configured incorrectly. We can catch some of these
-mistakes [as noted here](./contributing-to-translations.md#fix-mistakes).
-
-Punctuation and delimiting characters (e.g. `:`, `:`, `?`) should be part of the translatable string.
-Those characters and their position may vary depending on the language.
+We use [tongue](https://github.com/tonsky/tongue), a simple and effective
+library, for translations. We have a couple bb tasks for working with
+translations under `lang:` e.g. `bb lang:list`. See [the translator
+guide](./contributing-to-translations.md) for usage.
+
+One useful task for reviewers (us) and contributors alike, is `bb
+lang:validate-translations` which catches [common
+mistakes](./contributing-to-translations.md#fix-mistakes)). When reviewing
+translations here are some things to keep in mind:
+
+* Punctuation and delimiting characters (e.g. `:`, `:`, `?`) should be part of
+  the translatable string. Those characters and their position may vary depending on the language.
+* Translations usually return strings but they can return hiccup vectors with a
+  fn translation. Hiccup vectors are needed when word order matters for a
+  translation and formatting is involved. See [this 3 word Turkish
+  example](https://github.com/logseq/logseq/commit/1d932f07c4a0aad44606da6df03a432fe8421480#r118971415).
+* Translations can have arguments for interpolating strings. When they do, be
+  sure translators are using them correctly.
 
 ### Spell Checker
 

+ 3 - 3
docs/develop-logseq-on-mobile.md

@@ -24,7 +24,7 @@
     ```
 - Working directory: Logseq root directory
 - Run `yarn && yarn app-watch` from the logseq project root directory in terminal.
-- Run `npx cap sync ios` in another termimal to copy web assets from public to *ios/App/App/public*, and create *capacitor.config.json* in *ios/App/App*, and update iOS plugins.
+- Run `npx cap sync ios` in another terminal to copy web assets from public to *ios/App/App/public*, and create *capacitor.config.json* in *ios/App/App*, and update iOS plugins.
 - Connect your iOS device to MacBook.
 - Run `npx cap open ios` to open Logseq project in Xcode, and build the app there.
 
@@ -70,13 +70,13 @@ or, you can run `bb release:ios-app` to do those steps with one command.
         } 
     ```
 - Run `yarn && yarn app-watch` from the logseq project root directory in terminal.
-- Run `npx cap sync android` in another termimal.
+- Run `npx cap sync android` in another terminal.
 - Run `npx cap run android` to install app into your device.
 
 or, you can run `bb dev:android-app` to do those steps with one command if you are on macOS.
 
 Then,
-- In Android Studio, open **Tools** -> **AVD Manager** to create Android Virtual Device (AVD), and lanuch it in the emulator.
+- In Android Studio, open **Tools** -> **AVD Manager** to create Android Virtual Device (AVD), and launch it in the emulator.
 - In Android Studio, open **Run** -> **Run** to run Logseq.
 - After logseq startup in Android virtual device, repl should be able to connect
 - For browser console print and devtool remote debug, open chrome, type url chrome://inspect/#devices, you should see your device there, click inspect

+ 15 - 10
docs/develop-logseq-on-windows.md

@@ -2,6 +2,17 @@
 
 This is a guide on setting up Logseq development dependencies on Windows.  Once these dependencies are installed, you can follow the  [develop-logseq](develop-logseq.md) docs for build instructions.
 
+## [scoop](https://scoop.sh/)
+
+Scoop provides a `clojure.exe` shim which works in Command Prompt and Powershell windows.
+
+```
+scoop bucket add scoop-clojure https://github.com/littleli/scoop-clojure
+scoop bucket add extras
+scoop bucket add java
+scoop install java/openjdk clj-deps babashka leiningen nodejs-lts
+```
+
 ## Winget
 
 Winget is a package manager installed by default on windows.
@@ -19,6 +30,10 @@ An installer for clojure is available from [casselc/clj-msi](https://github.com/
 
 ## [chocolatey](https://chocolatey.org/)
 
+Chocolatey installs Clojure as a PowerShell module and alias, and does not provide `clojure` for `cmd.exe`.
+
+[@andelf has written a wrapper utility](https://github.com/andelf/clojure-cli) which you can install with `cargo install --git https://github.com/andelf/clojure-cli.git` instead.
+
 ```
 choco install nvm
 nvm install 18
@@ -29,16 +44,6 @@ choco install javaruntime
 choco install clojure
 ```
 
-
-## [scoop](https://scoop.sh/)
-
-```
-scoop bucket add scoop-clojure https://github.com/littleli/scoop-clojure
-scoop bucket add extras
-scoop bucket add java
-scoop install java/openjdk clojure clj-deps babashka leiningen nodejs-lts
-```
-
 ## Troubleshooting
 
 ### Configuring a proxy for internet access

+ 9 - 4
docs/docker-web-app-guide.md

@@ -3,17 +3,18 @@
 From v0.5.6, Logseq is also available as a Docker image of Web App.
 The Docker image is available at [ghcr.io/logseq/logseq-webapp:latest](https://github.com/logseq/logseq/pkgs/container/logseq-webapp).
 
-**NOTE:** Logseq web app uses [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) to access the file system. You need a [compatible browser](https://caniuse.com/native-filesystem-api).
-Also, an HTTPS connection is required if you are accessing it remotely.
+> **Note**
+> Logseq web app uses [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) to access the file system. You need a [compatible browser](https://caniuse.com/native-filesystem-api).
+> Also, an HTTPS connection is required if you are accessing it remotely.
 
 ## Simple one-line start(local machine)
 
 ```shell
 docker pull ghcr.io/logseq/logseq-webapp:latest
-docker run -d --rm -p 3001:80 ghcr.io/logseq/logseq-webapp:latest
+docker run -d --rm -p 127.0.0.1:3001:80 ghcr.io/logseq/logseq-webapp:latest
 ```
 
-Open the browser and go to http://localhost:3001.
+Open the browser and go to <http://localhost:3001>.
 
 ## Remote(non-local) access
 
@@ -70,6 +71,10 @@ docker pull ghcr.io/logseq/logseq-webapp:latest
 docker run -d --rm -p 8443:443 -v `pwd`:/etc/nginx/certs -v ./ssl.conf:/etc/nginx/conf.d/ssl.conf ghcr.io/logseq/logseq-webapp:latest
 ```
 
+> **Note**
+> The above command will expose the web app to the public network, which is not recommended and may cause security issues.
+> Please make sure the firewall is configured properly.
+
 ### Done!
 
 Open your browser and navigate to `https://192.168.11.95:8443`.

+ 42 - 1
e2e-tests/editor.spec.ts

@@ -817,4 +817,45 @@ test.describe('Auto-pair symbols only with text selection', () => {
       expect(selection).toBe('Lorem')
     })
   }
-})
+})
+
+test('copy blocks should remove all ref-related values', async ({ page, block }) => {
+  await createRandomPage(page)
+
+  await block.mustFill('test')
+  await page.keyboard.press(modKey + '+c', { delay: 10 })
+  await block.clickNext()
+  await page.keyboard.press(modKey + '+v')
+  await expect(page.locator('.open-block-ref-link')).toHaveCount(1)
+
+  await page.keyboard.press('ArrowUp', { delay: 10 })
+  await page.waitForTimeout(100)
+  await page.keyboard.press('Escape')
+  await expect(page.locator('.ls-block.selected')).toHaveCount(1)
+  await page.keyboard.press(modKey + '+c', { delay: 10 })
+  await block.clickNext()
+  await page.keyboard.press(modKey + '+v', { delay: 10 })
+  await block.clickNext() // let 3rd block leave editing state
+  await expect(page.locator('.open-block-ref-link')).toHaveCount(1)
+})
+
+test('undo cut block should recover refs', async ({ page, block }) => {
+  await createRandomPage(page)
+
+  await block.mustFill('test')
+  await page.keyboard.press(modKey + '+c', { delay: 10 })
+  await block.clickNext()
+  await page.keyboard.press(modKey + '+v')
+  await expect(page.locator('.open-block-ref-link')).toHaveCount(1)
+
+  await page.keyboard.press('ArrowUp', { delay: 10 })
+  await page.waitForTimeout(100)
+  await page.keyboard.press('Escape')
+  await expect(page.locator('.ls-block.selected')).toHaveCount(1)
+  await page.keyboard.press(modKey + '+x', { delay: 10 })
+  await expect(page.locator('.ls-block')).toHaveCount(1)
+  await page.keyboard.press(modKey + '+z')
+  await page.waitForTimeout(100)
+  await expect(page.locator('.ls-block')).toHaveCount(2)
+  await expect(page.locator('.open-block-ref-link')).toHaveCount(1)
+})

+ 30 - 8
gulpfile.js

@@ -52,17 +52,39 @@ const common = {
       () => gulp.src([
         './node_modules/@excalidraw/excalidraw/dist/excalidraw-assets/**',
         '!**/*/i18n-*.js'
-      ])
-        .pipe(gulp.dest(path.join(outputPath, 'js', 'excalidraw-assets'))),
-      () => gulp.src('node_modules/katex/dist/katex.min.js')
-        .pipe(gulp.dest(path.join(outputPath, 'js'))),
-      () => gulp.src('node_modules/@tabler/icons/iconfont/tabler-icons.min.css')
-        .pipe(gulp.dest(path.join(outputPath, 'css'))),
+      ]).pipe(gulp.dest(path.join(outputPath, 'js', 'excalidraw-assets'))),
+      () => gulp.src([
+        'node_modules/katex/dist/katex.min.js',
+        'node_modules/katex/dist/contrib/mhchem.min.js',
+        'node_modules/html2canvas/dist/html2canvas.min.js',
+        'node_modules/interactjs/dist/interact.min.js',
+        'node_modules/photoswipe/dist/umd/*.js',
+        'node_modules/reveal.js/dist/reveal.js',
+        'node_modules/shepherd.js/dist/js/shepherd.min.js',
+        'node_modules/marked/marked.min.js',
+        'node_modules/@highlightjs/cdn-assets/highlight.min.js',
+        'node_modules/@isomorphic-git/lightning-fs/dist/lightning-fs.min.js',
+        'packages/amplify/dist/amplify.js'
+      ]).pipe(gulp.dest(path.join(outputPath, 'js'))),
+      () => gulp.src([
+        'node_modules/pdfjs-dist/build/pdf.js',
+        'node_modules/pdfjs-dist/build/pdf.worker.js',
+        'node_modules/pdfjs-dist/web/pdf_viewer.js'
+      ]).pipe(gulp.dest(path.join(outputPath, 'js', 'pdfjs'))),
+      () => gulp.src([
+        'node_modules/pdfjs-dist/cmaps/*.*',
+      ]).pipe(gulp.dest(path.join(outputPath, 'js', 'pdfjs', 'cmaps'))),
+      () => gulp.src([
+        'node_modules/@tabler/icons/iconfont/tabler-icons.min.css',
+        'node_modules/inter-ui/inter.css',
+        'node_modules/reveal.js/dist/theme/fonts/source-sans-pro/**',
+      ]).pipe(gulp.dest(path.join(outputPath, 'css'))),
+      () => gulp.src('node_modules/inter-ui/Inter (web)/*.*')
+        .pipe(gulp.dest(path.join(outputPath, 'css', 'Inter (web)'))),
       () => gulp.src([
         'node_modules/@tabler/icons/iconfont/fonts/**',
         'node_modules/katex/dist/fonts/*.woff2'
-      ])
-        .pipe(gulp.dest(path.join(outputPath, 'css', 'fonts'))),
+      ]).pipe(gulp.dest(path.join(outputPath, 'css', 'fonts'))),
     )(...params)
   },
 

+ 4 - 4
ios/App/App.xcodeproj/project.pbxproj

@@ -519,7 +519,7 @@
 				INFOPLIST_FILE = App/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				MARKETING_VERSION = 0.9.10;
+				MARKETING_VERSION = 0.9.16;
 				OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
 				PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -546,7 +546,7 @@
 				INFOPLIST_FILE = App/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				MARKETING_VERSION = 0.9.10;
+				MARKETING_VERSION = 0.9.16;
 				PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
@@ -571,7 +571,7 @@
 				INFOPLIST_KEY_NSHumanReadableCopyright = "";
 				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 0.9.10;
+				MARKETING_VERSION = 0.9.16;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController;
@@ -598,7 +598,7 @@
 				INFOPLIST_KEY_NSHumanReadableCopyright = "";
 				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 0.9.10;
+				MARKETING_VERSION = 0.9.16;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController;
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 1 - 0
libs/package.json

@@ -18,6 +18,7 @@
   "dependencies": {
     "csstype": "3.1.0",
     "debug": "4.3.4",
+    "deepmerge": "4.3.1",
     "dompurify": "2.3.8",
     "eventemitter3": "4.0.7",
     "fast-deep-equal": "3.1.3",

+ 10 - 5
libs/src/LSPlugin.caller.ts

@@ -243,18 +243,23 @@ class LSPluginCaller extends EventEmitter {
         let { width, height, left, top, vw, vh } = mainLayoutInfo
 
         left = Math.max(left, 0)
-        left = (typeof vw === 'number') ?
-          `${Math.min(left * 100 / vw, 99)}%` : `${left}px`
+        left =
+          typeof vw === 'number'
+            ? `${Math.min((left * 100) / vw, 99)}%`
+            : `${left}px`
 
         // 45 is height of headbar
         top = Math.max(top, 45)
-        top = (typeof vh === 'number') ?
-          `${Math.min(top * 100 / vh, 99)}%` : `${top}px`
+        top =
+          typeof vh === 'number'
+            ? `${Math.min((top * 100) / vh, 99)}%`
+            : `${top}px`
 
         Object.assign(cnt.style, {
           width: width + 'px',
           height: height + 'px',
-          left, top
+          left,
+          top,
         })
       }
     } catch (e) {

+ 41 - 32
libs/src/LSPlugin.core.ts

@@ -91,7 +91,7 @@ class PluginSettings extends EventEmitter<'change' | 'reset'> {
       if (this._settings[k] == v) return
       this._settings[k] = v
     } else if (isObject(k)) {
-      deepMerge(this._settings, k)
+      this._settings = deepMerge(this._settings, k)
     } else {
       return
     }
@@ -395,11 +395,9 @@ class ExistedImportedPluginPackageError extends Error {
 /**
  * Host plugin for local
  */
-class PluginLocal extends EventEmitter<'loaded'
-  | 'unloaded'
-  | 'beforeunload'
-  | 'error'
-  | string> {
+class PluginLocal extends EventEmitter<
+  'loaded' | 'unloaded' | 'beforeunload' | 'error' | string
+> {
   private _sdk: Partial<PluginLocalSDKMetadata> = {}
   private _disposes: Array<() => Promise<any>> = []
   private _id: PluginLocalIdentity
@@ -534,7 +532,7 @@ class PluginLocal extends EventEmitter<'loaded'
     const localRoot = (this._localRoot = safetyPathNormalize(url))
     const logseq: Partial<LSPluginPkgConfig> = pkg.logseq || {}
 
-      // Pick legal attrs
+    // Pick legal attrs
     ;[
       'name',
       'author',
@@ -594,7 +592,9 @@ class PluginLocal extends EventEmitter<'loaded'
     // Validate id
     const { registeredPlugins, isRegistering } = this._ctx
     if (isRegistering && registeredPlugins.has(this.id)) {
-      throw new ExistedImportedPluginPackageError('Registered plugin package Error')
+      throw new ExistedImportedPluginPackageError(
+        'Registered plugin package Error'
+      )
     }
 
     return async () => {
@@ -642,10 +642,10 @@ class PluginLocal extends EventEmitter<'loaded'
     <meta charset="UTF-8">
     <title>logseq plugin entry</title>
     ${
-        IS_DEV
-          ? `<script src="${sdkPathRoot}/lsplugin.user.js?v=${tag}"></script>`
-          : `<script src="https://cdn.jsdelivr.net/npm/@logseq/libs/dist/lsplugin.user.min.js?v=${tag}"></script>`
-      }
+      IS_DEV
+        ? `<script src="${sdkPathRoot}/lsplugin.user.js?v=${tag}"></script>`
+        : `<script src="https://cdn.jsdelivr.net/npm/@logseq/libs/dist/lsplugin.user.min.js?v=${tag}"></script>`
+    }
     
   </head>
   <body>
@@ -924,7 +924,7 @@ class PluginLocal extends EventEmitter<'loaded'
           )
           this.emit('beforeunload', eventBeforeUnload)
         } catch (e) {
-          this.logger.error('[beforeunload Error]', e)
+          this.logger.error('[beforeunload]', e)
         }
 
         await this.dispose()
@@ -1103,7 +1103,8 @@ class LSPluginCore
     | 'beforereload'
     | 'reloaded'
   >
-  implements ILSPluginThemeManager {
+  implements ILSPluginThemeManager
+{
   private _isRegistering = false
   private _readyIndicator?: DeferredActor
   private readonly _hostMountedActor: DeferredActor = deferred()
@@ -1117,8 +1118,10 @@ class LSPluginCore
     externals: [],
   }
   private readonly _registeredThemes = new Map<PluginLocalIdentity, Theme[]>()
-  private readonly _registeredPlugins = new Map<PluginLocalIdentity,
-    PluginLocal>()
+  private readonly _registeredPlugins = new Map<
+    PluginLocalIdentity,
+    PluginLocal
+  >()
   private _currentTheme: {
     pid: PluginLocalIdentity
     opt: Theme | LegacyTheme
@@ -1194,14 +1197,18 @@ class LSPluginCore
       return
     }
 
-    const perfTable = new Map<string,
-      { o: PluginLocal; s: number; e: number }>()
+    const perfTable = new Map<
+      string,
+      { o: PluginLocal; s: number; e: number }
+    >()
     const debugPerfInfo = () => {
       const data: any = Array.from(perfTable.values()).reduce((ac, it) => {
         const { id, options, status, disabled } = it.o
 
-        if (disabled !== true &&
-          (options.entry || (!options.name && !options.entry))) {
+        if (
+          disabled !== true &&
+          (options.entry || (!options.name && !options.entry))
+        ) {
           ac[id] = {
             name: options.name,
             entry: options.entry,
@@ -1234,17 +1241,19 @@ class LSPluginCore
       // valid externals
       if (externals?.size) {
         try {
-          const validatedExternals: Record<string, boolean> = await invokeHostExportedApi(
-            'validate_external_plugins', [...externals]
-          )
+          const validatedExternals: Record<string, boolean> =
+            await invokeHostExportedApi('validate_external_plugins', [
+              ...externals,
+            ])
 
-          externals = new Set([...Object.entries(validatedExternals)].reduce(
-            (a, [k, v]) => {
+          externals = new Set(
+            [...Object.entries(validatedExternals)].reduce((a, [k, v]) => {
               if (v) {
                 a.push(k)
               }
               return a
-            }, []))
+            }, [])
+          )
         } catch (e) {
           console.error('[validatedExternals Error]', e)
         }
@@ -1557,12 +1566,12 @@ class LSPluginCore
       await this.saveUserPreferences(
         theme.mode
           ? {
-            themes: {
-              ...this._userPreferences.themes,
-              mode: theme.mode,
-              [theme.mode]: theme,
-            },
-          }
+              themes: {
+                ...this._userPreferences.themes,
+                mode: theme.mode,
+                [theme.mode]: theme,
+              },
+            }
           : { theme: theme }
       )
     }

+ 55 - 33
libs/src/LSPlugin.ts

@@ -6,7 +6,8 @@ import { LSPluginExperiments } from './modules/LSPlugin.Experiments'
 import { IAsyncStorage, LSPluginFileStorage } from './modules/LSPlugin.Storage'
 import { LSPluginRequest } from './modules/LSPlugin.Request'
 
-export type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
+export type WithOptional<T, K extends keyof T> = Omit<T, K> &
+  Partial<Pick<T, K>>
 
 export type PluginLocalIdentity = string
 
@@ -178,7 +179,6 @@ export interface BlockEntity {
   left: IEntityID
   format: 'markdown' | 'org'
   parent: IEntityID
-  unordered: boolean
   content: string
   page: IEntityID
   properties?: Record<string, any>
@@ -298,7 +298,12 @@ export type ExternalCommandType =
 export type UserProxyTags = 'app' | 'editor' | 'db' | 'git' | 'ui' | 'assets'
 
 export type SearchIndiceInitStatus = boolean
-export type SearchBlockItem = { id: EntityID, uuid: BlockIdentity, content: string, page: EntityID }
+export type SearchBlockItem = {
+  id: EntityID
+  uuid: BlockIdentity
+  content: string
+  page: EntityID
+}
 export type SearchPageItem = string
 export type SearchFileItem = string
 
@@ -310,21 +315,23 @@ export interface IPluginSearchServiceHooks {
     graph: string,
     key: string,
     opts: Partial<{ limit: number }>
-  ) =>
-    Promise<{
-      graph: string,
-      key: string,
-      blocks?: Array<Partial<SearchBlockItem>>,
-      pages?: Array<SearchPageItem>,
-      files?: Array<SearchFileItem>
-    }>
+  ) => Promise<{
+    graph: string
+    key: string
+    blocks?: Array<Partial<SearchBlockItem>>
+    pages?: Array<SearchPageItem>
+    files?: Array<SearchFileItem>
+  }>
 
   onIndiceInit: (graph: string) => Promise<SearchIndiceInitStatus>
   onIndiceReset: (graph: string) => Promise<void>
-  onBlocksChanged: (graph: string, changes: {
-    added: Array<SearchBlockItem>,
-    removed: Array<EntityID>
-  }) => Promise<void>
+  onBlocksChanged: (
+    graph: string,
+    changes: {
+      added: Array<SearchBlockItem>
+      removed: Array<EntityID>
+    }
+  ) => Promise<void>
   onGraphRemoved: (graph: string, opts?: {}) => Promise<any>
 }
 
@@ -373,8 +380,14 @@ export interface IAppProxy {
    * @param action
    */
   registerCommandShortcut: (
-    keybinding: SimpleCommandKeybinding,
-    action: SimpleCommandCallback
+    keybinding: SimpleCommandKeybinding | string,
+    action: SimpleCommandCallback,
+    opts?: Partial<{
+      key: string
+      label: string
+      desc: string
+      extras: Record<string, any>
+    }>
   ) => void
 
   /**
@@ -393,10 +406,7 @@ export interface IAppProxy {
    * @param type `xx-plugin-id.commands.xx-key`, `xx-plugin-id.models.xx-key`
    * @param args
    */
-  invokeExternalPlugin: (
-    type: string,
-    ...args: Array<any>
-  ) => Promise<unknown>
+  invokeExternalPlugin: (type: string, ...args: Array<any>) => Promise<unknown>
 
   /**
    * @added 0.0.13
@@ -453,7 +463,11 @@ export interface IAppProxy {
   // templates
   getTemplate: (name: string) => Promise<BlockEntity | null>
   existTemplate: (name: string) => Promise<Boolean>
-  createTemplate: (target: BlockUUID, name: string, opts?: { overwrite: boolean }) => Promise<any>
+  createTemplate: (
+    target: BlockUUID,
+    name: string,
+    opts?: { overwrite: boolean }
+  ) => Promise<any>
   removeTemplate: (name: string) => Promise<any>
   insertTemplate: (target: BlockUUID, name: string) => Promise<any>
 
@@ -496,15 +510,21 @@ export interface IAppProxy {
   onCurrentGraphChanged: IUserHook
   onGraphAfterIndexed: IUserHook<{ repo: string }>
   onThemeModeChanged: IUserHook<{ mode: 'dark' | 'light' }>
-  onThemeChanged: IUserHook<Partial<{ name: string, mode: string, pid: string, url: string }>>
+  onThemeChanged: IUserHook<
+    Partial<{ name: string; mode: string; pid: string; url: string }>>
   onTodayJournalCreated: IUserHook<{ title: string }>
+  onBeforeCommandInvoked: (condition: ExternalCommandType | string, callback: (e: IHookEvent) => void) => IUserOffHook
+  onAfterCommandInvoked: (condition: ExternalCommandType | string, callback: (e: IHookEvent) => void) => IUserOffHook
 
   /**
    * provide ui slot to specific block with UUID
    *
    * @added 0.0.13
    */
-  onBlockRendererSlotted: IUserConditionSlotHook<BlockUUID, Omit<BlockEntity, 'children' | 'page'>>
+  onBlockRendererSlotted: IUserConditionSlotHook<
+    BlockUUID,
+    Omit<BlockEntity, 'children' | 'page'>
+  >
 
   /**
    * provide ui slot to block `renderer` macro for `{{renderer arg1, arg2}}`
@@ -691,7 +711,7 @@ export interface IEditorProxy extends Record<string, any> {
   insertBatchBlock: (
     srcBlock: BlockIdentity,
     batch: IBatchBlock | Array<IBatchBlock>,
-    opts?: Partial<{ before: boolean; sibling: boolean, keepUUID: boolean }>
+    opts?: Partial<{ before: boolean; sibling: boolean; keepUUID: boolean }>
   ) => Promise<Array<BlockEntity> | null>
 
   updateBlock: (
@@ -897,14 +917,16 @@ export interface IAssetsProxy {
    * @added 0.0.2
    * @param exts
    */
-  listFilesOfCurrentGraph(exts?: string | string[]): Promise<Array<{
-    path: string
-    size: number
-    accessTime: number
-    modifiedTime: number
-    changeTime: number
-    birthTime: number
-  }>>
+  listFilesOfCurrentGraph(exts?: string | string[]): Promise<
+    Array<{
+      path: string
+      size: number
+      accessTime: number
+      modifiedTime: number
+      changeTime: number
+      birthTime: number
+    }>
+  >
 
   /**
    * @example https://github.com/logseq/logseq/pull/6488

+ 115 - 100
libs/src/LSPlugin.user.ts

@@ -35,7 +35,8 @@ import {
   BlockEntity,
   IDatom,
   IAssetsProxy,
-  AppInfo, IPluginSearchServiceHooks,
+  AppInfo,
+  IPluginSearchServiceHooks,
 } from './LSPlugin'
 import Debug from 'debug'
 import * as CSS from 'csstype'
@@ -52,8 +53,7 @@ declare global {
   }
 }
 
-type callableMethods =
-  keyof typeof callableAPIs | string // host exported SDK apis & host platform related apis
+type callableMethods = keyof typeof callableAPIs | string // host exported SDK apis & host platform related apis
 
 const PROXY_CONTINUE = Symbol.for('proxy-continue')
 const debug = Debug('LSPlugin:user')
@@ -64,7 +64,7 @@ const logger = new PluginLogger('', { console: true })
  * @param opts
  * @param action
  */
-function registerSimpleCommand(
+function registerSimpleCommand (
   this: LSPluginUser,
   type: string,
   opts: {
@@ -91,13 +91,16 @@ function registerSimpleCommand(
     args: [
       this.baseInfo.id,
       // [cmd, action]
-      [{ key, label, type, desc, keybinding, extras }, ['editor/hook', eventKey]],
+      [
+        { key, label, type, desc, keybinding, extras },
+        ['editor/hook', eventKey],
+      ],
       palette,
     ],
   })
 }
 
-function shouldValidUUID(uuid: string) {
+function shouldValidUUID (uuid: string) {
   if (!isValidUUID(uuid)) {
     logger.error(`#${uuid} is not a valid UUID string.`)
     return false
@@ -106,7 +109,7 @@ function shouldValidUUID(uuid: string) {
   return true
 }
 
-function checkEffect(p: LSPluginUser) {
+function checkEffect (p: LSPluginUser) {
   return p && (p.baseInfo?.effect || !p.baseInfo?.iir)
 }
 
@@ -114,10 +117,7 @@ let _appBaseInfo: AppInfo = null
 let _searchServices: Map<string, LSPluginSearchService> = new Map()
 
 const app: Partial<IAppProxy> = {
-  async getInfo(
-    this: LSPluginUser,
-    key
-  ) {
+  async getInfo (this: LSPluginUser, key) {
     if (!_appBaseInfo) {
       _appBaseInfo = await this._execCallableAPIAsync('get-app-info')
     }
@@ -126,7 +126,7 @@ const app: Partial<IAppProxy> = {
 
   registerCommand: registerSimpleCommand,
 
-  registerSearchService<T extends IPluginSearchServiceHooks>(
+  registerSearchService<T extends IPluginSearchServiceHooks> (
     this: LSPluginUser,
     s: T
   ) {
@@ -137,7 +137,7 @@ const app: Partial<IAppProxy> = {
     _searchServices.set(s.name, new LSPluginSearchService(this, s))
   },
 
-  registerCommandPalette(
+  registerCommandPalette (
     opts: { key: string; label: string; keybinding?: SimpleCommandKeybinding },
     action: SimpleCommandCallback
   ) {
@@ -152,10 +152,23 @@ const app: Partial<IAppProxy> = {
     )
   },
 
-  registerCommandShortcut(
-    keybinding: SimpleCommandKeybinding,
-    action: SimpleCommandCallback
+  registerCommandShortcut (
+    keybinding: SimpleCommandKeybinding | string,
+    action: SimpleCommandCallback,
+    opts: Partial<{
+      key: string
+      label: string
+      desc: string
+      extras: Record<string, any>
+    }> = {}
   ) {
+    if (typeof keybinding == 'string') {
+      keybinding = {
+        mode: 'global',
+        binding: keybinding,
+      }
+    }
+
     const { binding } = keybinding
     const group = '$shortcut$'
     const key = group + safeSnakeCase(binding)
@@ -163,12 +176,12 @@ const app: Partial<IAppProxy> = {
     return registerSimpleCommand.call(
       this,
       group,
-      { key, palette: false, keybinding },
+      { ...opts, key, palette: false, keybinding },
       action
     )
   },
 
-  registerUIItem(
+  registerUIItem (
     type: 'toolbar' | 'pagebar',
     opts: { key: string; template: string }
   ) {
@@ -181,7 +194,7 @@ const app: Partial<IAppProxy> = {
     })
   },
 
-  registerPageMenuItem(
+  registerPageMenuItem (
     this: LSPluginUser,
     tag: string,
     action: (e: IHookEvent & { page: string }) => void
@@ -205,9 +218,7 @@ const app: Partial<IAppProxy> = {
     )
   },
 
-  onBlockRendererSlotted(
-    uuid,
-    callback: (payload: any) => void) {
+  onBlockRendererSlotted (uuid, callback: (payload: any) => void) {
     if (!shouldValidUUID(uuid)) return
 
     const pid = this.baseInfo.id
@@ -222,11 +233,7 @@ const app: Partial<IAppProxy> = {
     }
   },
 
-  invokeExternalPlugin(
-    this: LSPluginUser,
-    type: string,
-    ...args: Array<any>
-  ) {
+  invokeExternalPlugin (this: LSPluginUser, type: string, ...args: Array<any>) {
     type = type?.trim()
     if (!type) return
     let [pid, group] = type.split('.')
@@ -240,11 +247,14 @@ const app: Partial<IAppProxy> = {
     }
     return this._execCallableAPIAsync(
       'invoke_external_plugin_cmd',
-      pid, group.toLowerCase(), key, args
+      pid,
+      group.toLowerCase(),
+      key,
+      args
     )
   },
 
-  setFullScreen(flag) {
+  setFullScreen (flag) {
     const sf = (...args) => this._callWin('setFullScreen', ...args)
 
     if (flag === 'toggle') {
@@ -254,17 +264,17 @@ const app: Partial<IAppProxy> = {
     } else {
       flag ? sf(true) : sf()
     }
-  }
+  },
 }
 
 let registeredCmdUid = 0
 
 const editor: Partial<IEditorProxy> = {
-  newBlockUUID(this: LSPluginUser): Promise<string> {
+  newBlockUUID (this: LSPluginUser): Promise<string> {
     return this._execCallableAPIAsync('new_block_uuid')
   },
 
-  registerSlashCommand(
+  registerSlashCommand (
     this: LSPluginUser,
     tag: string,
     actions: BlockCommandCallback | Array<SlashCommandAction>
@@ -312,7 +322,7 @@ const editor: Partial<IEditorProxy> = {
     })
   },
 
-  registerBlockContextMenuItem(
+  registerBlockContextMenuItem (
     this: LSPluginUser,
     label: string,
     action: BlockCommandCallback
@@ -335,11 +345,12 @@ const editor: Partial<IEditorProxy> = {
     )
   },
 
-  registerHighlightContextMenuItem(
+  registerHighlightContextMenuItem (
     this: LSPluginUser,
     label: string,
     action: SimpleCommandCallback,
-    opts?: { clearSelection: boolean }) {
+    opts?: { clearSelection: boolean }
+  ) {
     if (typeof action !== 'function') {
       return false
     }
@@ -353,13 +364,13 @@ const editor: Partial<IEditorProxy> = {
       {
         key,
         label,
-        extras: opts
+        extras: opts,
       },
       action
     )
   },
 
-  scrollToBlockInPage(
+  scrollToBlockInPage (
     this: LSPluginUser,
     pageName: BlockPageName,
     blockId: BlockIdentity,
@@ -371,11 +382,11 @@ const editor: Partial<IEditorProxy> = {
     } else {
       this.App.pushState('page', { name: pageName }, { anchor })
     }
-  }
+  },
 }
 
 const db: Partial<IDBProxy> = {
-  onBlockChanged(
+  onBlockChanged (
     this: LSPluginUser,
     uuid: BlockUUID,
     callback: (
@@ -405,7 +416,7 @@ const db: Partial<IDBProxy> = {
     }
   },
 
-  datascriptQuery<T = any>(
+  datascriptQuery<T = any> (
     this: LSPluginUser,
     query: string,
     ...inputs: Array<any>
@@ -413,16 +424,13 @@ const db: Partial<IDBProxy> = {
     // force remove proxy ns flag `db`
     inputs.pop()
 
-    if (inputs?.some(it => (typeof it === 'function'))) {
+    if (inputs?.some((it) => typeof it === 'function')) {
       const host = this.Experiments.ensureHostScope()
       return host.logseq.api.datascript_query(query, ...inputs)
     }
 
-    return this._execCallableAPIAsync(
-      `datascript_query`,
-      ...[query, ...inputs]
-    )
-  }
+    return this._execCallableAPIAsync(`datascript_query`, ...[query, ...inputs])
+  },
 }
 
 const git: Partial<IGitProxy> = {}
@@ -430,13 +438,9 @@ const git: Partial<IGitProxy> = {}
 const ui: Partial<IUIProxy> = {}
 
 const assets: Partial<IAssetsProxy> = {
-  makeSandboxStorage(
-    this: LSPluginUser
-  ): IAsyncStorage {
-    return new LSPluginFileStorage(
-      this, { assets: true }
-    )
-  }
+  makeSandboxStorage (this: LSPluginUser): IAsyncStorage {
+    return new LSPluginFileStorage(this, { assets: true })
+  },
 }
 
 type uiState = {
@@ -483,7 +487,7 @@ export class LSPluginUser
    * @param _baseInfo
    * @param _caller
    */
-  constructor(
+  constructor (
     private _baseInfo: LSPluginBaseInfo,
     private _caller: LSPluginCaller
   ) {
@@ -509,14 +513,14 @@ export class LSPluginUser
         cb && (await cb(rest))
         actor?.resolve(null)
       } catch (e) {
-        console.debug(`${_caller.debugTag} [beforeunload] `, e)
+        this.logger.error(`[beforeunload] `, e)
         actor?.reject(e)
       }
     })
   }
 
   // Life related
-  async ready(model?: any, callback?: any) {
+  async ready (model?: any, callback?: any) {
     if (this._connected) return
 
     try {
@@ -530,6 +534,7 @@ export class LSPluginUser
       this._connected = true
 
       baseInfo = deepMerge(this._baseInfo, baseInfo)
+      this._baseInfo = baseInfo
 
       if (baseInfo?.id) {
         this._debugTag =
@@ -562,39 +567,39 @@ export class LSPluginUser
     }
   }
 
-  ensureConnected() {
+  ensureConnected () {
     if (!this._connected) {
       throw new Error('not connected')
     }
   }
 
-  beforeunload(callback: (e: any) => Promise<void>): void {
+  beforeunload (callback: (e: any) => Promise<void>): void {
     if (typeof callback !== 'function') return
     this._beforeunloadCallback = callback
   }
 
-  provideModel(model: Record<string, any>) {
+  provideModel (model: Record<string, any>) {
     this.caller._extendUserModel(model)
     return this
   }
 
-  provideTheme(theme: Theme) {
+  provideTheme (theme: Theme) {
     this.caller.call('provider:theme', theme)
     return this
   }
 
-  provideStyle(style: StyleString) {
+  provideStyle (style: StyleString) {
     this.caller.call('provider:style', style)
     return this
   }
 
-  provideUI(ui: UIOptions) {
+  provideUI (ui: UIOptions) {
     this.caller.call('provider:ui', ui)
     return this
   }
 
   // Settings related
-  useSettingsSchema(schema: Array<SettingSchemaDesc>) {
+  useSettingsSchema (schema: Array<SettingSchemaDesc>) {
     if (this.connected) {
       this.caller.call('settings:schema', {
         schema,
@@ -606,35 +611,35 @@ export class LSPluginUser
     return this
   }
 
-  updateSettings(attrs: Record<string, any>) {
+  updateSettings (attrs: Record<string, any>) {
     this.caller.call('settings:update', attrs)
     // TODO: update associated baseInfo settings
   }
 
-  onSettingsChanged<T = any>(cb: (a: T, b: T) => void): IUserOffHook {
+  onSettingsChanged<T = any> (cb: (a: T, b: T) => void): IUserOffHook {
     const type = 'settings:changed'
     this.on(type, cb)
     return () => this.off(type, cb)
   }
 
-  showSettingsUI() {
+  showSettingsUI () {
     this.caller.call('settings:visible:changed', { visible: true })
   }
 
-  hideSettingsUI() {
+  hideSettingsUI () {
     this.caller.call('settings:visible:changed', { visible: false })
   }
 
   // UI related
-  setMainUIAttrs(attrs: Partial<UIContainerAttrs>): void {
+  setMainUIAttrs (attrs: Partial<UIContainerAttrs>): void {
     this.caller.call('main-ui:attrs', attrs)
   }
 
-  setMainUIInlineStyle(style: CSS.Properties): void {
+  setMainUIInlineStyle (style: CSS.Properties): void {
     this.caller.call('main-ui:style', style)
   }
 
-  hideMainUI(opts?: { restoreEditingCursor: boolean }): void {
+  hideMainUI (opts?: { restoreEditingCursor: boolean }): void {
     const payload = {
       key: KEY_MAIN_UI,
       visible: false,
@@ -645,7 +650,7 @@ export class LSPluginUser
     this._ui.set(payload.key, payload)
   }
 
-  showMainUI(opts?: { autoFocus: boolean }): void {
+  showMainUI (opts?: { autoFocus: boolean }): void {
     const payload = {
       key: KEY_MAIN_UI,
       visible: true,
@@ -656,7 +661,7 @@ export class LSPluginUser
     this._ui.set(payload.key, payload)
   }
 
-  toggleMainUI(): void {
+  toggleMainUI (): void {
     const payload = { key: KEY_MAIN_UI, toggle: true }
     const state = this._ui.get(payload.key)
     if (state && state.visible) {
@@ -667,40 +672,40 @@ export class LSPluginUser
   }
 
   // Getters
-  get version(): string {
+  get version (): string {
     return this._version
   }
 
-  get isMainUIVisible(): boolean {
+  get isMainUIVisible (): boolean {
     const state = this._ui.get(KEY_MAIN_UI)
     return Boolean(state && state.visible)
   }
 
-  get connected(): boolean {
+  get connected (): boolean {
     return this._connected
   }
 
-  get baseInfo(): LSPluginBaseInfo {
+  get baseInfo (): LSPluginBaseInfo {
     return this._baseInfo
   }
 
-  get effect(): Boolean {
+  get effect (): Boolean {
     return checkEffect(this)
   }
 
-  get logger() {
+  get logger () {
     return logger
   }
 
-  get settings() {
+  get settings () {
     return this.baseInfo?.settings
   }
 
-  get caller(): LSPluginCaller {
+  get caller (): LSPluginCaller {
     return this._caller
   }
 
-  resolveResourceFullUrl(filePath: string) {
+  resolveResourceFullUrl (filePath: string) {
     this.ensureConnected()
     if (!filePath) return
     filePath = filePath.replace(/^[.\\/]+/, '')
@@ -710,12 +715,12 @@ export class LSPluginUser
   /**
    * @internal
    */
-  _makeUserProxy(target: any, tag?: UserProxyTags) {
+  _makeUserProxy (target: any, tag?: UserProxyTags) {
     const that = this
     const caller = this.caller
 
     return new Proxy(target, {
-      get(target: any, propKey, receiver) {
+      get (target: any, propKey, receiver) {
         const origMethod = target[propKey]
 
         return function (this: any, ...args: any) {
@@ -731,13 +736,23 @@ export class LSPluginUser
             if (hookMatcher != null) {
               const f = hookMatcher[0].toLowerCase()
               const s = hookMatcher.input!
-              const e = s.slice(f.length)
               const isOff = f === 'off'
               const pid = that.baseInfo.id
 
-              const type = `hook:${tag}:${safeSnakeCase(e)}`
-              const handler = args[0]
-              const opts = args[1]
+              let type = s.slice(f.length)
+              let handler = args[0]
+              let opts = args[1]
+
+              // condition mode
+              if (typeof handler === 'string' && typeof opts === 'function') {
+                handler = handler.replace(/^logseq./, ':')
+                type = `${type}${handler}`
+                handler = opts
+                opts = args[2]
+              }
+
+              type = `hook:${tag}:${safeSnakeCase(type)}`
+
               caller[f](type, handler)
 
               const unlisten = () => {
@@ -775,64 +790,64 @@ export class LSPluginUser
     })
   }
 
-  _execCallableAPIAsync(method: callableMethods, ...args) {
+  _execCallableAPIAsync (method: callableMethods, ...args) {
     return this._caller.callAsync(`api:call`, {
       method,
       args,
     })
   }
 
-  _execCallableAPI(method: callableMethods, ...args) {
+  _execCallableAPI (method: callableMethods, ...args) {
     this._caller.call(`api:call`, {
       method,
       args,
     })
   }
 
-  _callWin(...args) {
+  _callWin (...args) {
     return this._execCallableAPIAsync(`_callMainWin`, ...args)
   }
 
   /**
    * The interface methods of {@link IAppProxy}
    */
-  get App(): IAppProxy {
+  get App (): IAppProxy {
     return this._makeUserProxy(app, 'app')
   }
 
-  get Editor(): IEditorProxy {
+  get Editor (): IEditorProxy {
     return this._makeUserProxy(editor, 'editor')
   }
 
-  get DB(): IDBProxy {
+  get DB (): IDBProxy {
     return this._makeUserProxy(db, 'db')
   }
 
-  get Git(): IGitProxy {
+  get Git (): IGitProxy {
     return this._makeUserProxy(git, 'git')
   }
 
-  get UI(): IUIProxy {
+  get UI (): IUIProxy {
     return this._makeUserProxy(ui, 'ui')
   }
 
-  get Assets(): IAssetsProxy {
+  get Assets (): IAssetsProxy {
     return this._makeUserProxy(assets, 'assets')
   }
 
-  get FileStorage(): LSPluginFileStorage {
+  get FileStorage (): LSPluginFileStorage {
     let m = this._mFileStorage
     if (!m) m = this._mFileStorage = new LSPluginFileStorage(this)
     return m
   }
 
-  get Request(): LSPluginRequest {
+  get Request (): LSPluginRequest {
     let m = this._mRequest
     if (!m) m = this._mRequest = new LSPluginRequest(this)
     return m
   }
 
-  get Experiments(): LSPluginExperiments {
+  get Experiments (): LSPluginExperiments {
     let m = this._mExperiments
     if (!m) m = this._mExperiments = new LSPluginExperiments(this)
     return m
@@ -844,7 +859,7 @@ export * from './LSPlugin'
 /**
  * @internal
  */
-export function setupPluginUserInstance(
+export function setupPluginUserInstance (
   pluginBaseInfo: LSPluginBaseInfo,
   pluginCaller: LSPluginCaller
 ) {

+ 47 - 39
libs/src/helpers.ts

@@ -2,7 +2,7 @@ import { SettingSchemaDesc, StyleString, UIOptions } from './LSPlugin'
 import { PluginLocal } from './LSPlugin.core'
 import * as nodePath from 'path'
 import DOMPurify from 'dompurify'
-import { merge } from 'lodash-es'
+import merge from 'deepmerge';
 import { snakeCase } from 'snake-case'
 import * as callables from './callable.apis'
 import EventEmitter from 'eventemitter3'
@@ -52,7 +52,10 @@ export function isObject(item: any) {
   return item === Object(item) && !Array.isArray(item)
 }
 
-export const deepMerge = merge
+export function deepMerge<T>(a: Partial<T>, b: Partial<T>): T {
+  const overwriteArrayMerge = (destinationArray, sourceArray) => sourceArray
+  return merge(a, b, { arrayMerge: overwriteArrayMerge })
+}
 
 export class PluginLogger extends EventEmitter<'change'> {
   private _logs: Array<[type: string, payload: any]> = []
@@ -67,7 +70,7 @@ export class PluginLogger extends EventEmitter<'change'> {
   }
 
   write(type: string, payload: any[], inConsole?: boolean) {
-    if (payload?.length && (true === payload[payload.length - 1])) {
+    if (payload?.length && true === payload[payload.length - 1]) {
       inConsole = true
       payload.pop()
     }
@@ -117,9 +120,13 @@ export class PluginLogger extends EventEmitter<'change'> {
 }
 
 export function isValidUUID(s: string) {
-  return (typeof s === 'string' &&
-    (s.length === 36) &&
-    (/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi).test(s))
+  return (
+    typeof s === 'string' &&
+    s.length === 36 &&
+    /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi.test(
+      s
+    )
+  )
 }
 
 export function genID() {
@@ -259,9 +266,9 @@ export function setupInjectedStyle(
   el.textContent = style
 
   attrs &&
-  Object.entries(attrs).forEach(([k, v]) => {
-    el.setAttribute(k, v)
-  })
+    Object.entries(attrs).forEach(([k, v]) => {
+      el.setAttribute(k, v)
+    })
 
   document.head.append(el)
 
@@ -337,22 +344,22 @@ export function setupInjectedUI(
 
     // update attributes
     attrs &&
-    Object.entries(attrs).forEach(([k, v]) => {
-      el.setAttribute(k, v)
-    })
+      Object.entries(attrs).forEach(([k, v]) => {
+        el.setAttribute(k, v)
+      })
 
     let positionDirty = el.dataset.dx != null
     ui.style &&
-    Object.entries(ui.style).forEach(([k, v]) => {
-      if (
-        positionDirty &&
-        ['left', 'top', 'bottom', 'right', 'width', 'height'].includes(k)
-      ) {
-        return
-      }
-
-      el.style[k] = v
-    })
+      Object.entries(ui.style).forEach(([k, v]) => {
+        if (
+          positionDirty &&
+          ['left', 'top', 'bottom', 'right', 'width', 'height'].includes(k)
+        ) {
+          return
+        }
+
+        el.style[k] = v
+      })
     return
   }
 
@@ -372,14 +379,14 @@ export function setupInjectedUI(
   content.innerHTML = ui.template
 
   attrs &&
-  Object.entries(attrs).forEach(([k, v]) => {
-    el.setAttribute(k, v)
-  })
+    Object.entries(attrs).forEach(([k, v]) => {
+      el.setAttribute(k, v)
+    })
 
   ui.style &&
-  Object.entries(ui.style).forEach(([k, v]) => {
-    el.style[k] = v
-  })
+    Object.entries(ui.style).forEach(([k, v]) => {
+      el.style[k] = v
+    })
 
   let teardownUI: () => void
   let disposeFloat: () => void
@@ -392,11 +399,11 @@ export function setupInjectedUI(
     el.classList.add('lsp-ui-float-container', 'visible')
     disposeFloat =
       (pl._setupResizableContainer(el, key),
-        pl._setupDraggableContainer(el, {
-          key,
-          close: () => teardownUI(),
-          title: attrs?.title,
-        }))
+      pl._setupDraggableContainer(el, {
+        key,
+        close: () => teardownUI(),
+        title: attrs?.title,
+      }))
   }
 
   if (!!slot && ui.reset) {
@@ -424,7 +431,7 @@ export function setupInjectedUI(
     'keydown',
     'change',
     'input',
-    'contextmenu'
+    'contextmenu',
   ].forEach((type) => {
     el.addEventListener(
       type,
@@ -435,7 +442,8 @@ export function setupInjectedUI(
 
         const { preventDefault } = trigger.dataset
         const msgType = trigger.dataset[`on${ucFirst(type)}`]
-        if (msgType) pl.caller?.callUserModel(msgType, transformableEvent(trigger, e))
+        if (msgType)
+          pl.caller?.callUserModel(msgType, transformableEvent(trigger, e))
         if (preventDefault?.toLowerCase() === 'true') e.preventDefault()
       },
       false
@@ -455,12 +463,12 @@ export function setupInjectedUI(
   return teardownUI
 }
 
-export function cleanInjectedUI(
-  id: string
-) {
+export function cleanInjectedUI(id: string) {
   if (!injectedUIEffects.has(id)) return
   const clean = injectedUIEffects.get(id)
-  try { clean() } catch (e) {
+  try {
+    clean()
+  } catch (e) {
     console.warn('[CLEAN Injected UI] ', id, e)
   }
 }

+ 2 - 1
libs/src/modules/LSPlugin.Experiments.ts

@@ -76,7 +76,8 @@ export class LSPluginExperiments {
 
     return host.logseq.api.exper_register_extensions_enhancer(
       this.ctx.baseInfo.id,
-      type, enhancer
+      type,
+      enhancer
     )
   }
 

+ 34 - 36
libs/src/modules/LSPlugin.Request.ts

@@ -31,23 +31,19 @@ export class LSPluginRequestTask<R = any> {
     private _requestId: RequestTaskID,
     private _requestOptions: Partial<IRequestOptions> = {}
   ) {
-
     this._promise = new Promise<any>((resolve, reject) => {
       if (!this._requestId) {
         return reject(null)
       }
 
       // task result listener
-      this._client.once(
-        genTaskCallbackType(this._requestId),
-        (e) => {
-          if (e && e instanceof Error) {
-            reject(e)
-          } else {
-            resolve(e)
-          }
+      this._client.once(genTaskCallbackType(this._requestId), (e) => {
+        if (e && e instanceof Error) {
+          reject(e)
+        } else {
+          resolve(e)
         }
-      )
+      })
     })
 
     const { success, fail, final } = this._requestOptions
@@ -65,15 +61,9 @@ export class LSPluginRequestTask<R = any> {
   }
 
   abort() {
-    if (
-      !this._requestOptions.abortable ||
-      this._aborted
-    ) return
-
-    this._client.ctx._execCallableAPI(
-      'http_request_abort',
-      this._requestId
-    )
+    if (!this._requestOptions.abortable || this._aborted) return
+
+    this._client.ctx._execCallableAPI('http_request_abort', this._requestId)
 
     this._aborted = true
   }
@@ -99,15 +89,12 @@ export class LSPluginRequest extends EventEmitter {
     super()
 
     // request callback listener
-    this.ctx.caller.on(
-      CLIENT_MSG_CALLBACK,
-      (e: any) => {
-        const reqId = e?.requestId
-        if (!reqId) return
+    this.ctx.caller.on(CLIENT_MSG_CALLBACK, (e: any) => {
+      const reqId = e?.requestId
+      if (!reqId) return
 
-        this.emit(genTaskCallbackType(reqId), e?.payload)
-      }
-    )
+      this.emit(genTaskCallbackType(reqId), e?.payload)
+    })
   }
 
   static createRequestTask(
@@ -115,21 +102,32 @@ export class LSPluginRequest extends EventEmitter {
     requestID: RequestTaskID,
     requestOptions: Partial<IRequestOptions>
   ) {
-    return new LSPluginRequestTask(
-      client, requestID, requestOptions
-    )
+    return new LSPluginRequestTask(client, requestID, requestOptions)
   }
 
-  async _request<R extends {},
-    T extends WithOptional<IRequestOptions<R>, keyof Omit<IRequestOptions, 'url'>>>(options: T):
-    Promise<T extends Pick<IRequestOptions, 'abortable'> ? LSPluginRequestTask<R> : R> {
+  async _request<
+    R extends {},
+    T extends WithOptional<
+      IRequestOptions<R>,
+      keyof Omit<IRequestOptions, 'url'>
+    >
+  >(
+    options: T
+  ): Promise<
+    T extends Pick<IRequestOptions, 'abortable'> ? LSPluginRequestTask<R> : R
+  > {
     const pid = this.ctx.baseInfo.id
     const { success, fail, final, ...requestOptions } = options
-    const reqID = this.ctx.Experiments.invokeExperMethod('request', pid, requestOptions)
+    const reqID = this.ctx.Experiments.invokeExperMethod(
+      'request',
+      pid,
+      requestOptions
+    )
 
     const task = LSPluginRequest.createRequestTask(
       this.ctx.Request,
-      reqID, options
+      reqID,
+      options
     )
 
     if (!requestOptions.abortable) {
@@ -142,4 +140,4 @@ export class LSPluginRequest extends EventEmitter {
   get ctx(): LSPluginUser {
     return this._ctx
   }
-}
+}

+ 48 - 51
libs/src/modules/LSPlugin.Search.ts

@@ -3,7 +3,6 @@ import { LSPluginUser } from '../LSPlugin.user'
 import { isArray, isFunction, mapKeys } from 'lodash-es'
 
 export class LSPluginSearchService {
-
   /**
    * @param ctx
    * @param serviceHooks
@@ -22,61 +21,59 @@ export class LSPluginSearchService {
     // hook events TODO: remove listeners
     const wrapHookEvent = (k) => `service:search:${k}:${serviceHooks.name}`
 
-    Object.entries(
-      {
-        query: {
-          f: 'onQuery', args: ['graph', 'q', true], reply: true,
-          transformOutput: (data: any) => {
-            // TODO: transform keys?
-            if (isArray(data?.blocks)) {
-              data.blocks = data.blocks.map(it => {
-                return it && mapKeys(it, (_, k) => `block/${k}`)
-              })
-            }
-
-            return data
+    Object.entries({
+      query: {
+        f: 'onQuery',
+        args: ['graph', 'q', true],
+        reply: true,
+        transformOutput: (data: any) => {
+          // TODO: transform keys?
+          if (isArray(data?.blocks)) {
+            data.blocks = data.blocks.map((it) => {
+              return it && mapKeys(it, (_, k) => `block/${k}`)
+            })
           }
+
+          return data
         },
-        rebuildBlocksIndice: { f: 'onIndiceInit', args: ['graph', 'blocks'] },
-        transactBlocks: { f: 'onBlocksChanged', args: ['graph', 'data'] },
-        truncateBlocks: { f: 'onIndiceReset', args: ['graph'] },
-        removeDb: { f: 'onGraph', args: ['graph'] }
-      }
-    ).forEach(
-      ([k, v]) => {
-        const hookEvent = wrapHookEvent(k)
-        ctx.caller.on(hookEvent, async (payload: any) => {
-          if (isFunction(serviceHooks?.[v.f])) {
-            let ret = null
+      },
+      rebuildBlocksIndice: { f: 'onIndiceInit', args: ['graph', 'blocks'] },
+      transactBlocks: { f: 'onBlocksChanged', args: ['graph', 'data'] },
+      truncateBlocks: { f: 'onIndiceReset', args: ['graph'] },
+      removeDb: { f: 'onGraph', args: ['graph'] },
+    }).forEach(([k, v]) => {
+      const hookEvent = wrapHookEvent(k)
+      ctx.caller.on(hookEvent, async (payload: any) => {
+        if (isFunction(serviceHooks?.[v.f])) {
+          let ret = null
 
-            try {
-              ret = await serviceHooks[v.f].apply(
-                serviceHooks, (v.args || []).map((prop: any) => {
-                  if (!payload) return
-                  if (prop === true) return payload
-                  if (payload.hasOwnProperty(prop)) {
-                    const ret = payload[prop]
-                    delete payload[prop]
-                    return ret
-                  }
-                })
-              )
+          try {
+            ret = await serviceHooks[v.f].apply(
+              serviceHooks,
+              (v.args || []).map((prop: any) => {
+                if (!payload) return
+                if (prop === true) return payload
+                if (payload.hasOwnProperty(prop)) {
+                  const ret = payload[prop]
+                  delete payload[prop]
+                  return ret
+                }
+              })
+            )
 
-              if (v.transformOutput) {
-                ret = v.transformOutput(ret)
-              }
-            } catch (e) {
-              console.error('[SearchService] ', e)
-              ret = e
-            } finally {
-              if (v.reply) {
-                ctx.caller.call(
-                  `${hookEvent}:reply`, ret
-                )
-              }
+            if (v.transformOutput) {
+              ret = v.transformOutput(ret)
+            }
+          } catch (e) {
+            console.error('[SearchService] ', e)
+            ret = e
+          } finally {
+            if (v.reply) {
+              ctx.caller.call(`${hookEvent}:reply`, ret)
             }
           }
-        })
+        }
       })
+    })
   }
-}
+}

+ 1 - 1
libs/src/modules/LSPlugin.Storage.ts

@@ -73,7 +73,7 @@ class LSPluginFileStorage implements IAsyncStorage {
   allKeys(): Promise<Array<string>> {
     return this.ctx.caller.callAsync(`api:call`, {
       method: 'list-plugin-storage-files',
-      args: [this.ctxId, this.opts?.assets]
+      args: [this.ctxId, this.opts?.assets],
     })
   }
 

+ 20 - 3
libs/src/postmate/index.ts

@@ -81,7 +81,9 @@ export const sanitize = (message, allowedOrigin) => {
  */
 export const resolveValue = (model, property, args) => {
   const unwrappedContext =
-    typeof model[property] === 'function' ? model[property].apply(null, args) : model[property]
+    typeof model[property] === 'function'
+      ? model[property].apply(null, args)
+      : model[property]
   return Promise.resolve(unwrappedContext)
 }
 
@@ -135,13 +137,17 @@ export class ParentAPI {
   }
 
   get(property, ...args) {
-    return new Promise((resolve) => {
+    return new Promise((resolve, reject) => {
       // Extract data from response and kill listeners
       const uid = generateNewMessageId()
       const transact = (e) => {
         if (e.data.uid === uid && e.data.postmate === 'reply') {
           this.parent.removeEventListener('message', transact, false)
-          resolve(e.data.value)
+          if (e.data.error) {
+            reject(e.data.error)
+          } else {
+            resolve(e.data.value)
+          }
         }
       }
 
@@ -243,6 +249,17 @@ export class ChildAPI {
           },
           e.origin
         )
+      }).catch((error) => {
+        ;(e.source as WindowProxy).postMessage(
+          {
+            property,
+            postmate: 'reply',
+            type: messageType,
+            uid,
+            error,
+          },
+          e.origin
+        )
       })
     })
   }

+ 11 - 6
libs/yarn.lock

@@ -1483,6 +1483,11 @@ [email protected], debug@^4.1.0, debug@^4.1.1:
   dependencies:
     ms "2.1.2"
 
+deepmerge@^4.3.1:
+  version "4.3.1"
+  resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
+  integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
 [email protected]:
   version "2.3.8"
   resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f"
@@ -2229,14 +2234,14 @@ schema-utils@^4.0.0:
     ajv-keywords "^5.0.0"
 
 semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
-  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+  version "6.3.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+  integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
 
 semver@^7.3.4:
-  version "7.3.5"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
-  integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+  integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
   dependencies:
     lru-cache "^6.0.0"
 

+ 16 - 6
package.json

@@ -73,7 +73,8 @@
         "ios:dev": "cross-env PLATFORM=ios gulp cap",
         "android:dev": "cross-env PLATFORM=android gulp cap",
         "tldraw:build": "yarn --cwd tldraw install",
-        "postinstall": "yarn tldraw:build"
+        "amplify:build": "yarn --cwd packages/amplify install",
+        "postinstall": "yarn tldraw:build && yarn amplify:build "
     },
     "dependencies": {
         "@capacitor/android": "^4.0.0",
@@ -89,10 +90,12 @@
         "@capacitor/splash-screen": "^4.0.0",
         "@capacitor/status-bar": "^4.0.0",
         "@capawesome/capacitor-background-task": "^2.0.0",
-        "@excalidraw/excalidraw": "0.12.0",
+        "@excalidraw/excalidraw": "0.15.3",
+        "@highlightjs/cdn-assets": "10.4.1",
         "@hugotomazi/capacitor-navigation-bar": "^2.0.0",
-        "@logseq/capacitor-file-sync": "0.0.30",
-        "@logseq/diff-merge": "0.1.0",
+        "@isomorphic-git/lightning-fs": "^4.6.0",
+        "@logseq/capacitor-file-sync": "0.0.35",
+        "@logseq/diff-merge": "0.2.2",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@radix-ui/colors": "^0.1.8",
         "@sentry/react": "^6.18.2",
@@ -108,20 +111,25 @@
         "d3-force": "3.0.0",
         "diff": "5.0.0",
         "dompurify": "2.4.0",
-        "electron": "24.3.1",
+        "electron": "24.6.3",
         "electron-dl": "3.3.0",
         "fs": "0.0.1-security",
         "fs-extra": "9.1.0",
         "fuse.js": "6.4.6",
         "grapheme-splitter": "1.0.4",
         "graphology": "0.20.0",
-        "highlight.js": "10.4.1",
+        "html2canvas": "^1.4.1",
         "ignore": "5.1.8",
+        "inter-ui": "^3.19.3",
+        "interactjs": "^1.10.17",
         "jszip": "3.8.0",
         "katex": "^0.16.7",
+        "marked": "^5.1.2",
         "mldoc": "1.5.7",
         "path": "0.12.7",
         "path-complete-extname": "1.0.0",
+        "pdfjs-dist": "^3.9.179",
+        "photoswipe": "^5.3.7",
         "pixi-graph-fork": "0.2.0",
         "pixi.js": "6.2.0",
         "posthog-js": "1.10.2",
@@ -134,8 +142,10 @@
         "react-tippy": "1.4.0",
         "react-transition-group": "4.3.0",
         "remove-accents": "0.4.2",
+        "reveal.js": "^4.5.0",
         "sanitize-filename": "1.6.3",
         "send-intent": "3.0.11",
+        "shepherd.js": "^9.1.0",
         "tailwind-capitalize-first-letter": "^1.0.4",
         "threads": "1.6.5",
         "url": "^0.11.0",

+ 2 - 1
packages/amplify/package.json

@@ -6,7 +6,8 @@
   "scripts": {
     "dev:amplify": "parcel watch ./src/amplify.ts --dist-dir ../src/main/frontend/ --no-hmr --no-source-maps",
     "dev:examples": "parcel serve ./examples/index.html",
-    "build:amplify": "parcel build ./src/amplify.ts --dist-dir ../../resources/js --no-source-maps && mv ../../resources/js/amplify.css ../../resources/css/"
+    "build:amplify": "parcel build ./src/amplify.ts --no-source-maps",
+    "postinstall": "yarn build:amplify"
   },
   "devDependencies": {
     "buffer": "^5.5.0",

+ 6 - 0
packages/amplify/src/LSAuthenticator.tsx

@@ -9,6 +9,12 @@ export function LSAuthenticator({ termsLink, children }: any) {
           username: { order: 2 },
           password: { order: 3 },
           confirm_password: { order: 4 },
+        },
+        signIn: {
+          username: {
+            placeholder: 'Enter your Username or Email',
+            label: 'Username or Email'
+          }
         }
       }}
       loginMechanisms={['username']}

+ 1 - 2
packages/amplify/src/amplify.ts

@@ -5,7 +5,6 @@ import { dict } from 'aws-amplify-react/lib-esm/AmplifyI18n'
 
 // fix i18n
 dict.zh['Reset Password'] = '重置密码'
-dict.zh['Enter your username'] = '请输入用户名'
 dict.zh['Enter your email'] = '请输入邮箱'
 dict.zh['Enter your password'] = '请输入密码'
 dict.zh['Confirm Password'] = '确认密码'
@@ -26,7 +25,7 @@ const fixesMapping = {
   'Forgot Password': ['Forgot your password?'],
   'Enter your email': ['Enter your Email'],
   'Enter your password': ['Enter your Password'],
-  'Enter your username': ['Enter your Username']
+  'Enter your username': ['Enter your Username or Email']
 }
 
 Object.keys(dict).forEach((k) => {

+ 3 - 3
packages/amplify/yarn.lock

@@ -5087,9 +5087,9 @@ scheduler@^0.20.2:
     object-assign "^4.1.1"
 
 semver@^5.7.0, semver@^5.7.1:
-  version "5.7.1"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
-  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+  version "5.7.2"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+  integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
 
 sentence-case@^3.0.4:
   version "3.0.4"

File diff suppressed because it is too large
+ 0 - 0
resources/css/amplify.css


+ 0 - 349
resources/css/codemirror.min.css

@@ -1,349 +0,0 @@
-/* BASICS */
-
-.CodeMirror {
-  /* Set height, width, borders, and global font properties here */
-  font-family: monospace;
-  color: black;
-  direction: ltr;
-}
-
-/* PADDING */
-
-.CodeMirror-lines {
-  padding: 4px 0; /* Vertical padding around content */
-}
-.CodeMirror pre.CodeMirror-line,
-.CodeMirror pre.CodeMirror-line-like {
-  padding: 0 4px; /* Horizontal padding of content */
-}
-
-.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
-  background-color: white; /* The little square between H and V scrollbars */
-}
-
-/* GUTTER */
-
-.CodeMirror-gutters {
-  border-right: 1px solid #ddd;
-  background-color: #f7f7f7;
-  white-space: nowrap;
-}
-.CodeMirror-linenumbers {}
-.CodeMirror-linenumber {
-  padding: 0 3px 0 5px;
-  min-width: 20px;
-  text-align: right;
-  color: #999;
-  white-space: nowrap;
-}
-
-.CodeMirror-guttermarker { color: black; }
-.CodeMirror-guttermarker-subtle { color: #999; }
-
-/* CURSOR */
-
-.CodeMirror-cursor {
-  border-left: 1px solid black;
-  border-right: none;
-  width: 0;
-}
-/* Shown when moving in bi-directional text */
-.CodeMirror div.CodeMirror-secondarycursor {
-  border-left: 1px solid silver;
-}
-.cm-fat-cursor .CodeMirror-cursor {
-  width: auto;
-  border: 0 !important;
-  background: #7e7;
-}
-.cm-fat-cursor div.CodeMirror-cursors {
-  z-index: 1;
-}
-.cm-fat-cursor-mark {
-  background-color: rgba(20, 255, 20, 0.5);
-  -webkit-animation: blink 1.06s steps(1) infinite;
-  -moz-animation: blink 1.06s steps(1) infinite;
-  animation: blink 1.06s steps(1) infinite;
-}
-.cm-animate-fat-cursor {
-  width: auto;
-  border: 0;
-  -webkit-animation: blink 1.06s steps(1) infinite;
-  -moz-animation: blink 1.06s steps(1) infinite;
-  animation: blink 1.06s steps(1) infinite;
-  background-color: #7e7;
-}
-@-moz-keyframes blink {
-  0% {}
-  50% { background-color: transparent; }
-  100% {}
-}
-@-webkit-keyframes blink {
-  0% {}
-  50% { background-color: transparent; }
-  100% {}
-}
-@keyframes blink {
-  0% {}
-  50% { background-color: transparent; }
-  100% {}
-}
-
-/* Can style cursor different in overwrite (non-insert) mode */
-.CodeMirror-overwrite .CodeMirror-cursor {}
-
-.cm-tab { display: inline-block; text-decoration: inherit; }
-
-.CodeMirror-rulers {
-  position: absolute;
-  left: 0; right: 0; top: -50px; bottom: 0;
-  overflow: hidden;
-}
-.CodeMirror-ruler {
-  border-left: 1px solid #ccc;
-  top: 0; bottom: 0;
-  position: absolute;
-}
-
-/* DEFAULT THEME */
-
-.cm-s-default .cm-header {color: blue;}
-.cm-s-default .cm-quote {color: #090;}
-.cm-negative {color: #d44;}
-.cm-positive {color: #292;}
-.cm-header, .cm-strong {font-weight: bold;}
-.cm-em {font-style: italic;}
-.cm-link {text-decoration: underline;}
-.cm-strikethrough {text-decoration: line-through;}
-
-.cm-s-default .cm-keyword {color: #708;}
-.cm-s-default .cm-atom {color: #219;}
-.cm-s-default .cm-number {color: #164;}
-.cm-s-default .cm-def {color: #00f;}
-.cm-s-default .cm-variable,
-.cm-s-default .cm-punctuation,
-.cm-s-default .cm-property,
-.cm-s-default .cm-operator {}
-.cm-s-default .cm-variable-2 {color: #05a;}
-.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
-.cm-s-default .cm-comment {color: #a50;}
-.cm-s-default .cm-string {color: #a11;}
-.cm-s-default .cm-string-2 {color: #f50;}
-.cm-s-default .cm-meta {color: #555;}
-.cm-s-default .cm-qualifier {color: #555;}
-.cm-s-default .cm-builtin {color: #30a;}
-.cm-s-default .cm-bracket {color: #997;}
-.cm-s-default .cm-tag {color: #170;}
-.cm-s-default .cm-attribute {color: #00c;}
-.cm-s-default .cm-hr {color: #999;}
-.cm-s-default .cm-link {color: #00c;}
-
-.cm-s-default .cm-error {color: #f00;}
-.cm-invalidchar {color: #f00;}
-
-.CodeMirror-composing { border-bottom: 2px solid; }
-
-/* Default styles for common addons */
-
-div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
-div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
-.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
-.CodeMirror-activeline-background {background: #e8f2ff;}
-
-/* STOP */
-
-/* The rest of this file contains styles related to the mechanics of
-   the editor. You probably shouldn't touch them. */
-
-.CodeMirror {
-  position: relative;
-  overflow: hidden;
-  background: white;
-}
-
-.CodeMirror-scroll {
-  overflow: scroll !important; /* Things will break if this is overridden */
-  /* 50px is the magic margin used to hide the element's real scrollbars */
-  /* See overflow: hidden in .CodeMirror */
-  margin-bottom: -50px; margin-right: -50px;
-  padding-bottom: 50px;
-  height: 100%;
-  outline: none; /* Prevent dragging from highlighting the element */
-  position: relative;
-}
-.CodeMirror-sizer {
-  position: relative;
-  border-right: 50px solid transparent;
-}
-
-/* The fake, visible scrollbars. Used to force redraw during scrolling
-   before actual scrolling happens, thus preventing shaking and
-   flickering artifacts. */
-.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
-  position: absolute;
-  z-index: 6;
-  display: none;
-  outline: none;
-}
-.CodeMirror-vscrollbar {
-  right: 0; top: 0;
-  overflow-x: hidden;
-  overflow-y: scroll;
-}
-.CodeMirror-hscrollbar {
-  bottom: 0; left: 0;
-  overflow-y: hidden;
-  overflow-x: scroll;
-}
-.CodeMirror-scrollbar-filler {
-  right: 0; bottom: 0;
-}
-.CodeMirror-gutter-filler {
-  left: 0; bottom: 0;
-}
-
-.CodeMirror-gutters {
-  position: absolute; left: 0; top: 0;
-  min-height: 100%;
-  z-index: 3;
-}
-.CodeMirror-gutter {
-  white-space: normal;
-  height: 100%;
-  display: inline-block;
-  vertical-align: top;
-  margin-bottom: -50px;
-}
-.CodeMirror-gutter-wrapper {
-  position: absolute;
-  z-index: 4;
-  background: none !important;
-  border: none !important;
-}
-.CodeMirror-gutter-background {
-  position: absolute;
-  top: 0; bottom: 0;
-  z-index: 4;
-}
-.CodeMirror-gutter-elt {
-  position: absolute;
-  cursor: default;
-  z-index: 4;
-}
-.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
-.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
-
-.CodeMirror-lines {
-  cursor: text;
-  min-height: 1px; /* prevents collapsing before first draw */
-}
-.CodeMirror pre.CodeMirror-line,
-.CodeMirror pre.CodeMirror-line-like {
-  /* Reset some styles that the rest of the page might have set */
-  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
-  border-width: 0;
-  background: transparent;
-  font-family: inherit;
-  font-size: inherit;
-  margin: 0;
-  white-space: pre;
-  word-wrap: normal;
-  line-height: inherit;
-  color: inherit;
-  z-index: 2;
-  position: relative;
-  overflow: visible;
-  -webkit-tap-highlight-color: transparent;
-  -webkit-font-variant-ligatures: contextual;
-  font-variant-ligatures: contextual;
-}
-.CodeMirror-wrap pre.CodeMirror-line,
-.CodeMirror-wrap pre.CodeMirror-line-like {
-  word-wrap: break-word;
-  white-space: pre-wrap;
-  word-break: normal;
-}
-
-.CodeMirror-linebackground {
-  position: absolute;
-  left: 0; right: 0; top: 0; bottom: 0;
-  z-index: 0;
-}
-
-.CodeMirror-linewidget {
-  position: relative;
-  z-index: 2;
-  padding: 0.1px; /* Force widget margins to stay inside of the container */
-}
-
-.CodeMirror-widget {}
-
-.CodeMirror-rtl pre { direction: rtl; }
-
-.CodeMirror-code {
-  outline: none;
-}
-
-/* Force content-box sizing for the elements where we expect it */
-.CodeMirror-scroll,
-.CodeMirror-sizer,
-.CodeMirror-gutter,
-.CodeMirror-gutters,
-.CodeMirror-linenumber {
-  -moz-box-sizing: content-box;
-  box-sizing: content-box;
-}
-
-.CodeMirror-measure {
-  position: absolute;
-  width: 100%;
-  height: 0;
-  overflow: hidden;
-  visibility: hidden;
-}
-
-.CodeMirror-cursor {
-  position: absolute;
-  pointer-events: none;
-}
-.CodeMirror-measure pre { position: static; }
-
-div.CodeMirror-cursors {
-  visibility: hidden;
-  position: relative;
-  z-index: 3;
-}
-div.CodeMirror-dragcursors {
-  visibility: visible;
-}
-
-.CodeMirror-focused div.CodeMirror-cursors {
-  visibility: visible;
-}
-
-.CodeMirror-selected { background: #d9d9d9; }
-.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
-.CodeMirror-crosshair { cursor: crosshair; }
-.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
-.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
-
-.cm-searching {
-  background-color: #ffa;
-  background-color: rgba(255, 255, 0, .4);
-}
-
-/* Used to force a border model for a node */
-.cm-force-border { padding-right: .1px; }
-
-@media print {
-  /* Hide the cursor when printing */
-  .CodeMirror div.CodeMirror-cursors {
-    visibility: hidden;
-  }
-}
-
-/* See issue #2901 */
-.cm-tab-wrap-hack:after { content: ''; }
-
-/* Help users use markselection to safely style text background */
-span.CodeMirror-selectedtext { background: none; }

+ 0 - 160
resources/css/codemirror.solarized.css

@@ -1,160 +0,0 @@
-/*
-Solarized theme for code-mirror
-http://ethanschoonover.com/solarized
-*/
-
-/*
-Solarized color palette
-http://ethanschoonover.com/solarized/img/solarized-palette.png
-*/
-
-.solarized.base03 { color: #002b36; }
-.solarized.base02 { color: #073642; }
-.solarized.base01 { color: #586e75; }
-.solarized.base00 { color: #657b83; }
-.solarized.base0 { color: #839496; }
-.solarized.base1 { color: #93a1a1; }
-.solarized.base2 { color: #eee8d5; }
-.solarized.base3  { color: #fdf6e3; }
-.solarized.solar-yellow  { color: #b58900; }
-.solarized.solar-orange  { color: #cb4b16; }
-.solarized.solar-red { color: #dc322f; }
-.solarized.solar-magenta { color: #d33682; }
-.solarized.solar-violet  { color: #6c71c4; }
-.solarized.solar-blue { color: #268bd2; }
-.solarized.solar-cyan { color: #2aa198; }
-.solarized.solar-green { color: #859900; }
-
-/* Color scheme for code-mirror */
-
-.cm-s-solarized {
-  line-height: 1.45em;
-  color-profile: sRGB;
-  rendering-intent: auto;
-}
-.cm-s-solarized.cm-s-dark {
-  color: #839496;
-  background-color: #002b36;
-  text-shadow: #002b36 0 1px;
-}
-.cm-s-solarized.cm-s-light {
-  background-color: #fdf6e3;
-  color: #657b83;
-  text-shadow: #eee8d5 0 1px;
-}
-
-.cm-s-solarized .CodeMirror-widget {
-  text-shadow: none;
-}
-
-.cm-s-solarized .cm-header { color: #586e75; }
-.cm-s-solarized .cm-quote { color: #93a1a1; }
-
-.cm-s-solarized .cm-keyword { color: #cb4b16; }
-.cm-s-solarized .cm-atom { color: #d33682; }
-.cm-s-solarized .cm-number { color: #d33682; }
-.cm-s-solarized .cm-def { color: #2aa198; }
-
-.cm-s-solarized .cm-variable { color: #839496; }
-.cm-s-solarized .cm-variable-2 { color: #b58900; }
-.cm-s-solarized .cm-variable-3, .cm-s-solarized .cm-type { color: #6c71c4; }
-
-.cm-s-solarized .cm-property { color: #2aa198; }
-.cm-s-solarized .cm-operator { color: #6c71c4; }
-
-.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; }
-
-.cm-s-solarized .cm-string { color: #859900; }
-.cm-s-solarized .cm-string-2 { color: #b58900; }
-
-.cm-s-solarized .cm-meta { color: #859900; }
-.cm-s-solarized .cm-qualifier { color: #b58900; }
-.cm-s-solarized .cm-builtin { color: #d33682; }
-.cm-s-solarized .cm-bracket { color: #cb4b16; }
-.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; }
-.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; }
-.cm-s-solarized .cm-tag { color: #93a1a1; }
-.cm-s-solarized .cm-attribute { color: #2aa198; }
-.cm-s-solarized .cm-hr {
-  color: transparent;
-  border-top: 1px solid #586e75;
-  display: block;
-}
-.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; }
-.cm-s-solarized .cm-special { color: #6c71c4; }
-.cm-s-solarized .cm-em {
-  color: #999;
-  text-decoration: underline;
-  text-decoration-style: dotted;
-}
-.cm-s-solarized .cm-error,
-.cm-s-solarized .cm-invalidchar {
-  color: #586e75;
-  border-bottom: 1px dotted #dc322f;
-}
-
-.cm-s-solarized.cm-s-dark div.CodeMirror-selected { background: #073642; }
-.cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); }
-.cm-s-solarized.cm-s-dark .CodeMirror-line::-moz-selection, .cm-s-dark .CodeMirror-line > span::-moz-selection, .cm-s-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(7, 54, 66, 0.99); }
-
-.cm-s-solarized.cm-s-light div.CodeMirror-selected { background: #eee8d5; }
-.cm-s-solarized.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: #eee8d5; }
-.cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-light .CodeMirror-line > span::-moz-selection, .cm-s-light .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; }
-
-/* Editor styling */
-
-
-/* Remove gutter border */
-.cm-s-solarized .CodeMirror-gutters {
-  border-right: 0;
-}
-
-/* Gutter colors and line number styling based of color scheme (dark / light) */
-
-/* Dark */
-.cm-s-solarized.cm-s-dark .CodeMirror-gutters {
-  background-color: #073642;
-}
-
-.cm-s-solarized.cm-s-dark .CodeMirror-linenumber {
-  color: #586e75;
-  text-shadow: #021014 0 -1px;
-}
-
-/* Light */
-.cm-s-solarized.cm-s-light .CodeMirror-gutters {
-  background-color: #eee8d5;
-}
-
-.cm-s-solarized.cm-s-light .CodeMirror-linenumber {
-  color: #839496;
-}
-
-/* Common */
-.cm-s-solarized .CodeMirror-linenumber {
-  padding: 0 5px;
-}
-.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; }
-.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; }
-.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; }
-
-.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text {
-  color: #586e75;
-}
-
-/* Cursor */
-.cm-s-solarized .CodeMirror-cursor { border-left: 1px solid #819090; }
-
-/* Fat cursor */
-.cm-s-solarized.cm-s-light.cm-fat-cursor .CodeMirror-cursor { background: #77ee77; }
-.cm-s-solarized.cm-s-light .cm-animate-fat-cursor { background-color: #77ee77; }
-.cm-s-solarized.cm-s-dark.cm-fat-cursor .CodeMirror-cursor { background: #586e75; }
-.cm-s-solarized.cm-s-dark .cm-animate-fat-cursor { background-color: #586e75; }
-
-/* Active line */
-.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {
-  background: rgba(255, 255, 255, 0.06);
-}
-.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {
-  background: rgba(0, 0, 0, 0.06);
-}

+ 0 - 230
resources/css/datepicker.css

@@ -1,230 +0,0 @@
-/*----------------------------------------------------------------------------------------
- Stylesheet for re-com.date Date Picker variants inline-picker & dropdown-picker
- Day8 variation loosely based on:
- Copyright 2013 Dan Grossman ( http://www.dangrossman.info )
- Licensed under the Apache License v2.0
- http://www.apache.org/licenses/LICENSE-2.0
- Built for http://www.improvely.com
- http://eternicode.github.io/bootstrap-datepicker
-
-  START OF DATE PICKER SECTION...
-----------------------------------------------------------------------------------------*/
-.noselect {
-    -webkit-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
-}
-
-.datepicker.single .calendar {
-    float: none;
-}
-
-.datepicker .calendar {
-    display: none;
-    max-width: 200px;
-}
-
-.datepicker .calendar.single .calendar-date {
-    border: none;
-}
-
-.datepicker .calendar th, .datepicker .calendar td {
-    white-space: nowrap;
-    text-align: center;
-    min-width: 32px;
-}
-
-.datepicker .calendar-date {
-    border: 1px solid #ddd;
-    padding: 4px;
-    border-radius: 4px;
-    /* background: #fff; */
-}
-
-.datepicker .calendar-time {
-    text-align: center;
-    margin: 8px auto 0 auto;
-    line-height: 30px;
-}
-
-.datepicker {
-    position: absolute;
-    top: 100px;
-    left: 20px;
-    padding: 10px;
-    margin-top: 1px;
-    -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-    line-height: 16px;
-    border-radius: 4px;
-    background: #efefef;
-}
-
-.datepicker table {
-    width: 100%;
-    margin: 0;
-    border-collapse: separate;
-    border-spacing: 0;
-    background: transparent;
-    border: none;
-}
-
-.datepicker td, .datepicker th {
-    text-align: center;
-    width: 27px;
-    height: 26px;
-    max-width: 27px;
-    max-height: 26px;
-    min-width: 27px;
-    min-height: 26px;
-    padding: 4px;
-    cursor: default;
-    white-space: nowrap;
-    font-weight: normal;
-}
-
-.datepicker td.off {
-    padding: 4px;
-    color: #999;
-}
-
-.datepicker td.disabled {
-    color: #999;
-}
-
-.datepicker th.disabled {
-    color: #999;
-}
-
-.datepicker td.available:hover, .datepicker th.available:hover {
-    background: #357ebd;
-    cursor: pointer;
-    color: #FFF;
-    border-radius: 4px;
-}
-
-.datepicker td.in-range {
-    background: #ebf4f8;
-    -webkit-border-radius: 0;
-    -moz-border-radius: 0;
-  border-radius: 0;
-}
-
-.datepicker td.start-date {
-    -webkit-border-radius: 4px 0 0 4px;
-    -moz-border-radius: 4px 0 0 4px;
-    border-radius: 4px 0 0 4px;
-}
-
-.datepicker td.end-date {
-    -webkit-border-radius: 0 4px 4px 0;
-    -moz-border-radius: 0 4px 4px 0;
-    border-radius: 0 4px 4px 0;
-}
-
-.datepicker td.start-date.end-date {
-    -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-    border-radius: 4px;
-}
-
-.datepicker td.active, .datepicker td.active:hover {
-    background-color: #357ebd;
-    border-color: #3071a9;
-    color: #fff;
-}
-
-/* Introduced by Day8 from http://eternicode.github.io/bootstrap-datepicker */
-.datepicker td.today, .datepicker td.today:hover {
-    background-color: #ffcd70;
-    border-color: #f59e00;
-    border-radius: 18px;
-    color: #fff;
-}
-
-.datepicker th.day-enabled, label.day-enabled {
-    font-weight: normal;
-    font-size: 10px;
-    color: #333;
-}
-
-.datepicker th.selectable {
-    font-weight: normal;
-    color: #357ebd;
-}
-
-.datepicker th.day-disabled {
-    font-weight: normal;
-    font-size: 10px;
-    color: #999;
-}
-
-.datepicker td.week, .datepicker th.week {
-  font-size: 80%;
-  color: #ccc;
-}
-
-.datepicker th.month {
-    width: auto;
-    font-size: 14px;
-    color: var(--ls-title-text-color);
-}
-
-.dropdown-button {
-    cursor: pointer;
-    height: 32px;
-    font-size: 13px;
-    font-weight: normal;
-}
-
-.dropdown-button.activator {
-    width: 40px;
-    color: #777;
-    /* background-color: #F7F7F7 */
-}
-
-.table-condensed > thead > tr > th,
-.table-condensed > tbody > tr > th,
-.table-condensed > tfoot > tr > th,
-.table-condensed > thead > tr > td,
-.table-condensed > tbody > tr > td,
-.table-condensed > tfoot > tr > td {
-    padding: 5px;
-}
-
-.dark-theme .datepicker {
-    background: var(--ls-secondary-background-color);
-}
-
-.dark-theme .datepicker th.day-disabled, .dark-theme .datepicker th.disabled, .dark-theme .datepicker td.disabled, .dark-theme .datepicker td.off {
-    color: #666;
-}
-
-.dark-theme .datepicker th.day-enabled, .dark-theme  label.day-enabled {
-    color: currentColor;
-}
-
-.dark-theme .datepicker td.active, .dark-theme .datepicker td.active:hover {
-    background-color: var(--ls-block-properties-background-color);
-    border-color: var(--ls-block-properties-background-color);
-}
-
-.dark-theme .datepicker th.selectable {
-     color: var(--ls-primary-text-color);
-}
-
-.dark-theme .datepicker td.available:hover, .dark-theme .datepicker th.available:hover {
-    background: var(--ls-block-properties-background-color);
-}
-
-.datepicker tr:nth-child(odd), .datepicker tr:nth-child(even), .dark-theme .datepicker tr:nth-child(odd), .dark-theme .datepicker tr:nth-child(even) {
-    background: transparent;
-}
-
-.datepicker th, .datepicker tr, .datepicker td, .dark-theme .datepicker th, .dark-theme .datepicker tr, .dark-theme .datepicker td {
-    border-bottom: none;
-}
-/*----------------------------------------------------------------------------------------
-  END OF DATE PICKER SECTION...
-----------------------------------------------------------------------------------------*/

File diff suppressed because it is too large
+ 0 - 0
resources/css/excalidraw.min.css


+ 0 - 13
resources/css/fonts.css

@@ -1,13 +0,0 @@
-/* http://www.eaglefonts.com/fg-virgil-ttf-131249.htm */
-@font-face {
-    font-family: "Virgil";
-    src: url("../fonts/Virgil.woff2");
-    font-display: swap;
-}
-
-/* https://github.com/microsoft/cascadia-code */
-@font-face {
-    font-family: "Cascadia";
-    src: url("../fonts/Cascadia.woff2");
-    font-display: swap;
-}

+ 0 - 200
resources/css/inter.css

@@ -1,200 +0,0 @@
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 100;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-Thin.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-Thin.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 100;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-ThinItalic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-ThinItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 200;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-ExtraLight.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-ExtraLight.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 200;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-ExtraLightItalic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-ExtraLightItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 300;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-Light.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-Light.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 300;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-LightItalic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-LightItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 400;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-Regular.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-Regular.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 400;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-Italic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-Italic.woff?v=3.15") format("woff");
-}
-
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 500;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-Medium.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-Medium.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 500;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-MediumItalic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-MediumItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 600;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-SemiBold.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-SemiBold.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 600;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-SemiBoldItalic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-SemiBoldItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 700;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-Bold.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-Bold.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 700;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-BoldItalic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-BoldItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 800;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-ExtraBold.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-ExtraBold.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 800;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-ExtraBoldItalic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-ExtraBoldItalic.woff?v=3.15") format("woff");
-}
-
-@font-face {
-  font-family: 'Inter';
-  font-style:  normal;
-  font-weight: 900;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-Black.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-Black.woff?v=3.15") format("woff");
-}
-@font-face {
-  font-family: 'Inter';
-  font-style:  italic;
-  font-weight: 900;
-  font-display: swap;
-  src: url("../fonts/inter/Inter-BlackItalic.woff2?v=3.15") format("woff2"),
-       url("../fonts/inter/Inter-BlackItalic.woff?v=3.15") format("woff");
-}
-
-/* -------------------------------------------------------
-Variable font.
-Usage:
-
-  html { font-family: 'Inter', sans-serif; }
-  @supports (font-variation-settings: normal) {
-    html { font-family: 'Inter var', sans-serif; }
-  }
-*/
-@font-face {
-  font-family: 'Inter var';
-  font-weight: 100 900;
-  font-display: swap;
-  font-style: normal;
-  font-named-instance: 'Regular';
-  src: url("../fonts/inter/Inter-roman.var.woff2?v=3.15") format("woff2");
-}
-@font-face {
-  font-family: 'Inter var';
-  font-weight: 100 900;
-  font-display: swap;
-  font-style: italic;
-  font-named-instance: 'Italic';
-  src: url("../fonts/inter/Inter-italic.var.woff2?v=3.15") format("woff2");
-}
-
-
-/* --------------------------------------------------------------------------
-[EXPERIMENTAL] Multi-axis, single variable font.
-
-Slant axis is not yet widely supported (as of February 2019) and thus this
-multi-axis single variable font is opt-in rather than the default.
-
-When using this, you will probably need to set font-variation-settings
-explicitly, e.g.
-
-  * { font-variation-settings: "slnt" 0deg }
-  .italic { font-variation-settings: "slnt" 10deg }
-
-*/
-@font-face {
-  font-family: 'Inter var experimental';
-  font-weight: 100 900;
-  font-display: swap;
-  font-style: oblique 0deg 10deg;
-  src: url("../fonts/inter/Inter.var.woff2?v=3.15") format("woff2");
-}

+ 0 - 441
resources/css/photoswipe.css

@@ -1,441 +0,0 @@
-/*! PhotoSwipe main CSS by Dmytro Semenov | photoswipe.com */
-
-.pswp {
-  --pswp-bg: #000;
-  --pswp-placeholder-bg: #222;
-  --pswp-error-text-color: #f7f7f7;
-
-  --pswp-root-z-index: 100000;
-  
-  --pswp-preloader-color: rgba(79, 79, 79, 0.4);
-  --pswp-preloader-color-secondary: rgba(255, 255, 255, 0.9);
-  
-  /* defined via js:
-  --pswp-transition-duration: 333ms; */
-  
-  --pswp-icon-color: #fff;
-  --pswp-icon-color-secondary: #4f4f4f;
-  --pswp-icon-stroke-color: #4f4f4f;
-  --pswp-icon-stroke-width: 2px;
-}
-
-
-/*
-	Styles for basic PhotoSwipe (pswp) functionality (sliding area, open/close transitions)
-*/
-
-.pswp {
-	position: fixed;
-	z-index: var(--pswp-root-z-index);
-	display: none;
-	touch-action: none;
-	outline: 0;
-	opacity: 0.003;
-	contain: layout style size;
-	-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-}
-
-/* Prevents focus outline on the root element,
-  (it may be focused initially) */
-.pswp:focus {
-  outline: 0;
-}
-
-.pswp * {
-  box-sizing: border-box;
-}
-
-.pswp img {
-  max-width: none;
-}
-
-.pswp--open {
-	display: block;
-}
-
-.pswp,
-.pswp__bg {
-	transform: translateZ(0);
-	will-change: opacity;
-}
-
-.pswp__bg {
-  opacity: 0.005;
-	background: var(--pswp-bg);
-}
-
-.pswp,
-.pswp__scroll-wrap {
-	overflow: hidden;
-}
-
-.pswp,
-.pswp__scroll-wrap,
-.pswp__bg,
-.pswp__container,
-.pswp__item,
-.pswp__img,
-.pswp__zoom-wrap {
-	position: absolute;
-	top: 0;
-	left: 0;
-	width: 100%;
-	height: 100%;
-}
-
-.pswp {
-	position: fixed;
-}
-
-.pswp__img,
-.pswp__zoom-wrap {
-	width: auto;
-	height: auto;
-}
-
-.pswp--click-to-zoom.pswp--zoom-allowed .pswp__img {
-	cursor: -webkit-zoom-in;
-	cursor: -moz-zoom-in;
-	cursor: zoom-in;
-}
-
-.pswp--click-to-zoom.pswp--zoomed-in .pswp__img {
-	cursor: move;
-	cursor: -webkit-grab;
-	cursor: -moz-grab;
-	cursor: grab;
-}
-
-.pswp--click-to-zoom.pswp--zoomed-in .pswp__img:active {
-  cursor: -webkit-grabbing;
-  cursor: -moz-grabbing;
-  cursor: grabbing;
-}
-
-/* :active to override grabbing cursor */
-.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img,
-.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img:active,
-.pswp__img {
-	cursor: -webkit-zoom-out;
-	cursor: -moz-zoom-out;
-	cursor: zoom-out;
-}
-
-
-/* Prevent selection and tap highlights */
-.pswp__container,
-.pswp__img,
-.pswp__button {
-	-webkit-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
-}
-
-.pswp__item {
-	/* z-index for fade transition */
-	z-index: 1;
-	overflow: hidden;
-}
-
-.pswp__hidden {
-	display: none !important;
-}
-
-
-/*
-
-  PhotoSwipe UI
-
-*/
-
-/*
-	Error message appears when image is not loaded
-	(JS option errorMsg controls markup)
-*/
-.pswp__error-msg {
-	position: absolute;
-	top: 50%;
-	left: 0;
-	width: 100%;
-	padding: 0 10px;
-	margin-top: -0.5em;
-	font-size: 1em;
-	line-height: 1;
-	color: var(--pswp-error-text-color);
-	text-align: center;
-}
-
-.pswp__error-msg a {
-  color: var(--pswp-error-text-color);
-  text-decoration: underline;
-}
-
-/*
-class pswp__hide-on-close is applied to elements that
-should hide (for example fade out) when PhotoSwipe is closed
-and show (for example fade in) when PhotoSwipe is opened
- */
-.pswp .pswp__hide-on-close {
-	opacity: 0.005;
-	will-change: opacity;
-	transition: opacity var(--pswp-transition-duration) cubic-bezier(0.4, 0, 0.22, 1);
-	z-index: 10; /* always overlap slide content */
-	pointer-events: none; /* hidden elements should not be clickable */
-}
-
-/* class pswp--ui-visible is added when opening or closing transition starts */
-.pswp--ui-visible .pswp__hide-on-close {
-	opacity: 1;
-	pointer-events: auto;
-}
-
-/* <button> styles, including css reset */
-.pswp__button {
-	position: relative;
-	display: block;
-	width: 50px;
-	height: 60px;
-	padding: 0;
-	margin: 0;
-	overflow: hidden;
-	cursor: pointer;
-	background: none;
-	border: 0;
-	box-shadow: none;
-	opacity: 0.85;
-	-webkit-appearance: none;
-	-webkit-touch-callout: none;
-}
-
-.pswp__button:hover,
-.pswp__button:active,
-.pswp__button:focus {
-  transition: none;
-  padding: 0;
-  background: none;
-  border: 0;
-  box-shadow: none;
-  opacity: 1;
-}
-
-.pswp__icn {
-  position: absolute;
-  top: 14px;
-  left: 9px;
-  width: 32px;
-  height: 32px;
-  overflow: hidden;
-  pointer-events: none;
-  fill: var(--pswp-icon-color);
-  color: var(--pswp-icon-color-secondary);
-  border-radius: 50%;
-}
-
-.pswp__icn-shadow {
-  stroke: var(--pswp-icon-stroke-color);
-  stroke-width: var(--pswp-icon-stroke-width);
-  fill: none;
-}
-
-.pswp__icn:focus {
-	outline: 0;
-}
-
-/*
-	div element that matches size of large image,
-	large image loads on top of it,
-	used when msrc is not provided
-*/
-div.pswp__img--placeholder,
-.pswp__img--with-bg {
-	background: var(--pswp-placeholder-bg);
-}
-
-.pswp__top-bar {
-	position: absolute;
-	left: 0;
-	top: 0;
-	width: 100%;
-	height: 60px;
-	display: flex;
-  flex-direction: row;
-  justify-content: flex-end;
-	z-index: 10;
-
-	/* allow events to pass through top bar itself */
-	pointer-events: none !important;
-}
-.pswp__top-bar > * {
-  pointer-events: auto;
-  /* this makes transition significantly more smooth,
-     even though inner elements are not animated */
-  will-change: opacity;
-}
-
-
-/*
-
-  Close button
-
-*/
-.pswp__button--close {
-  margin-right: 6px;
-}
-
-
-/*
-
-  Arrow buttons
-
-*/
-.pswp__button--arrow {
-  position: absolute;
-  top: 0;
-  width: 75px;
-  height: 100px;
-  top: 50%;
-  margin-top: -50px;
-}
-
-.pswp__button--arrow:disabled {
-  display: none;
-  cursor: default;
-}
-
-.pswp__button--arrow .pswp__icn {
-  top: 50%;
-  margin-top: -30px;
-  width: 60px;
-  height: 60px;
-  background: none;
-  border-radius: 0;
-}
-
-/* Display arrows only when user hovers over them */
-/* .pswp--ui-visible {
-  .pswp__button--arrow, {
-    opacity: 0.75;
-
-    &:hover,
-    &:focus {
-      opacity: 1;
-      outline: none;
-    }
-  }
-} */
-
-.pswp--one-slide .pswp__button--arrow {
-  display: none;
-}
-
-/* hide arrows on touch screens */
-.pswp--touch .pswp__button--arrow {
-  visibility: hidden;
-}
-
-/* show arrows only after mouse was used */
-.pswp--has_mouse .pswp__button--arrow {
-  visibility: visible;
-}
-
-.pswp__button--arrow--prev {
-  right: auto;
-  left: 0px;
-}
-
-.pswp__button--arrow--next {
-  right: 0px;
-}
-.pswp__button--arrow--next .pswp__icn {
-  left: auto;
-  right: 14px;
-  /* flip horizontally */
-  transform: scale(-1, 1);
-}
-
-/*
-
-  Zoom button
-
-*/
-.pswp__button--zoom {
-  display: none;
-}
-
-.pswp--zoom-allowed .pswp__button--zoom {
-  display: block;
-}
-
-/* "+" => "-" */
-.pswp--zoomed-in .pswp__zoom-icn-bar-v {
-  display: none;
-}
-
-
-/*
-
-  Loading indicator
-
-*/
-.pswp__preloader {
-  position: absolute;
-  display: none;
-  width: 24px;
-  height: 24px;
-  pointer-events: none;
-  border: 3px solid var(--pswp-preloader-color);
-  border-left-color: var(--pswp-preloader-color-secondary);
-  border-radius: 50%;
-
-
-  
-
-  /* left:50% / top:50% styles are defined via JS,
-    as size of PhotoSwipe viewport might change visually
-    (because of UI elements like sidebar),
-    use !important if you want to override them */
-}
-
-.pswp__preloader--active {
-  display: block;
-  animation: pswp-fadein 333ms linear, pswp-clockwise 600ms linear infinite;
-}
-
-.pswp__preloader--hiding {
-  animation: pswp-clockwise 600ms linear infinite;
-
-  /* use of !important to override hide-on-close styles */
-  opacity: 0 !important;
-}
-
-
-@keyframes pswp-clockwise {
-  0% { transform: rotate(0deg); }
-  100% { transform: rotate(360deg); }
-}
-
-@keyframes pswp-fadein {
-  0% { opacity: 0; }
-  100% { opacity: 1; }
-}
-
-
-/*
-
-  "1 of 10" counter
-
-*/
-.pswp__counter {
-  height: 30px;
-  margin: 18px 0 0 20px;
-  font-size: 14px;
-  line-height: 30px;
-  color: var(--pswp-icon-color);
-  opacity: 0.85;
-  margin-right: auto; /* align left */
-}
-
-.pswp--one-slide .pswp__counter {
-  display: none;
-}

File diff suppressed because it is too large
+ 0 - 6
resources/css/reveal.min.css


File diff suppressed because it is too large
+ 0 - 0
resources/css/reveal_black.min.css


+ 0 - 9
resources/css/shepherd.css

@@ -1,9 +0,0 @@
-.shepherd-button{background:#3288e6;border:0;border-radius:3px;color:hsla(0,0%,100%,.75);cursor:pointer;margin-right:.5rem;padding:.5rem 1.5rem;transition:all .5s ease}.shepherd-button:not(:disabled):hover{background:#196fcc;color:hsla(0,0%,100%,.75)}.shepherd-button.shepherd-button-secondary{background:#f1f2f3;color:rgba(0,0,0,.75)}.shepherd-button.shepherd-button-secondary:not(:disabled):hover{background:#d6d9db;color:rgba(0,0,0,.75)}.shepherd-button:disabled{cursor:not-allowed}
-.shepherd-footer{border-bottom-left-radius:5px;border-bottom-right-radius:5px;display:flex;justify-content:flex-end;padding:0 .75rem .75rem}.shepherd-footer .shepherd-button:last-child{margin-right:0}
-.shepherd-cancel-icon{background:transparent;border:none;color:hsla(0,0%,50%,.75);cursor:pointer;font-size:2em;font-weight:400;margin:0;padding:0;transition:color .5s ease}.shepherd-cancel-icon:hover{color:rgba(0,0,0,.75)}.shepherd-has-title .shepherd-content .shepherd-cancel-icon{color:hsla(0,0%,50%,.75)}.shepherd-has-title .shepherd-content .shepherd-cancel-icon:hover{color:rgba(0,0,0,.75)}
-.shepherd-title{color:rgba(0,0,0,.75);display:flex;flex:1 0 auto;font-size:1rem;font-weight:400;margin:0;padding:0}
-.shepherd-header{align-items:center;border-top-left-radius:5px;border-top-right-radius:5px;display:flex;justify-content:flex-end;line-height:2em;padding:.75rem .75rem 0}.shepherd-has-title .shepherd-content .shepherd-header{background:#e6e6e6;padding:1em}
-.shepherd-text{color:rgba(0,0,0,.75);font-size:1rem;line-height:1.3em;padding:.75em}.shepherd-text p{margin-top:0}.shepherd-text p:last-child{margin-bottom:0}
-.shepherd-content{border-radius:5px;outline:none;padding:0}
-.shepherd-element{background:#fff;border-radius:5px;box-shadow:0 1px 4px rgba(0,0,0,.2);max-width:400px;opacity:0;outline:none;transition:opacity .3s,visibility .3s;visibility:hidden;width:100%;z-index:9999}.shepherd-enabled.shepherd-element{opacity:1;visibility:visible}.shepherd-element[data-popper-reference-hidden]:not(.shepherd-centered){opacity:0;pointer-events:none;visibility:hidden}.shepherd-element,.shepherd-element *,.shepherd-element :after,.shepherd-element :before{box-sizing:border-box}.shepherd-arrow,.shepherd-arrow:before{height:16px;position:absolute;width:16px;z-index:-1}.shepherd-arrow:before{background:#fff;content:"";transform:rotate(45deg)}.shepherd-element[data-popper-placement^=top]>.shepherd-arrow{bottom:-8px}.shepherd-element[data-popper-placement^=bottom]>.shepherd-arrow{top:-8px}.shepherd-element[data-popper-placement^=left]>.shepherd-arrow{right:-8px}.shepherd-element[data-popper-placement^=right]>.shepherd-arrow{left:-8px}.shepherd-element.shepherd-centered>.shepherd-arrow{opacity:0}.shepherd-element.shepherd-has-title[data-popper-placement^=bottom]>.shepherd-arrow:before{background-color:#e6e6e6}.shepherd-target-click-disabled.shepherd-enabled.shepherd-target,.shepherd-target-click-disabled.shepherd-enabled.shepherd-target *{pointer-events:none}
-.shepherd-modal-overlay-container{height:0;left:0;opacity:0;overflow:hidden;pointer-events:none;position:fixed;top:0;transition:all .3s ease-out,height 0ms .3s,opacity .3s 0ms;width:100vw;z-index:9997}.shepherd-modal-overlay-container.shepherd-modal-is-visible{height:100vh;opacity:.5;transition:all .3s ease-out,height 0s 0s,opacity .3s 0s}.shepherd-modal-overlay-container.shepherd-modal-is-visible path{pointer-events:all}

+ 0 - 36
resources/css/show-hint.css

@@ -1,36 +0,0 @@
-.CodeMirror-hints {
-  position: absolute;
-  z-index: 10;
-  overflow: hidden;
-  list-style: none;
-
-  margin: 0;
-  padding: 2px;
-
-  -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
-  -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
-  box-shadow: 2px 3px 5px rgba(0,0,0,.2);
-  border-radius: 3px;
-  border: 1px solid silver;
-
-  background: white;
-  font-size: 90%;
-  font-family: monospace;
-
-  max-height: 20em;
-  overflow-y: auto;
-}
-
-.CodeMirror-hint {
-  margin: 0;
-  padding: 0 4px;
-  border-radius: 2px;
-  white-space: pre;
-  color: black;
-  cursor: pointer;
-}
-
-li.CodeMirror-hint-active {
-  background: #08f;
-  color: white;
-}

+ 0 - 47
resources/css/table.css

@@ -1,47 +0,0 @@
-div.table-wrapper {
-    overflow: auto;
-}
-
-table {
-    width: 100%;
-    border-collapse: collapse;
-    text-align: left;
-    margin: 1rem 0;
-}
-
-th {
-    font-size: 14px;
-    font-weight: 400;
-    color: var(--ls-primary-text-color);
-    border-bottom: 2px solid var(--ls-border-color);
-    padding: 10px 8px;
-}
-
-td {
-    padding: 6px 8px;
-    text-align: left;
-}
-
-tr:nth-child(even) {background: or(--logseq-og-table-stripe-background, --lx-gray-03, --ls-table-tr-even-background-color);}
-tr:nth-child(odd) {background:  or(--logseq-og-table-background, --lx-gray-01, --ls-primary-background-color);}
-
-caption.t-above {caption-side:top}
-caption.t-bottom {caption-side:bottom}
-caption {margin-bottom:.3em}
-figcaption{margin-top:.3em}
-.org-right{text-align:right}
-.org-left{text-align:left}
-.org-center{text-align:center}
-
-.dark-theme th {
-    color: var(--ls-primary-text-color);
-}
-
-.dark-theme tr:nth-child(even) {background: or(--logseq-og-table-stripe-background, --lx-gray-03, --ls-table-tr-even-background-color);}
-.dark-theme tr:nth-child(odd) {background: or(--logseq-og-table-background, --lx-gray-02, --ls-primary-background-color);}
-.dark-theme td, .dark-theme tr {
-    border-bottom: none;
-}
-.dark-theme th {
-    border-bottom: 2px solid var(--ls-border-color);
-}

+ 0 - 665
resources/css/tooltip.css

@@ -1,665 +0,0 @@
-.tippy-touch {
-  cursor: pointer !important
-}
-
-.tippy-notransition {
-  transition: none !important
-}
-
-.tippy-popper {
-  max-width: 800px;
-  -webkit-perspective: 800px;
-  perspective: 800px;
-  z-index: 9999;
-  outline: 0;
-  transition-timing-function: cubic-bezier(.165, .84, .44, 1);
-  pointer-events: none
-}
-
-.tippy-popper.html-template {
-  max-width: 96%;
-  max-width: calc(100% - 20px)
-}
-
-.tippy-popper[x-placement^=top] [x-arrow] {
-  border-top: 7px solid var(--ls-quaternary-background-color);
-  border-right: 7px solid transparent;
-  border-left: 7px solid transparent;
-  bottom: -7px;
-  margin: 0 9px
-}
-
-.tippy-popper[x-placement^=top] [x-arrow].arrow-small {
-  border-top: 5px solid var(--ls-quaternary-background-color);
-  border-right: 5px solid transparent;
-  border-left: 5px solid transparent;
-  bottom: -5px
-}
-
-.tippy-popper[x-placement^=top] [x-arrow].arrow-big {
-  border-top: 10px solid var(--ls-quaternary-background-color);
-  border-right: 10px solid transparent;
-  border-left: 10px solid transparent;
-  bottom: -10px
-}
-
-.tippy-popper[x-placement^=top] [x-circle] {
-  -webkit-transform-origin: 0 33%;
-  transform-origin: 0 33%
-}
-
-.tippy-popper[x-placement^=top] [x-circle].enter {
-  -webkit-transform: scale(1) translate(-50%, -55%);
-  transform: scale(1) translate(-50%, -55%);
-  opacity: 1
-}
-
-.tippy-popper[x-placement^=top] [x-circle].leave {
-  -webkit-transform: scale(.15) translate(-50%, -50%);
-  transform: scale(.15) translate(-50%, -50%);
-  opacity: 0
-}
-
-.tippy-popper[x-placement^=top] .tippy-tooltip.light-theme [x-circle] {
-  background-color: #fff
-}
-
-.tippy-popper[x-placement^=top] .tippy-tooltip.light-theme [x-arrow] {
-  border-top: 7px solid #fff;
-  border-right: 7px solid transparent;
-  border-left: 7px solid transparent
-}
-
-.tippy-popper[x-placement^=top] .tippy-tooltip.light-theme [x-arrow].arrow-small {
-  border-top: 5px solid #fff;
-  border-right: 5px solid transparent;
-  border-left: 5px solid transparent
-}
-
-.tippy-popper[x-placement^=top] .tippy-tooltip.light-theme [x-arrow].arrow-big {
-  border-top: 10px solid #fff;
-  border-right: 10px solid transparent;
-  border-left: 10px solid transparent
-}
-
-.tippy-popper[x-placement^=top] .tippy-tooltip.transparent-theme [x-circle] {
-  background-color: var(--ls-secondary-background-color)
-}
-
-.tippy-popper[x-placement^=top] .tippy-tooltip.transparent-theme [x-arrow] {
-  border-top: 7px solid var(--ls-secondary-background-color);
-  border-right: 7px solid transparent;
-  border-left: 7px solid transparent
-}
-
-.tippy-popper[x-placement^=top] .tippy-tooltip.transparent-theme [x-arrow].arrow-small {
-  border-top: 5px solid var(--ls-secondary-background-color);
-  border-right: 5px solid transparent;
-  border-left: 5px solid transparent
-}
-
-.tippy-popper[x-placement^=top] .tippy-tooltip.transparent-theme [x-arrow].arrow-big {
-  border-top: 10px solid var(--ls-secondary-background-color);
-  border-right: 10px solid transparent;
-  border-left: 10px solid transparent
-}
-
-.tippy-popper[x-placement^=top] [data-animation=perspective] {
-  -webkit-transform-origin: bottom;
-  transform-origin: bottom
-}
-
-.tippy-popper[x-placement^=top] [data-animation=perspective].enter {
-  opacity: 1;
-  -webkit-transform: translateY(-10px) rotateX(0);
-  transform: translateY(-10px) rotateX(0)
-}
-
-.tippy-popper[x-placement^=top] [data-animation=perspective].leave {
-  opacity: 0;
-  -webkit-transform: translateY(0) rotateX(90deg);
-  transform: translateY(0) rotateX(90deg)
-}
-
-.tippy-popper[x-placement^=top] [data-animation=fade].enter {
-  opacity: 1;
-  -webkit-transform: translateY(-10px);
-  transform: translateY(-10px)
-}
-
-.tippy-popper[x-placement^=top] [data-animation=fade].leave {
-  opacity: 0;
-  -webkit-transform: translateY(-10px);
-  transform: translateY(-10px)
-}
-
-.tippy-popper[x-placement^=top] [data-animation=shift].enter {
-  opacity: 1;
-  -webkit-transform: translateY(-10px);
-  transform: translateY(-10px)
-}
-
-.tippy-popper[x-placement^=top] [data-animation=shift].leave {
-  opacity: 0;
-  -webkit-transform: translateY(0);
-  transform: translateY(0)
-}
-
-.tippy-popper[x-placement^=top] [data-animation=scale].enter {
-  opacity: 1;
-  -webkit-transform: translateY(-10px) scale(1);
-  transform: translateY(-10px) scale(1)
-}
-
-.tippy-popper[x-placement^=top] [data-animation=scale].leave {
-  opacity: 0;
-  -webkit-transform: translateY(0) scale(0);
-  transform: translateY(0) scale(0)
-}
-
-.tippy-popper[x-placement^=bottom] [x-arrow] {
-  border-bottom: 7px solid var(--ls-quaternary-background-color);
-  border-right: 7px solid transparent;
-  border-left: 7px solid transparent;
-  top: -7px;
-  margin: 0 9px
-}
-
-.tippy-popper[x-placement^=bottom] [x-arrow].arrow-small {
-  border-bottom: 5px solid var(--ls-quaternary-background-color);
-  border-right: 5px solid transparent;
-  border-left: 5px solid transparent;
-  top: -5px
-}
-
-.tippy-popper[x-placement^=bottom] [x-arrow].arrow-big {
-  border-bottom: 10px solid var(--ls-quaternary-background-color);
-  border-right: 10px solid transparent;
-  border-left: 10px solid transparent;
-  top: -10px
-}
-
-.tippy-popper[x-placement^=bottom] [x-circle] {
-  -webkit-transform-origin: 0 -50%;
-  transform-origin: 0 -50%
-}
-
-.tippy-popper[x-placement^=bottom] [x-circle].enter {
-  -webkit-transform: scale(1) translate(-50%, -45%);
-  transform: scale(1) translate(-50%, -45%);
-  opacity: 1
-}
-
-.tippy-popper[x-placement^=bottom] [x-circle].leave {
-  -webkit-transform: scale(.15) translate(-50%, -5%);
-  transform: scale(.15) translate(-50%, -5%);
-  opacity: 0
-}
-
-.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-circle] {
-  background-color: #fff
-}
-
-.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-arrow] {
-  border-bottom: 7px solid #fff;
-  border-right: 7px solid transparent;
-  border-left: 7px solid transparent
-}
-
-.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-arrow].arrow-small {
-  border-bottom: 5px solid #fff;
-  border-right: 5px solid transparent;
-  border-left: 5px solid transparent
-}
-
-.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-arrow].arrow-big {
-  border-bottom: 10px solid #fff;
-  border-right: 10px solid transparent;
-  border-left: 10px solid transparent
-}
-
-.tippy-popper[x-placement^=bottom] .tippy-tooltip.transparent-theme [x-circle] {
-  background-color: var(--ls-secondary-background-color)
-}
-
-.tippy-popper[x-placement^=bottom] .tippy-tooltip.transparent-theme [x-arrow] {
-  border-bottom: 7px solid var(--ls-secondary-background-color);
-  border-right: 7px solid transparent;
-  border-left: 7px solid transparent
-}
-
-.tippy-popper[x-placement^=bottom] .tippy-tooltip.transparent-theme [x-arrow].arrow-small {
-  border-bottom: 5px solid var(--ls-secondary-background-color);
-  border-right: 5px solid transparent;
-  border-left: 5px solid transparent
-}
-
-.tippy-popper[x-placement^=bottom] .tippy-tooltip.transparent-theme [x-arrow].arrow-big {
-  border-bottom: 10px solid var(--ls-secondary-background-color);
-  border-right: 10px solid transparent;
-  border-left: 10px solid transparent
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=perspective] {
-  -webkit-transform-origin: top;
-  transform-origin: top
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=perspective].enter {
-  opacity: 1;
-  -webkit-transform: translateY(10px) rotateX(0);
-  transform: translateY(10px) rotateX(0)
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=perspective].leave {
-  opacity: 0;
-  -webkit-transform: translateY(0) rotateX(-90deg);
-  transform: translateY(0) rotateX(-90deg)
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=fade].enter {
-  opacity: 1;
-  -webkit-transform: translateY(10px);
-  transform: translateY(10px)
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=fade].leave {
-  opacity: 0;
-  -webkit-transform: translateY(10px);
-  transform: translateY(10px)
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=shift].enter {
-  opacity: 1;
-  -webkit-transform: translateY(10px);
-  transform: translateY(10px)
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=shift].leave {
-  opacity: 0;
-  -webkit-transform: translateY(0);
-  transform: translateY(0)
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=scale].enter {
-  opacity: 1;
-  -webkit-transform: translateY(10px) scale(1);
-  transform: translateY(10px) scale(1)
-}
-
-.tippy-popper[x-placement^=bottom] [data-animation=scale].leave {
-  opacity: 0;
-  -webkit-transform: translateY(0) scale(0);
-  transform: translateY(0) scale(0)
-}
-
-.tippy-popper[x-placement^=left] [x-arrow] {
-  border-left: 7px solid var(--ls-quaternary-background-color);
-  border-top: 7px solid transparent;
-  border-bottom: 7px solid transparent;
-  right: -7px;
-  margin: 6px 0
-}
-
-.tippy-popper[x-placement^=left] [x-arrow].arrow-small {
-  border-left: 5px solid var(--ls-quaternary-background-color);
-  border-top: 5px solid transparent;
-  border-bottom: 5px solid transparent;
-  right: -5px
-}
-
-.tippy-popper[x-placement^=left] [x-arrow].arrow-big {
-  border-left: 10px solid var(--ls-quaternary-background-color);
-  border-top: 10px solid transparent;
-  border-bottom: 10px solid transparent;
-  right: -10px
-}
-
-.tippy-popper[x-placement^=left] [x-circle] {
-  -webkit-transform-origin: 50% 0;
-  transform-origin: 50% 0
-}
-
-.tippy-popper[x-placement^=left] [x-circle].enter {
-  -webkit-transform: scale(1) translate(-50%, -50%);
-  transform: scale(1) translate(-50%, -50%);
-  opacity: 1
-}
-
-.tippy-popper[x-placement^=left] [x-circle].leave {
-  -webkit-transform: scale(.15) translate(-50%, -50%);
-  transform: scale(.15) translate(-50%, -50%);
-  opacity: 0
-}
-
-.tippy-popper[x-placement^=left] .tippy-tooltip.light-theme [x-circle] {
-  background-color: #fff
-}
-
-.tippy-popper[x-placement^=left] .tippy-tooltip.light-theme [x-arrow] {
-  border-left: 7px solid #fff;
-  border-top: 7px solid transparent;
-  border-bottom: 7px solid transparent
-}
-
-.tippy-popper[x-placement^=left] .tippy-tooltip.light-theme [x-arrow].arrow-small {
-  border-left: 5px solid #fff;
-  border-top: 5px solid transparent;
-  border-bottom: 5px solid transparent
-}
-
-.tippy-popper[x-placement^=left] .tippy-tooltip.light-theme [x-arrow].arrow-big {
-  border-left: 10px solid #fff;
-  border-top: 10px solid transparent;
-  border-bottom: 10px solid transparent
-}
-
-.tippy-popper[x-placement^=left] .tippy-tooltip.transparent-theme [x-circle] {
-  background-color: var(--ls-secondary-background-color)
-}
-
-.tippy-popper[x-placement^=left] .tippy-tooltip.transparent-theme [x-arrow] {
-  border-left: 7px solid var(--ls-secondary-background-color);
-  border-top: 7px solid transparent;
-  border-bottom: 7px solid transparent
-}
-
-.tippy-popper[x-placement^=left] .tippy-tooltip.transparent-theme [x-arrow].arrow-small {
-  border-left: 5px solid var(--ls-secondary-background-color);
-  border-top: 5px solid transparent;
-  border-bottom: 5px solid transparent
-}
-
-.tippy-popper[x-placement^=left] .tippy-tooltip.transparent-theme [x-arrow].arrow-big {
-  border-left: 10px solid var(--ls-secondary-background-color);
-  border-top: 10px solid transparent;
-  border-bottom: 10px solid transparent
-}
-
-.tippy-popper[x-placement^=left] [data-animation=perspective] {
-  -webkit-transform-origin: right;
-  transform-origin: right
-}
-
-.tippy-popper[x-placement^=left] [data-animation=perspective].enter {
-  opacity: 1;
-  -webkit-transform: translateX(-10px) rotateY(0);
-  transform: translateX(-10px) rotateY(0)
-}
-
-.tippy-popper[x-placement^=left] [data-animation=perspective].leave {
-  opacity: 0;
-  -webkit-transform: translateX(0) rotateY(-90deg);
-  transform: translateX(0) rotateY(-90deg)
-}
-
-.tippy-popper[x-placement^=left] [data-animation=fade].enter {
-  opacity: 1;
-  -webkit-transform: translateX(-10px);
-  transform: translateX(-10px)
-}
-
-.tippy-popper[x-placement^=left] [data-animation=fade].leave {
-  opacity: 0;
-  -webkit-transform: translateX(-10px);
-  transform: translateX(-10px)
-}
-
-.tippy-popper[x-placement^=left] [data-animation=shift].enter {
-  opacity: 1;
-  -webkit-transform: translateX(-10px);
-  transform: translateX(-10px)
-}
-
-.tippy-popper[x-placement^=left] [data-animation=shift].leave {
-  opacity: 0;
-  -webkit-transform: translateX(0);
-  transform: translateX(0)
-}
-
-.tippy-popper[x-placement^=left] [data-animation=scale].enter {
-  opacity: 1;
-  -webkit-transform: translateX(-10px) scale(1);
-  transform: translateX(-10px) scale(1)
-}
-
-.tippy-popper[x-placement^=left] [data-animation=scale].leave {
-  opacity: 0;
-  -webkit-transform: translateX(0) scale(0);
-  transform: translateX(0) scale(0)
-}
-
-.tippy-popper[x-placement^=right] [x-arrow] {
-  border-right: 7px solid var(--ls-quaternary-background-color);
-  border-top: 7px solid transparent;
-  border-bottom: 7px solid transparent;
-  left: -7px;
-  margin: 6px 0
-}
-
-.tippy-popper[x-placement^=right] [x-arrow].arrow-small {
-  border-right: 5px solid var(--ls-quaternary-background-color);
-  border-top: 5px solid transparent;
-  border-bottom: 5px solid transparent;
-  left: -5px
-}
-
-.tippy-popper[x-placement^=right] [x-arrow].arrow-big {
-  border-right: 10px solid var(--ls-quaternary-background-color);
-  border-top: 10px solid transparent;
-  border-bottom: 10px solid transparent;
-  left: -10px
-}
-
-.tippy-popper[x-placement^=right] [x-circle] {
-  -webkit-transform-origin: -50% 0;
-  transform-origin: -50% 0
-}
-
-.tippy-popper[x-placement^=right] [x-circle].enter {
-  -webkit-transform: scale(1) translate(-50%, -50%);
-  transform: scale(1) translate(-50%, -50%);
-  opacity: 1
-}
-
-.tippy-popper[x-placement^=right] [x-circle].leave {
-  -webkit-transform: scale(.15) translate(-50%, -50%);
-  transform: scale(.15) translate(-50%, -50%);
-  opacity: 0
-}
-
-.tippy-popper[x-placement^=right] .tippy-tooltip.light-theme [x-circle] {
-  background-color: #fff
-}
-
-.tippy-popper[x-placement^=right] .tippy-tooltip.light-theme [x-arrow] {
-  border-right: 7px solid #fff;
-  border-top: 7px solid transparent;
-  border-bottom: 7px solid transparent
-}
-
-.tippy-popper[x-placement^=right] .tippy-tooltip.light-theme [x-arrow].arrow-small {
-  border-right: 5px solid #fff;
-  border-top: 5px solid transparent;
-  border-bottom: 5px solid transparent
-}
-
-.tippy-popper[x-placement^=right] .tippy-tooltip.light-theme [x-arrow].arrow-big {
-  border-right: 10px solid #fff;
-  border-top: 10px solid transparent;
-  border-bottom: 10px solid transparent
-}
-
-.tippy-popper[x-placement^=right] .tippy-tooltip.transparent-theme [x-circle] {
-  background-color: var(--ls-secondary-background-color)
-}
-
-.tippy-popper[x-placement^=right] .tippy-tooltip.transparent-theme [x-arrow] {
-  border-right: 7px solid var(--ls-secondary-background-color);
-  border-top: 7px solid transparent;
-  border-bottom: 7px solid transparent
-}
-
-.tippy-popper[x-placement^=right] .tippy-tooltip.transparent-theme [x-arrow].arrow-small {
-  border-right: 5px solid var(--ls-secondary-background-color);
-  border-top: 5px solid transparent;
-  border-bottom: 5px solid transparent
-}
-
-.tippy-popper[x-placement^=right] .tippy-tooltip.transparent-theme [x-arrow].arrow-big {
-  border-right: 10px solid var(--ls-secondary-background-color);
-  border-top: 10px solid transparent;
-  border-bottom: 10px solid transparent
-}
-
-.tippy-popper[x-placement^=right] [data-animation=perspective] {
-  -webkit-transform-origin: left;
-  transform-origin: left
-}
-
-.tippy-popper[x-placement^=right] [data-animation=perspective].enter {
-  opacity: 1;
-  -webkit-transform: translateX(10px) rotateY(0);
-  transform: translateX(10px) rotateY(0)
-}
-
-.tippy-popper[x-placement^=right] [data-animation=perspective].leave {
-  opacity: 0;
-  -webkit-transform: translateX(0) rotateY(90deg);
-  transform: translateX(0) rotateY(90deg)
-}
-
-.tippy-popper[x-placement^=right] [data-animation=fade].enter {
-  opacity: 1;
-  -webkit-transform: translateX(10px);
-  transform: translateX(10px)
-}
-
-.tippy-popper[x-placement^=right] [data-animation=fade].leave {
-  opacity: 0;
-  -webkit-transform: translateX(10px);
-  transform: translateX(10px)
-}
-
-.tippy-popper[x-placement^=right] [data-animation=shift].enter {
-  opacity: 1;
-  -webkit-transform: translateX(10px);
-  transform: translateX(10px)
-}
-
-.tippy-popper[x-placement^=right] [data-animation=shift].leave {
-  opacity: 0;
-  -webkit-transform: translateX(0);
-  transform: translateX(0)
-}
-
-.tippy-popper[x-placement^=right] [data-animation=scale].enter {
-  opacity: 1;
-  -webkit-transform: translateX(10px) scale(1);
-  transform: translateX(10px) scale(1)
-}
-
-.tippy-popper[x-placement^=right] [data-animation=scale].leave {
-  opacity: 0;
-  -webkit-transform: translateX(0) scale(0);
-  transform: translateX(0) scale(0)
-}
-
-.tippy-popper .tippy-tooltip.transparent-theme {
-  background-color: var(--ls-secondary-background-color)
-}
-
-.tippy-popper .tippy-tooltip.transparent-theme[data-animatefill] {
-  background-color: transparent
-}
-
-.tippy-popper .tippy-tooltip.light-theme {
-  color: #26323d;
-  box-shadow: 0 4px 20px 4px rgba(0, 20, 60, .1), 0 4px 80px -8px rgba(0, 20, 60, .2);
-  background-color: #fff
-}
-
-.tippy-popper .tippy-tooltip.light-theme[data-animatefill] {
-  background-color: transparent
-}
-
-.tippy-tooltip {
-  position: relative;
-  color: var(--ls-primary-text-color);
-  border-radius: 4px;
-  text-align: center;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  background-color: var(--ls-quaternary-background-color);
-}
-
-.tippy-tooltip--small {
-  padding: .25rem .5rem;
-  font-size: .8rem
-}
-
-.tippy-tooltip--big {
-  padding: .6rem 1.2rem;
-  font-size: 1.2rem
-}
-
-.tippy-tooltip[data-animatefill] {
-  overflow: hidden;
-  background-color: transparent
-}
-
-.tippy-tooltip[data-interactive] {
-  pointer-events: auto
-}
-
-.tippy-tooltip[data-inertia] {
-  transition-timing-function: cubic-bezier(.53, 2, .36, .85)
-}
-
-.tippy-tooltip [x-arrow] {
-  position: absolute;
-  width: 0;
-  height: 0
-}
-
-.tippy-tooltip [x-circle] {
-  position: absolute;
-  background-color: var(--ls-quaternary-background-color);
-  border-radius: 50%;
-  width: 130%;
-  width: calc(110% + 2rem);
-  left: 50%;
-  top: 50%;
-  z-index: -1;
-  overflow: hidden;
-  transition: all ease
-}
-
-.tippy-tooltip [x-circle]:before {
-  content: "";
-  padding-top: 90%;
-  float: left
-}
-
-@media (max-width: 450px) {
-  .tippy-popper {
-    max-width: 96%;
-    max-width: calc(100% - 20px)
-  }
-}
-
-.tippy-popper .tippy-tooltip.customized-theme * {
-  text-align: left;
-}
-
-.tippy-wrapper {
-  background-color: var(--ls-quaternary-background-color);
-}
-
-.tippy-hover {
-  cursor: pointer;
-}
-
-.tippy-popper .tippy-tooltip.monospace-theme {
-  font-family: 'Fira Code', Monaco, Menlo, Consolas, 'COURIER NEW', monospace;
-}

BIN
resources/fonts/Cascadia.woff2


BIN
resources/fonts/FG_Virgil.woff2


BIN
resources/fonts/IBMPlexMono-Text-Latin1.woff


BIN
resources/fonts/IBMPlexSans-Bold.woff


BIN
resources/fonts/IBMPlexSans-Text.woff


BIN
resources/fonts/IBMPlexSans-TextItalic.woff


BIN
resources/fonts/Virgil.woff2


BIN
resources/fonts/inter/Inter-Black.woff


BIN
resources/fonts/inter/Inter-Black.woff2


BIN
resources/fonts/inter/Inter-BlackItalic.woff


BIN
resources/fonts/inter/Inter-BlackItalic.woff2


BIN
resources/fonts/inter/Inter-Bold.woff


BIN
resources/fonts/inter/Inter-Bold.woff2


BIN
resources/fonts/inter/Inter-BoldItalic.woff


BIN
resources/fonts/inter/Inter-BoldItalic.woff2


BIN
resources/fonts/inter/Inter-ExtraBold.woff


BIN
resources/fonts/inter/Inter-ExtraBold.woff2


BIN
resources/fonts/inter/Inter-ExtraBoldItalic.woff


BIN
resources/fonts/inter/Inter-ExtraBoldItalic.woff2


BIN
resources/fonts/inter/Inter-ExtraLight.woff


BIN
resources/fonts/inter/Inter-ExtraLight.woff2


BIN
resources/fonts/inter/Inter-ExtraLightItalic.woff


BIN
resources/fonts/inter/Inter-ExtraLightItalic.woff2


BIN
resources/fonts/inter/Inter-Italic.woff


BIN
resources/fonts/inter/Inter-Italic.woff2


BIN
resources/fonts/inter/Inter-Light.woff


BIN
resources/fonts/inter/Inter-Light.woff2


BIN
resources/fonts/inter/Inter-LightItalic.woff


BIN
resources/fonts/inter/Inter-LightItalic.woff2


BIN
resources/fonts/inter/Inter-Medium.woff


BIN
resources/fonts/inter/Inter-Medium.woff2


BIN
resources/fonts/inter/Inter-MediumItalic.woff


BIN
resources/fonts/inter/Inter-MediumItalic.woff2


BIN
resources/fonts/inter/Inter-Regular.woff


BIN
resources/fonts/inter/Inter-Regular.woff2


BIN
resources/fonts/inter/Inter-SemiBold.woff


BIN
resources/fonts/inter/Inter-SemiBold.woff2


BIN
resources/fonts/inter/Inter-SemiBoldItalic.woff


BIN
resources/fonts/inter/Inter-SemiBoldItalic.woff2


BIN
resources/fonts/inter/Inter-Thin.woff


BIN
resources/fonts/inter/Inter-Thin.woff2


BIN
resources/fonts/inter/Inter-ThinItalic.woff


BIN
resources/fonts/inter/Inter-ThinItalic.woff2


BIN
resources/fonts/inter/Inter-italic.var.woff2


BIN
resources/fonts/inter/Inter-roman.var.woff2


Some files were not shown because too many files changed in this diff