Browse Source

Merge branch 'master' into feat/db

Gabriel Horner 2 years ago
parent
commit
de3d7b7b5f
49 changed files with 2039 additions and 476 deletions
  1. 2 3
      .github/workflows/build-stage.yml
  2. 2 2
      android/app/build.gradle
  3. 13 13
      android/app/src/main/AndroidManifest.xml
  4. 121 16
      libs/yarn.lock
  5. 2 2
      package.json
  6. 2 2
      packages/amplify/src/LSAuthenticator.tsx
  7. 6 1
      packages/amplify/src/amplify.ts
  8. 1 1
      resources/forge.config.js
  9. 1 0
      resources/js/glide/glide.core.min.css
  10. 5 0
      resources/js/glide/glide.min.js
  11. 1 0
      resources/js/glide/glide.theme.min.css
  12. 6 5
      resources/package.json
  13. 9 3
      src/electron/electron/url.cljs
  14. 7 1
      src/main/electron/listener.cljs
  15. 5 4
      src/main/frontend/components/block.cljs
  16. 68 10
      src/main/frontend/components/container.cljs
  17. 34 11
      src/main/frontend/components/container.css
  18. 40 0
      src/main/frontend/components/handbooks.cljs
  19. 1 0
      src/main/frontend/components/onboarding/index.css
  20. 4 1
      src/main/frontend/components/search.cljs
  21. 14 5
      src/main/frontend/date.cljs
  22. 658 0
      src/main/frontend/extensions/handbooks/core.cljs
  23. 412 0
      src/main/frontend/extensions/handbooks/handbooks.css
  24. 51 46
      src/main/frontend/extensions/pdf/core.cljs
  25. 2 2
      src/main/frontend/extensions/pdf/pdf.css
  26. 13 1
      src/main/frontend/extensions/pdf/toolbar.cljs
  27. 46 44
      src/main/frontend/extensions/srs.cljs
  28. 24 24
      src/main/frontend/extensions/video/youtube.cljs
  29. 3 4
      src/main/frontend/handler/file_based/property/util.cljs
  30. 1 5
      src/main/frontend/handler/ui.cljs
  31. 2 1
      src/main/frontend/modules/file/core.cljs
  32. 76 68
      src/main/frontend/modules/layout/core.cljs
  33. 36 16
      src/main/frontend/state.cljs
  34. 7 1
      src/main/frontend/ui.cljs
  35. 3 3
      src/main/frontend/ui.css
  36. 24 0
      src/main/frontend/util.cljc
  37. 18 0
      src/main/frontend/util/block_content.cljs
  38. 1 1
      src/main/frontend/version.cljs
  39. 9 0
      src/resources/dicts/en.edn
  40. 9 0
      src/resources/dicts/es.edn
  41. 15 15
      src/resources/dicts/fr.edn
  42. 1 0
      src/resources/dicts/ja.edn
  43. 3 1
      src/resources/dicts/ko.edn
  44. 1 0
      src/resources/dicts/zh-cn.edn
  45. 1 0
      src/resources/dicts/zh-hant.edn
  46. 48 48
      static/yarn.lock
  47. 28 14
      tldraw/cljs-demo/yarn.lock
  48. 142 65
      tldraw/yarn.lock
  49. 61 37
      yarn.lock

+ 2 - 3
.github/workflows/build-stage.yml

@@ -3,10 +3,9 @@
 name: Build-Stage
 
 on:
-#  push:
-#    branches: [master, stage]
-
   workflow_dispatch:
+  release:
+    types: [released]
 
 jobs:
   build:

+ 2 - 2
android/app/build.gradle

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

+ 13 - 13
android/app/src/main/AndroidManifest.xml

@@ -1,5 +1,16 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- Permissions -->
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
     <application
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
@@ -11,7 +22,7 @@
 
         <activity
             android:exported="true"
-            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
             android:name="com.logseq.app.MainActivity"
             android:label="@string/title_activity_main"
             android:theme="@style/AppTheme.NoActionBarLaunch"
@@ -47,18 +58,7 @@
             android:grantUriPermissions="true">
             <meta-data
                 android:name="android.support.FILE_PROVIDER_PATHS"
-                android:resource="@xml/file_paths"></meta-data>
+                android:resource="@xml/file_paths" />
         </provider>
     </application>
-
-    <!-- Permissions -->
-
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
-    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
-    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.RECORD_AUDIO" />
 </manifest>

+ 121 - 16
libs/yarn.lock

@@ -17,6 +17,14 @@
   dependencies:
     "@babel/highlight" "^7.18.6"
 
+"@babel/code-frame@^7.22.13":
+  version "7.22.13"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
+  integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
+  dependencies:
+    "@babel/highlight" "^7.22.13"
+    chalk "^2.4.2"
+
 "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.0", "@babel/compat-data@^7.20.1":
   version "7.20.1"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30"
@@ -43,7 +51,7 @@
     json5 "^2.2.1"
     semver "^6.3.0"
 
-"@babel/generator@^7.20.1", "@babel/generator@^7.20.2":
+"@babel/generator@^7.20.2":
   version "7.20.4"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.4.tgz#4d9f8f0c30be75fd90a0562099a26e5839602ab8"
   integrity sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==
@@ -52,6 +60,16 @@
     "@jridgewell/gen-mapping" "^0.3.2"
     jsesc "^2.5.1"
 
+"@babel/generator@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
+  integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
+  dependencies:
+    "@babel/types" "^7.23.0"
+    "@jridgewell/gen-mapping" "^0.3.2"
+    "@jridgewell/trace-mapping" "^0.3.17"
+    jsesc "^2.5.1"
+
 "@babel/helper-annotate-as-pure@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
@@ -115,6 +133,11 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
   integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
 
+"@babel/helper-environment-visitor@^7.22.20":
+  version "7.22.20"
+  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+  integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
 "@babel/helper-explode-assignable-expression@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096"
@@ -130,6 +153,14 @@
     "@babel/template" "^7.18.10"
     "@babel/types" "^7.19.0"
 
+"@babel/helper-function-name@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+  integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
+  dependencies:
+    "@babel/template" "^7.22.15"
+    "@babel/types" "^7.23.0"
+
 "@babel/helper-hoist-variables@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
@@ -137,6 +168,13 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
+"@babel/helper-hoist-variables@^7.22.5":
+  version "7.22.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+  integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+  dependencies:
+    "@babel/types" "^7.22.5"
+
 "@babel/helper-member-expression-to-functions@^7.18.9":
   version "7.18.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
@@ -219,16 +257,33 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
+"@babel/helper-split-export-declaration@^7.22.6":
+  version "7.22.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+  integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+  dependencies:
+    "@babel/types" "^7.22.5"
+
 "@babel/helper-string-parser@^7.19.4":
   version "7.19.4"
   resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
   integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
 
+"@babel/helper-string-parser@^7.22.5":
+  version "7.22.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
+  integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+
 "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
   version "7.19.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
   integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
 
+"@babel/helper-validator-identifier@^7.22.20":
+  version "7.22.20"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+  integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
 "@babel/helper-validator-option@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
@@ -262,11 +317,25 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2":
+"@babel/highlight@^7.22.13":
+  version "7.22.20"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
+  integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.22.20"
+    chalk "^2.4.2"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.18.10", "@babel/parser@^7.20.2":
   version "7.20.3"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2"
   integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==
 
+"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
+  integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
+
 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
@@ -875,19 +944,28 @@
     "@babel/parser" "^7.18.10"
     "@babel/types" "^7.18.10"
 
-"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1":
-  version "7.20.1"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
-  integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
+"@babel/template@^7.22.15":
+  version "7.22.15"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
+  integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
   dependencies:
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.20.1"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.19.0"
-    "@babel/helper-hoist-variables" "^7.18.6"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/parser" "^7.20.1"
-    "@babel/types" "^7.20.0"
+    "@babel/code-frame" "^7.22.13"
+    "@babel/parser" "^7.22.15"
+    "@babel/types" "^7.22.15"
+
+"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1":
+  version "7.23.2"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
+  integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
+  dependencies:
+    "@babel/code-frame" "^7.22.13"
+    "@babel/generator" "^7.23.0"
+    "@babel/helper-environment-visitor" "^7.22.20"
+    "@babel/helper-function-name" "^7.23.0"
+    "@babel/helper-hoist-variables" "^7.22.5"
+    "@babel/helper-split-export-declaration" "^7.22.6"
+    "@babel/parser" "^7.23.0"
+    "@babel/types" "^7.23.0"
     debug "^4.1.0"
     globals "^11.1.0"
 
@@ -900,6 +978,15 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
+  integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+  dependencies:
+    "@babel/helper-string-parser" "^7.22.5"
+    "@babel/helper-validator-identifier" "^7.22.20"
+    to-fast-properties "^2.0.0"
+
 "@discoveryjs/json-ext@^0.5.0":
   version "0.5.3"
   resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d"
@@ -927,6 +1014,11 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
   integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
 
+"@jridgewell/resolve-uri@^3.1.0":
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+  integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
 "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
@@ -945,6 +1037,11 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
   integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
 
+"@jridgewell/sourcemap-codec@^1.4.14":
+  version "1.4.15"
+  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+  integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
 "@jridgewell/trace-mapping@^0.3.14":
   version "0.3.17"
   resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
@@ -953,6 +1050,14 @@
     "@jridgewell/resolve-uri" "3.1.0"
     "@jridgewell/sourcemap-codec" "1.4.14"
 
+"@jridgewell/trace-mapping@^0.3.17":
+  version "0.3.20"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
+  integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
+  dependencies:
+    "@jridgewell/resolve-uri" "^3.1.0"
+    "@jridgewell/sourcemap-codec" "^1.4.14"
+
 "@jridgewell/trace-mapping@^0.3.9":
   version "0.3.14"
   resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
@@ -1365,7 +1470,7 @@ caniuse-lite@^1.0.30001400:
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz#e7c59bd1bc518fae03a4656be442ce6c4887a795"
   integrity sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==
 
-chalk@^2.0.0:
+chalk@^2.0.0, chalk@^2.4.2:
   version "2.4.2"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
   integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -1483,7 +1588,7 @@ [email protected], debug@^4.1.0, debug@^4.1.1:
   dependencies:
     ms "2.1.2"
 
-deepmerge@^4.3.1:
[email protected]:
   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==

+ 2 - 2
package.json

@@ -97,7 +97,7 @@
         "@excalidraw/excalidraw": "0.15.3",
         "@highlightjs/cdn-assets": "10.4.1",
         "@isomorphic-git/lightning-fs": "^4.6.0",
-        "@logseq/capacitor-file-sync": "5.0.0",
+        "@logseq/capacitor-file-sync": "5.0.1",
         "@logseq/diff-merge": "0.2.2",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@radix-ui/colors": "^0.1.8",
@@ -115,7 +115,7 @@
         "d3-force": "3.0.0",
         "diff": "5.0.0",
         "dompurify": "2.4.0",
-        "electron": "24.6.3",
+        "electron": "25.9.3",
         "electron-dl": "3.3.0",
         "emoji-mart": "^5.5.2",
         "fs": "0.0.1-security",

+ 2 - 2
packages/amplify/src/LSAuthenticator.tsx

@@ -5,8 +5,8 @@ export function LSAuthenticator({ termsLink, children }: any) {
     <Authenticator
       formFields={{
         signUp: {
-          email: { order: 1 },
-          username: { order: 2 },
+          email: { order: 1, isRequired: true },
+          username: { order: 2, isRequired: true },
           password: { order: 3 },
           confirm_password: { order: 4 },
         },

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

@@ -7,14 +7,19 @@ import { dict } from 'aws-amplify-react/lib-esm/AmplifyI18n'
 dict.zh['Reset Password'] = '重置密码'
 dict.zh['Enter your email'] = '请输入邮箱'
 dict.zh['Enter your password'] = '请输入密码'
+dict.zh['Enter your Username'] = '请输入用户名'
 dict.zh['Confirm Password'] = '确认密码'
 dict.zh['Please confirm your Password'] = '请确认密码'
 dict.zh['Incorrect username or password.'] = '用户名或者密码不正确。如果您的邮箱未验证,请尝试使用用户名(非邮箱)登录,以保证再次邮箱验证流程。'
+dict.zh['User already exists'] = '用户名已经存在'
+dict.zh['Username or Email'] = '用户名或邮箱'
+dict.zh['Enter your Username or Email'] = '请输入用户名或邮箱'
 
 // @ts-ignore attach defaults
 dict.en = {
   'Incorrect username or password.': 'Incorrect username or password!   ' +
-    'For unconfirmed users, please input your username instead of Email to receive the code.'
+    'For unconfirmed users, please input your username instead of Email to receive the code.',
+  'User already exists': 'Username already exists'
 }
 
 const fixesMapping = {

+ 1 - 1
resources/forge.config.js

@@ -4,7 +4,7 @@ module.exports = {
   packagerConfig: {
     name: 'Logseq',
     icon: './icons/logseq_big_sur.icns',
-    buildVersion: 72,
+    buildVersion: 73,
     protocols: [
       {
         "protocol": "logseq",

+ 1 - 0
resources/js/glide/glide.core.min.css

@@ -0,0 +1 @@
+.glide{position:relative;width:100%;box-sizing:border-box}.glide *{box-sizing:inherit}.glide__track{overflow:hidden}.glide__slides{position:relative;width:100%;list-style:none;backface-visibility:hidden;transform-style:preserve-3d;touch-action:pan-Y;overflow:hidden;margin:0;padding:0;white-space:nowrap;display:flex;flex-wrap:nowrap;will-change:transform}.glide__slides--dragging{user-select:none}.glide__slide{width:100%;height:100%;flex-shrink:0;white-space:normal;user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}.glide__slide a{user-select:none;-webkit-user-drag:none;-moz-user-select:none;-ms-user-select:none}.glide__arrows{-webkit-touch-callout:none;user-select:none}.glide__bullets{-webkit-touch-callout:none;user-select:none}.glide--rtl{direction:rtl}

File diff suppressed because it is too large
+ 5 - 0
resources/js/glide/glide.min.js


+ 1 - 0
resources/js/glide/glide.theme.min.css

@@ -0,0 +1 @@
+.glide__arrow{position:absolute;display:block;top:50%;z-index:2;color:#fff;text-transform:uppercase;padding:9px 12px;background-color:transparent;border:2px solid rgba(255,255,255,.5);border-radius:4px;box-shadow:0 .25em .5em 0 rgba(0,0,0,.1);text-shadow:0 .25em .5em rgba(0,0,0,.1);opacity:1;cursor:pointer;transition:opacity 150ms ease,border 300ms ease-in-out;transform:translateY(-50%);line-height:1}.glide__arrow:focus{outline:none}.glide__arrow:hover{border-color:#fff}.glide__arrow--left{left:2em}.glide__arrow--right{right:2em}.glide__arrow--disabled{opacity:.33}.glide__bullets{position:absolute;z-index:2;bottom:2em;left:50%;display:inline-flex;list-style:none;transform:translateX(-50%)}.glide__bullet{background-color:rgba(255,255,255,.5);width:9px;height:9px;padding:0;border-radius:50%;border:2px solid transparent;transition:all 300ms ease-in-out;cursor:pointer;line-height:0;box-shadow:0 .25em .5em 0 rgba(0,0,0,.1);margin:0 .25em}.glide__bullet:focus{outline:none}.glide__bullet:hover,.glide__bullet:focus{border:2px solid #fff;background-color:rgba(255,255,255,.5)}.glide__bullet--active{background-color:#fff}.glide--swipeable{cursor:grab;cursor:-moz-grab;cursor:-webkit-grab}.glide--dragging{cursor:grabbing;cursor:-moz-grabbing;cursor:-webkit-grabbing}

+ 6 - 5
resources/package.json

@@ -1,7 +1,7 @@
 {
   "name": "Logseq",
   "productName": "Logseq",
-  "version": "0.9.19",
+  "version": "0.9.20",
   "main": "electron.js",
   "author": "Logseq",
   "license": "AGPL-3.0",
@@ -13,7 +13,7 @@
     "electron:make": "electron-forge make",
     "electron:make-macos-arm64": "electron-forge make --platform=darwin --arch=arm64",
     "electron:publish:github": "electron-forge publish",
-    "rebuild:all": "electron-rebuild -v 24.6.3 -f",
+    "rebuild:all": "electron-rebuild -v 25.9.3 -f",
     "postinstall": "install-app-deps"
   },
   "config": {
@@ -38,7 +38,7 @@
     "socks-proxy-agent": "8.0.2",
     "@sentry/electron": "2.5.1",
     "posthog-js": "1.10.2",
-    "@logseq/rsapi": "0.0.73",
+    "@logseq/rsapi": "0.0.75",
     "electron-deeplink": "1.0.10",
     "abort-controller": "3.0.0",
     "fastify": "latest",
@@ -53,12 +53,13 @@
     "@electron-forge/maker-squirrel": "^6.0.4",
     "@electron-forge/maker-zip": "^6.0.4",
     "@electron/rebuild": "3.2.10",
-    "electron": "24.6.3",
+    "electron": "25.9.3",
     "electron-builder": "^22.11.7",
     "electron-forge-maker-appimage": "https://github.com/logseq/electron-forge-maker-appimage.git"
   },
   "resolutions": {
-    "**/electron": "24.6.3",
+    "**/electron": "25.9.3",
+    "**/node-abi": "3.51.0",
     "**/node-gyp": "9.0.0"
   }
 }

+ 9 - 3
src/electron/electron/url.cljs

@@ -100,7 +100,13 @@
       (= "new-window" url-host)
       (local-url-handler win parsed-url true)
 
+      (= "handbook" url-host)
+      (send-to-renderer :handbook
+                        {:key  (some-> (.-pathname parsed-url) (string/replace-first #"^[\/]+" ""))
+                         :args (some-> (.-searchParams parsed-url) (js/Object.fromEntries))})
+
       :else
-      (send-to-renderer "notification" {:type "error"
-                                        :payload (str "Failed to open link. Cannot match `" url-host
-                                                      "` to any target.")}))))
+      (send-to-renderer :notification
+                        {:type    "error"
+                         :payload (str "Failed to open link. Cannot match `" url-host
+                                       "` to any target.")}))))

+ 7 - 1
src/main/electron/listener.cljs

@@ -186,7 +186,13 @@
 
   (safe-api-call "syncAPIServerState"
                  (fn [^js data]
-                   (state/set-state! :electron/server (bean/->clj data)))))
+                   (state/set-state! :electron/server (bean/->clj data))))
+
+
+  (safe-api-call "handbook"
+                 (fn [^js data]
+                   (when-let [k (and data (.-key data))]
+                     (state/open-handbook-pane! k)))))
 
 (defn listen!
   []

+ 5 - 4
src/main/frontend/components/block.cljs

@@ -544,8 +544,9 @@
 
    All page-names are sanitized except page-name-in-block"
   [state config page-name-in-block page-name redirect-page-name page-entity contents-page? children html-export? label whiteboard-page?]
-  (let [*mouse-down? (::mouse-down? state)
-        *hover? (::hover? state)
+  (let [*hover? (::hover? state)
+        ;; FIXME: Bring back fix from https://github.com/logseq/logseq/pull/10434/commits/42f68ce32e7a035e6926bc2798d46843bbd70297
+        *mouse-down? (::mouse-down? state)
         tag? (:tag? config)
         config (assoc config :whiteboard-page? whiteboard-page?)
         untitled? (model/untitled-page? page-name)
@@ -1363,7 +1364,7 @@
                   url)]
         (if (and (coll? src)
                  (= (first src) "youtube-player"))
-          (youtube/youtube-video (last src))
+          (youtube/youtube-video (last src) nil)
           (when src
             (let [width (min (- (util/get-width) 96) 560)
                   height (int (* width (/ (if (string/includes? src "player.bilibili.com")
@@ -1500,7 +1501,7 @@
                                 :else
                                 (nth (util/safe-re-find text-util/youtube-regex url) 5))]
           (when-not (string/blank? youtube-id)
-            (youtube/youtube-video youtube-id))))
+            (youtube/youtube-video youtube-id nil))))
 
       (= name "youtube-timestamp")
       (when-let [timestamp (first arguments)]

+ 68 - 10
src/main/frontend/components/container.cljs

@@ -1,6 +1,7 @@
 (ns frontend.components.container
   (:require [cljs-drag-n-drop.core :as dnd]
             [clojure.string :as string]
+            [frontend.version :refer [version]]
             [frontend.components.find-in-page :as find-in-page]
             [frontend.components.header :as header]
             [frontend.components.journal :as journal]
@@ -13,6 +14,7 @@
             [frontend.components.widgets :as widgets]
             [frontend.components.dnd :as dnd-component]
             [frontend.components.icon :as icon]
+            [frontend.components.handbooks :as handbooks]
             [frontend.config :as config]
             [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
@@ -38,6 +40,7 @@
             [frontend.util :as util]
             [frontend.util.cursor :as cursor]
             [frontend.components.window-controls :as window-controls]
+            [medley.core :as medley]
             [goog.dom :as gdom]
             [goog.object :as gobj]
             [logseq.common.path :as path]
@@ -654,15 +657,71 @@
                {:on-click state/toggle-document-mode!}
                "D"])))
 
+(def help-menu-items
+  [{:title "Handbook" :icon "book-2" :on-click #(handbooks/toggle-handbooks)}
+   {:title "Keyboard shortcuts" :icon "command" :on-click #(state/sidebar-add-block! (state/get-current-repo) "shortcut-settings" :shortcut-settings)}
+   {:title "Documentation" :icon "help" :href "https://docs.logseq.com/"}
+   :hr
+   {:title "Report bug" :icon "bug" :on-click #(rfe/push-state :bug-report)}
+   {:title "Request feature" :icon "git-pull-request" :href "https://discuss.logseq.com/c/feature-requests/"}
+   {:title "Submit feedback" :icon "messages" :href "https://discuss.logseq.com/c/feedback/13"}
+   :hr
+   {:title "Ask the community" :icon "brand-discord" :href "https://discord.com/invite/KpN4eHY"}
+   {:title "Support forum" :icon "message" :href "https://discuss.logseq.com/"}
+   :hr
+   {:title "Release notes" :icon "asterisk" :href "https://docs.logseq.com/#/page/changelog"}])
+
+(rum/defc help-menu-popup
+  []
+
+  (rum/use-effect!
+    (fn []
+      (state/set-state! :ui/handbooks-open? false))
+    [])
+
+  (rum/use-effect!
+    (fn []
+      (let [h #(state/set-state! :ui/help-open? false)]
+        (.addEventListener js/document.body "click" h)
+        #(.removeEventListener js/document.body "click" h)))
+    [])
+
+  [:div.cp__sidebar-help-menu-popup
+   [:div.list-wrap
+    (for [[idx {:keys [title icon href on-click] :as item}] (medley/indexed help-menu-items)]
+      (case item
+        :hr
+        [:hr.my-2 {:key idx}]
+
+        ;; default
+        [:a.it.flex.items-center.px-4.py-1.select-none
+         {:key      title
+          :on-click (fn []
+                      (cond
+                        (fn? on-click) (on-click)
+                        (string? href) (util/open-url href))
+                      (state/set-state! :ui/help-open? false))}
+         [:span.flex.items-center.pr-2.opacity-40 (ui/icon icon {:size 20})]
+         [:strong.font-normal title]]))]
+   [:div.ft.pl-11.pb-3
+    [:span.opacity.text-xs.opacity-30 "Logseq " version]]])
+
 (rum/defc help-button < rum/reactive
   []
-  (when-not (state/sub :ui/sidebar-open?)
-    [:div.cp__sidebar-help-btn
-     [:div.inner
-      {:title    (t :help-shortcut-title)
-       :on-click (fn []
-                   (state/sidebar-add-block! (state/get-current-repo) "help" :help))}
-      "?"]]))
+  (let [help-open?      (state/sub :ui/help-open?)
+        handbooks-open? (state/sub :ui/handbooks-open?)]
+    [:<>
+     [:div.cp__sidebar-help-btn
+      [:div.inner
+       {:title    (t :help-shortcut-title)
+        :on-click #(state/toggle! :ui/help-open?)}
+       "?"]]
+
+     (when help-open?
+       (help-menu-popup))
+
+     (when handbooks-open?
+       (handbooks/handbooks-popup))]))
 
 (rum/defcs ^:large-vars/cleanup-todo sidebar <
   (mixins/modal :modal/show?)
@@ -786,7 +845,6 @@
                                     :nfs-granted? granted?
                                     :db-restoring? db-restoring?})
       [:a#download.hidden]
-      (when
-       (and (not config/mobile?)
-            (not config/publishing?))
+      (when (and (not config/mobile?)
+                 (not config/publishing?))
         (help-button))])))

+ 34 - 11
src/main/frontend/components/container.css

@@ -487,14 +487,6 @@
   }
 }
 
-html[data-theme='dark'] {
-  #left-sidebar {
-    > .shade-mask {
-      background-color: rgba(0, 0, 0, .15);
-    }
-  }
-}
-
 .settings-modal {
   @apply -m-8 rounded-lg;
   /* box-shadow: inset 0 0 0 1px var(--ls-border-color); */
@@ -527,13 +519,36 @@ html[data-theme='dark'] {
     @apply fixed bottom-4 right-4 sm:right-8;
 
     > .inner {
-      @apply font-bold
-      rounded-full h-8 w-8 flex items-center justify-center font-bold
-      select-none cursor-help;
+      @apply rounded-full h-8 w-8 flex items-center justify-center
+      font-bold select-none cursor-help;
 
       background-color: var(--ls-secondary-background-color);
     }
   }
+
+  &-menu-popup {
+    @apply fixed bottom-14 right-8 z-10 border
+    rounded-lg min-w-[260px] shadow;
+
+    background-color: var(--ls-secondary-background-color);
+    border-color: var(--ls-border-color);
+
+    > .list-wrap {
+      @apply flex flex-col pt-3;
+
+      .it {
+        color: var(--ls-primary-text-color);
+
+        &:active, &:hover {
+          background-color: var(--ls-tertiary-background-color);
+        }
+      }
+    }
+  }
+
+  &-handbook-btn {
+    @apply bottom-16;
+  }
 }
 
 .cp__right-sidebar {
@@ -754,3 +769,11 @@ a.ui__modal-close, a.close {
 a.ui__modal-close:hover, a.close:hover {
   opacity: 1;
 }
+
+html[data-theme='dark'] {
+  #left-sidebar {
+    > .shade-mask {
+      background-color: rgba(0, 0, 0, .15);
+    }
+  }
+}

+ 40 - 0
src/main/frontend/components/handbooks.cljs

@@ -0,0 +1,40 @@
+(ns frontend.components.handbooks
+  (:require [rum.core :as rum]
+            [frontend.state :as state]
+            [frontend.modules.layout.core :as layout]
+            ;[shadow.lazy :as lazy]
+            [frontend.extensions.handbooks.core :as handbooks]))
+
+#_:clj-kondo/ignore
+;(def lazy-handbooks (lazy/loadable frontend.extensions.handbooks.core/content))
+;
+;(rum/defc loadable-handbooks
+;  []
+;  (let [[content set-content] (rum/use-state nil)]
+;
+;    (rum/use-effect!
+;     (fn []
+;       (lazy/load lazy-handbooks #(set-content %))) [])
+;
+;    [:div.cp__handbooks-content
+;     content]))
+
+(rum/defc handbooks-popup
+  []
+  (let [popup-ref (rum/use-ref nil)]
+    (rum/use-effect!
+     (fn []
+       (when-let [^js popup-el (rum/deref popup-ref)]
+         (comp
+          (layout/setup-draggable-container! popup-el nil))))
+     [])
+
+    [:div.cp__handbooks-popup
+     {:data-identity "logseq-handbooks"
+      :ref popup-ref}
+     [:div.cp__handbooks-content-wrap
+      (handbooks/content)]]))
+
+(defn toggle-handbooks
+  []
+  (state/toggle! :ui/handbooks-open?))

+ 1 - 0
src/main/frontend/components/onboarding/index.css

@@ -506,6 +506,7 @@ body[data-page=import] {
 
   &.cp__sidebar-help-btn {
     background-color: rgba(0, 0, 0, .4);
+    z-index: 9;
 
     > .inner {
       opacity: 1;

+ 4 - 1
src/main/frontend/components/search.cljs

@@ -115,8 +115,11 @@
     :graph-add-filter
     (state/add-graph-search-filter! search-q)
 
+    ;; If it's a journal title or journal file name, translate the title
     :new-page
-    (page-handler/create! search-q {:redirect? true})
+    (if-let [journal-title (date/journal-title->custom-format search-q)]
+        (page-handler/create! journal-title {:redirect? true :journal? true})
+        (page-handler/create! search-q {:redirect? true}))
 
     :new-class
     (let [search-q' (subs search-q 1)]

+ 14 - 5
src/main/frontend/date.cljs

@@ -1,5 +1,5 @@
 (ns frontend.date
-  "Date related utility fns"
+  "Journal date related utility fns"
   (:require ["chrono-node" :as chrono]
             [cljs-bean.core :as bean]
             [cljs-time.coerce :as tc]
@@ -154,12 +154,18 @@
    (journal-title-formatters)))
 
 (defn normalize-journal-title
-  "Normalize journal title at best effort. Return nil if title is not a valid date"
+  "Normalize journal title at best effort. Return nil if title is not a valid date.
+   Return goog.date.Date.
+
+   Return format: 20220812T000000"
   [title]
   (and title
        (normalize-date (gp-util/capitalize-all title))))
 
 (defn valid-journal-title?
+  "This is a loose rule, requires double check by journal-title->custom-format.
+
+   BUG: This also accepts strings like 3/4/5 as journal titles"
   [title]
   (boolean (normalize-journal-title title)))
 
@@ -176,6 +182,7 @@
    (date-time-util/safe-journal-title-formatters (state/get-date-formatter))))
 
 (defn journal-day->ts
+  "journal-day format yyyyMMdd"
   [day]
   (when day
     (-> (tf/parse (tf/formatter "yyyyMMdd") (str day))
@@ -185,20 +192,22 @@
   [journal-title]
   (journal-title-> journal-title #(tc/to-long %)))
 
-(def default-journal-title-formatter (tf/formatter "yyyy_MM_dd"))
+(def default-journal-filename-formatter (tf/formatter "yyyy_MM_dd"))
 
 (defn journal-title->default
+  "Journal title to filename format"
   [journal-title]
   (let [formatter (if-let [format (state/get-journal-file-name-format)]
                     (tf/formatter format)
-                    default-journal-title-formatter)]
+                    default-journal-filename-formatter)]
     (journal-title-> journal-title #(tf/unparse formatter %))))
 
 (defn date->file-name
+  "Date object to filename format"
   [date]
   (let [formatter (if-let [format (state/get-journal-file-name-format)]
                     (tf/formatter format)
-                    default-journal-title-formatter)]
+                    default-journal-filename-formatter)]
     (tf/unparse formatter date)))
 
 (defn journal-title->custom-format

+ 658 - 0
src/main/frontend/extensions/handbooks/core.cljs

@@ -0,0 +1,658 @@
+(ns frontend.extensions.handbooks.core
+  (:require [clojure.string :as string]
+            [rum.core :as rum]
+            [cljs.core.async :as async :refer [<! >!]]
+            [frontend.ui :as ui]
+            [frontend.state :as state]
+            [frontend.search :as search]
+            [frontend.config :as config]
+            [frontend.handler.notification :as notification]
+            [frontend.extensions.lightbox :as lightbox]
+            [frontend.modules.shortcut.config :as shortcut-config]
+            [frontend.rum :as r]
+            [cljs-bean.core :as bean]
+            [promesa.core :as p]
+            [camel-snake-kebab.core :as csk]
+            [medley.core :as medley]
+            [frontend.util :as util]
+            [frontend.storage :as storage]
+            [frontend.extensions.video.youtube :as youtube]
+            [frontend.context.i18n :refer [t]]
+            [clojure.edn :as edn]))
+
+(defonce *config (atom {}))
+
+(defn get-handbooks-endpoint
+  [resource]
+  (str
+    (if (storage/get :handbooks-dev-watch?)
+      "http://localhost:1337"
+      "https://handbooks.pages.dev")
+    resource))
+
+(defn resolve-asset-url
+  [path]
+  (if (string/starts-with? path "http")
+    path (str (get-handbooks-endpoint "/")
+              (-> path (string/replace-first "./" "")
+                  (string/replace-first #"^/+" "")))))
+
+(defn inflate-content-assets-urls
+  [content]
+  (if-let [matches (and (not (string/blank? content))
+                        (re-seq #"src=\"([^\"]+)\"" content))]
+    (reduce
+      (fn [content matched]
+        (if-let [matched (second matched)]
+          (string/replace content matched (resolve-asset-url matched)) content))
+      content matches)
+    content))
+
+(defn parse-key-from-href
+  [href base]
+  (when (and (string? href)
+             (not (string/blank? href)))
+    (when-let [href (some-> href (string/trim) (string/replace #".edn$" ""))]
+      (some-> (if (string/starts-with? href "@")
+                (string/replace href #"^[@\/]+" "")
+                (util/node-path.join base href))
+              (string/lower-case)
+              (csk/->snake_case_string)))))
+
+(defn parse-parent-key
+  [s]
+  (if (and (string? s) (string/includes? s "/"))
+    (subs s 0 (string/last-index-of s "/"))
+    s))
+
+(defn bind-parent-key
+  [{:keys [key] :as node}]
+  (cond-> node
+          (and (string? key)
+               (string/includes? key "/"))
+          (assoc :parent (parse-parent-key key))))
+
+(defn load-glide-assets!
+  []
+  (p/let [_ (util/css-load$ (str util/JS_ROOT "/glide/glide.core.min.css"))
+          _ (util/css-load$ (str util/JS_ROOT "/glide/glide.theme.min.css"))
+          _ (when-not (aget js/window "Glide")
+              (util/js-load$ (str util/JS_ROOT "/glide/glide.min.js")))]))
+
+(rum/defc topic-card
+  [{:keys [key title description cover] :as _topic} nav-fn! opts]
+  [:button.w-full.topic-card.flex.text-left
+   (merge
+     {:key      key
+      :on-click nav-fn!} opts)
+   (when cover
+     [:div.l.flex.items-center
+      [:img {:src (resolve-asset-url cover)}]])
+   [:div.r.flex.flex-col
+    [:strong title]
+    [:span description]]])
+
+(rum/defc pane-category-topics
+  [handbook-nodes pane-state nav!]
+
+  [:div.pane.pane-category-topics
+   [:div.topics-list
+    (let [category-key (:key (second pane-state))]
+      (when-let [category (get handbook-nodes category-key)]
+        (for [topic (:children category)]
+          (rum/with-key
+            (topic-card topic #(nav! [:topic-detail topic (:title category)] pane-state) nil)
+            (:key topic)))))]])
+
+(rum/defc media-render
+  [src]
+  (let [src (util/trim-safe src)
+        extname (some-> src (util/full-path-extname) (subs 1))
+        youtube-id (and (string/includes? src "youtube.com/watch?v=")
+                        (subs src (+ 2 (string/last-index-of src "v="))))]
+    (cond
+      (and extname (contains? config/video-formats (keyword extname)))
+      [:video {:src src :controls true}]
+
+      (string? youtube-id)
+      (youtube/youtube-video youtube-id {:width "100%" :height 235})
+
+      :else [:img {:src src}])))
+
+(rum/defc chapter-select
+  [topic children on-select]
+  (let [[open?, set-open?] (rum/use-state false)]
+    (rum/use-effect!
+      (fn []
+        (when-let [^js el (js/document.querySelector "[data-identity=logseq-handbooks]")]
+          (let [h #(when-not (some->> (.-target %)
+                                      (.contains (js/document.querySelector ".chapters-select")))
+                     (set-open? false))]
+            (.addEventListener el "click" h)
+            #(.removeEventListener el "click" h))))
+      [])
+
+    [:div.chapters-select.w-full
+     [:a.select-trigger
+      {:on-click #(set-open? (not open?))
+       :tabIndex "0"}
+      [:small "Current chapter"]
+      [:strong (:title topic)]
+      (if open?
+        (ui/icon "chevron-down")
+        (ui/icon "chevron-left"))
+
+      (when open?
+        [:ul
+         (for [c children]
+           (when (and (seq c) (not= (:key c) (:key topic)))
+             [:li {:key (:key c)}
+              [:a.flex {:tabIndex "0" :on-click #(on-select (:key c))}
+               (or (:title c) (:key c))]]))])]]))
+
+(rum/defc ^:large-vars/cleanup-todo pane-topic-detail
+  [handbook-nodes pane-state nav!]
+
+  (let [[deps-pending?, set-deps-pending?] (rum/use-state false)
+        *id-ref (rum/use-ref (str "glide--" (js/Date.now)))]
+
+    ;; load deps assets
+    (rum/use-effect!
+      (fn []
+        (set-deps-pending? true)
+        (-> (load-glide-assets!)
+            (p/then (fn [] (js/setTimeout
+                             #(when (js/document.getElementById (rum/deref *id-ref))
+                                (doto (js/window.Glide. (str "#" (rum/deref *id-ref))) (.mount))) 50)))
+            (p/finally #(set-deps-pending? false))))
+      [])
+
+    (rum/use-effect!
+      (fn []
+        (js/setTimeout #(some-> (js/document.querySelector ".cp__handbooks-content")
+                                (.scrollTo 0 0))))
+      [pane-state])
+
+    (when-let [topic-key (:key (second pane-state))]
+      (when-let [topic (get handbook-nodes topic-key)]
+        (let [chapters (:children topic)
+              has-chapters? (seq chapters)
+              topic (if has-chapters? (first chapters) topic)
+              parent (get handbook-nodes (:parent (bind-parent-key topic)))
+              chapters (or chapters (:children parent))
+              parent-key (:key parent)
+              parent-category? (not (string/includes? parent-key "/"))
+              show-chapters? (and (not parent-category?) (seq chapters))
+
+              chapters-len (count chapters)
+              chapter-current-idx (when-not (zero? chapters-len)
+                                    (util/find-index #(= (:key %) (:key topic)) chapters))]
+
+          (when-not deps-pending?
+            [:div.pane.pane-topic-detail
+             (when-not show-chapters?
+               [:h1.text-2xl.pb-3.font-semibold (:title topic)])
+
+             ;; chapters list
+             (when show-chapters?
+               [:div.chapters-wrap.py-2
+                (chapter-select
+                  topic chapters
+                  (fn [k]
+                    (when-let [chapter (get handbook-nodes k)]
+                      (nav! [:topic-detail chapter (:title parent)] pane-state))))])
+
+             ;; demos gallery
+             (when-let [demos (:demos topic)]
+               (let [demos (cond-> demos
+                                   (string? demos) (list))]
+                 (if (> (count demos) 1)
+                   [:div.flex.demos.glide
+                    {:id (rum/deref *id-ref)}
+
+                    [:div.glide__track {:data-glide-el "track"}
+                     [:div.glide__slides
+                      (for [demo demos]
+                        [:div.item.glide__slide
+                         (media-render (resolve-asset-url demo))])]]
+
+                    [:div.glide__bullets {:data-glide-el "controls[nav]"}
+                     (map-indexed
+                       (fn [idx _]
+                         [:button.glide__bullet {:data-glide-dir (str "=" idx)}
+                          (inc idx)])
+                       demos)]]
+
+                   [:div.flex.demos.pt-1
+                    (media-render (resolve-asset-url (first demos)))])))
+
+             [:div.content-wrap
+              (when-let [content (:content topic)]
+                [:<>
+                 [:div.content.markdown-body
+                  {:dangerouslySetInnerHTML {:__html (inflate-content-assets-urls content)}
+                   :on-click                (fn [^js e]
+                                              (when-let [target (.-target e)]
+                                                (if-let [^js img (.closest target "img")]
+                                                  (lightbox/preview-images! [{:src (.-src img)
+                                                                              :w   (.-naturalWidth img)
+                                                                              :h   (.-naturalHeight img)}])
+                                                  (when-let [link (some-> (.closest target "a") (.getAttribute "href"))]
+                                                    (when-let [to-k (and (not (string/starts-with? link "http"))
+                                                                         (parse-key-from-href link parent-key))]
+                                                      (if-let [to (get handbook-nodes to-k)]
+                                                        (nav! [:topic-detail to (:title parent)] pane-state)
+                                                        (js/console.error "ERROR: handbook link resource not found: " to-k link))
+                                                      (util/stop e))))))}]
+
+                 (when-let [idx (and (> chapters-len 1) chapter-current-idx)]
+                   (let [prev (when-not (zero? idx) (dec idx))
+                         next (when-not (= idx (dec chapters-len)) (inc idx))]
+
+                     [:div.controls.flex.justify-between.pt-4
+                      [:div (when prev (ui/button [:span.flex.items-center (ui/icon "arrow-left") "Prev chapter"]
+                                                  :small? true :on-click #(nav! [:topic-detail (nth chapters prev) (:title parent)] pane-state)))]
+                      [:div (when next (ui/button [:span.flex.items-center "Next chapter" (ui/icon "arrow-right")]
+                                                  :small? true :on-click #(nav! [:topic-detail (nth chapters next) (:title parent)] pane-state)))]]))])]]))))))
+
+(rum/defc pane-dashboard
+  [handbooks-nodes pane-state nav-to-pane!]
+  (when-let [root (get handbooks-nodes "__root")]
+    [:div.pane.dashboard-pane
+     (when-let [popular-topics (:popular-topics root)]
+       [:<>
+        [:h2 (t :handbook/popular-topics)]
+        [:div.topics-list
+         (for [topic-key popular-topics]
+           (when-let [topic (and (string? topic-key)
+                                 (->> (util/safe-lower-case topic-key)
+                                      (csk/->snake_case_string)
+                                      (get handbooks-nodes)))]
+             (topic-card topic #(nav-to-pane! [:topic-detail topic (t :handbook/title)] [:dashboard]) nil)))]])
+
+     [:h2 (t :handbook/help-categories)]
+     [:div.categories-list
+      (let [categories (:children root)
+            categories (conj (vec categories)
+                             {:key      :ls-shortcuts
+                              :title    [:span "Keyboard shortcuts"]
+                              :children [:span (->> (vals @shortcut-config/*config)
+                                                    (map count)
+                                                    (apply +))
+                                         " shortcuts"]
+                              :color    "#2563EB"
+                              :icon     "command"})]
+        (for [{:keys [key title children color icon] :as category} categories
+              :let [total (if counted? (count children) 0)]]
+          [:button.category-card.text-left
+           {:key      key
+            :style    {:border-left-color (or (ui/->block-background-color color) "var(--ls-secondary-background-color)")}
+            :data-total total
+            :on-click #(if (= key :ls-shortcuts)
+                         (do (state/toggle! :ui/handbooks-open?)
+                             (state/open-right-sidebar!)
+                             (state/sidebar-add-block! (state/get-current-repo) "shortcut-settings" :shortcut-settings))
+                         (nav-to-pane! [:topics category title] pane-state))}
+           [:div.icon-wrap
+            (ui/icon (or icon "chart-bubble") {:size 20})]
+           [:div.text-wrap
+            [:strong title]
+            (cond
+              (vector? children)
+              children
+
+              :else
+              [:span (str total " " (util/safe-lower-case (t :handbook/topics)))])]]))]]))
+
+(rum/defc pane-settings
+  [dev-watch? set-dev-watch?]
+  [:div.pane.pane-settings
+   [:div.item
+    [:p.flex.items-center.space-x-3.mb-0
+     [:strong "Writing mode (preview in time)"]
+     (ui/toggle dev-watch? #(set-dev-watch? (not dev-watch?)) true)]
+    [:small.opacity-30 (str "Resources from " (get-handbooks-endpoint "/"))]]])
+
+(rum/defc search-bar
+  [pane-state nav! handbooks-nodes search-state set-search-state!]
+  (let [*input-ref (rum/use-ref nil)
+        [q, set-q!] (rum/use-state "")
+        [results, set-results!] (rum/use-state nil)
+        [selected, set-selected!] (rum/use-state 0)
+        select-fn! #(when-let [ldx (and (seq results) (dec (count results)))]
+                      (set-selected!
+                        (case %
+                          :up (if (zero? selected) ldx (max (dec selected) 0))
+                          :down (if (= selected ldx) 0 (min (inc selected) ldx))
+                          :dune)))
+
+        q (util/trim-safe q)
+        active? (not (string/blank? (util/trim-safe q)))
+        reset-q! #(->> "" (set! (.-value (rum/deref *input-ref))) (set-q!))
+        focus-q! #(some-> (rum/deref *input-ref) (.focus))]
+
+    (rum/use-effect!
+      #(focus-q!)
+      [pane-state])
+
+    (rum/use-effect!
+      (fn []
+        (let [pane-nodes (:children (second pane-state))
+              pane-nodes (and (seq pane-nodes)
+                              (mapcat #(conj (:children %) %) pane-nodes))]
+
+          (set-search-state!
+            (merge search-state {:active? active?}))
+
+          (if (and (seq handbooks-nodes) active?)
+            (-> (or pane-nodes
+                    ;; global
+                    (vals (dissoc handbooks-nodes "__root")))
+                (search/fuzzy-search q :limit 30 :extract-fn :title)
+                (set-results!))
+            (set-results! nil))
+
+          (set-selected! 0)))
+      [q])
+
+    [:div.search
+     [:div.input-wrap.relative
+      [:span.icon.absolute.opacity-90
+       {:style {:top 6 :left 7}}
+       (ui/icon "search" {:size 12})]
+
+      [:input {:placeholder   (t :handbook/search)
+               :auto-focus    true
+               :default-value q
+               :on-change     #(set-q! (util/evalue %))
+               :on-key-down   #(case (.-keyCode %)
+                                 ;; ESC
+                                 27
+                                 (if-not active?
+                                   (state/toggle! :ui/handbooks-open?)
+                                   (reset-q!))
+
+                                 ;; Up
+                                 38
+                                 (do
+                                   (util/stop %)
+                                   (select-fn! :up))
+
+                                 ;; Down
+                                 40
+                                 (do
+                                   (util/stop %)
+                                   (select-fn! :down))
+
+                                 ;; Enter
+                                 13
+                                 (when-let [topic (and active? (nth results selected))]
+                                   (util/stop %)
+                                   (nav! [:topic-detail topic (:title topic)] pane-state))
+
+                                 :dune)
+               :ref           *input-ref}]
+
+      (when active?
+        [:button.icon.absolute.opacity-50.hover:opacity-80.select-none
+         {:style    {:right 6 :top 7}
+          :on-click #(do (reset-q!) (focus-q!))}
+         (ui/icon "x" {:size 12})])]
+
+     (when (:active? search-state)
+       [:div.search-results-wrap
+        [:div.results-wrap
+         (for [[idx topic] (medley/indexed results)]
+           (rum/with-key
+             (topic-card topic #(nav! [:topic-detail topic (:title topic)] pane-state)
+                         {:class (util/classnames [{:active (= selected idx)}])})
+             (:key topic)))]])]))
+
+(rum/defc link-card
+  [opts child]
+
+  (let [{:keys [href]} opts]
+    [:div.link-card
+     (cond-> opts
+             (string? href)
+             (assoc :on-click #(util/open-url href)))
+     child]))
+
+;(rum/defc related-topics
+;  []
+;  [:div.related-topics
+;   (link-card {} [:strong.text-md "How to do something?"])])
+
+(def panes-mapping
+  {:dashboard    [pane-dashboard]
+   :topics       [pane-category-topics]
+   :topic-detail [pane-topic-detail]
+   :settings     [pane-settings]})
+
+
+(defonce discord-endpoint "https://plugins.logseq.io/ds")
+
+(rum/defc footer-link-cards
+  []
+  (let [[config _] (r/use-atom *config)
+        discord-count (:discord-online config)]
+
+    (rum/use-effect!
+      (fn []
+        (when (or (nil? discord-count)
+                  (> (- (js/Date.now) (:discord-online-created config)) (* 10 60 1000)))
+          (-> (js/window.fetch discord-endpoint)
+              (p/then #(.json %))
+              (p/then #(when-let [count (.-approximate_presence_count ^js %)]
+                         (swap! *config assoc
+                                :discord-online (.toLocaleString count)
+                                :discord-online-created (js/Date.now)))))))
+      [discord-count])
+
+    [:<>
+     ;; more links
+     [:div.flex.space-x-3
+      {:style {:padding-top "4px"}}
+      (link-card
+        {:class "flex-1" :href "https://discord.gg/KpN4eHY"}
+        [:div.inner.flex.space-x-1.flex-col
+         (ui/icon "brand-discord" {:class "opacity-30" :size 26})
+         [:h1.font-medium.py-1 "Chat on Discord"]
+         [:h2.text-xs.leading-4.opacity-40 "Ask quick questions, meet fellow users, and learn new workflows."]
+         [:small.flex.items-center.pt-1.5
+          [:i.block.rounded-full.bg-green-500 {:style {:width "8px" :height "8px"}}]
+          [:span.pl-2.opacity-90
+           [:strong.opacity-60 (or discord-count "?")]
+           [:span.opacity-70.font-light " users online"]]]])
+
+      (link-card
+        {:class "flex-1" :href "https://discuss.logseq.com"}
+        [:div.inner.flex.space-x-1.flex-col
+         (ui/icon "message-dots" {:class "opacity-30" :size 26})
+         [:h1.font-medium.py-1 "Visit the forum"]
+         [:h2.text-xs.leading-4.opacity-40 "Give feedback, request features, and have in-depth conversations."]
+         [:small.flex.items-center.pt-1.5
+          [:i.flex.items-center.opacity-50 (ui/icon "bolt" {:size 14})]
+          [:span.pl-1.opacity-90
+           [:strong.opacity-60 "800+"]
+           [:span.opacity-70.font-light " monthly posts"]]]])]]))
+
+(rum/defc ^:large-vars/data-var content
+  []
+  (let [[active-pane-state, set-active-pane-state!]
+        (rum/use-state [:dashboard nil (t :handbook/title)])
+
+        [handbooks-state, set-handbooks-state!]
+        (rum/use-state nil)
+
+        [handbooks-nodes, set-handbooks-nodes!]
+        (rum/use-state nil)
+
+        [history-state, set-history-state!]
+        (rum/use-state ())
+
+        [dev-watch?, set-dev-watch?]
+        (rum/use-state (storage/get :handbooks-dev-watch?))
+
+        [search-state, set-search-state!]
+        (rum/use-state {:active? false})
+
+        reset-handbooks! #(set-handbooks-state! {:status nil :data nil :error nil})
+        update-handbooks! #(set-handbooks-state! (fn [v] (merge v %)))
+        load-handbooks! (fn []
+                          (when-not (= :pending (:status handbooks-state))
+                            (reset-handbooks!)
+                            (update-handbooks! {:status :pending})
+                            (-> (p/let [^js res (js/fetch (get-handbooks-endpoint "/handbooks.edn"))
+                                        data (.text res)]
+                                  (update-handbooks! {:data (edn/read-string data)}))
+                                (p/catch #(update-handbooks! {:error (str %)}))
+                                (p/finally #(update-handbooks! {:status :completed})))))
+
+        active-pane-name (first active-pane-state)
+        pane-render (first (get panes-mapping active-pane-name))
+        pane-dashboard? (= :dashboard active-pane-name)
+        pane-settings? (= :settings active-pane-name)
+        pane-topic? (= :topic-detail active-pane-name)
+        force-nav-dashboard! (fn []
+                               (set-active-pane-state! [:dashboard])
+                               (set-history-state! '()))
+
+        handbooks-loaded? (and (seq (:data handbooks-state))
+                               (= :completed (:status handbooks-state)))
+        handbooks-data (:data handbooks-state)
+        nav-to-pane! (fn [next-state prev-state]
+                       (let [next-key (:key (second next-state))
+                             prev-key (:key (second prev-state))
+                             in-chapters? (and prev-key next-key (string/includes? prev-key "/")
+                                               (or (string/starts-with? next-key prev-key)
+                                                   (apply = (map parse-parent-key [prev-key next-key]))))]
+                         (when-not in-chapters?
+                           (set-history-state!
+                             (conj (sequence history-state) prev-state))))
+                       (set-active-pane-state! next-state))
+
+        [scrolled?, set-scrolled!] (rum/use-state false)
+        on-scroll (rum/use-memo #(util/debounce 100 (fn [^js e] (set-scrolled! (not (< (.. e -target -scrollTop) 10))))) [])]
+
+    ;; load handbooks
+    (rum/use-effect!
+      #(load-handbooks!)
+      [])
+
+    ;; navigation sentry
+    (rum/use-effect!
+      (fn []
+        (when (seq handbooks-nodes)
+          (let [c (:handbook/route-chan @state/state)]
+            (async/go-loop []
+                           (let [v (<! c)]
+                             (when (not= v :return)
+                               (when-let [to (get handbooks-nodes v)]
+                                 (nav-to-pane! [:topic-detail to (t :handbook/title)] [:dashboard]))
+                               (recur))))
+            #(async/go (>! c :return)))))
+      [handbooks-nodes])
+
+    (rum/use-effect!
+      (fn []
+        (let [*cnt-len (atom 0)
+              check! (fn []
+                       (-> (p/let [^js res (js/fetch (get-handbooks-endpoint "/handbooks.edn") #js{:method "HEAD"})]
+                             (when-let [cl (.get (.-headers res) "content-length")]
+                               (when (not= @*cnt-len cl)
+                                 (println "[Handbooks] dev reload!")
+                                 (load-handbooks!))
+                               (reset! *cnt-len cl)))
+                           (p/catch #(println "[Handbooks] dev check Error:" %))))
+              timer0 (if dev-watch?
+                       (js/setInterval check! 2000) 0)]
+          #(js/clearInterval timer0)))
+      [dev-watch?])
+
+    (rum/use-effect!
+      (fn []
+        (when handbooks-data
+          (let [nodes (->> (tree-seq map? :children handbooks-data)
+                           (reduce #(assoc %1 (or (:key %2) "__root") (bind-parent-key %2)) {}))]
+            (set-handbooks-nodes! nodes)
+            (set! (.-handbook-nodes js/window) (bean/->js nodes)))))
+      [handbooks-data])
+
+    [:div.cp__handbooks-content
+     {:class     (util/classnames [{:search-active (:active? search-state)
+                                    :scrolled      scrolled?}])
+      :on-scroll on-scroll}
+     [:div.pane-wrap
+      [:div.hd.flex.justify-between.select-none.draggable-handle
+       [:h1.text-xl.flex.items-center.font-bold
+        (if pane-dashboard?
+          [:span (t :handbook/title)]
+          [:button.active:opacity-80.flex.items-center.cursor-pointer
+           {:on-click (fn [] (let [prev (first history-state)
+                                   prev (cond-> prev
+                                                (nil? (seq prev))
+                                                [:dashboard])]
+                               (set-active-pane-state! prev)
+                               (set-history-state! (rest history-state))))}
+           [:span.pr-2.flex.items-center (ui/icon "chevron-left")]
+           (let [title (or (last active-pane-state) (t :handbook/title) "")]
+             [:span.truncate.title {:title title} title])])]
+
+       [:div.flex.items-center.space-x-3
+        (when (> (count history-state) 1)
+          [:a.flex.items-center {:aria-label (t :handbook/home) :tabIndex "0" :on-click #(force-nav-dashboard!)} (ui/icon "home")])
+        (when pane-topic?
+          [:a.flex.items-center
+           {:aria-label "Copy topic link" :tabIndex "0"
+            :on-click   (fn []
+                          (let [s (str "logseq://handbook/" (:key (second active-pane-state)))]
+                            (util/copy-to-clipboard! s)
+                            (notification/show!
+                              [:div [:strong.block "Handbook link copied!"]
+                               [:label.opacity-50 s]] :success)))}
+           (ui/icon "copy")])
+        (when (state/developer-mode?)
+          [:a.flex.items-center {:aria-label (t :handbook/settings)
+                                 :tabIndex   "0"
+                                 :on-click   #(nav-to-pane! [:settings nil "Settings"] active-pane-state)}
+           (ui/icon "settings")])
+        [:a.flex.items-center {:aria-label (t :handbook/close) :tabIndex "0" :on-click #(state/toggle! :ui/handbooks-open?)}
+         (ui/icon "x")]]]
+
+      (when (and (not pane-settings?) (not handbooks-loaded?))
+        [:div.flex.items-center.justify-center.pt-32
+         (if-not (:error handbooks-state)
+           (ui/loading "Loading ...")
+           [:code (:error handbooks-state)])])
+
+      (when (or pane-settings? handbooks-loaded?)
+        [:<>
+         ;; search bar
+         (when (or pane-dashboard? (= :topics active-pane-name))
+           (search-bar active-pane-state nav-to-pane!
+                       handbooks-nodes search-state set-search-state!))
+
+         ;; entry pane
+         (when pane-render
+           (apply pane-render
+                  (case active-pane-name
+                    :settings
+                    [dev-watch? #(do (set-dev-watch? %)
+                                     (storage/set :handbooks-dev-watch? %))]
+
+                    ;; default inputs
+                    [handbooks-nodes active-pane-state nav-to-pane!])))])]
+
+     (when handbooks-loaded?
+       ;; footer
+       (when pane-dashboard?
+         [:div.ft
+          (footer-link-cards)
+
+          ;; TODO: how to get related topics?
+          ;(when (= :topic-detail active-pane)
+          ;  [:<>
+          ;   [:h2.uppercase.opacity-60 "Related"]
+          ;   (related-topics)])
+          ]))]))

+ 412 - 0
src/main/frontend/extensions/handbooks/handbooks.css

@@ -0,0 +1,412 @@
+.cp__handbooks {
+  &-content {
+    @apply flex flex-col justify-between flex-1 overflow-y-auto;
+
+    -webkit-font-smoothing: antialiased;
+    overflow-y: overlay;
+
+    &-wrap {
+      @apply flex justify-center flex-col flex-1 h-full overflow-y-auto relative;
+    }
+
+    .hd {
+      @apply dark:text-white px-3 pt-3 pb-2 sticky top-0 left-0 z-[4]
+      transition-shadow duration-200;
+
+      background-color: var(--ls-tertiary-background-color);
+
+      .title {
+        text-align: left;
+        width: 266px;
+      }
+    }
+
+    &.scrolled {
+      .hd {
+        box-shadow: -3px 4px 6px -6px #ccc;
+      }
+    }
+
+    .search {
+      @apply flex flex-col pb-[6px] mb-0;
+
+      > .input-wrap {
+        @apply mx-4 mb-2 flex rounded-lg mt-1.5;
+
+        border: 3px solid var(--ls-primary-background-color);
+        background-color: var(--ls-primary-background-color);
+
+        &:focus-within {
+          border: 3px solid var(--ls-secondary-border-color);
+        }
+
+        > input {
+          @apply text-base leading-none w-full border-none py-[7px] px-[24px] bg-transparent
+          focus:outline-0 dark:text-gray-100 font-medium;
+        }
+
+      }
+
+      > .search-results-wrap {
+        @apply px-4 py-1;
+      }
+    }
+
+    .pane {
+      @apply py-1 px-4 dark:text-gray-50;
+    }
+
+    .pane > h2, .ft > h2 {
+      @apply py-2 text-base font-medium dark:text-gray-100;
+    }
+
+    .ft {
+      @apply px-4 pt-4 pb-2;
+
+      background-color: var(--ls-quaternary-background-color);
+
+      /*noinspection ALL*/
+
+      svg {
+        stroke-width: 1.5px;
+      }
+    }
+
+    .topic-card, .link-card {
+      @apply text-sm px-3 py-2.5 rounded-lg cursor-pointer
+      mb-2 active:opacity-90 select-none items-center;
+
+      background-color: var(--ls-secondary-background-color);
+      border: 1px solid var(--ls-border-color);
+      transition: background-color .3s;
+
+      > .l {
+        @apply pr-2.5 w-[80px] min-h-[64px] bg-transparent rounded overflow-hidden;
+
+        img {
+          mix-blend-mode: luminosity;
+          opacity: .8;
+          float: left;
+          width: 100%;
+        }
+      }
+
+      > .r {
+        @apply leading-none flex-1;
+
+        > strong {
+          @apply font-medium text-sm pt-0.5 pb-[1px] opacity-90 leading-5 dark:text-gray-5;
+        }
+
+        > span {
+          @apply text-xs opacity-40 leading-4;
+        }
+      }
+
+      &:hover, &.active {
+        background-color: var(--ls-primary-background-color);
+        border-color: var(--ls-secondary-border-color);
+
+        > .l {
+          img {
+            mix-blend-mode: unset;
+            opacity: 1;
+          }
+        }
+      }
+    }
+
+    .link-card {
+      @apply dark:text-gray-100;
+
+      border-color: var(--ls-tertiary-border-color);
+
+      &:hover {
+        border-color: var(--ls-tertiary-border-color);
+      }
+
+      &.as-primary {
+        @apply bg-indigo-500 text-white;
+      }
+    }
+
+    .category-card {
+      @apply flex rounded px-2 py-3 active:opacity-90 cursor-pointer transition-colors items-end;
+
+      border-left: 4px solid var(--ls-secondary-background-color);
+      background-color: var(--ls-secondary-background-color);
+
+      &[data-total="0"] {
+        @apply hidden;
+      }
+
+      &:hover, &:active {
+        background-color: var(--ls-primary-background-color);
+      }
+
+      > .icon-wrap {
+        @apply flex justify-end pr-2 pb-[2px] opacity-20;
+      }
+
+      > .text-wrap {
+        @apply flex flex-col min-h-[48px] justify-end;
+
+        > strong {
+          @apply font-medium leading-tight text-sm;
+        }
+
+        > span {
+          @apply text-xs pt-1;
+
+          color: var(--ls-primary-text-color);
+        }
+      }
+    }
+
+    .categories-list {
+      @apply grid grid-cols-2 gap-3;
+    }
+
+    .pane-topic-detail {
+      @apply flex flex-col h-full;
+
+      > h1 {
+        @apply pb-1;
+      }
+
+      > .demos {
+        img, video {
+          @apply w-full;
+        }
+
+        &.glide {
+          @apply mb-[10px];
+        }
+
+        .glide__slide {
+          background-color: var(--ls-secondary-border-color);
+        }
+      }
+
+      .content {
+        @apply overflow-hidden pt-1 leading-6;
+
+        &-wrap {
+          @apply flex flex-col justify-around;
+        }
+      }
+
+      iframe {
+        margin: 0;
+      }
+    }
+
+    .glide {
+      &__bullets {
+        @apply w-full bottom-0 left-0 transform-none
+        flex items-center justify-end pb-2 pr-1;
+      }
+
+      &__bullet {
+        @apply dark:text-black;
+
+        width: 24px;
+        height: 24px;
+        font-size: 13px;
+        border: none;
+        margin: 0 5px;
+      }
+
+      &--swipeable {
+        cursor: default !important;
+      }
+    }
+
+    &.search-active {
+      .pane {
+        &:not(.pane-topic-detail) {
+          display: none;
+        }
+      }
+
+      .ft {
+        display: none;
+      }
+    }
+
+    .markdown-body {
+      @apply pt-4;
+
+      -webkit-font-smoothing: initial;
+
+      h1 {
+        @apply py-1 text-2xl font-bold;
+      }
+
+      h2 {
+        @apply py-1 text-xl font-bold;
+      }
+
+      h3, h4 {
+        @apply py-1 text-lg font-semibold;
+      }
+
+      h4 {
+        @apply text-base;
+      }
+
+      h5 {
+        @apply py-0.5 font-semibold text-sm;
+      }
+
+      h6 {
+        @apply py-0.5 text-xs font-semibold;
+      }
+
+      p {
+        @apply leading-[1.6rem] my-[0.75rem];
+      }
+
+      blockquote {
+        margin: 0;
+      }
+    }
+
+    .chapters {
+      &-wrap {
+
+      }
+
+      &-select {
+        .select-trigger {
+          @apply relative flex flex-col rounded py-2 px-3 leading-5 select-none z-[1];
+
+          color: var(--ls-primary-text-color);
+          background-color: var(--ls-secondary-background-color);
+
+          small {
+            @apply text-[11px] opacity-50 pl-0.5;
+          }
+
+          strong {
+            @apply text-sm dark:text-gray-100;
+          }
+
+          .ui__icon {
+            @apply absolute right-2 top-5 opacity-70;
+          }
+
+          &:active {
+            .ui__icon, strong {
+              @apply opacity-80;
+            }
+          }
+
+          ul {
+            @apply absolute top-[58px] left-0 w-full list-none m-0 rounded-b py-2;
+
+            background-color: var(--ls-secondary-background-color);
+            transform: translateY(-5px);
+            max-height: 300px;
+            overflow: auto;
+
+            li {
+              @apply list-none px-3 py-1 transition-colors text-sm;
+
+              &:hover {
+                background-color: var(--ls-tertiary-background-color);
+              }
+            }
+          }
+        }
+      }
+    }
+
+    :not(pre) > code {
+      white-space: nowrap;
+    }
+
+    img {
+      @apply cursor-pointer active:opacity-80;
+    }
+
+    img, video {
+      @apply inline-block my-1;
+    }
+  }
+
+  &-popup {
+    @apply fixed rounded-lg overflow-hidden
+    z-[19] shadow-lg flex justify-center flex-col;
+
+    background-color: var(--ls-tertiary-background-color);
+    border: 1px solid var(--ls-tertiary-background-color);
+    touch-action: none;
+    height: 686px;
+    max-height: 86vh;
+    width: 420px;
+    right: 32px;
+    bottom: 58px;
+  }
+}
+
+html[data-theme="light"] {
+  .cp__handbooks-popup {
+    background-color: var(--ls-primary-background-color);
+
+    .input-wrap {
+      background-color: #f1f1f1;
+
+      &:focus-within {
+        background-color: transparent;
+      }
+    }
+
+    .topic-card, :not(.as-primary).link-card {
+      &:hover, &.active {
+        background-color: var(--ls-tertiary-background-color);
+        border-color: var(--ls-secondary-border-color);
+      }
+    }
+  }
+
+  .cp__handbooks-content {
+    .hd {
+      background-color: var(--ls-primary-background-color);
+    }
+
+    .ft {
+      background-color: var(--ls-primary-background-color);
+    }
+
+    .search {
+      background-color: var(--ls-primary-background-color);
+    }
+
+    .chapters-select {
+      .select-trigger {
+        background-color: var(--ls-tertiary-background-color);
+      }
+    }
+
+    .categories-list {
+      .category-card {
+        &:hover, &:active {
+          background-color: var(--ls-tertiary-background-color);
+        }
+      }
+    }
+
+    ul {
+      list-style: unset;
+
+      ul {
+        list-style: circle;
+
+        ul {
+          list-style: square;
+        }
+      }
+    }
+  }
+}

+ 51 - 46
src/main/frontend/extensions/pdf/core.cljs

@@ -121,63 +121,66 @@
   ;;page-bounding (and highlight (pdf-utils/get-page-bounding viewer (:page highlight)))
   ;;])
 
-  (let [*el         (rum/use-ref nil)
-        ^js cnt     (.-container viewer)
+  (let [*el (rum/use-ref nil)
+        ^js cnt (.-container viewer)
         head-height 0                                       ;; 48 temp
-        top         (- (+ (:y point) (.-scrollTop cnt)) head-height)
-        left        (+ (:x point) (.-scrollLeft cnt))
-        id          (:id highlight)
-        new?        (nil? id)
-        content     (:content highlight)
-        area?       (not (string/blank? (:image content)))
-        action-fn!  (fn [action clear?]
-                      (when-let [action (and action (name action))]
-                        (let [highlight (if (fn? highlight) (highlight) highlight)
-                              content   (:content highlight)]
-                          (case action
-                            "ref"
-                            (pdf-assets/copy-hl-ref! highlight viewer)
-
-                            "copy"
-                            (do
-                              (util/copy-to-clipboard!
+        top (- (+ (:y point) (.-scrollTop cnt)) head-height)
+        left (+ (:x point) (.-scrollLeft cnt))
+        id (:id highlight)
+        new? (nil? id)
+        new-&-highlight-mode? (and @*highlight-mode? new?)
+        show-ctx-menu? (and (not new-&-highlight-mode?)
+                            (or (not selection) (and selection (state/sub :pdf/auto-open-ctx-menu?))))
+        content (:content highlight)
+        area? (not (string/blank? (:image content)))
+        action-fn! (fn [action clear?]
+                     (when-let [action (and action (name action))]
+                       (let [highlight (if (fn? highlight) (highlight) highlight)
+                             content (:content highlight)]
+                         (case action
+                           "ref"
+                           (pdf-assets/copy-hl-ref! highlight viewer)
+
+                           "copy"
+                           (do
+                             (util/copy-to-clipboard!
                                (or (:text content) (pdf-utils/fix-selection-text-breakline (.toString selection)))
                                :owner-window (pdf-windows/resolve-own-window viewer))
-                              (pdf-utils/clear-all-selection))
+                             (pdf-utils/clear-all-selection))
 
-                            "link"
-                            (pdf-assets/goto-block-ref! highlight)
+                           "link"
+                           (pdf-assets/goto-block-ref! highlight)
 
-                            "del"
-                            (do
-                              (del-hl! highlight)
-                              (pdf-assets/del-ref-block! highlight)
-                              (pdf-assets/unlink-hl-area-image$ viewer (:pdf/current @state/state) highlight))
+                           "del"
+                           (do
+                             (del-hl! highlight)
+                             (pdf-assets/del-ref-block! highlight)
+                             (pdf-assets/unlink-hl-area-image$ viewer (:pdf/current @state/state) highlight))
 
-                            "hook"
-                            :dune
+                           "hook"
+                           :dune
 
-                            ;; colors
-                            (let [properties {:color action}]
-                              (if-not id
-                                ;; add highlight
-                                (let [highlight (merge highlight
-                                                       {:id         (pdf-utils/gen-uuid)
-                                                        :properties properties})]
-                                  (add-hl! highlight)
-                                  (pdf-utils/clear-all-selection)
-                                  (pdf-assets/copy-hl-ref! highlight viewer))
+                           ;; colors
+                           (let [properties {:color action}]
+                             (if-not id
+                               ;; add highlight
+                               (let [highlight (merge highlight
+                                                      {:id         (pdf-utils/gen-uuid)
+                                                       :properties properties})]
+                                 (add-hl! highlight)
+                                 (pdf-utils/clear-all-selection)
+                                 (pdf-assets/copy-hl-ref! highlight viewer))
 
-                                ;; update highlight
-                                (upd-hl! (assoc highlight :properties properties)))
+                               ;; update highlight
+                               (upd-hl! (assoc highlight :properties properties)))
 
-                              (reset! *highlight-last-color (keyword action)))))
+                             (reset! *highlight-last-color (keyword action)))))
 
-                        (and clear? (js/setTimeout #(clear-ctx-menu!) 68))))]
+                       (and clear? (js/setTimeout #(clear-ctx-menu!) 68))))]
 
     (rum/use-effect!
      (fn []
-       (if (and @*highlight-mode? new?)
+       (if new-&-highlight-mode?
          ;; wait for selection cleared ...
          (js/setTimeout #(action-fn! @*highlight-last-color true) 300)
          (let [^js el (rum/deref *el)
@@ -189,7 +192,9 @@
 
     [:ul.extensions__pdf-hls-ctx-menu
      {:ref      *el
-      :style    {:top top :left left :visibility (if (and @*highlight-mode? new?) "hidden" "visible")}
+      :style    {:top top
+                 :left left
+                 :visibility (if show-ctx-menu? "visible" "hidden")}
       :on-click (fn [^js/MouseEvent e]
                   (.stopPropagation e)
                   (when-let [action (.. e -target -dataset -action)]
@@ -502,7 +507,7 @@
                                                       :content    {:text "[:span]" :image (js/Date.now)}
                                                       :properties {}}]
 
-                                     ;; ctx tips
+                                     ;; ctx tips for area
                                      (show-ctx-menu! viewer hl point {:reset-fn #(reset-coords!)}))
 
                                    (set-area-mode! false))

+ 2 - 2
src/main/frontend/extensions/pdf/pdf.css

@@ -274,8 +274,8 @@ input::-webkit-inner-spin-button {
   &-settings {
     &-inner.hls-popup-box {
       position: absolute;
-      right: 345px;
-      width: 178px;
+      right: 375px;
+      width: 235px;
       padding: 15px 10px;
     }
 

+ 13 - 1
src/main/frontend/extensions/pdf/toolbar.cljs

@@ -29,7 +29,8 @@
 
   (let [*el-popup (rum/use-ref nil)
         [area-dashed? set-area-dashed?] (use-atom *area-dashed?)
-        [hl-block-colored? set-hl-block-colored?] (rum/use-state (state/sub :pdf/block-highlight-colored?))]
+        [hl-block-colored? set-hl-block-colored?] (rum/use-state (state/sub :pdf/block-highlight-colored?))
+        [auto-open-ctx-menu? set-auto-open-ctx-menu!] (rum/use-state (state/sub :pdf/auto-open-ctx-menu?))]
 
     (rum/use-effect!
      (fn []
@@ -54,6 +55,13 @@
          (storage/set "ls-pdf-hl-block-is-colored" b)))
      [hl-block-colored?])
 
+    (rum/use-effect!
+      (fn []
+        (let [b (boolean auto-open-ctx-menu?)]
+          (state/set-state! :pdf/auto-open-ctx-menu? b)
+          (storage/set "ls-pdf-auto-open-ctx-menu" b)))
+      [auto-open-ctx-menu?])
+
     (rum/use-effect!
      (fn []
        (let [cb  #(let [^js target (.-target %)]
@@ -85,6 +93,10 @@
        [:label (t :pdf/hl-block-colored)]
        (ui/toggle hl-block-colored? #(set-hl-block-colored? (not hl-block-colored?)) true)]
 
+      [:div.extensions__pdf-settings-item.toggle-input.is-between
+       [:label (t :pdf/auto-open-context-menu)]
+       (ui/toggle auto-open-ctx-menu? #(set-auto-open-ctx-menu! (not auto-open-ctx-menu?)) true)]
+
       [:div.extensions__pdf-settings-item.toggle-input
        [:a.is-info.w-full.text-gray-500
         {:title    (t :pdf/doc-metadata)

+ 46 - 44
src/main/frontend/extensions/srs.cljs

@@ -1,36 +1,37 @@
 (ns frontend.extensions.srs
-  (:require [frontend.template :as template]
-            [frontend.db.query-dsl :as query-dsl]
-            [frontend.db.query-react :as query-react]
-            [frontend.util :as util]
-            [logseq.graph-parser.property :as gp-property]
-            [logseq.graph-parser.util.page-ref :as page-ref]
-            [frontend.handler.property.file :as property-file]
-            [frontend.util.drawer :as drawer]
-            [frontend.util.persist-var :as persist-var]
-            [frontend.db :as db]
-            [frontend.db.model :as db-model]
-            [frontend.db-mixins :as db-mixins]
-            [frontend.state :as state]
-            [frontend.handler.editor :as editor-handler]
-            [frontend.handler.property :as property-handler]
+  (:require [cljs-time.coerce :as tc]
+            [cljs-time.core :as t]
+            [cljs-time.local :as tl]
+            [clojure.string :as string]
+            [frontend.config :as config]
+            [frontend.commands :as commands]
             [frontend.components.block :as component-block]
+            [frontend.components.editor :as editor]
             [frontend.components.macro :as component-macro]
             [frontend.components.select :as component-select]
             [frontend.components.svg :as svg]
-            [frontend.ui :as ui]
+            [frontend.context.i18n :refer [t]]
             [frontend.date :as date]
-            [frontend.commands :as commands]
-            [frontend.components.editor :as editor]
-            [cljs-time.core :as t]
-            [cljs-time.local :as tl]
-            [cljs-time.coerce :as tc]
-            [clojure.string :as string]
-            [rum.core :as rum]
+            [frontend.db :as db]
+            [frontend.db-mixins :as db-mixins]
+            [frontend.db.model :as db-model]
+            [frontend.db.query-dsl :as query-dsl]
+            [frontend.db.query-react :as query-react]
+            [frontend.handler.editor :as editor-handler]
+            [frontend.handler.property :as property-handler]
+            [frontend.handler.property.file :as property-file]
             [frontend.modules.shortcut.core :as shortcut]
+            [frontend.state :as state]
+            [frontend.template :as template]
+            [frontend.ui :as ui]
+            [frontend.util :as util]
+            [frontend.util.block-content :as content]
+            [frontend.util.drawer :as drawer]
+            [frontend.util.persist-var :as persist-var]
+            [logseq.graph-parser.property :as gp-property]
+            [logseq.graph-parser.util.page-ref :as page-ref]
             [medley.core :as medley]
-            [frontend.context.i18n :refer [t]]
-            [frontend.config :as config]))
+            [rum.core :as rum]))
 
 ;;; ================================================================
 ;;; Commentary
@@ -771,32 +772,33 @@
                                   "Create a cloze"])
 
 ;; handlers
+(defn add-card-tag-to-block
+  "given a block struct, adds the #card to title and returns
+   a seq of [original-block new-content-string]"
+  [block]
+    (when-let [content (:block/content block)]
+      (let [format (:block/format block)
+            content (-> (property-file/remove-built-in-properties-when-file-based
+                         (state/get-current-repo) (:block/format block) content)
+                        (drawer/remove-logbook))
+            [title body] (content/get-title&body content format)]
+        [block (str title " #" card-hash-tag "\n" body)])))
+
 (defn make-block-a-card!
   [block-id]
   (when-let [block (db/entity [:block/uuid block-id])]
-    (when-let [content (:block/content block)]
-      (let [content (-> (property-file/remove-built-in-properties-when-file-based
-                         (state/get-current-repo) (:block/format block) content)
-                        (drawer/remove-logbook))]
-        (editor-handler/save-block!
-         (state/get-current-repo)
-         block-id
-         (str (string/trim content) " #" card-hash-tag))))))
+    (let [block-content (add-card-tag-to-block block)
+          new-content (get block-content 1)]
+      (editor-handler/save-block! (state/get-current-repo) block-id new-content))))
 
 (defn batch-make-cards!
   ([] (batch-make-cards! (state/get-selection-block-ids)))
   ([block-ids]
-   (let [block-content-fn (fn [block]
-                            [block (-> (property-file/remove-built-in-properties-when-file-based
-                                        (state/get-current-repo) (:block/format block) (:block/content block))
-                                       (drawer/remove-logbook)
-                                       string/trim
-                                       (str " #" card-hash-tag))])
-         blocks (->> block-ids
-                     (map #(db/entity [:block/uuid %]))
-                     (remove card-block?)
-                     (map #(db/pull [:block/uuid (:block/uuid %)]))
-                     (map block-content-fn))]
+   (let [valid-blocks (->> block-ids
+                           (map #(db/entity [:block/uuid %]))
+                           (remove card-block?)
+                           (map #(db/pull [:block/uuid (:block/uuid %)])))
+         blocks (map add-card-tag-to-block valid-blocks)]
      (when-not (empty? blocks)
        (editor-handler/save-blocks! blocks)))))
 

+ 24 - 24
src/main/frontend/extensions/video/youtube.cljs

@@ -28,17 +28,17 @@
 
 (defn register-player [state]
   (try
-    (let [id (first (:rum/args state))
-         node (rum/dom-node state)]
-     (when node
-       (let [player (js/window.YT.Player.
-                     node
-                     (clj->js
-                      {:events
-                       {"onReady" (fn [_e] (js/console.log id " ready"))}}))]
-         (state/update-state! [:youtube/players]
-                              (fn [players]
-                                (assoc players id player))))))
+    (let [id   (first (:rum/args state))
+          node (rum/dom-node state)]
+      (when node
+        (let [player (js/window.YT.Player.
+                      node
+                      (clj->js
+                       {:events
+                        {"onReady" (fn [_e] (js/console.log id " ready"))}}))]
+          (state/update-state! [:youtube/players]
+                               (fn [players]
+                                 (assoc players id player))))))
     (catch :default _e
       nil)))
 
@@ -51,14 +51,14 @@
        (<! (load-youtube-api))
        (register-player state))
      state)}
-  [state id]
-  (let [width  (min (- (util/get-width) 96)
-                    560)
-        height (int (* width (/ 315 560)))]
+  [state id {:keys [width height] :as _opts}]
+  (let [width  (or width (min (- (util/get-width) 96)
+                              560))
+        height (or height (int (* width (/ 315 560))))]
     [:iframe
      {:id                (str "youtube-player-" id)
       :allow-full-screen "allowfullscreen"
-      :allow "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope"
+      :allow             "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope"
       :frame-border      "0"
       :src               (str "https://www.youtube.com/embed/" id "?enablejsapi=1")
       :height            height
@@ -141,13 +141,13 @@ Remember: You can paste a raw YouTube url as embedded video on mobile."
   (re-matches #"^(?:(\d+):)?([0-5]?\d):([0-5]?\d)$" "123:22:23") ;; => ["123:22:23" "123" "22" "23"]
   (re-matches #"^(?:(\d+):)?([0-5]?\d):([0-5]?\d)$" "30:23") ;; => ["30:23" nil "30" "23"]
 
-  (parse-timestamp "01:23") ;; => 83
+ (parse-timestamp "01:23")                                  ;; => 83
 
-  (parse-timestamp "01:01:23") ;; => 3683
+ (parse-timestamp "01:01:23")                               ;; => 3683
 
-  ;; seconds->display
-  ;; https://stackoverflow.com/questions/1322732/convert-seconds-to-hh-mm-ss-with-javascript
-  (seconds->display 129600) ;; => "36:00:00"
-  (seconds->display 13545) ;; => "03:45:45"
-  (seconds->display 18) ;; => "00:18"
-  )
+ ;; seconds->display
+ ;; https://stackoverflow.com/questions/1322732/convert-seconds-to-hh-mm-ss-with-javascript
+ (seconds->display 129600)                                  ;; => "36:00:00"
+ (seconds->display 13545)                                   ;; => "03:45:45"
+ (seconds->display 18)                                      ;; => "00:18"
+ )

+ 3 - 4
src/main/frontend/handler/file_based/property/util.cljs

@@ -11,7 +11,8 @@
             [logseq.graph-parser.text :as text]
             [frontend.db :as db]
             [frontend.state :as state]
-            [frontend.util.cursor :as cursor]))
+            [frontend.util.cursor :as cursor]
+            [frontend.util.block-content :as content]))
 
 (defn hidden-properties
   "These are properties hidden from user including built-in ones and ones
@@ -231,9 +232,7 @@
                                                              ast)))))
                                (mldoc/properties? (first ast)))
            lines (string/split-lines content)
-           [title body] (if title?
-                          [(first lines) (string/join "\n" (rest lines))]
-                          [nil (string/join "\n" lines)])
+           [title body] (content/get-title&body content format)
            scheduled (filter #(string/starts-with? % "SCHEDULED") lines)
            deadline (filter #(string/starts-with? % "DEADLINE") lines)
            body-without-timestamps (filter

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

@@ -68,11 +68,7 @@
 
 (defn toggle-help!
   []
-  (when-let [current-repo (state/get-current-repo)]
-    (let [id "help"]
-      (if (state/sidebar-block-exists? id)
-        (state/sidebar-remove-block! id)
-        (state/sidebar-add-block! current-repo id :help)))))
+  (state/toggle! :ui/help-open?))
 
 (defn toggle-settings-modal!
   []

+ 2 - 1
src/main/frontend/modules/file/core.cljs

@@ -124,7 +124,8 @@
           format (if whiteboard-page? "edn" format)
           journal-page? (date/valid-journal-title? title)
           journal-title (date/normalize-journal-title title)
-          filename (if (and journal-page? (not (string/blank? journal-title)))
+          journal-page? (and journal-page? (not (string/blank? journal-title)))
+          filename (if journal-page?
                      (date/date->file-name journal-title)
                      (-> (or (:block/original-name page-block) (:block/name page-block))
                          (fs-util/file-name-sanity)))

+ 76 - 68
src/main/frontend/modules/layout/core.cljs

@@ -16,19 +16,19 @@
   [identity]
   (when-let [^js/HTMLElement container (and (> (count @*movable-containers) 1)
                                             (get @*movable-containers identity))]
-    (let [zdx (->> @*movable-containers
-                   (map (fn [[_ ^js el]]
-                          (let [^js c (js/getComputedStyle el)
-                                v1 (.-visibility c)
-                                v2 (.-display c)]
-                            (when-let [z (and (= "visible" v1)
-                                              (not= "none" v2)
-                                              (.-zIndex c))]
-                              z))))
-                   (remove nil?))
-          zdx (bean/->js zdx)
-          zdx (and zdx (js/Math.max.apply nil zdx))
-          zdx' (util/safe-parse-int (.. container -style -zIndex))]
+    (let [zdx  (->> @*movable-containers
+                    (map (fn [[_ ^js el]]
+                           (let [^js c (js/getComputedStyle el)
+                                 v1    (.-visibility c)
+                                 v2    (.-display c)]
+                             (when-let [z (and (= "visible" v1)
+                                               (not= "none" v2)
+                                               (.-zIndex c))]
+                               z))))
+                    (remove nil?))
+          zdx  (bean/->js zdx)
+          zdx  (and zdx (js/Math.max.apply nil zdx))
+          zdx' (some-> (.. container -style -zIndex) (parse-long))]
 
       (when (or (nil? zdx') (not= zdx zdx'))
         (set! (.. container -style -zIndex) (inc zdx))))))
@@ -36,35 +36,38 @@
 (defn ^:export setup-draggable-container!
   [^js/HTMLElement el callback]
   (when-let [^js/HTMLElement handle (.querySelector el ".draggable-handle")]
-    (let [^js cls (.-classList el)
-          ^js ds (.-dataset el)
+    (let [^js cls  (.-classList el)
+          ^js ds   (.-dataset el)
           identity (.-identity ds)
-          ing? "is-dragging"]
+          ing?     "is-dragging"]
 
       ;; draggable
       (-> (js/interact handle)
           (.draggable
-            (bean/->js
-              {:listeners
-               {:move (fn [^js/MouseEvent e]
-                        (let [^js dset (.-dataset el)
-                              dx (.-dx e)
-                              dy (.-dy e)
-                              dx' (util/safe-parse-float (.-dx dset))
-                              dy' (util/safe-parse-float (.-dy dset))
-                              x (+ dx (if dx' dx' 0))
-                              y (+ dy (if dy' dy' 0))]
-
-                          ;; update container position
-                          (set! (.. el -style -transform) (str "translate(" x "px, " y "px)"))
-
-                          ;; cache dx dy
-                          (set! (.. el -dataset -dx) x)
-                          (set! (.. el -dataset -dy) y)))}}))
+           (bean/->js
+            {:listeners
+             {:move (fn [^js/MouseEvent e]
+                      (let [^js dset (.-dataset el)
+                            dx       (.-dx e)
+                            dy       (.-dy e)
+                            dx'      (.-dx dset)
+                            dy'      (.-dy dset)
+                            dx'      (and dx' (util/safe-parse-float dx'))
+                            dy'      (and dy' (util/safe-parse-float dy'))
+                            x        (+ dx (or dx' 0))
+                            y        (+ dy (or dy' 0))]
+
+                        ;; update container position
+                        (set! (.. el -style -transform) (str "translate(" x "px, " y "px)"))
+
+                        ;; cache dx dy
+                        (set! (.. el -dataset -dx) x)
+                        (set! (.. el -dataset -dy) y)))}}))
           (.on "dragstart" (fn [] (.add cls ing?)))
           (.on "dragend" (fn [e]
                            (.remove cls ing?)
-                           (callback (bean/->js (calc-layout-data el e))))))
+                           (when (fn? callback)
+                             (callback (bean/->js (calc-layout-data el e)))))))
       ;; manager
       (swap! *movable-containers assoc identity el)
 
@@ -72,45 +75,50 @@
 
 (defn ^:export setup-resizable-container!
   [^js/HTMLElement el callback]
-  (let [^js cls (.-classList el)
-        ^js ds (.-dataset el)
+  (let [^js cls  (.-classList el)
+        ^js ds   (.-dataset el)
         identity (.-identity ds)
-        ing? "is-resizing"]
+        ing?     "is-resizing"]
 
     ;; resizable
     (-> (js/interact el)
         (.resizable
-          (bean/->js
-            {:edges
-             {:left true :top true :bottom true :right true}
-
-             :listeners
-             {:start (fn [] (.add cls ing?))
-              :end   (fn [e] (.remove cls ing?) (callback (bean/->js (calc-layout-data el e))))
-              :move  (fn [^js/MouseEvent e]
-                       (let [^js dset (.-dataset el)
-                             w (.. e -rect -width)
-                             h (.. e -rect -height)
-
-                             ;; update position from top/left
-                             dx (.. e -deltaRect -left)
-                             dy (.. e -deltaRect -top)
-
-                             dx' (util/safe-parse-float (.-dx dset))
-                             dy' (util/safe-parse-float (.-dy dset))
-
-                             x (+ dx (if dx' dx' 0))
-                             y (+ dy (if dy' dy' 0))]
-
-                         ;; update container position
-                         (set! (.. el -style -transform) (str "translate(" x "px, " y "px)"))
-
-                         ;; update container size
-                         (set! (.. el -style -width) (str w "px"))
-                         (set! (.. el -style -height) (str h "px"))
-
-                         (set! (. dset -dx) x)
-                         (set! (. dset -dy) y)))}})))
+         (bean/->js
+          {:edges
+           {:left true :top true :bottom true :right true}
+
+           :listeners
+           {:start (fn [] (.add cls ing?))
+            :end   (fn [e]
+                     (.remove cls ing?)
+                     (when (fn? callback)
+                       (callback (bean/->js (calc-layout-data el e)))))
+            :move  (fn [^js/MouseEvent e]
+                     (let [^js dset (.-dataset el)
+                           w        (.. e -rect -width)
+                           h        (.. e -rect -height)
+
+                           ;; update position from top/left
+                           dx       (.. e -deltaRect -left)
+                           dy       (.. e -deltaRect -top)
+
+                           dx'      (.-dx dset)
+                           dy'      (.-dy dset)
+                           dx'      (and dx' (util/safe-parse-float dx'))
+                           dy'      (and dy' (util/safe-parse-float dy'))
+
+                           x        (+ dx (or dx' 0))
+                           y        (+ dy (or dy' 0))]
+
+                       ;; update container position
+                       (set! (.. el -style -transform) (str "translate(" x "px, " y "px)"))
+
+                       ;; update container size
+                       (set! (.. el -style -width) (str w "px"))
+                       (set! (.. el -style -height) (str h "px"))
+
+                       (set! (. dset -dx) x)
+                       (set! (. dset -dy) y)))}})))
 
     ;; manager
     (swap! *movable-containers assoc identity el)

+ 36 - 16
src/main/frontend/state.cljs

@@ -2,7 +2,7 @@
   "Provides main application state, fns associated to set and state based rum
   cursors"
   (:require [cljs-bean.core :as bean]
-            [cljs.core.async :as async :refer [<!]]
+            [cljs.core.async :as async :refer [<! >!]]
             [cljs.spec.alpha :as s]
             [clojure.string :as string]
             [dommy.core :as dom]
@@ -79,15 +79,18 @@
       :ui/recent-pages                       (or (storage/get :ui/recent-pages) {})
       :ui/recent-search                      (or (storage/get :ui/recent-search) {})
 
-      ;; right sidebar
-      :ui/settings-open?                     false
-      :ui/sidebar-open?                      false
-      :ui/sidebar-width                      "40%"
-      :ui/left-sidebar-open?                 (boolean (storage/get "ls-left-sidebar-open?"))
-      :ui/theme                              (or (storage/get :ui/theme) "light")
-      :ui/system-theme?                      ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
-      :ui/custom-theme                       (or (storage/get :ui/custom-theme) {:light {:mode "light"} :dark {:mode "dark"}})
-      :ui/wide-mode?                         (storage/get :ui/wide-mode)
+     ;; right sidebar
+     :ui/handbooks-open?                    false
+     :ui/help-open?                         false
+     :ui/fullscreen?                        false
+     :ui/settings-open?                     false
+     :ui/sidebar-open?                      false
+     :ui/sidebar-width                      "40%"
+     :ui/left-sidebar-open?                 (boolean (storage/get "ls-left-sidebar-open?"))
+     :ui/theme                              (or (storage/get :ui/theme) "light")
+     :ui/system-theme?                      ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
+     :ui/custom-theme                       (or (storage/get :ui/custom-theme) {:light {:mode "light"} :dark {:mode "dark"}})
+     :ui/wide-mode?                         (storage/get :ui/wide-mode)
 
       ;; ui/collapsed-blocks is to separate the collapse/expand state from db for:
       ;; 1. right sidebar
@@ -226,11 +229,12 @@
       :plugin/navs-settings?                 true
       :plugin/focused-settings               nil ;; plugin id
 
-      ;; pdf
-      :pdf/system-win?                       false
-      :pdf/current                           nil
-      :pdf/ref-highlight                     nil
-      :pdf/block-highlight-colored?          (or (storage/get "ls-pdf-hl-block-is-colored") true)
+     ;; pdf
+     :pdf/system-win?                       false
+     :pdf/current                           nil
+     :pdf/ref-highlight                     nil
+     :pdf/block-highlight-colored?          (or (storage/get "ls-pdf-hl-block-is-colored") true)
+     :pdf/auto-open-ctx-menu?               (not= false (storage/get "ls-pdf-auto-open-ctx-menu"))
 
       ;; all notification contents as k-v pairs
       :notification/contents                 {}
@@ -286,13 +290,14 @@
 
       :ui/loading?                           {}
       :feature/enable-sync?                  (storage/get :logseq-sync-enabled)
-      :feature/enable-sync-diff-merge?       (storage/get :logseq-sync-diff-merge-enabled)
+      :feature/enable-sync-diff-merge?       ((fnil identity true) (storage/get :logseq-sync-diff-merge-enabled))
 
       :file/rename-event-chan                (async/chan 100)
       :ui/find-in-page                       nil
       :graph/importing                       nil
       :graph/importing-state                 {}
       :graph/loading?                        nil
+      :handbook/route-chan                   (async/chan (async/sliding-buffer 1))
 
       :whiteboard/onboarding-whiteboard?     (or (storage/get :ls-onboarding-whiteboard?) false)
       :whiteboard/onboarding-tour?           (or (storage/get :whiteboard-onboarding-tour?) false)
@@ -2321,6 +2326,21 @@ Similar to re-frame subscriptions"
      (fn [s]
        (contains? s (str block-uuid))))))
 
+(defn handbook-open?
+  []
+  (:ui/handbooks-open? @state))
+
+(defn get-handbook-route-chan
+  []
+  (:handbook/route-chan @state))
+
+(defn open-handbook-pane!
+  [k]
+  (when-not (handbook-open?)
+    (set-state! :ui/handbooks-open? true))
+  (js/setTimeout #(async/go
+                    (>! (get-handbook-route-chan) k))))
+
 (defn set-page-properties-changed!
   [page-name]
   (when-not (string/blank? page-name)

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

@@ -63,6 +63,12 @@
    "purple"
    "gray"])
 
+(defn ->block-background-color
+ [color]
+ (if (some #{color} built-in-colors)
+   (str "var(--ls-highlight-color-" color ")")
+   color))
+
 (defn built-in-color?
   [color]
   (some #{color} built-in-colors))
@@ -1064,7 +1070,7 @@
            :as   option}]
   (let [klass (if-not intent ".bg-indigo-600.hover:bg-indigo-700.focus:border-indigo-700.active:bg-indigo-700.text-center" intent)
         klass (if background (string/replace klass "indigo" background) klass)
-        klass (if small? (str klass ".px-2.py-1") klass)
+        klass (if small? (str klass ".is-small") klass)
         klass (if large? (str klass ".text-base") klass)
         klass (if disabled? (str klass "disabled:opacity-75") klass)]
     [:button.ui__button

+ 3 - 3
src/main/frontend/ui.css

@@ -275,7 +275,7 @@ html.is-mobile {
 
 .ui__button {
   @apply inline-flex items-center px-3 py-2 border border-transparent
-  text-sm leading-4 font-medium rounded-md text-white
+  text-sm leading-4 font-medium rounded-[6px] text-white
   focus:outline-none transition ease-in-out duration-150;
 
   &:disabled {
@@ -317,8 +317,8 @@ html.is-mobile {
     border: 1px solid;
   }
 
-  &.p-1 {
-    padding: 0.25rem 0.5rem !important;
+  &.is-small {
+    @apply px-2.5 py-1;
   }
 }
 

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

@@ -232,6 +232,13 @@
   [pred coll]
   (first (filter pred coll)))
 
+(defn find-index
+  "Find first index of an element in list"
+  [pred-or-val coll]
+  (let [pred (if (fn? pred-or-val) pred-or-val #(= pred-or-val %))]
+    (reduce-kv #(if (pred %3) (reduced %2) %1) -1
+               (cond-> coll (list? coll) (vec)))))
+
 ;; (defn format
 ;;   [fmt & args]
 ;;   (apply gstring/format fmt args))
@@ -1451,6 +1458,23 @@
       (fn [resolve]
         (load url resolve)))))
 
+#?(:cljs
+   (defn css-load$
+     ([url] (css-load$ url nil))
+     ([url id]
+      (p/create
+       (fn [resolve reject]
+         (let [id (str "css-load-" (or id url))]
+           (if-not (gdom/getElement id)
+             (let [^js link (js/document.createElement "link")]
+               (set! (.-id link) id)
+               (set! (.-rel link) "stylesheet")
+               (set! (.-href link) url)
+               (set! (.-onload link) resolve)
+               (set! (.-onerror link) reject)
+               (.append (.-head js/document) link))
+             (resolve))))))))
+
 #?(:cljs
    (defn copy-image-to-clipboard
      [src]

+ 18 - 0
src/main/frontend/util/block_content.cljs

@@ -0,0 +1,18 @@
+(ns frontend.util.block-content
+  "utils for text content residing in a block"
+  (:require [clojure.string :as string]
+            [frontend.format.mldoc :as mldoc]))
+
+(defn- has-title?
+  [content format]
+  (let [ast (mldoc/->edn content format)]
+    (mldoc/block-with-title? (ffirst (map first ast)))))
+
+(defn get-title&body
+  "parses content and returns [title body]
+   returns nil if no title"
+  [content format]
+  (let [lines (string/split-lines content)]
+    (if (has-title? content format)
+      [(first lines) (string/join "\n" (rest lines))]
+      [nil (string/join "\n" lines)])))

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

@@ -1,3 +1,3 @@
 (ns ^:no-doc frontend.version)
 
-(defonce version "0.9.19")
+(defonce version "0.9.20")

+ 9 - 0
src/resources/dicts/en.edn

@@ -17,6 +17,14 @@
  :on-boarding/tour-whiteboard-home-description "Whiteboards have their own section in the app where you can see them at a glance, create new ones or delete them easily."
  :on-boarding/tour-whiteboard-new "{1} Create new whiteboard"
  :on-boarding/tour-whiteboard-new-description "There are multiple ways of creating a new whiteboard. One of them is always right here in the dashboard."
+ :handbook/title "Help"
+ :handbook/topics "Topics"
+ :handbook/popular-topics "Popular topics"
+ :handbook/help-categories "Help categories"
+ :handbook/search "Search"
+ :handbook/home "Home"
+ :handbook/settings "Settings"
+ :handbook/close "Close"
  :on-boarding/tour-whiteboard-btn-next "Next"
  :on-boarding/tour-whiteboard-btn-back "Back"
  :on-boarding/tour-whiteboard-btn-finish "Finish"
@@ -610,6 +618,7 @@
  :pdf/linked-ref "Linked references"
  :pdf/toggle-dashed "Dashed style for area highlight"
  :pdf/hl-block-colored "Colored label for highlight block"
+ :pdf/auto-open-context-menu "Auto open context menu for selections"
  :pdf/doc-metadata "Document metadata"
 
  :updater/new-version-install "A new version has been downloaded."

+ 9 - 0
src/resources/dicts/es.edn

@@ -362,6 +362,14 @@
  :graph/save                                        "Guardando..."
  :graph/save-error                                  "Falló el guardado"
  :graph/save-success                                "Guardado satisfactoriamente"
+ :handbook/close                                    "Cerrar"
+ :handbook/help-categories                          "Categorías de ayuda"
+ :handbook/home                                     "Inicio"
+ :handbook/popular-topics                           "Temas populares"
+ :handbook/search                                   "Buscar"
+ :handbook/settings                                 "Opciones"
+ :handbook/title                                    "Ayuda"
+ :handbook/topics                                   "Temas"
  :header/go-back                                    "Ir hacia atrás"
  :header/go-forward                                 "Ir haca adelante"
  :header/more                                       "Más"
@@ -504,6 +512,7 @@
  :paginates/next                                    "Siguiente"
  :paginates/pages                                   "Total {1} páginas"
  :paginates/prev                                    "Anterior"
+ :pdf/auto-open-context-menu                        "Abrir automaticamente menú contextual para la selección."
  :pdf/copy-ref                                      "Copiar referencia"
  :pdf/copy-text                                     "Copiar texto"
  :pdf/doc-metadata                                  "Metadatos del documento"

+ 15 - 15
src/resources/dicts/fr.edn

@@ -49,7 +49,7 @@
     :content/copy-block-ref "Copier la référence du bloc"
     :content/open-in-sidebar "Ouvrir dans la barre latérale"
     :content/click-to-edit "Cliquer pour éditer"
-    :settings-page/custom-date-format-warning "Réindexation requise ! Les références existantes vers les journaux  risquent d'être cassées !"
+    :settings-page/custom-date-format-warning "Réindexation requise ! Les références existantes vers les journaux risquent d'être cassées !"
     :settings-page/edit-config-edn "Éditer config.edn (pour le dépôt actuel)"
     :settings-page/preferred-file-format "Format de fichier préféré"
     :settings-page/preferred-workflow "Workflow préféré"
@@ -159,7 +159,7 @@
     :file-rn/select-confirm-proceed "Dev: format d'écriture"
     :file-rn/select-format "(Option du Mode Developpeur, Danger !) Sélectionnez le format de nom de fichier"
     :file-rn/suggest-rename "Action requise : "
-    :file-rn/unreachable-title "Attention ! la page deviendra {1} sous le format actuel, à moins que vous n'ayez modifié la propriété `title::`"
+    :file-rn/unreachable-title "Attention ! La page deviendra {1} sous le format actuel, à moins que vous n'ayez modifié la propriété `title::`"
     :graph/all-graphs "Tous les graphes"
     :graph/persist "Logseq synchronise son statut local, veuillez patienter quelques secondes."
     :graph/persist-error "La synchronisation interne a échoué."
@@ -207,8 +207,8 @@
     :plugin/check-all-updates "Vérifier toutes les mises à jour"
     :plugin/check-update "Vérifier la mise à jour"
     :plugin/contribute "✨ Écrire et proposer une nouvelle extension"
-    :plugin/custom-js-alert "Fichier custom.js trouvé, est-il autorisé à s'éxécuter ? (Si vous ne comprenez pas le contenu de ce fichier, il est recommandé de ne pas en autoriser l'exécution, car cela vous expose à des risques de sécurité)."
-    :plugin/delete-alert "Êtes-vous sûr de vouloir désintaller l'extension [{1}] ?"
+    :plugin/custom-js-alert "Fichier custom.js trouvé, est-il autorisé à s'exécuter ? (Si vous ne comprenez pas le contenu de ce fichier, il est recommandé de ne pas en autoriser l'exécution, car cela vous expose à des risques de sécurité)."
+    :plugin/delete-alert "Êtes-vous sûr de vouloir désinstaller l'extension [{1}] ?"
     :plugin/disabled "Désactivée"
     :plugin/downloads "Téléchargements"
     :plugin/enabled "Activée"
@@ -259,7 +259,7 @@
     :settings-page/custom-date-format "Format de date préféré"
     :settings-page/custom-global-configuration "Configuration globale personnalisée"
     :settings-page/custom-theme "Thème personnalisé"
-    :settings-page/disable-sentry "Envoyer des données d'utilisation et de diagnostique à Logseq"
+    :settings-page/disable-sentry "Envoyer des données d'utilisation et de diagnostic à Logseq"
     :settings-page/edit-custom-css "Modifier custom.css"
     :settings-page/edit-export-css "Modifier export.css"
     :settings-page/edit-global-config-edn "Modifier le fichier global config.edn"
@@ -289,7 +289,7 @@
     :settings-page/tab-general "Général"
     :settings-page/tab-version-control "Contrôle de version"
     :text/image "Image"
-    :updater/new-version-install "Une nouvelle version a été téléchargée."
+    :updater/new-version-install "Une nouvelle version a été téléchargé."
     :updater/quit-and-install "Relancez pour installer"
     :whiteboard/link-whiteboard-or-block "Lier un tablau blanc/page/bloc"
     :file/validate-existing-file-error "La page existe déjà avec un autre fichier: {1}, fichier actuel: {2}. Veuillez n'en garder qu'un et réindexer votre graphe."
@@ -298,7 +298,7 @@
     :on-boarding/tour-whiteboard-home-description "Les tableaux blancs ont leur propre section dans l'application où vous pouvez les voir en un coup d'œil, en créer de nouveaux ou les supprimer facilement."
     :on-boarding/tour-whiteboard-new "{1} Créer un nouveau tableau blanc"
     :on-boarding/tour-whiteboard-new-description "Il existe plusieurs façons de créer un nouveau tableau blanc. L'un d'eux est toujours ici dans le tableau de bord."
-    :on-boarding/welcome-whiteboard-modal-description "Les tableaux blancs sont un excellent outil de remue-méninge et d'organisation. Vous pouvez maintenant placer n'importe laquelle de vos pensées de la base de connaissances ou de nouvelles à côté l'une de l'autre sur une toile spatiale pour vous connecter, vous associer et comprendre de nouvelles façons."
+    :on-boarding/welcome-whiteboard-modal-description "Les tableaux blancs sont un excellent outil de remue-méninges et d'organisation. Vous pouvez maintenant placer n'importe laquelle de vos pensées de la base de connaissances ou de nouvelles à côté l'une de l'autre sur une toile spatiale pour vous connecter, vous associer et comprendre de nouvelles façons."
     :on-boarding/welcome-whiteboard-modal-skip "Sauter"
     :on-boarding/welcome-whiteboard-modal-start "Démarrer le tableau blanc"
     :on-boarding/welcome-whiteboard-modal-title "Un nouveau cadre pour vos pensées."
@@ -421,7 +421,7 @@
     :command.ui/toggle-contents  "Basculer l'affichage du contenu dans la barre latérale"
     :command.ui/toggle-left-sidebar  "Basculer la barre latérale gauche"
     :command.ui/toggle-settings  "Basculer l'affichage des réglages"
-    :command.ui/toggle-wide-mode  "Basculer le vue en pleine largeur"
+    :command.ui/toggle-wide-mode  "Basculer la vue en pleine largeur"
     :shortcut.category/basics  "Bases"
     :shortcut.category/block-command-editing  "Édition de commande de bloc"
     :shortcut.category/block-editing  "Édition de bloc en général"
@@ -515,7 +515,7 @@
     :whiteboard/highlight "Surligner"
     :whiteboard/group "Groupe"
     :whiteboard/flip-vertically "Pivoter verticalement"
-    :whiteboard/flip-horizontally "Pivoter horizontallement"
+    :whiteboard/flip-horizontally "Pivoter horizontalement"
     :whiteboard/fill "Remplir"
     :whiteboard/extra-small "Très petit"
     :whiteboard/extra-large "Très grand"
@@ -526,7 +526,7 @@
     :whiteboard/draw "Dessiner"
     :whiteboard/distribute-vertically "Distribution verticale"
     :whiteboard/distribute-horizontally "Distribution horizontale"
-    :whiteboard/dev-print-shape-props "(Dev) Afficher les accesoires des formes"
+    :whiteboard/dev-print-shape-props "(Dev) Afficher les accessoires des formes"
     :whiteboard/deselect-all "Tout désélectionner"
     :whiteboard/delete "Supprimer"
     :whiteboard/dashboard-card-new-whiteboard "Nouveau tableau blanc"
@@ -561,7 +561,7 @@
     :settings-page/theme-dark "Foncé"
     :settings-page/tab-account "Compte"
     :settings-page/sync-diff-merge-warn "Le fusionnement intelligent n'est activé que pour un client ..."
-    :settings-page/sync-diff-merge-desc "Fusionner les mises à jours locales avec les fichiers distants automatiqu..."
+    :settings-page/sync-diff-merge-desc "Fusionner les mises à jour locales avec les fichiers distants automatiqu..."
     :settings-page/sync-diff-merge "Permettre le fusionnement intelligent lors de la synchronisation"
     :settings-page/sync-desc-1 "Cliquez"
     :settings-page/sync-desc-2 "ici"
@@ -648,17 +648,17 @@
     :flashcards/modal-btn-next-card "Suivante"
     :flashcards/modal-btn-recall "A pris du temps à se souvenir"
     :flashcards/modal-btn-reset "Réinitialiser"
-    :flashcards/modal-btn-reset-tip "Réinitialisez cette carte pour povoir la réviser immédiate..."
+    :flashcards/modal-btn-reset-tip "Réinitialisez cette carte pour pouvoir la réviser immédiate..."
     :flashcards/modal-btn-show-answers "Montrer les réponses"
     :flashcards/modal-btn-show-clozes "Montre les clozes"
     :flashcards/modal-current-total "Courant/Total"
-    :flashcards/modal-finished "Bravo, vous avez révisé toutes les carte pour ce..."
+    :flashcards/modal-finished "Bravo, vous avez révisé toutes les cartes pour ce..."
     :flashcards/modal-overdue-total "En retard/Total"
     :flashcards/modal-select-all "Toutes"
     :flashcards/modal-select-switch "Basculer à"
     :flashcards/modal-toggle-preview-mode "Activer la prévisualisation"
     :flashcards/modal-toggle-random-mode "Activer le mode aléatoire"
-    :flashcards/modal-welcome-desc-1 "Vous pouvez ajouter \"#card\" à un bloc pour le transfomer en..."
+    :flashcards/modal-welcome-desc-1 "Vous pouvez ajouter \"#card\" à un bloc pour le transformer en..."
     :flashcards/modal-welcome-desc-2 "Vous pouvez"
     :flashcards/modal-welcome-desc-3 "cliquer ce lien"
     :flashcards/modal-welcome-desc-4 "pour consulter la documentation."
@@ -768,7 +768,7 @@
     :settings-page/git-tip "Si vous avez Logseq Sync activé, vous pouvez visualiser une pa..."
     :settings-page/native-titlebar "Barre de titre native"
     :settings-page/native-titlebar-desc "Active la barre de titre native de la fenêtre sur Windows et..."
-    :settings-page/preferred-outdenting-tip "Le côté gauche montre la désindentation  avec les paramètres par déf..."
+    :settings-page/preferred-outdenting-tip "Le côté gauche montre la désindentation avec les paramètres par déf..."
     :settings-page/preferred-outdenting-tip-more "→ Apprnez-en plus"
     :settings-page/preferred-pasting-file-hint "Lorsqu'activé, coller une image d'Internet..."
     :settings-page/revision "Révision:"

+ 1 - 0
src/resources/dicts/ja.edn

@@ -602,6 +602,7 @@
  :pdf/linked-ref "リンクありの参照元"
  :pdf/toggle-dashed "領域のハイライトに破線を使う"
  :pdf/hl-block-colored "ブロックをハイライトするための色付きラベル"
+ :pdf/auto-open-context-menu "自動でコンテキストメニューを開く"
  :pdf/doc-metadata "ドキュメントのメタデータ"
 
  :updater/new-version-install "新しいバージョンがダウンロードされました。"

+ 3 - 1
src/resources/dicts/ko.edn

@@ -209,6 +209,9 @@
  :pdf/copy-text "텍스트 복사하기"
  :pdf/linked-ref "링크된 레퍼런스"
  :pdf/toggle-dashed "영역 하이라이트를 위해 Dashed style 사용"
+ :pdf/hl-block-colored "색상으로 강조된 블록입니다"
+ :pdf/auto-open-context-menu "자동으로 컨텍스트 메뉴를 엽니다"
+ :pdf/doc-metadata "메타데이터"
 
  :updater/new-version-install "새 버전이 다운로드되었습니다."
  :updater/quit-and-install "다시 시작하여 설치하십시오."
@@ -288,7 +291,6 @@
  :page/something-went-wrong "문제가 발생하였습니다."
  :page/step "스텝 {1}"
  :page/try "시도"
- :pdf/doc-metadata "메타데이터"
  :plugin.install-from-file/title "plugins.edn에서 설치"
  :plugin.install-from-file/notice "다음의 플러그인들이 교체될 것입니다:"
  :plugin.install-from-file/success "플러그인 설치 성공!"

+ 1 - 0
src/resources/dicts/zh-cn.edn

@@ -356,6 +356,7 @@
  :pdf/linked-ref "转到注解"
  :pdf/toggle-dashed "区域选取为虚线"
  :pdf/hl-block-colored "颜色标识高亮块"
+ :pdf/auto-open-context-menu "为选中文本自动打开上下文菜单"
  :pdf/doc-metadata "查看文档元数据"
 
  :asset/open-in-browser "在浏览器打开"

+ 1 - 0
src/resources/dicts/zh-hant.edn

@@ -300,6 +300,7 @@
  :pdf/linked-ref "已連結的引用"
  :pdf/toggle-dashed "使用線條顯示高亮區塊"
  :pdf/hl-block-colored "使用有色標籤顯示高亮區塊"
+ :pdf/auto-open-context-menu "為選中文本自動打開上下文菜單"
  :pdf/doc-metadata "metadata 文件"
 
  :updater/new-version-install "已下載新版本。"

+ 48 - 48
static/yarn.lock

@@ -400,47 +400,47 @@
   resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
   integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
 
-"@logseq/[email protected]3":
-  version "0.0.73"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.73.tgz#4753f05e2dc70f37a31dfb7440e9b2601acb7696"
-  integrity sha512-TvFwh3/fnwRAZwourk1UUgptcNN7FqmOcL07F373M2rWhTIOba/u1eBwjW9wNMRcXtgLWacaXzBmC4ENvAKDpg==
-
-"@logseq/[email protected]3":
-  version "0.0.73"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.73.tgz#44180532e3ccf62a7fe597e385ee85a700b14bea"
-  integrity sha512-tnOSgQ1qgerwDTnR5v1TMbHnVXVabzZf9i3bxon0y9ItwlIY7j7OW80+1AfNoHu9Fbo/e+3bFg5Muq3/Gm7Yrw==
-
-"@logseq/[email protected]3":
-  version "0.0.73"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-freebsd-x64/-/rsapi-freebsd-x64-0.0.73.tgz#3ff4f720eb05d9ffd32a5391ddf33034a05f42e0"
-  integrity sha512-YAjggQHzVCZYhXDybR/37Y5czTQbYDE5A5piwsg09Xt4/m5REFSVKqdeQpnOb2LX7wBGbnPxMhsg6QUV/y/eHA==
-
-"@logseq/[email protected]3":
-  version "0.0.73"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.73.tgz#1f423e296ca69e6e92a06afbb25f9f2f0e452b69"
-  integrity sha512-t5W9SBraKYU2iGPzBgUhSzVPtH98RwuE1tLW2MpAJh0QNb2DI4/axbc9nrC1IVc1dqAmTkuL8GGGN80VONisUA==
-
-"@logseq/[email protected]3":
-  version "0.0.73"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.73.tgz#d33e621d7ea24089a9b863809e6dfbe4362443d5"
-  integrity sha512-WidDZv4mnG6Ys90KYLzJl0fwMWj/kEItGHjfR3FoDAVKkvu3mezNDWCsd+I2kMrh1dlIpPqcP+BJ9evI4Gbwkw==
-
-"@logseq/[email protected]3":
-  version "0.0.73"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.73.tgz#7734187c1b56da6373c947680a65b21551134bec"
-  integrity sha512-YQTE4ZMtlrbuDVfD/6DWtnsiC2uUZpNDqcy6LIN6Ui98yeZ88ktOsEV/lQJF4+4cAflrzW7Xr8ejl2SWSdX6EQ==
-
-"@logseq/[email protected]3":
-  version "0.0.73"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.73.tgz#b02fc017bb12df3afa0fce60ba13e1b01bbf4342"
-  integrity sha512-ppQCCzc1pAgqlxkYg2CprcU5RTz01fWqba9lhEVg2FpeF9l8IVVCXhbBIUnWPEFTqkoySiwXpMU8kbkTgvEPIg==
+"@logseq/[email protected]5":
+  version "0.0.75"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.75.tgz#726034266119e92a78f52ba8a56f00383023f4fd"
+  integrity sha512-fnJd6tbM1Sa47sZva7d2sH0u6L+RYoHLdi84GGQddDnA/2iWzajrH1qCeXTcO0se1W9+bMp1+CbyyYlvCOuD0Q==
+
+"@logseq/[email protected]5":
+  version "0.0.75"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.75.tgz#523a748aa982065f942679664aef4c25acd034ac"
+  integrity sha512-GNk0RvZRLORn0uxLEzkQHVxT+EomBskGw1bFozAhafhHLy9/HxaV3Bifq/+26DCQ1PbpVUwJNh3lLOfX24+JfA==
+
+"@logseq/[email protected]5":
+  version "0.0.75"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-freebsd-x64/-/rsapi-freebsd-x64-0.0.75.tgz#f27a5bd8f5a5564b02606fcb28ef61300c6d6bea"
+  integrity sha512-TSlHnH1SivUkfLbNu0AyxiGuk1lBJ0cHkj9Ifc+s4WZhrVvujxykOib6OMoN7Yj1+SHO3MzOvVYXeLrJOH5l0g==
+
+"@logseq/[email protected]5":
+  version "0.0.75"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.75.tgz#905e205eca1decb08ee86ac3a8292524745962f4"
+  integrity sha512-6vw7U8Bb1KNYQqaTQYPpy0ja5UwMQOkfbEh3HK2t+YmLTGObvyGv11HLSEID7XLEuL97h6BU7dHSnhTxoglZZQ==
+
+"@logseq/[email protected]5":
+  version "0.0.75"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.75.tgz#f16f3fc784de0a853e15b995d0c056dbe0711229"
+  integrity sha512-ly2xhXe1oJLmwSS9R7vnKa9Ml+P4nbu/zFGqtA3LzH9hbN2naqgP0TlUlAe3OcMKeOrRn1FuwV9aeEjySlh4vQ==
+
+"@logseq/[email protected]5":
+  version "0.0.75"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.75.tgz#7e445b4c3a5c3e3b7b393158a36d1a5ee61a7700"
+  integrity sha512-A+eS4Lj8ZJMoY+tCFcSku+/5bXxpXvX8cG2Vb/TBjELaSTD6zNUWUonpEmu/PQyJEaVBAEf6Tl9FAEL6Q95bmw==
+
+"@logseq/[email protected]5":
+  version "0.0.75"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.75.tgz#0561a58057af112817f9b6aa496446a5eac2e31e"
+  integrity sha512-+cspXIrm0+8Exjnw+2bAzzwFA7HII5i5nmAIOeQ9dCHr0Bp1I0Kw5ledLBxcYt/wVvH37swiDjk69/WVRXX2sg==
   optionalDependencies:
-    "@logseq/rsapi-darwin-arm64" "0.0.73"
-    "@logseq/rsapi-darwin-x64" "0.0.73"
-    "@logseq/rsapi-freebsd-x64" "0.0.73"
-    "@logseq/rsapi-linux-arm64-gnu" "0.0.73"
-    "@logseq/rsapi-linux-x64-gnu" "0.0.73"
-    "@logseq/rsapi-win32-x64-msvc" "0.0.73"
+    "@logseq/rsapi-darwin-arm64" "0.0.75"
+    "@logseq/rsapi-darwin-x64" "0.0.75"
+    "@logseq/rsapi-freebsd-x64" "0.0.75"
+    "@logseq/rsapi-linux-arm64-gnu" "0.0.75"
+    "@logseq/rsapi-linux-x64-gnu" "0.0.75"
+    "@logseq/rsapi-win32-x64-msvc" "0.0.75"
 
 "@malept/cross-spawn-promise@^1.0.0", "@malept/cross-spawn-promise@^1.1.0":
   version "1.1.1"
@@ -2093,10 +2093,10 @@ electron-winstaller@^5.0.0:
     lodash.template "^4.2.2"
     temp "^0.9.0"
 
-electron@*, electron@24.6.3:
-  version "24.6.3"
-  resolved "https://registry.yarnpkg.com/electron/-/electron-24.6.3.tgz#fc41279a5ec7b0aa3d48128df61fa29ca8a21199"
-  integrity sha512-hWy2ot0987DRzhOxIyv9tgybd0yrAcc9MRFYZ+znjXgdmbvcSveXdcGKGdtpgw1EW/TKUonJMH3VfDNeAmdPUg==
+electron@*, electron@25.9.3:
+  version "25.9.3"
+  resolved "https://registry.yarnpkg.com/electron/-/electron-25.9.3.tgz#cdd53a30fb914adadcfbd34124237fb38b1c07d0"
+  integrity sha512-dacaHg/PuwVcFRgPDCM5j7UDzqGJWOsbBRdS5wPKLNS/ejPeccIjuNUT1cqcrpvCJKAFW8swHWg9kdizNSEDHQ==
   dependencies:
     "@electron/get" "^2.0.0"
     "@types/node" "^18.11.18"
@@ -3634,10 +3634,10 @@ nice-try@^1.0.4:
   resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
   integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
 
-node-abi@^3.0.0, node-abi@^3.3.0:
-  version "3.40.0"
-  resolved "https://registry.npmjs.org/node-abi/-/node-abi-3.40.0.tgz#51d8ed44534f70ff1357dfbc3a89717b1ceac1b4"
-  integrity sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA==
+[email protected], node-abi@^3.0.0, node-abi@^3.3.0:
+  version "3.51.0"
+  resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.51.0.tgz#970bf595ef5a26a271307f8a4befa02823d4e87d"
+  integrity sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==
   dependencies:
     semver "^7.3.5"
 

+ 28 - 14
tldraw/cljs-demo/yarn.lock

@@ -30,11 +30,16 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
   integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
 
-bn.js@^5.0.0, bn.js@^5.1.1:
+bn.js@^5.0.0:
   version "5.2.0"
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
   integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
 
+bn.js@^5.2.1:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
+  integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
+
 brorand@^1.0.1, brorand@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -71,7 +76,7 @@ browserify-des@^1.0.0:
     inherits "^2.0.1"
     safe-buffer "^5.1.2"
 
-browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
+browserify-rsa@^4.0.0, browserify-rsa@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d"
   integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==
@@ -80,19 +85,19 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
     randombytes "^2.0.1"
 
 browserify-sign@^4.0.0:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3"
-  integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e"
+  integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==
   dependencies:
-    bn.js "^5.1.1"
-    browserify-rsa "^4.0.1"
+    bn.js "^5.2.1"
+    browserify-rsa "^4.1.0"
     create-hash "^1.2.0"
     create-hmac "^1.1.7"
-    elliptic "^6.5.3"
+    elliptic "^6.5.4"
     inherits "^2.0.4"
-    parse-asn1 "^5.1.5"
-    readable-stream "^3.6.0"
-    safe-buffer "^5.2.0"
+    parse-asn1 "^5.1.6"
+    readable-stream "^3.6.2"
+    safe-buffer "^5.2.1"
 
 browserify-zlib@^0.2.0:
   version "0.2.0"
@@ -213,7 +218,7 @@ domain-browser@^1.1.1:
   resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
   integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
 
-elliptic@^6.5.3:
+elliptic@^6.5.3, elliptic@^6.5.4:
   version "6.5.4"
   resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
   integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
@@ -383,7 +388,7 @@ pako@~1.0.5:
   resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
   integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
 
-parse-asn1@^5.0.0, parse-asn1@^5.1.5:
+parse-asn1@^5.0.0, parse-asn1@^5.1.6:
   version "5.1.6"
   resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4"
   integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==
@@ -506,6 +511,15 @@ readable-stream@^3.6.0:
     string_decoder "^1.1.1"
     util-deprecate "^1.0.1"
 
+readable-stream@^3.6.2:
+  version "3.6.2"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+  integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
 readline-sync@^1.4.7:
   version "1.4.10"
   resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b"
@@ -519,7 +533,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
     hash-base "^3.0.0"
     inherits "^2.0.1"
 
-safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==

+ 142 - 65
tldraw/yarn.lock

@@ -17,6 +17,14 @@
   dependencies:
     "@babel/highlight" "^7.18.6"
 
+"@babel/code-frame@^7.22.13":
+  version "7.22.13"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
+  integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
+  dependencies:
+    "@babel/highlight" "^7.22.13"
+    chalk "^2.4.2"
+
 "@babel/compat-data@^7.20.0":
   version "7.20.1"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30"
@@ -43,16 +51,7 @@
     json5 "^2.2.1"
     semver "^6.3.0"
 
-"@babel/generator@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.0.tgz#785596c06425e59334df2ccee63ab166b738419a"
-  integrity sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==
-  dependencies:
-    "@babel/types" "^7.19.0"
-    "@jridgewell/gen-mapping" "^0.3.2"
-    jsesc "^2.5.1"
-
-"@babel/generator@^7.20.1", "@babel/generator@^7.20.2":
+"@babel/generator@^7.20.2":
   version "7.20.4"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.4.tgz#4d9f8f0c30be75fd90a0562099a26e5839602ab8"
   integrity sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==
@@ -61,6 +60,16 @@
     "@jridgewell/gen-mapping" "^0.3.2"
     jsesc "^2.5.1"
 
+"@babel/generator@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
+  integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
+  dependencies:
+    "@babel/types" "^7.23.0"
+    "@jridgewell/gen-mapping" "^0.3.2"
+    "@jridgewell/trace-mapping" "^0.3.17"
+    jsesc "^2.5.1"
+
 "@babel/helper-annotate-as-pure@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
@@ -96,6 +105,11 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
   integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
 
+"@babel/helper-environment-visitor@^7.22.20":
+  version "7.22.20"
+  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+  integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
 "@babel/helper-function-name@^7.19.0":
   version "7.19.0"
   resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c"
@@ -104,12 +118,20 @@
     "@babel/template" "^7.18.10"
     "@babel/types" "^7.19.0"
 
-"@babel/helper-hoist-variables@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
-  integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
+"@babel/helper-function-name@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+  integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
   dependencies:
-    "@babel/types" "^7.18.6"
+    "@babel/template" "^7.22.15"
+    "@babel/types" "^7.23.0"
+
+"@babel/helper-hoist-variables@^7.22.5":
+  version "7.22.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+  integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+  dependencies:
+    "@babel/types" "^7.22.5"
 
 "@babel/helper-member-expression-to-functions@^7.18.9":
   version "7.18.9"
@@ -181,6 +203,13 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
+"@babel/helper-split-export-declaration@^7.22.6":
+  version "7.22.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+  integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+  dependencies:
+    "@babel/types" "^7.22.5"
+
 "@babel/helper-string-parser@^7.18.10":
   version "7.18.10"
   resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
@@ -191,6 +220,11 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
   integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
 
+"@babel/helper-string-parser@^7.22.5":
+  version "7.22.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
+  integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+
 "@babel/helper-validator-identifier@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
@@ -201,6 +235,11 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
   integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
 
+"@babel/helper-validator-identifier@^7.22.20":
+  version "7.22.20"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+  integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
 "@babel/helper-validator-option@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
@@ -224,21 +263,30 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
+"@babel/highlight@^7.22.13":
+  version "7.22.20"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
+  integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.22.20"
+    chalk "^2.4.2"
+    js-tokens "^4.0.0"
+
 "@babel/parser@^7.18.10":
   version "7.18.11"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9"
   integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==
 
-"@babel/parser@^7.19.1":
-  version "7.19.1"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.1.tgz#6f6d6c2e621aad19a92544cc217ed13f1aac5b4c"
-  integrity sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==
-
-"@babel/parser@^7.20.1", "@babel/parser@^7.20.2":
+"@babel/parser@^7.20.2":
   version "7.20.3"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2"
   integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==
 
+"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
+  integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
+
 "@babel/plugin-proposal-decorators@^7.20.2":
   version "7.20.2"
   resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.2.tgz#1c6c32b2a44b154ebeec2bb534f9eaebdb541fb6"
@@ -323,35 +371,28 @@
     "@babel/parser" "^7.18.10"
     "@babel/types" "^7.18.10"
 
-"@babel/traverse@^7.19.1":
-  version "7.19.1"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.1.tgz#0fafe100a8c2a603b4718b1d9bf2568d1d193347"
-  integrity sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==
-  dependencies:
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.19.0"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.19.0"
-    "@babel/helper-hoist-variables" "^7.18.6"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/parser" "^7.19.1"
-    "@babel/types" "^7.19.0"
-    debug "^4.1.0"
-    globals "^11.1.0"
-
-"@babel/traverse@^7.20.1":
-  version "7.20.1"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
-  integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
-  dependencies:
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.20.1"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.19.0"
-    "@babel/helper-hoist-variables" "^7.18.6"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/parser" "^7.20.1"
-    "@babel/types" "^7.20.0"
+"@babel/template@^7.22.15":
+  version "7.22.15"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
+  integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
+  dependencies:
+    "@babel/code-frame" "^7.22.13"
+    "@babel/parser" "^7.22.15"
+    "@babel/types" "^7.22.15"
+
+"@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1":
+  version "7.23.2"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
+  integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
+  dependencies:
+    "@babel/code-frame" "^7.22.13"
+    "@babel/generator" "^7.23.0"
+    "@babel/helper-environment-visitor" "^7.22.20"
+    "@babel/helper-function-name" "^7.23.0"
+    "@babel/helper-hoist-variables" "^7.22.5"
+    "@babel/helper-split-export-declaration" "^7.22.6"
+    "@babel/parser" "^7.23.0"
+    "@babel/types" "^7.23.0"
     debug "^4.1.0"
     globals "^11.1.0"
 
@@ -382,6 +423,15 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
+  integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+  dependencies:
+    "@babel/helper-string-parser" "^7.22.5"
+    "@babel/helper-validator-identifier" "^7.22.20"
+    to-fast-properties "^2.0.0"
+
 "@esbuild/[email protected]":
   version "0.15.14"
   resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.14.tgz#5d0027f920eeeac313c01fd6ecb8af50c306a466"
@@ -497,6 +547,11 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
   integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
 
+"@jridgewell/resolve-uri@^3.1.0":
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+  integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
 "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
@@ -507,6 +562,19 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
   integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
 
+"@jridgewell/sourcemap-codec@^1.4.14":
+  version "1.4.15"
+  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+  integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@^0.3.17":
+  version "0.3.20"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
+  integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
+  dependencies:
+    "@jridgewell/resolve-uri" "^3.1.0"
+    "@jridgewell/sourcemap-codec" "^1.4.14"
+
 "@jridgewell/trace-mapping@^0.3.9":
   version "0.3.15"
   resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
@@ -1632,7 +1700,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
   integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
 
-bn.js@^5.0.0, bn.js@^5.1.1:
+bn.js@^5.0.0, bn.js@^5.2.1:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
   integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
@@ -1688,7 +1756,7 @@ browserify-des@^1.0.0:
     inherits "^2.0.1"
     safe-buffer "^5.1.2"
 
-browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
+browserify-rsa@^4.0.0, browserify-rsa@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d"
   integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==
@@ -1697,19 +1765,19 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
     randombytes "^2.0.1"
 
 browserify-sign@^4.0.0:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3"
-  integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e"
+  integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==
   dependencies:
-    bn.js "^5.1.1"
-    browserify-rsa "^4.0.1"
+    bn.js "^5.2.1"
+    browserify-rsa "^4.1.0"
     create-hash "^1.2.0"
     create-hmac "^1.1.7"
-    elliptic "^6.5.3"
+    elliptic "^6.5.4"
     inherits "^2.0.4"
-    parse-asn1 "^5.1.5"
-    readable-stream "^3.6.0"
-    safe-buffer "^5.2.0"
+    parse-asn1 "^5.1.6"
+    readable-stream "^3.6.2"
+    safe-buffer "^5.2.1"
 
 browserify-zlib@^0.2.0:
   version "0.2.0"
@@ -1789,7 +1857,7 @@ caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426:
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz#e7c59bd1bc518fae03a4656be442ce6c4887a795"
   integrity sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==
 
-chalk@^2.0.0:
+chalk@^2.0.0, chalk@^2.4.2:
   version "2.4.2"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
   integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -2166,7 +2234,7 @@ electron-to-chromium@^1.4.251:
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592"
   integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==
 
-elliptic@^6.5.3:
+elliptic@^6.5.3, elliptic@^6.5.4:
   version "6.5.4"
   resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
   integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
@@ -3752,7 +3820,7 @@ parent-module@^1.0.0:
   dependencies:
     callsites "^3.0.0"
 
-parse-asn1@^5.0.0, parse-asn1@^5.1.5:
+parse-asn1@^5.0.0, parse-asn1@^5.1.6:
   version "5.1.6"
   resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4"
   integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==
@@ -4142,6 +4210,15 @@ readable-stream@^3.6.0:
     string_decoder "^1.1.1"
     util-deprecate "^1.0.1"
 
+readable-stream@^3.6.2:
+  version "3.6.2"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+  integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
 readdirp@~3.6.0:
   version "3.6.0"
   resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@@ -4261,7 +4338,7 @@ sade@^1.7.3:
   dependencies:
     mri "^1.1.0"
 
-safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==

+ 61 - 37
yarn.lock

@@ -62,6 +62,16 @@
     "@jridgewell/trace-mapping" "^0.3.17"
     jsesc "^2.5.1"
 
+"@babel/generator@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
+  integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
+  dependencies:
+    "@babel/types" "^7.23.0"
+    "@jridgewell/gen-mapping" "^0.3.2"
+    "@jridgewell/trace-mapping" "^0.3.17"
+    jsesc "^2.5.1"
+
 "@babel/helper-compilation-targets@^7.22.15":
   version "7.22.15"
   resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52"
@@ -78,13 +88,13 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
   integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
 
-"@babel/helper-function-name@^7.22.5":
-  version "7.22.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be"
-  integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==
+"@babel/helper-function-name@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+  integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
   dependencies:
-    "@babel/template" "^7.22.5"
-    "@babel/types" "^7.22.5"
+    "@babel/template" "^7.22.15"
+    "@babel/types" "^7.23.0"
 
 "@babel/helper-hoist-variables@^7.22.5":
   version "7.22.5"
@@ -163,6 +173,11 @@
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95"
   integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==
 
+"@babel/parser@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
+  integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
+
 "@babel/[email protected]":
   version "7.11.2"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
@@ -177,7 +192,7 @@
   dependencies:
     regenerator-runtime "^0.14.0"
 
-"@babel/template@^7.22.15", "@babel/template@^7.22.5":
+"@babel/template@^7.22.15":
   version "7.22.15"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
   integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
@@ -187,18 +202,18 @@
     "@babel/types" "^7.22.15"
 
 "@babel/traverse@^7.22.15", "@babel/traverse@^7.22.20":
-  version "7.22.20"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.20.tgz#db572d9cb5c79e02d83e5618b82f6991c07584c9"
-  integrity sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==
+  version "7.23.2"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
+  integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
   dependencies:
     "@babel/code-frame" "^7.22.13"
-    "@babel/generator" "^7.22.15"
+    "@babel/generator" "^7.23.0"
     "@babel/helper-environment-visitor" "^7.22.20"
-    "@babel/helper-function-name" "^7.22.5"
+    "@babel/helper-function-name" "^7.23.0"
     "@babel/helper-hoist-variables" "^7.22.5"
     "@babel/helper-split-export-declaration" "^7.22.6"
-    "@babel/parser" "^7.22.16"
-    "@babel/types" "^7.22.19"
+    "@babel/parser" "^7.23.0"
+    "@babel/types" "^7.23.0"
     debug "^4.1.0"
     globals "^11.1.0"
 
@@ -211,6 +226,15 @@
     "@babel/helper-validator-identifier" "^7.22.19"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
+  integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+  dependencies:
+    "@babel/helper-string-parser" "^7.22.5"
+    "@babel/helper-validator-identifier" "^7.22.20"
+    to-fast-properties "^2.0.0"
+
 "@capacitor/android@^5.0.0":
   version "5.4.1"
   resolved "https://registry.yarnpkg.com/@capacitor/android/-/android-5.4.1.tgz#5b0445202ca5e48fcb79d0c88e4403acc32504bc"
@@ -508,10 +532,10 @@
     "@jridgewell/resolve-uri" "^3.1.0"
     "@jridgewell/sourcemap-codec" "^1.4.14"
 
-"@logseq/[email protected].0":
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-5.0.0.tgz#bd340e63119c6bb548844195f2802150621b23d1"
-  integrity sha512-x1Yi1GJRINIa4joeKIURDYuaTXZ3d/HV4PeLQaura1dTkYxQHhes40mNO+bGPSykHWzds8InN+/o7G2TzwSKKA==
+"@logseq/[email protected].1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-5.0.1.tgz#e154f715597785518ccd7d058f353acb67fbc2b8"
+  integrity sha512-C1fLSS53orxsUWBsNb6LKwuOdlEU9ZhxkweMjNKG9VaSkLFTFqpjFG36OTso23WQ7hC5e45jjXq79aoWuqJaKA==
 
 "@logseq/[email protected]":
   version "0.2.2"
@@ -1508,7 +1532,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
   integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
 
-bn.js@^5.0.0, bn.js@^5.1.1:
+bn.js@^5.0.0, bn.js@^5.2.1:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
   integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
@@ -1604,7 +1628,7 @@ browserify-des@^1.0.0:
     inherits "^2.0.1"
     safe-buffer "^5.1.2"
 
-browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
+browserify-rsa@^4.0.0, browserify-rsa@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d"
   integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==
@@ -1613,19 +1637,19 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
     randombytes "^2.0.1"
 
 browserify-sign@^4.0.0:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3"
-  integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e"
+  integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==
   dependencies:
-    bn.js "^5.1.1"
-    browserify-rsa "^4.0.1"
+    bn.js "^5.2.1"
+    browserify-rsa "^4.1.0"
     create-hash "^1.2.0"
     create-hmac "^1.1.7"
-    elliptic "^6.5.3"
+    elliptic "^6.5.4"
     inherits "^2.0.4"
-    parse-asn1 "^5.1.5"
-    readable-stream "^3.6.0"
-    safe-buffer "^5.2.0"
+    parse-asn1 "^5.1.6"
+    readable-stream "^3.6.2"
+    safe-buffer "^5.2.1"
 
 browserify-zlib@^0.2.0:
   version "0.2.0"
@@ -2689,10 +2713,10 @@ electron-to-chromium@^1.4.526:
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz#7c900fd73d9d2e8bb0dab0e301f25f0f4776ef2c"
   integrity sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==
 
-electron@24.6.3:
-  version "24.6.3"
-  resolved "https://registry.yarnpkg.com/electron/-/electron-24.6.3.tgz#fc41279a5ec7b0aa3d48128df61fa29ca8a21199"
-  integrity sha512-hWy2ot0987DRzhOxIyv9tgybd0yrAcc9MRFYZ+znjXgdmbvcSveXdcGKGdtpgw1EW/TKUonJMH3VfDNeAmdPUg==
+electron@25.9.3:
+  version "25.9.3"
+  resolved "https://registry.yarnpkg.com/electron/-/electron-25.9.3.tgz#cdd53a30fb914adadcfbd34124237fb38b1c07d0"
+  integrity sha512-dacaHg/PuwVcFRgPDCM5j7UDzqGJWOsbBRdS5wPKLNS/ejPeccIjuNUT1cqcrpvCJKAFW8swHWg9kdizNSEDHQ==
   dependencies:
     "@electron/get" "^2.0.0"
     "@types/node" "^18.11.18"
@@ -2712,7 +2736,7 @@ elementtree@^0.1.7:
   dependencies:
     sax "1.1.4"
 
-elliptic@^6.5.3:
+elliptic@^6.5.3, elliptic@^6.5.4:
   version "6.5.4"
   resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
   integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
@@ -5456,7 +5480,7 @@ parent-module@^1.0.0:
   dependencies:
     callsites "^3.0.0"
 
-parse-asn1@^5.0.0, parse-asn1@^5.1.5:
+parse-asn1@^5.0.0, parse-asn1@^5.1.6:
   version "5.1.6"
   resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4"
   integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==
@@ -6506,7 +6530,7 @@ read-pkg@^5.2.0:
     parse-json "^5.0.0"
     type-fest "^0.6.0"
 
-"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.1.1, readable-stream@^3.6.0:
+"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.1.1, readable-stream@^3.6.0, readable-stream@^3.6.2:
   version "3.6.2"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
   integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
@@ -6804,7 +6828,7 @@ safe-array-concat@^1.0.1:
     has-symbols "^1.0.3"
     isarray "^2.0.5"
 
-safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==

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