Browse Source

Merge branch 'master' into feat/web-bi-client

charlie 1 năm trước cách đây
mục cha
commit
3b27beee0e
38 tập tin đã thay đổi với 606 bổ sung384 xóa
  1. 3 1
      .github/workflows/build-android.yml
  2. 3 0
      android/.gitignore
  3. 16 0
      android/app/build.gradle
  4. 16 1
      android/app/src/main/AndroidManifest.xml
  5. 0 1
      android/app/src/main/java/com/logseq/app/FsWatcher.java
  6. 1 1
      deps/shui/src/logseq/shui/demo.cljs
  7. 8 2
      deps/shui/src/logseq/shui/list_item/v1.cljs
  8. 2 1
      e2e-tests/accessibility.spec.ts
  9. 16 51
      e2e-tests/basic.spec.ts
  10. 2 2
      e2e-tests/page-rename.spec.ts
  11. 41 41
      packages/amplify/yarn.lock
  12. 3 3
      packages/ui/yarn.lock
  13. 1 1
      resources/package.json
  14. 1 1
      scripts/src/logseq/tasks/lang.clj
  15. 1 1
      src/main/frontend/components/block.css
  16. 4 7
      src/main/frontend/components/cmdk.cljs
  17. 108 33
      src/main/frontend/components/container.cljs
  18. 78 51
      src/main/frontend/components/container.css
  19. 11 17
      src/main/frontend/components/query_table.cljs
  20. 13 12
      src/main/frontend/components/right_sidebar.cljs
  21. 4 4
      src/main/frontend/components/right_sidebar.css
  22. 1 1
      src/main/frontend/config.cljs
  23. 1 1
      src/main/frontend/extensions/pdf/pdf.css
  24. 13 12
      src/main/frontend/fs/sync.cljs
  25. 32 8
      src/main/frontend/handler/export/common.cljs
  26. 4 1
      src/main/frontend/handler/export/html.cljs
  27. 4 1
      src/main/frontend/handler/export/opml.cljs
  28. 29 19
      src/main/frontend/handler/export/text.cljs
  29. 2 1
      src/main/frontend/ui.cljs
  30. 7 0
      src/main/frontend/ui.css
  31. 3 0
      src/main/logseq/api.cljs
  32. 13 1
      src/resources/dicts/es.edn
  33. 2 2
      src/resources/dicts/fr.edn
  34. 28 1
      src/resources/dicts/nb-no.edn
  35. 17 0
      src/test/frontend/handler/export_test.cljs
  36. 40 40
      static/yarn.lock
  37. 1 1
      tldraw/demo/package.json
  38. 77 64
      tldraw/yarn.lock

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

@@ -146,11 +146,13 @@ jobs:
           ./gradlew clean
           ./gradlew zipApksForRelease
         working-directory: android
+        env:
+          LOGSEQ_SENTRY_DSN: ${{ secrets.LOGSEQ_SENTRY_DSN }}
 
       - name: Sign Android APK
         run: |
           echo ${{ secrets.ANDROID_KEYSTORE }} | base64 -d > keystore.jks
-          /usr/local/lib/android/sdk/build-tools/30.0.3/apksigner sign \
+          /usr/local/lib/android/sdk/build-tools/33.0.0/apksigner sign \
             --ks keystore.jks --ks-pass "pass:${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" \
             --in app/build/outputs/apk/release/app-release-unsigned.apk \
             --out app-signed.apk

+ 3 - 0
android/.gitignore

@@ -94,3 +94,6 @@ capacitor-cordova-android-plugins
 
 # Copied web assets
 app/src/main/assets/public
+
+# Sentry Config File
+sentry.properties

+ 16 - 0
android/app/build.gradle

@@ -1,3 +1,8 @@
+
+plugins {
+    id 'io.sentry.android.gradle' version '4.1.1'
+}
+
 apply plugin: 'com.android.application'
 
 android {
@@ -15,6 +20,7 @@ android {
              // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
             ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
         }
+        manifestPlaceholders = [LOGSEQ_SENTRY_DSN: "$System.env.LOGSEQ_SENTRY_DSN"]
     }
     buildTypes {
         release {
@@ -53,3 +59,13 @@ try {
 } catch(Exception e) {
     logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
 }
+
+
+sentry {
+    org = "logseq"
+    projectName = "logseq"
+
+    // this will upload your source code to Sentry to show it as part of the stack traces
+    // disable if you don't want to expose your sources
+    includeSourceContext = false
+}

+ 16 - 1
android/app/src/main/AndroidManifest.xml

@@ -60,5 +60,20 @@
                 android:name="android.support.FILE_PROVIDER_PATHS"
                 android:resource="@xml/file_paths" />
         </provider>
-    </application>
+
+    <!-- Required: set your sentry.io project identifier (DSN) -->
+    <meta-data android:name="io.sentry.dsn" android:value="${LOGSEQ_SENTRY_DSN}" />
+
+    <!-- enable automatic breadcrumbs for user interactions (clicks, swipes, scrolls) -->
+    <meta-data android:name="io.sentry.traces.user-interaction.enable" android:value="true" />
+    <!-- enable screenshot for crashes (could contain sensitive/PII data) -->
+    <meta-data android:name="io.sentry.attach-screenshot" android:value="true" />
+    <!-- enable view hierarchy for crashes -->
+    <meta-data android:name="io.sentry.attach-view-hierarchy" android:value="true" />
+
+    <!-- enable the performance API by setting a sample-rate, adjust in production env -->
+    <meta-data android:name="io.sentry.traces.sample-rate" android:value="1.0" />
+    <!-- enable profiling when starting transactions, adjust in production env -->
+    <meta-data android:name="io.sentry.traces.profiling.sample-rate" android:value="1.0" />
+</application>
 </manifest>

+ 0 - 1
android/app/src/main/java/com/logseq/app/FsWatcher.java

@@ -101,7 +101,6 @@ public class FsWatcher extends Plugin {
             if (relpath.startsWith("/")) {
                 relpath = relpath.substring(1);
             }
-            relpath = Uri.decode(relpath);
         } else {
             Log.e("FsWatcher", "file path not under watch path");
             return;

+ 1 - 1
deps/shui/src/logseq/shui/demo.cljs

@@ -60,7 +60,7 @@
          [:span.opacity-50 "Right click here"]])
       ;; content
       (ui/context-menu-content
-        {:class "w-60"}
+        {:class "w-60 max-h-[80vh] overflow-auto"}
         (ui/context-menu-item
           (icon "arrow-left")
           "Back"

+ 8 - 2
deps/shui/src/logseq/shui/list_item/v1.cljs

@@ -77,7 +77,7 @@
 
 (rum/defc root [{:keys [icon icon-theme query text info shortcut value-label value
                         title highlighted on-highlight on-highlight-dep header on-click
-                        hoverable compact rounded on-mouse-enter component-opts] :as _props
+                        hoverable compact rounded on-mouse-enter component-opts source-page] :as _props
                  :or {hoverable true rounded true}}
                 {:keys [app-config] :as context}]
   (let [ref (rum/create-ref)
@@ -124,7 +124,13 @@
       [:div.flex.flex-1.flex-col
        (when title
          [:div.text-sm.pb-2.font-bold.text-gray-11 (highlight-query title)])
-       [:div {:class "text-sm font-medium text-gray-12"} (highlight-query text)
+       [:div {:class "text-sm font-medium text-gray-12"}
+        (if (and (= icon "page") (not= text source-page)) ;; alias
+          [:div.flex.flex-row.items-center.gap-2
+            (highlight-query text)
+            [:div.opacity-50.font-normal "alias of"]
+            source-page]
+          (highlight-query text))
         (when info
           [:span.text-xs.text-gray-11 " — " (highlight-query info)])]]
       (when (or value-label value)

+ 2 - 1
e2e-tests/accessibility.spec.ts

@@ -3,7 +3,8 @@ import { createRandomPage } from './utils'
 import { expect } from '@playwright/test'
 import AxeBuilder from '@axe-core/playwright'
 
-test('should not have any automatically detectable accessibility issues', async ({ page }) => {
+// TODO: more configuration is required for this test
+test.skip('should not have any automatically detectable accessibility issues', async ({ page }) => {
   try {
     await page.waitForSelector('.notification-clear', { timeout: 10 })
     page.click('.notification-clear')

+ 16 - 51
e2e-tests/basic.spec.ts

@@ -116,56 +116,34 @@ test('block selection', async ({ page, block }) => {
   await page.keyboard.down('Shift')
   await page.keyboard.press('ArrowUp')
   await block.waitForSelectedBlocks(1)
-  var locator = page.locator('.ls-block >> nth=8')
-  await expect(locator).toHaveAttribute('level', '1')
-  await expect(locator).toHaveCSS('border-radius', '2px')
+  let locator = page.locator('.ls-block >> nth=8')
+
   await page.keyboard.press('ArrowUp')
   await block.waitForSelectedBlocks(2)
-  locator = page.locator('.ls-block >> nth=7')
-  await expect(locator).toHaveAttribute('level', '2')
-  await expect(locator).toHaveCSS('border-radius', '2px')
+
   await page.keyboard.press('ArrowUp')
   await block.waitForSelectedBlocks(3)
-  locator = page.locator('.ls-block >> nth=6')
-  await expect(locator).toHaveAttribute('level', '1')
-  locator = page.locator('.block-main-container >> nth=6')
-  await expect(locator).toHaveCSS('border-radius', '2px')
+
   await page.keyboard.press('ArrowDown')
   await block.waitForSelectedBlocks(2)
-  locator = page.locator('.block-main-container >> nth=6')
-  await expect(locator).toHaveCSS('border-radius', '0px')
   await page.keyboard.up('Shift')
 
   // mod+click select or deselect
   await page.keyboard.down(modKey)
   await page.click('.ls-block >> nth=7')
   await block.waitForSelectedBlocks(1)
-  locator = page.locator('.ls-block >> nth=7')
-  await expect(locator).toHaveCSS('border-radius', '0px')
+
   await page.click('.block-main-container >> nth=6')
   await block.waitForSelectedBlocks(2)
-  locator = page.locator('.block-main-container >> nth=6')
-  await expect(locator).toHaveCSS('border-radius', '2px')
 
   // mod+shift+click
   await page.click('.ls-block >> nth=4')
   await block.waitForSelectedBlocks(3)
-  locator = page.locator('.ls-block >> nth=4')
-  await expect(locator).toHaveAttribute('level', '2')
-  await expect(locator).toHaveCSS('border-radius', '2px')
+
   await page.keyboard.down('Shift')
   await page.click('.ls-block >> nth=1')
   await block.waitForSelectedBlocks(6)
-  locator = page.locator('.ls-block >> nth=3')
-  await expect(locator).toHaveAttribute('level', '1')
-  locator = page.locator('.block-main-container >> nth=3')
-  await expect(locator).toHaveCSS('border-radius', '2px')
-  locator = page.locator('.ls-block >> nth=2')
-  await expect(locator).toHaveAttribute('level', '2')
-  await expect(locator).toHaveCSS('border-radius', '2px')
-  locator = page.locator('.ls-block >> nth=1')
-  await expect(locator).toHaveAttribute('level', '2')
-  await expect(locator).toHaveCSS('border-radius', '2px')
+
   await page.keyboard.up('Shift')
   await page.keyboard.up(modKey)
   await page.keyboard.press('Escape')
@@ -173,25 +151,12 @@ test('block selection', async ({ page, block }) => {
   // shift+click
   await page.keyboard.down('Shift')
   await page.click('.block-main-container >> nth=0')
-  await expect(page.locator('.block-main-container >> nth=0')).toHaveCSS('border-radius', '0px')
   await page.click('.block-main-container >> nth=3')
   await block.waitForSelectedBlocks(4)
-  await expect(page.locator('.block-main-container >> nth=0')).toHaveCSS('border-radius', '2px')
-  await expect(page.locator('.ls-block >> nth=1')).toHaveCSS('border-radius', '2px')
-  await expect(page.locator('.ls-block >> nth=2')).toHaveCSS('border-radius', '2px')
-  await expect(page.locator('.block-main-container >> nth=3')).toHaveCSS('border-radius', '2px')
   await page.click('.ls-block >> nth=8')
   await block.waitForSelectedBlocks(9)
-  await expect(page.locator('.ls-block >> nth=4')).toHaveCSS('border-radius', '2px')
-  await expect(page.locator('.ls-block >> nth=5')).toHaveCSS('border-radius', '2px')
-  await expect(page.locator('.block-main-container >> nth=6')).toHaveCSS('border-radius', '2px')
-  await expect(page.locator('.ls-block >> nth=7')).toHaveCSS('border-radius', '2px')
-  await expect(page.locator('.ls-block >> nth=8')).toHaveCSS('border-radius', '2px')
   await page.click('.ls-block >> nth=5')
   await block.waitForSelectedBlocks(6)
-  await expect(page.locator('.block-main-container >> nth=6')).toHaveCSS('border-radius', '0px')
-  await expect(page.locator('.ls-block >> nth=7')).toHaveCSS('border-radius', '0px')
-  await expect(page.locator('.ls-block >> nth=8')).toHaveCSS('border-radius', '0px')
   await page.keyboard.up('Shift')
 })
 
@@ -201,7 +166,7 @@ test('template', async ({ page, block }) => {
   await createRandomPage(page)
 
   await block.mustFill('template test\ntemplate:: ')
-  await page.keyboard.type(randomTemplate, {delay: 100})
+  await page.keyboard.type(randomTemplate, { delay: 100 })
   await page.keyboard.press('Enter')
   await block.clickNext()
 
@@ -323,7 +288,7 @@ test('invalid page props #3944', async ({ page, block }) => {
   await block.enterNext()
 })
 
-test('Scheduled date picker should point to the already specified Date #6985', async({page,block})=>{
+test('Scheduled date picker should point to the already specified Date #6985', async ({ page, block }) => {
   await createRandomPage(page)
 
   await block.mustFill('testTask \n SCHEDULED: <2000-05-06 Sat>')
@@ -334,15 +299,15 @@ test('Scheduled date picker should point to the already specified Date #6985', a
   // Open date picker
   await page.click('a.opacity-80')
   await page.waitForTimeout(500)
-  expect(page.locator('text=May 2000')).toBeVisible()
-  expect(page.locator('td:has-text("6").active')).toBeVisible()
+  await expect(page.locator('text=May 2000')).toBeVisible()
+  await expect(page.locator('td:has-text("6").active')).toBeVisible()
 
   // Close date picker
   await page.click('a.opacity-80')
   await page.waitForTimeout(500)
 })
 
-test('Opening a second datepicker should close the first one #7341', async({page,block})=>{
+test('Opening a second datepicker should close the first one #7341', async ({ page, block }) => {
   await createRandomPage(page)
 
   await block.mustFill('testTask \n SCHEDULED: <2000-05-06 Sat>')
@@ -360,10 +325,10 @@ test('Opening a second datepicker should close the first one #7341', async({page
   await page.waitForTimeout(50)
   await page.click('a:has-text("2000-05-06 Sat").opacity-80')
   await page.waitForTimeout(50)
-  expect(page.locator('text=May 2000')).toBeVisible()
-  expect(page.locator('td:has-text("6").active')).toBeVisible()
-  expect(page.locator('text=June 2000')).not.toBeVisible()
-  expect(page.locator('td:has-text("7").active')).not.toBeVisible()
+  await expect(page.locator('text=May 2000')).toBeVisible()
+  await expect(page.locator('td:has-text("6").active')).toBeVisible()
+  await expect(page.locator('text=June 2000')).not.toBeVisible()
+  await expect(page.locator('td:has-text("7").active')).not.toBeVisible()
 
   // Close date picker
   await page.click('a:has-text("2000-05-06 Sat").opacity-80')

+ 2 - 2
e2e-tests/page-rename.spec.ts

@@ -91,7 +91,7 @@ test('page title property test', async ({ page }) => {
   await page.type(':nth-match(textarea, 1)', 'title:: ' + new_name + "     ")
   await page.press(':nth-match(textarea, 1)', 'Enter') // DWIM property mode creates new line
   await page.press(':nth-match(textarea, 1)', 'Enter')
-  expect(await page.innerText('.page-title .title')).toBe(new_name)
+  await expect(page.locator('.page-title .title')).toHaveText(new_name)
 
   // Edit Title Property and Esc (ETPE)
   // exit editing via moving out focus
@@ -101,5 +101,5 @@ test('page title property test', async ({ page }) => {
   await createPage(page, original_name)
   await page.type(':nth-match(textarea, 1)', 'title:: ' + new_name)
   await page.press(':nth-match(textarea, 1)', 'Escape')
-  expect(await page.innerText('.page-title .title')).toBe(new_name)
+  await expect(page.locator('.page-title .title')).toHaveText(new_name)
 })

+ 41 - 41
packages/amplify/yarn.lock

@@ -2461,35 +2461,35 @@
     "@lezer/lr" "^0.15.4"
     json5 "^2.2.1"
 
-"@msgpackr-extract/[email protected].0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.0.tgz#d31a238c943ffc34bab73ad6ce7a6466d65888ef"
-  integrity sha512-5qpnNHUyyEj9H3sm/4Um/bnx1lrQGhe8iqry/1d+cQYCRd/gzYA0YLeq0ezlk4hKx4vO+dsEsNyeowqRqslwQA==
+"@msgpackr-extract/[email protected].2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz#44d752c1a2dc113f15f781b7cc4f53a307e3fa38"
+  integrity sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==
 
-"@msgpackr-extract/[email protected].0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.0.tgz#2f6fbbec3d3f0bbe9c6678c899f1c1a6e25ed980"
-  integrity sha512-ZphTFFd6SFweNAMKD+QJCrWpgkjf4qBuHltiMkKkD6FFrB3NOTRVmetAGTkJ57pa+s6J0yCH06LujWB9rZe94g==
+"@msgpackr-extract/[email protected].2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz#f954f34355712212a8e06c465bc06c40852c6bb3"
+  integrity sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==
 
-"@msgpackr-extract/[email protected].0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.0.tgz#19875441da50b9aa8f8e726eb097a4cead435a3f"
-  integrity sha512-NEX6hdSvP4BmVyegaIbrGxvHzHvTzzsPaxXCsUt0mbLbPpEftsvNwaEVKOowXnLoeuGeD4MaqSwL3BUK2elsUA==
+"@msgpackr-extract/[email protected].2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz#45c63037f045c2b15c44f80f0393fa24f9655367"
+  integrity sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==
 
-"@msgpackr-extract/[email protected].0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.0.tgz#3b855ac72cc16e89db2f72adf47ddc964c20a53d"
-  integrity sha512-ztKVV1dO/sSZyGse0PBCq3Pk1PkYjsA/dsEWE7lfrGoAK3i9HpS2o7XjGQ7V4va6nX+xPPOiuYpQwa4Bi6vlww==
+"@msgpackr-extract/[email protected].2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz#35707efeafe6d22b3f373caf9e8775e8920d1399"
+  integrity sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==
 
-"@msgpackr-extract/[email protected].0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.0.tgz#455f1d5bb00e87f78c67711f26e7bff9f1457684"
-  integrity sha512-9uvdAkZMOPCY7SPRxZLW8XGqBOVNVEhqlgffenN8shA1XR9FWVsSM13nr/oHtNgXg6iVyML7RwWPyqUeThlwxg==
+"@msgpackr-extract/[email protected].2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz#091b1218b66c341f532611477ef89e83f25fae4f"
+  integrity sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==
 
-"@msgpackr-extract/[email protected].0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.0.tgz#03c6bfcd3acb179ea69546c20d50895b9d623ada"
-  integrity sha512-Wg0+9615kHKlr9iLVcG5I+/CHnf6w3x5UADRv8Ad16yA0Bu5l9eVOROjV7aHPG6uC8ZPFIVVaoSjDChD+Y0pzg==
+"@msgpackr-extract/[email protected].2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407"
+  integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==
 
 "@parcel/[email protected]":
   version "2.8.3"
@@ -4113,9 +4113,9 @@ find-up@^4.1.0:
     path-exists "^4.0.0"
 
 follow-redirects@^1.14.8:
-  version "1.15.2"
-  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
-  integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+  version "1.15.4"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
+  integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
 
 fs-extra@^10.0.0:
   version "10.1.0"
@@ -4616,26 +4616,26 @@ minimist@^1.2.5, minimist@^1.2.6:
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
   integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
 
-msgpackr-extract@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.0.tgz#5b5c5fbfff25be5ee5b5a82a9cbe02e37f72bed0"
-  integrity sha512-oy6KCk1+X4Bn5m6Ycq5N1EWl9npqG/cLrE8ga8NX7ZqfqYUUBS08beCQaGq80fjbKBySur0E6x//yZjzNJDt3A==
+msgpackr-extract@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz#e05ec1bb4453ddf020551bcd5daaf0092a2c279d"
+  integrity sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==
   dependencies:
     node-gyp-build-optional-packages "5.0.7"
   optionalDependencies:
-    "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.0"
-    "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.0"
-    "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.0"
-    "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.0"
-    "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.0"
-    "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.0"
+    "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.2"
+    "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.2"
+    "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.2"
+    "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.2"
+    "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2"
+    "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2"
 
 msgpackr@^1.5.4:
-  version "1.8.3"
-  resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.3.tgz#78c1b91359f72707f4abeaca40cc423bd2d75185"
-  integrity sha512-m2JefwcKNzoHYXkH/5jzHRxAw7XLWsAdvu0FOJ+OLwwozwOV/J6UA62iLkfIMbg7G8+dIuRwgg6oz+QoQ4YkoA==
+  version "1.10.1"
+  resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.10.1.tgz#51953bb4ce4f3494f0c4af3f484f01cfbb306555"
+  integrity sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==
   optionalDependencies:
-    msgpackr-extract "^3.0.0"
+    msgpackr-extract "^3.0.2"
 
 murmurhash-js@^1.0.0:
   version "1.0.0"

+ 3 - 3
packages/ui/yarn.lock

@@ -7341,9 +7341,9 @@ msgpackr-extract@^3.0.2:
     "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2"
 
 msgpackr@^1.5.4:
-  version "1.9.9"
-  resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.9.9.tgz#ec71e37beb8729280847f683cb0a340eb35ce70f"
-  integrity sha512-sbn6mioS2w0lq1O6PpGtsv6Gy8roWM+o3o4Sqjd6DudrL/nOugY+KyJUimoWzHnf9OkO0T6broHFnYE/R05t9A==
+  version "1.10.1"
+  resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.10.1.tgz#51953bb4ce4f3494f0c4af3f484f01cfbb306555"
+  integrity sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==
   optionalDependencies:
     msgpackr-extract "^3.0.2"
 

+ 1 - 1
resources/package.json

@@ -38,7 +38,7 @@
     "socks-proxy-agent": "8.0.2",
     "@sentry/electron": "2.5.1",
     "posthog-js": "1.10.2",
-    "@logseq/rsapi": "0.0.76",
+    "@logseq/rsapi": "0.0.81",
     "electron-deeplink": "1.0.10",
     "abort-controller": "3.0.0",
     "fastify": "latest",

+ 1 - 1
scripts/src/logseq/tasks/lang.clj

@@ -176,7 +176,7 @@
    :nb-NO #{:port :type :whiteboard :right-side-bar/flashcards :right-side-bar/whiteboards
             :search-item/whiteboard :settings-page/enable-flashcards :settings-page/enable-whiteboards
             :settings-page/tab-editor :shortcut.category/whiteboard :whiteboard/medium
-            :whiteboard/twitter-url :whiteboard/youtube-url :right-side-bar/history-global}
+            :whiteboard/twitter-url :whiteboard/youtube-url :right-side-bar/history-global :linked-references/filter-heading}
    :tr #{:help/awesome-logseq}
    :id #{:host :port :on-boarding/section-app :right-side-bar/history-global}})
 

+ 1 - 1
src/main/frontend/components/block.css

@@ -377,7 +377,7 @@
   }
 
   .bullet-container .selected {
-    border: 1px solid;
+    border: 3px solid;
   }
 }
 

+ 4 - 7
src/main/frontend/components/cmdk.cljs

@@ -227,13 +227,10 @@
                                 source-page (model/get-alias-source-page repo page)]
                             (hash-map :icon (if whiteboard? "whiteboard" "page")
                                       :icon-theme :gray
-                                      :text (if source-page
-                                              [:div.flex.flex-row.items-center.gap-2
-                                               page
-                                               [:div.opacity-50.font-normal "alias of"]
-                                               (:block/original-name source-page)]
-                                              page)
-                                      :source-page page)))))]
+                                      :text page
+                                      :source-page (if source-page
+                                              (:block/original-name source-page)
+                                              page))))))]
       (swap! !results update group        merge {:status :success :items items}))))
 
 (defmethod load-results :whiteboards [group state]

+ 108 - 33
src/main/frontend/components/container.cljs

@@ -16,13 +16,16 @@
             [frontend.config :as config]
             [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
+            [electron.ipc :as ipc]
             [frontend.db-mixins :as db-mixins]
             [frontend.db.model :as db-model]
             [frontend.extensions.pdf.utils :as pdf-utils]
+            [frontend.storage :as storage]
             [frontend.extensions.srs :as srs]
             [frontend.handler.common :as common-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.page :as page-handler]
+            [frontend.util.page :as page-util]
             [frontend.handler.route :as route-handler]
             [frontend.handler.user :as user-handler]
             [frontend.handler.whiteboard :as whiteboard-handler]
@@ -32,8 +35,10 @@
             [frontend.mobile.mobile-bar :refer [mobile-bar]]
             [frontend.mobile.util :as mobile-util]
             [frontend.modules.shortcut.data-helper :as shortcut-dh]
+            [frontend.modules.shortcut.utils :as shortcut-utils]
             [frontend.state :as state]
             [frontend.ui :as ui]
+            [logseq.shui.ui :as shui]
             [logseq.shui.toaster.core :as shui-toaster]
             [logseq.shui.dialog.core :as shui-dialog]
             [frontend.util :as util]
@@ -49,20 +54,16 @@
 
 (rum/defc nav-content-item < rum/reactive
   [name {:keys [class count]} child]
-  (let [collapsed? (state/sub [:ui/navigation-item-collapsed? class])
-        shrink? (and (not collapsed?) (> count 3))
-        list-item-height 28]
-    [:div.nav-content-item.mt-3
+  (let [collapsed? (state/sub [:ui/navigation-item-collapsed? class])]
+    [:div.nav-content-item
      {:class (util/classnames [class {:is-expand (not collapsed?)
-                                      :flex-shrink-0 (not shrink?)
-                                      :flex-shrink shrink?}])
-      :style {:min-height (when-not collapsed? (* (min count 4) list-item-height))}}
+                                      :has-children (and (number? count) (> count 0))}])}
      [:div.nav-content-item-inner
       [:div.header.items-center
        {:on-click (fn [^js/MouseEvent _e]
                     (state/toggle-navigation-item-collapsed! class))}
-       [:div.font-medium name]
-       (ui/icon "chevron-left" {:class "more"})]
+       [:div.a name]
+       [:div.b (ui/icon "chevron-left" {:class "more" :size 14})]]
       (when child [:div.bd child])]]))
 
 (defn- delta-y
@@ -80,26 +81,60 @@
   [name icon recent?]
   (let [original-name (db-model/get-page-original-name name)
         whiteboard-page? (db-model/whiteboard-page? name)
-        untitiled? (db-model/untitled-page? name)]
-    [:a.flex.items-center
-     {:on-click
-      (fn [e]
-        (let [name        (util/safe-page-name-sanity-lc name)
-              source-page (db-model/get-alias-source-page (state/get-current-repo) name)
-              name        (if (empty? source-page) name (:block/name source-page))]
-          (if (and (gobj/get e "shiftKey") (not whiteboard-page?))
-            (when-let [page-entity (if (empty? source-page) (db/entity [:block/name name]) source-page)]
-              (state/sidebar-add-block!
-               (state/get-current-repo)
-               (:db/id page-entity)
-               :page))
-            (if whiteboard-page?
-              (route-handler/redirect-to-whiteboard! name {:click-from-recent? recent?})
-              (route-handler/redirect-to-page! name {:click-from-recent? recent?})))))}
-     [:span.page-icon.ml-3.justify-center (if whiteboard-page? (ui/icon "whiteboard" {:extension? true}) icon)]
-     [:span.page-title {:class (when untitiled? "opacity-50")}
-      (if untitiled? (t :untitled)
-          (pdf-utils/fix-local-asset-pagename original-name))]]))
+        untitled? (db-model/untitled-page? name)
+        name (util/safe-page-name-sanity-lc name)
+        file-rpath (when (util/electron?) (page-util/get-page-file-rpath name))
+        source-page (db-model/get-alias-source-page (state/get-current-repo) name)
+        ctx-icon #(shui/tabler-icon %1 {:class "scale-90 pr-1 opacity-80"})
+        open-in-sidebar #(when-let [page-entity (and (not whiteboard-page?)
+                                                  (if (empty? source-page)
+                                                    (db/entity [:block/name name]) source-page))]
+                           (state/sidebar-add-block!
+                             (state/get-current-repo)
+                             (:db/id page-entity)
+                             :page))]
+    (shui/context-menu
+      (shui/context-menu-trigger
+        [:a.flex.items-center
+         {:on-click
+          (fn [e]
+            (let [name (if (empty? source-page) name (:block/name source-page))]
+              (if (gobj/get e "shiftKey")
+                (open-in-sidebar)
+                (if whiteboard-page?
+                  (route-handler/redirect-to-whiteboard! name {:click-from-recent? recent?})
+                  (route-handler/redirect-to-page! name {:click-from-recent? recent?})))))}
+         [:span.page-icon.ml-3.justify-center (if whiteboard-page? (ui/icon "whiteboard" {:extension? true}) icon)]
+         [:span.page-title {:class (when untitled? "opacity-50")}
+          (if untitled? (t :untitled)
+                        (pdf-utils/fix-local-asset-pagename original-name))]]
+        (shui/context-menu-content
+          {:class "w-60"}
+          (when-not recent?
+            (shui/context-menu-item
+              {:on-click #(page-handler/unfavorite-page! original-name)}
+              (ctx-icon "star-off")
+              (t :page/unfavorite)
+              (shui/context-menu-shortcut (some-> (shortcut-dh/shortcut-binding :command/toggle-favorite) (first)
+                                            (shortcut-utils/decorate-binding)))))
+          (when-let [page-fpath (and (util/electron?) file-rpath
+                                  (config/get-repo-fpath (state/get-current-repo) file-rpath))]
+            [:<>
+             (shui/context-menu-item
+               {:on-click #(ipc/ipc :openFileInFolder page-fpath)}
+               (ctx-icon "folder")
+               (t :page/open-in-finder))
+
+             (shui/context-menu-item
+               {:on-click #(js/window.apis.openPath page-fpath)}
+               (ctx-icon "file")
+               (t :page/open-with-default-app))])
+
+          (shui/context-menu-item
+            {:on-click open-in-sidebar}
+            (ctx-icon "layout-sidebar-right")
+            (t :content/open-in-sidebar)
+            (shui/context-menu-shortcut (shortcut-utils/decorate-binding "shift+click"))))))))
 
 (defn get-page-icon [page-entity]
   (let [default-icon (ui/icon "page" {:extension? true})
@@ -153,7 +188,7 @@
     (nav-content-item
      [:a.flex.items-center.text-sm.font-medium.rounded-md.wrap-th
       (ui/icon "star" {:size 16})
-      [:span.flex-1.ml-2 (string/upper-case (t :left-side-bar/nav-favorites))]]
+      [:strong.flex-1.ml-2 (string/upper-case (t :left-side-bar/nav-favorites))]]
 
      {:class "favorites"
       :count (count favorite-entities)
@@ -179,7 +214,7 @@
     (nav-content-item
      [:a.flex.items-center.text-sm.font-medium.rounded-md.wrap-th
       (ui/icon "history" {:size 16})
-      [:span.flex-1.ml-2
+      [:strong.flex-1.ml-2
        (string/upper-case (t :left-side-bar/nav-recent-pages))]]
 
      {:class "recent"
@@ -356,7 +391,7 @@
         {:aria-label "Navigation menu"}
         (repo/repos-dropdown)
 
-        [:div.nav-header.flex.gap-1.flex-col.mt-3
+        [:div.nav-header.flex.flex-col.mt-2
          (let [page (:page default-home)]
            (if (and page (not (state/enable-journals? (state/get-current-repo))))
              (sidebar-item
@@ -435,6 +470,44 @@
                                   (neg? offset-ratio)
                                   (+ 1))}))]]))
 
+(rum/defc sidebar-resizer
+  []
+  (let [*el-ref (rum/use-ref nil)
+        ^js el-doc js/document.documentElement
+        adjust-size! (fn [width]
+                       (.setProperty (.-style el-doc) "--ls-left-sidebar-width" width)
+                       (storage/set :ls-left-sidebar-width width))]
+
+    ;; restore size
+    (rum/use-layout-effect!
+      (fn []
+        (when-let [width (storage/get :ls-left-sidebar-width)]
+          (.setProperty (.-style el-doc) "--ls-left-sidebar-width" width)))
+      [])
+
+    ;; draggable handler
+    (rum/use-effect!
+      (fn []
+        (when-let [el (and (fn? js/window.interact) (rum/deref *el-ref))]
+          (let [^js sidebar-el (.querySelector el-doc "#left-sidebar")]
+            (-> (js/interact el)
+              (.draggable
+                #js {:listeners
+                     #js {:move (fn [^js/MouseEvent e]
+                                  (when-let [offset (.-left (.-rect e))]
+                                    (let [width (.toFixed (max (min offset 460) 240) 2)]
+                                      (adjust-size! (str width "px")))))}})
+              (.styleCursor false)
+              (.on "dragstart" (fn []
+                                 (.. sidebar-el -classList (add "is-resizing"))
+                                 (.. el-doc -classList (add "is-resizing-buf"))))
+              (.on "dragend" (fn []
+                               (.. sidebar-el -classList (remove "is-resizing"))
+                               (.. el-doc -classList (remove "is-resizing-buf"))))))
+          #()))
+      [])
+    [:span.left-sidebar-resizer {:ref *el-ref}]))
+
 (rum/defcs left-sidebar < rum/reactive
   (rum/local false ::closing?)
   (rum/local -1 ::close-signal)
@@ -477,7 +550,9 @@
 
      ;; sidebar contents
      (sidebar-nav route-match close-fn left-sidebar-open? enable-whiteboards? srs-open? *closing?
-                  @*close-signal (and touch-pending? touching-x-offset))]))
+       @*close-signal (and touch-pending? touching-x-offset))
+     ;; resizer
+     (sidebar-resizer)]))
 
 (rum/defc recording-bar
   []

+ 78 - 51
src/main/frontend/components/container.css

@@ -80,17 +80,19 @@
 }
 
 .dark .left-sidebar-inner {
-  background-color: or(--ls-left-sidebar-background-color, --lx-gray-01, --ls-primary-background-color);
+  --left-sidebar-bg-color: or(--ls-left-sidebar-background, --lx-gray-02, --ls-secondary-background-color);
 }
 
 .left-sidebar-inner {
+  --left-sidebar-bg-color: or(--ls-left-sidebar-background-color, --lx-gray-02, --ls-primary-background-color);
+
   position: relative;
   height: 100%;
   padding-top: 12px;
   width: var(--ls-left-sidebar-sm-width);
   overflow-y: auto;
   overflow-x: hidden;
-  background-color: or(--ls-left-sidebar-background-color, --lx-gray-02, --ls-primary-background-color);
+  background-color: var(--left-sidebar-bg-color);
   border-right: 1px solid or(--ls-left-sidebar-border-color, --lx-gray-03, --ls-tertiary-background-color);
   transition: transform .3s;
   transform: translate3d(-100%, 0, 0);
@@ -125,19 +127,21 @@
     }
   }
 
-  .nav-header a {
-    .keyboard-shortcut {
-        @apply w-0 opacity-0;
-        visibility: hidden;
-    }
+  .nav-header {
+    @apply gap-0.5;
 
-    &:hover {
+    a {
       .keyboard-shortcut {
-        visibility: visible;
-        transition: opacity 1s;
-        transition-delay: 2s;
-        width: auto;
-        opacity: 1;
+        @apply opacity-0 invisible;
+      }
+
+      &:hover {
+        .keyboard-shortcut {
+          visibility: visible;
+          transition: opacity 1s;
+          transition-delay: 2s;
+          opacity: 1;
+        }
       }
     }
   }
@@ -167,24 +171,20 @@
     }
 
     .graph-icon .ui__icon {
-        padding: 0;
-        width: unset;
-        margin-right: 0px;
+      padding: 0;
+      width: unset;
+      margin-right: 0px;
     }
 
     .graph-icon {
-        margin-left: 3px;
-        margin-right: 11px;
-    }
-
-    &:hover {
-      background-color: or(--ls-left-sidebar-hover-background, --lx-gray-04, --ls-primary-background-color);
-      color: or(--ls-left-sidebar-text-color-hover, --lx-gray-12);
+      margin-left: 3px;
+      margin-right: 11px;
     }
 
-    &.active {
+    &:hover, &.active {
       background-color: or(--ls-left-sidebar-active-background, --lx-gray-04, --color-level-3);
       color: or(--ls-left-sidebar-active-text-color, --lx-gray-12);
+
       .ui__icon {
         opacity: .9;
       }
@@ -192,7 +192,7 @@
   }
 
   .nav-contents-container {
-    @apply h-full flex-grow-0 overflow-x-hidden overflow-y-auto;
+    @apply relative h-full flex-grow-0 overflow-x-hidden overflow-y-auto;
 
     &.is-scrolled {
       border-top: 1px solid var(--ls-tertiary-border-color);
@@ -200,8 +200,6 @@
   }
 
   .nav-content-item {
-    @apply overflow-hidden;
-
     &:not(:hover) {
       ::-webkit-scrollbar-thumb,
       ::-webkit-scrollbar,
@@ -211,16 +209,14 @@
     }
 
     .nav-content-item-inner {
-      @apply flex flex-col h-full overflow-hidden;
+      @apply flex flex-col;
     }
 
     .header {
-      @apply px-6 py-1;
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      user-select: none;
-      cursor: pointer;
+      @apply pl-6 pr-4 py-1 flex justify-between items-center select-none sticky top-[-4px];
+      @apply cursor-pointer z-[2] active:opacity-80;
+
+      background-color: var(--left-sidebar-bg-color);
 
       .ui__icon {
         @apply flex justify-center;
@@ -228,7 +224,7 @@
       }
 
       .more {
-        display: none;
+        opacity: 0;
         transition: .15s transform;
       }
 
@@ -240,16 +236,19 @@
         }
 
         .more {
-
-          display: block;
-          opacity: .6;
+          opacity: .8 !important;
         }
       }
 
       .wrap-th {
-        > span {
-          font-size: 11px;
-          font-weight: 600;
+        @apply opacity-50;
+
+        > .ui__icon {
+          @apply relative top-[-1px];
+        }
+
+        > strong {
+          @apply text-[11px] font-semibold;
         }
       }
     }
@@ -298,17 +297,25 @@
 
     &.is-expand {
       .header .more {
+        opacity: 0;
         transform: rotate(-90deg);
       }
+
       .bd {
         display: block;
       }
     }
+
+    &.has-children:not(.is-expand) {
+      .header .more {
+        opacity: .4;
+      }
+    }
   }
 
   .create {
     width: 100%;
-    padding: 14px;
+    padding: 4px 14px 14px;
     background-image: linear-gradient(transparent, var(--ls-primary-background-color));
     user-select: none;
 
@@ -361,12 +368,13 @@
   }
 
   @screen sm {
+    --left-sidebar-bg-color: or(--ls-left-sidebar-background, --lx-gray-02, --ls-secondary-background-color);
+
     padding-top: 0;
     width: var(--ls-left-sidebar-width);
-    background-color: or(--ls-left-sidebar-background, --lx-gray-02, --ls-secondary-background-color);
 
     .dark & {
-      background-color: or(--ls-left-sidebar-background, --lx-gray-01, --ls-secondary-background-color);
+      --left-sidebar-bg-color: or(--ls-left-sidebar-background, --lx-gray-02, --ls-secondary-background-color);
     }
 
     > .wrap {
@@ -453,6 +461,14 @@
     }
   }
 
+  &.is-resizing {
+    @apply transition-none;
+
+    .left-sidebar-resizer {
+      @apply bg-primary/90;
+    }
+  }
+
   &:before {
     content: " ";
     height: 3rem;
@@ -464,6 +480,19 @@
     z-index: 5;
   }
 
+  .left-sidebar-resizer {
+    @apply absolute w-[3px] top-0 right-[-2px] bottom-0 overflow-hidden cursor-col-resize;
+    @apply z-10;
+
+    transition: background-color 300ms;
+    transition-delay: 300ms;
+
+    &.is-active, &:hover,
+    &:focus, &:active {
+      @apply bg-primary/90;
+    }
+  }
+
   @screen sm {
     width: 0;
     z-index: var(--ls-z-index-level-1);
@@ -602,11 +631,13 @@
 
   .resizer {
     @apply absolute top-0 bottom-0;
+
     touch-action: none;
-    left: 2px;
-    width: 4px;
+    left: 1px;
+    width: 3px;
     user-select: none;
     cursor: col-resize !important;
+
     transition: background-color 300ms;
     transition-delay: 300ms;
     z-index: 1000;
@@ -614,16 +645,12 @@
     &:hover,
     &:focus,
     &:active {
-      background-color: or(--ls-right-sidebar-resizer-color, --lx-gray-08-alpha, --ls-active-primary-color);
+      @apply bg-primary/90;
     }
   }
 
   &.closed {
     width: 0 !important;
-
-    @screen lg {
-      width: 4px !important;
-    }
   }
 
   &.open {

+ 11 - 17
src/main/frontend/components/query_table.cljs

@@ -106,14 +106,8 @@
         query-properties (if page? (remove #{:block} query-properties) query-properties)
         columns (if (seq query-properties)
                   query-properties
-                  (get-keys result page?))
-        included-columns #{:created-at :updated-at}]
-    (distinct
-     (if (some included-columns columns)
-       (concat (remove included-columns columns)
-               (filter included-columns columns)
-               included-columns)
-       columns))))
+                  (get-keys result page?))]
+    (distinct columns)))
 
 (defn- build-column-value
   "Builds a column's tuple value for a query table given a row, column and
@@ -156,12 +150,12 @@
                    (get-in row [:block/properties column])))]))
 
 (defn build-column-text [row column]
-  (case column 
+  (case column
     :page  (or (get-in row [:block/page :block/original-name])
                (get-in row [:block/original-name])
                (get-in row [:block/content]))
-    :block (or (get-in row [:block/original-name]) 
-               (get-in row [:block/content])) 
+    :block (or (get-in row [:block/original-name])
+               (get-in row [:block/content]))
            (or (get-in row [:block/properties column])
                (get-in row [:block/properties-text-values column])
                (get-in row [(keyword :block column)]))))
@@ -185,27 +179,27 @@
           property-separated-by-commas? (partial text/separated-by-commas? (state/get-config))
           table-version (get-shui-component-version :table config)
           result-as-text (for [row sort-result]
-                           (for [column columns] 
+                           (for [column columns]
                              (build-column-text row column)))
           render-column-value (fn [row-format cell-format value]
-                                (cond 
+                                (cond
                                   ;; elements should be rendered as they are provided
                                   (= :element cell-format) value
                                   ;; collections are treated as a comma separated list of page-cps
                                   (coll? value) (->> (map #(page-cp {} {:block/name %}) value)
                                                      (interpose [:span ", "]))
                                   ;; boolean values need to first be stringified
-                                  (boolean? value) (str value) 
-                                  ;; string values will attempt to be rendered as pages, falling back to 
+                                  (boolean? value) (str value)
+                                  ;; string values will attempt to be rendered as pages, falling back to
                                   ;; inline-text when no page entity is found
                                   (string? value) (if-let [page (db/entity [:block/name (util/page-name-sanity-lc value)])]
                                                     (page-cp {} page)
                                                     (inline-text row-format value))
                                   ;; anything else should just be rendered as provided
                                   :else value))]
-                      
+
       (case table-version
-        2 (shui/table-v2 {:data (conj [[columns]] result-as-text)} 
+        2 (shui/table-v2 {:data (conj [[columns]] result-as-text)}
                          (make-shui-context config inline))
         1 [:div.overflow-x-auto {:on-mouse-down (fn [e] (.stopPropagation e))
                                  :style {:width "100%"}

+ 13 - 12
src/main/frontend/components/right_sidebar.cljs

@@ -322,7 +322,7 @@
 (rum/defc sidebar-resizer
   [sidebar-open? sidebar-id handler-position]
   (let [el-ref (rum/use-ref nil)
-        min-px-width 144 ; Custom window controls width
+        min-px-width 320 ; Custom window controls width
         min-ratio 0.1
         max-ratio 0.7
         keyboard-step 5
@@ -395,15 +395,16 @@
           #(reset! ui-handler/*right-sidebar-resized-at (js/Date.now)) 300))
       [sidebar-open?])
 
-    [:.resizer {:ref el-ref
-                :role "separator"
-                :aria-orientation "vertical"
-                :aria-label (t :right-side-bar/separator)
-                :aria-valuemin (* min-ratio 100)
-                :aria-valuemax (* max-ratio 100)
-                :aria-valuenow 50
-                :tabIndex "0"
-                :data-expanded sidebar-open?}]))
+    [:.resizer
+     {:ref              el-ref
+      :role             "separator"
+      :aria-orientation "vertical"
+      :aria-label       (t :right-side-bar/separator)
+      :aria-valuemin    (* min-ratio 100)
+      :aria-valuemax    (* max-ratio 100)
+      :aria-valuenow    50
+      :tabIndex         "0"
+      :data-expanded    sidebar-open?}]))
 
 (rum/defcs sidebar-inner <
   (rum/local false ::anim-finished?)
@@ -417,7 +418,7 @@
 
      [:div.cp__right-sidebar-scrollable
       {:on-drag-over util/stop}
-      [:div.cp__right-sidebar-topbar.flex.flex-row.justify-between.items-center.px-2.h-12
+      [:div.cp__right-sidebar-topbar.flex.flex-row.justify-between.items-center
        [:div.cp__right-sidebar-settings.hide-scrollbar.gap-1 {:key "right-sidebar-settings"}
         [:div.text-sm
          [:button.button.cp__right-sidebar-settings-btn {:on-click (fn [_e]
@@ -444,7 +445,7 @@
                                                                        (state/sidebar-add-block! repo "history" :history))}
             (t :right-side-bar/history)]])]]
 
-      [:.sidebar-item-list.flex-1.scrollbar-spacing.ml-2
+      [:.sidebar-item-list.flex-1.scrollbar-spacing
        (if @*anim-finished?
          (for [[idx [repo db-id block-type]] (medley/indexed blocks)]
             (rum/with-key

+ 4 - 4
src/main/frontend/components/right_sidebar.css

@@ -16,13 +16,12 @@ html[data-theme=light] {
 }
 
 .sidebar-item-list {
-  margin-top: -8px;
-  padding-bottom: 150px;
+  @apply ml-1 mt-[-8px] pb-[150px];
+
   height: calc(100vh - 48px);
   background-color: or(--ls-right-ridebar-color, --lx-gray-01, --ls-secondary-background-color, #d8e1e8);
 }
 
-
 html[data-theme=light] a.toggle:hover {
   color: var(--ls-primary-text-color);
 }
@@ -37,10 +36,11 @@ html[data-theme=light] a.toggle:hover {
 }
 
 .cp__right-sidebar-topbar {
+  @apply px-1 h-12;
   background-color: var(--ls-primary-background-color);
 
   button {
-    opacity: 1;
+    @apply opacity-100;
   }
 }
 

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

@@ -124,7 +124,7 @@
 (def video-formats
   #{:mp4 :webm :mov :flv :avi :mkv})
 
-(def media-formats (set/union (gp-config/img-formats) audio-formats))
+(def media-formats (set/union (gp-config/img-formats) audio-formats video-formats))
 
 (defn extname-of-supported?
   ([input] (extname-of-supported?

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

@@ -433,7 +433,7 @@ input::-webkit-inner-spin-button {
     z-index: 4;
     top: 10vh;
     cursor: col-resize;
-    right: 0;;
+    right: 0;
   }
 
   &-hls-text-region {

+ 13 - 12
src/main/frontend/fs/sync.cljs

@@ -3364,18 +3364,19 @@
           ok? (and (= 200 (:status r1*))
                    (= 200 (:status r2*))
                    (= "OK" (:body r2*)))]
-      (if ok?
-        (notification/clear! :sync-connection-failed)
-        (notification/show! [:div
-                             (t :file-sync/connectivity-testing-failed)
-                             [:a {:href api-url} api-url]
-                             " and "
-                             [:a
-                              {:href config/CONNECTIVITY-TESTING-S3-URL}
-                              config/CONNECTIVITY-TESTING-S3-URL]]
-                            :warning
-                            false
-                            :sync-connection-failed))
+      (when (user/logged-in?)
+        (if ok?
+          (notification/clear! :sync-connection-failed)
+          (notification/show! [:div
+                               (t :file-sync/connectivity-testing-failed)
+                               [:a {:href api-url} api-url]
+                               " and "
+                               [:a
+                                {:href config/CONNECTIVITY-TESTING-S3-URL}
+                                config/CONNECTIVITY-TESTING-S3-URL]]
+                              :warning
+                              false
+                              :sync-connection-failed)))
       ok?)))
 
 (declare network-online-cursor)

+ 32 - 8
src/main/frontend/handler/export/common.cljs

@@ -567,6 +567,7 @@
       :result-ast-tcoll
       persistent!))
 
+
 ;;; inline transformers
 
 (defn remove-emphasis
@@ -605,14 +606,35 @@
       ;; else
       [inline-ast])))
 
+(defn remove-prefix-spaces-in-Plain
+  [inline-coll]
+  (:r
+   (reduce
+    (fn [{:keys [r after-break-line?]} ast]
+      (let [[ast-type ast-content] ast]
+        (case ast-type
+          "Plain"
+          (let [trimmed-content (string/triml ast-content)]
+            (if after-break-line?
+              (if (empty? trimmed-content)
+                {:r r :after-break-line? false}
+                {:r (conj r ["Plain" trimmed-content]) :after-break-line? false})
+              {:r (conj r ast) :after-break-line? false}))
+          ("Break_Line" "Hard_Break_Line")
+          {:r (conj r ast) :after-break-line? true}
+        ;; else
+          {:r (conj r ast) :after-break-line? false})))
+    {:r [] :after-break-line? true}
+    inline-coll)))
+
 ;;; inline transformers (ends)
 
 ;;; walk on block-ast, apply inline transformers
 
 (defn- walk-block-ast-helper
-  [inline-coll map-fns-on-inline-ast mapcat-fns-on-inline-ast]
+  [inline-coll map-fns-on-inline-ast mapcat-fns-on-inline-ast fns-on-inline-coll]
   (->>
-   inline-coll
+   (reduce (fn [inline-coll f] (f inline-coll)) inline-coll fns-on-inline-coll)
    (mapv #(reduce (fn [inline-ast f] (f inline-ast)) % map-fns-on-inline-ast))
    (mapcatv #(reduce
               (fn [inline-ast-coll f] (mapcatv f inline-ast-coll)) [%] mapcat-fns-on-inline-ast))))
@@ -635,18 +657,20 @@
    list-items))
 
 (defn walk-block-ast
-  [{:keys [map-fns-on-inline-ast mapcat-fns-on-inline-ast] :as fns}
+  [{:keys [map-fns-on-inline-ast mapcat-fns-on-inline-ast fns-on-inline-coll] :as fns}
    block-ast]
   (let [[ast-type ast-content] block-ast]
     (case ast-type
       "Paragraph"
-      (mk-paragraph-ast (walk-block-ast-helper ast-content map-fns-on-inline-ast mapcat-fns-on-inline-ast) (meta block-ast))
+      (mk-paragraph-ast
+       (walk-block-ast-helper ast-content map-fns-on-inline-ast mapcat-fns-on-inline-ast fns-on-inline-coll)
+       (meta block-ast))
       "Heading"
       (let [{:keys [title]} ast-content]
         ["Heading"
          (assoc ast-content
                 :title
-                (walk-block-ast-helper title map-fns-on-inline-ast mapcat-fns-on-inline-ast))])
+                (walk-block-ast-helper title map-fns-on-inline-ast mapcat-fns-on-inline-ast fns-on-inline-coll))])
       "List"
       ["List" (walk-block-ast-for-list ast-content map-fns-on-inline-ast mapcat-fns-on-inline-ast)]
       "Quote"
@@ -654,11 +678,11 @@
       "Footnote_Definition"
       (let [[name contents] (rest block-ast)]
         ["Footnote_Definition"
-         name (walk-block-ast-helper contents map-fns-on-inline-ast mapcat-fns-on-inline-ast)])
+         name (walk-block-ast-helper contents map-fns-on-inline-ast mapcat-fns-on-inline-ast fns-on-inline-coll)])
       "Table"
       (let [{:keys [header groups]} ast-content
             header* (mapv
-                     #(walk-block-ast-helper % map-fns-on-inline-ast mapcat-fns-on-inline-ast)
+                     #(walk-block-ast-helper % map-fns-on-inline-ast mapcat-fns-on-inline-ast fns-on-inline-coll)
                      header)
             groups* (mapv
                      (fn [group]
@@ -666,7 +690,7 @@
                         (fn [row]
                           (mapv
                            (fn [col]
-                             (walk-block-ast-helper col map-fns-on-inline-ast mapcat-fns-on-inline-ast))
+                             (walk-block-ast-helper col map-fns-on-inline-ast mapcat-fns-on-inline-ast fns-on-inline-coll))
                            row))
                         group))
                      groups)]

+ 4 - 1
src/main/frontend/handler/export/html.cljs

@@ -402,7 +402,10 @@
                                         (update :map-fns-on-inline-ast conj common/remove-page-ref-brackets)
 
                                         (get-in *state* [:export-options :remove-tags?])
-                                        (update :mapcat-fns-on-inline-ast conj common/remove-tags))
+                                        (update :mapcat-fns-on-inline-ast conj common/remove-tags)
+
+                                        (= "no-indent" (get-in *state* [:export-options :indent-style]))
+                                        (update :mapcat-fns-on-inline-ast conj common/remove-prefix-spaces-in-Plain))
             ast*** (if-not (empty? config-for-walk-block-ast)
                      (util/profile :walk-block-ast (mapv (partial common/walk-block-ast config-for-walk-block-ast) ast**))
                      ast**)

+ 4 - 1
src/main/frontend/handler/export/opml.cljs

@@ -420,7 +420,10 @@
                                         (update :map-fns-on-inline-ast conj common/remove-page-ref-brackets)
 
                                         (get-in *state* [:export-options :remove-tags?])
-                                        (update :mapcat-fns-on-inline-ast conj common/remove-tags))
+                                        (update :mapcat-fns-on-inline-ast conj common/remove-tags)
+
+                                        (= "no-indent" (get-in *state* [:export-options :indent-style]))
+                                        (update :mapcat-fns-on-inline-ast conj common/remove-prefix-spaces-in-Plain))
             ast*** (if-not (empty? config-for-walk-block-ast)
                      (mapv (partial common/walk-block-ast config-for-walk-block-ast) ast**)
                      ast**)

+ 29 - 19
src/main/frontend/handler/export/text.cljs

@@ -104,14 +104,18 @@
      l)))
 
 (defn- block-src
-  [{:keys [lines language]}]
-  (let [level (dec (get *state* :current-level 1))]
-    (concatv
-     [(indent-with-2-spaces level) (raw-text "```")]
-     (when language [(raw-text language)])
-     [(newline* 1)]
-     (mapv raw-text lines)
-     [(indent-with-2-spaces level) (raw-text "```") (newline* 1)])))
+  [{:keys [lines language full_content]}]
+  (if (= "no-indent" (get-in *state* [:export-options :indent-style]))
+    ;; when "no-indent", just use :full_content in 'Src' ast
+    [(raw-text full_content) (newline* 1)]
+
+    (let [level (dec (get *state* :current-level 1))]
+      (concatv
+       [(indent-with-2-spaces level) (raw-text "```")]
+       (when language [(raw-text language)])
+       [(newline* 1)]
+       (mapv raw-text lines)
+       [(indent-with-2-spaces level) (raw-text "```") (newline* 1)]))))
 
 (defn- block-quote
   [block-coll]
@@ -313,7 +317,9 @@
 
 (defn- inline-break-line
   []
-  [(raw-text "  \n")
+  [(if (= "no-indent" (get-in *state* [:export-options :indent-style]))
+     (raw-text "\n")
+     (raw-text "  \n"))
    (when (:indent-after-break-line? *state*)
      (let [current-level (get *state* :current-level 1)]
        (when (> current-level 1)
@@ -465,13 +471,17 @@
                                         (update :map-fns-on-inline-ast conj common/remove-page-ref-brackets)
 
                                         (get-in *state* [:export-options :remove-tags?])
-                                        (update :mapcat-fns-on-inline-ast conj common/remove-tags))
+                                        (update :mapcat-fns-on-inline-ast conj common/remove-tags)
+
+                                        (= "no-indent" (get-in *state* [:export-options :indent-style]))
+                                        (update :fns-on-inline-coll conj common/remove-prefix-spaces-in-Plain))
             ast*** (if-not (empty? config-for-walk-block-ast)
                      (mapv (partial common/walk-block-ast config-for-walk-block-ast) ast**)
                      ast**)
             simple-asts (mapcatv block-ast->simple-ast ast***)]
         (simple-asts->string simple-asts)))))
 
+
 (defn export-blocks-as-markdown
   "options:
   :indent-style \"dashes\" | \"spaces\" | \"no-indent\"
@@ -481,15 +491,15 @@
   {:pre [(or (coll? root-block-uuids-or-page-name)
              (string? root-block-uuids-or-page-name))]}
   (util/profile
-   :export-blocks-as-markdown
-   (let [content
-         (if (string? root-block-uuids-or-page-name)
-           ;; page
-           (common/get-page-content root-block-uuids-or-page-name)
-           (common/root-block-uuids->content repo root-block-uuids-or-page-name))
-         first-block (db/entity [:block/uuid (first root-block-uuids-or-page-name)])
-         format (or (:block/format first-block) (state/get-preferred-format))]
-     (export-helper content format options))))
+      :export-blocks-as-markdown
+      (let [content
+            (if (string? root-block-uuids-or-page-name)
+              ;; page
+              (common/get-page-content root-block-uuids-or-page-name)
+              (common/root-block-uuids->content repo root-block-uuids-or-page-name))
+            first-block (db/entity [:block/uuid (first root-block-uuids-or-page-name)])
+            format (or (:block/format first-block) (state/get-preferred-format))]
+        (export-helper content format options))))
 
 (defn export-files-as-markdown
   "options see also `export-blocks-as-markdown`"

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

@@ -635,7 +635,8 @@
      (mixins/on-key-down
       state
       {;; enter
-       13 (fn [state _e]
+       13 (fn [state e]
+            (.preventDefault e)
             (some->
              (.querySelector (rum/dom-node state) "button.ui__modal-enter")
              (.click)))})))

+ 7 - 0
src/main/frontend/ui.css

@@ -259,6 +259,13 @@ html.is-mobile {
         padding-bottom: 0;
       }
     }
+
+    &[label="ls-modal-align-center"] {
+      .ui__modal-panel {
+        top: 8vh;
+        transform: translateY(-10%);
+      }
+    }
   }
 }
 

+ 3 - 0
src/main/logseq/api.cljs

@@ -2,6 +2,7 @@
   (:require [cljs-bean.core :as bean]
             [cljs.reader]
             [logseq.sdk.core]
+            [logseq.sdk.git]
             [logseq.sdk.utils :as sdk-utils]
             [logseq.sdk.ui :as sdk-ui]
             [logseq.sdk.assets :as sdk-assets]
@@ -907,6 +908,8 @@
 
 ;; ui
 (def ^:export show_msg sdk-ui/-show_msg)
+(def ^:export query_element_rect sdk-ui/query_element_rect)
+(def ^:export query_element_by_id sdk-ui/query_element_by_id)
 
 ;; assets
 (def ^:export make_asset_url sdk-assets/make_url)

+ 13 - 1
src/resources/dicts/es.edn

@@ -242,6 +242,10 @@
  :command.ui/toggle-wide-mode                       "Alternar modo ancho"
  :command.whiteboard/bring-forward                  "Avanzar"
  :command.whiteboard/bring-to-front                 "Mover al frente"
+ :command.whiteboard/clone-down                     "Clonar abajo"
+ :command.whiteboard/clone-left                     "Clonar a la izquierda"
+ :command.whiteboard/clone-right                    "Clonar a la derecha"
+ :command.whiteboard/clone-up                       "Clonar arriba"
  :command.whiteboard/connector                      "Herramienta conector"
  :command.whiteboard/ellipse                        "Herramienta elipse"
  :command.whiteboard/eraser                         "Herramienta borrador"
@@ -417,7 +421,13 @@
  :left-side-bar/new-page                            "Nueva página"
  :left-side-bar/new-whiteboard                      "Nueva pizarra"
  :left-side-bar/switch                              "Cambiar a:"
+ :linked-references/filter-directions               "Haga clic para incluir y haga shift-clic para excluir. Haga clic nuevamente para eliminar."
+ :linked-references/filter-excludes                 "Excluye: "
+ :linked-references/filter-heading                  "Filtro"
+ :linked-references/filter-includes                 "Incluye: "
  :linked-references/filter-search                   "Buscar en las páginas vinculadas"
+ :linked-references/reference-count (fn [filtered-count total] (str (when filtered-count (str filtered-count " de ")) total (if (= total 1) " Referencia vinculada" " Referencias vinculadas")))
+ :linked-references/unexpected-error                "Referencias vinculadas: Error inesperado. Reindexa tu gráfico primero."
  :notification/clear-all                            "Limpiar todo"
  :on-boarding/add-graph                             "Añadir grafo"
  :on-boarding/command-palette-quick-tour            "Tour rápido para acostumbrarse"
@@ -430,7 +440,7 @@
  :on-boarding/importing-roam-desc                   "Importar un archivo JSON exportado de tu grafo de Roam"
  :on-boarding/importing-title                       "¿Tienes notas que quieras importar?"
  :on-boarding/main-desc                             "Primero tienes que escoger una carpeta donde Logseq va a guardar tus pensamientos, ideas y notas."
- :on-boarding/main-title (fn [] [                   "¡Bienvenido a " [:strong "Logseq!"]])
+ :on-boarding/main-title (fn [] ["¡Bienvenido a " [:strong "Logseq!"]])
  :on-boarding/new-graph-desc-1                      "Logseq soporta tanto Markdown como Org-mode. Puede abrir un directorio existente o crear uno nuevo en su dispositivo, un directorio se conoce simplemente como una carpeta. Sus datos se almacenarán únicamente en este dispositivo."
  :on-boarding/new-graph-desc-2                      "Después que abra un directorio se crearán tres carpetas en ese directorio:"
  :on-boarding/new-graph-desc-3                      "/journals - almacena sus páginas de diarios"
@@ -697,6 +707,7 @@
  :shortcut.category/whiteboard                      "Pizarra"
  :text/image                                        "Imagen"
  :tips/all-done                                     "¡Todo hecho!"
+ :unlinked-references/reference-count (fn [total] (str total (if (= total 1) " Referencia desvinculada" " Referencias desvinculadas")))
  :updater/new-version-install                       "Se descargó una nueva versión."
  :updater/quit-and-install                          "Reiniciar para instalar"
  :whiteboard/add-block-or-page                      "Añadir bloque o página"
@@ -761,6 +772,7 @@
  :whiteboard/paste-as-link                          "Pegar como enlace"
  :whiteboard/rectangle                              "Recargar"
  :whiteboard/redo                                   "Rehacer"
+ :whiteboard/reference-count (fn [refs-count] (if (= refs-count 1) "Referencia" "Referencias"))
  :whiteboard/references                             "Referencias"
  :whiteboard/reload                                 "Recargar"
  :whiteboard/remove-link                            "Eliminar enlace"

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

@@ -172,7 +172,7 @@
     :linked-references/filter-excludes "Exclut : "
     :linked-references/filter-heading "Filtrer"
     :linked-references/filter-includes "Inclut : "
-    :linked-references/reference-count (fn [filtered-count total] (str filtered-count (when filtered-count (if (= filtered-count 1) " référence liée" " références liées")) " parmi " total))
+    :linked-references/reference-count (fn [filtered-count total] (cond (= filtered-count nil) (cond (= total 0) "Aucune référence liée" (= total 1) "1 référence liée" :else (str total " références liées")) (= filtered-count 1) (str "1 référence liée / " total) :else (str filtered-count " références liées / " total) ))
     :linked-references/filter-search "Rechercher dans les pages liées"
     :linked-references/unexpected-error "Références liées : erreur inattendue. Veuillez d'abord ré-indexer votre graphe."
     :on-boarding/add-graph "Ajouter un graphe"
@@ -806,5 +806,5 @@
     :settings-page/auto-chmod "Automatiquement changer les permissions du fichier"
     :settings-page/auto-chmod-desc "Désactiver pour permettre l'édition par plusieurs utilisateurs avec les permissions données par l'appartenance au groupe."
     :settings-page/tab-keymap "Raccourcis"
-    :unlinked-references/reference-count (fn [total] (str total (if (= total 1) " référence non liée" " références non liées")))
+    :unlinked-references/reference-count (fn [total] (cond (= total "") "Références non liées" (= total 0) "Aucune référence non liée" (= total 1) "1 référence non liée" (> total 1) (str total " références non liées")))
 }

+ 28 - 1
src/resources/dicts/nb-no.edn

@@ -789,4 +789,31 @@
  :settings-page/auto-chmod "Automatisk endre filtillatelser"
  :settings-page/auto-chmod-desc "Deaktiver for å tillate redigering av flere brukere med tillatelser gitt av gruppemedlemskap."
  :settings-page/tab-keymap "Tastatur"
- :whiteboard/toggle-pen-mode "Veksle pen-modus"}
+ :whiteboard/toggle-pen-mode "Veksle pen-modus"
+ 
+ :command.command-palette/toggle "Søk kommandoer"
+ :command.go/search-in-page "Søk blokker på side"
+ :command.ui/cycle-color "Veksle farge"
+ :command.ui/cycle-color-off "Veksle farge av"
+ :command.whiteboard/clone-down "Klon ned"
+ :command.whiteboard/clone-left "Klon venstre"
+ :command.whiteboard/clone-right "Klon høyre"
+ :command.whiteboard/clone-up "Klon opp"
+ :handbook/close "Lukk"
+ :handbook/help-categories "Hjelp kategorier"
+ :handbook/home "Hjem"
+ :handbook/popular-topics "Populære emner"
+ :handbook/search "Søk"
+ :handbook/settings "Innstillinger"
+ :handbook/title "Hjelp"
+ :handbook/topics "Emner"
+ :help/search "Søk sider/blokker/kommandoer"
+ :linked-references/filter-directions "Klikk for å inkludere og shift-klikk for å ekskludere. Klikk igjen for å fjerne."
+ :linked-references/filter-excludes "Ekskluderer: "
+ :linked-references/filter-heading "Filter"
+ :linked-references/filter-includes "Inkluderer: "
+ :linked-references/reference-count (fn [filtered-count total] (str (when filtered-count (str filtered-count " av ")) total (if (= total 1) " Lenket Referanse" " Lenkede Referanser")))
+ :linked-references/unexpected-error "Lenkede Referanser: Uventet feil. Vennligst re-indekser din graf først."
+ :pdf/auto-open-context-menu "Auto-åpne kontekstmeny for valg"
+ :unlinked-references/reference-count (fn [total] (str total (if (= total 1) " Ulenket Referanse" " Ulenkede Referanser")))
+ :whiteboard/reference-count (fn [refs-count] (if (= refs-count 1) "Referanse" "Referanser"))}

+ 17 - 0
src/test/frontend/handler/export_test.cljs

@@ -129,6 +129,23 @@
 	- 4")
     "97a00e55-48c3-48d8-b9ca-417b16e3a616"))
 
+(deftest export-blocks-as-markdown-no-indent
+  (are [expect content]
+      (= (string/trim expect)
+         (string/trim (#'export-text/export-helper (string/trim content) :markdown {:indent-style "no-indent"})))
+      "
+1
+2
+3
+4
+5"
+      "
+- 1
+  2
+  3
+  - 4
+    5"))
+
 
 (deftest-async export-files-as-markdown
   (p/do!

+ 40 - 40
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].76":
-  version "0.0.76"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.76.tgz#58094734c80ff6765ed0d9716a4cd60585007d13"
-  integrity sha512-vhujPjhMvFjUOUXvKkaocxJ5M9VjHtt+IQwrXhlqSEreA+IYeg9Wcc6ryws5PkGzhxb/HVTYTpeCQWz5f++49w==
-
-"@logseq/[email protected].76":
-  version "0.0.76"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.76.tgz#90fbed4431abacf927892bb794065b501c8cb1b5"
-  integrity sha512-XvAJGF1Lf2Z2VDVni1ey0Fcfd0Qsva6NculBkRMu9Fdvn3HcVqZ2aoFXvuVshhG5c/kmr9gCr/bFNMQhkpyqxA==
-
-"@logseq/[email protected].76":
-  version "0.0.76"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-freebsd-x64/-/rsapi-freebsd-x64-0.0.76.tgz#e5ad91bbaa55f1de28e0ab8a14b2dce7b0bac33d"
-  integrity sha512-GQf517+cUGJtXccAPRfnWCiEXMtp7eOjL95Z69z+hNGLBeIYPgywpcPFuJzeU1gwnwNm9jkZ+eoCzOo4icovtg==
-
-"@logseq/[email protected].76":
-  version "0.0.76"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.76.tgz#1e4dc52eb2968329af7e9259ed622cabf393e8d3"
-  integrity sha512-YfnlhCb0IxDzwyj+yK8OUrhGtkhSxgajJ74lU3z5Z9onywGIj2E8skFxFbyh6uZMkwIlITfz6Kh3OrZUNCF2+g==
-
-"@logseq/[email protected].76":
-  version "0.0.76"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.76.tgz#69a1ad7e2b548a6e04b485cccc2b6d24e632717f"
-  integrity sha512-Q5RC5iyGcG/EWGU+zgHLXIGs7SKIZlT1smpmtJvXhjnKgd0j2vJtbdudi4sRxPomuquw+xaqdio2pvVO3OCRHA==
-
-"@logseq/[email protected].76":
-  version "0.0.76"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.76.tgz#79dedcbad0603ccb6f5612982cd18ce5fd7bd4a9"
-  integrity sha512-X+CFXZi7xuSTdbl2l6GDgVvSVAaBaZwZw40Glc97fePfrAoAdvmkea18Ym0HwOZct3jcQUiEcCelKxwA8j5MFQ==
-
-"@logseq/[email protected].76":
-  version "0.0.76"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.76.tgz#67d3d44e540a6b89f0df0b7c0e2097692229c099"
-  integrity sha512-ELoILQnHHnHLpKiFJZ/c9buapmHktjh/KfyzIEdwTb0bibeuLOS+FbUviaLfNvvn4XkQQUBrO3Ei4M2ivEZUzQ==
+"@logseq/[email protected].81":
+  version "0.0.81"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.81.tgz#1ac2660fb54d313e6aa8553c75e3b31415356e4f"
+  integrity sha512-f6Npp9kUWC0nV9g6THWl60VrVbWRuQjsixYBq8a0/4MwruHamFqauVWkCk4iUNw6htw8wZfHVHUIgiwAg3hibw==
+
+"@logseq/[email protected].81":
+  version "0.0.81"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.81.tgz#8879b16db494cc67902a21eb5136d67b9bba6141"
+  integrity sha512-LTqyXSpbWJlAAJ8NtNzT/t+8gL/wgU+PXFtw8VAwD9TrsKl8I+gjzmTJf0Y6Ej8BACRGTusyelh7BAGoeLKHqg==
+
+"@logseq/[email protected].81":
+  version "0.0.81"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-freebsd-x64/-/rsapi-freebsd-x64-0.0.81.tgz#99d7c8de99f8ffa9b4fd33d972fda971d137298c"
+  integrity sha512-e+MAt8K0uztIk7FtAHRsKFX9bqqBr2zJEZBCMUnguBB9ezx/dCF2OJXPB38Aw6Is8lJcfb8ZxewJj0AsIwBPJw==
+
+"@logseq/[email protected].81":
+  version "0.0.81"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.81.tgz#9de9bf394dfdc26545a4537506f8498a5cc06fdd"
+  integrity sha512-m5H1xFcovCbp2fs47dICxA5pZCQUV0t5lJfeHZjNsYniXKADIdEry9U6jef8GTAI73ABXTpjQ3L1oq2W7QsmBA==
+
+"@logseq/[email protected].81":
+  version "0.0.81"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.81.tgz#f5a090fa34892cd7ec2ea81fcf67b4f4fb1e9ade"
+  integrity sha512-QW7QRkkaB9CUP4tgbv2hUbSBd/wTd5FWSg+qoKe/k0hydtaD6JsP1uMQuTdkvwxbi8735PMvuB4Q5p01+cGpRQ==
+
+"@logseq/[email protected].81":
+  version "0.0.81"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.81.tgz#baa0f4ac5978ed27d3771a01f7b4ee7cc5bfd15d"
+  integrity sha512-hTdE8H6URdN0Y6B2gEnCDeEFDlgpEMydvnCDiJEOBNugsuue0AGB5phGn/DaxQ7t9S1KH+YPBRzxb+oPU6hMrQ==
+
+"@logseq/[email protected].81":
+  version "0.0.81"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.81.tgz#665b3a87a2bca08b2755865c9cc9d5e584b17e8d"
+  integrity sha512-tzUk2y9TVJlY6ZlA6tSDOQ+/n2bdbrNPX+A7SintnJXhsyJLXhszLcnWJU1dIj2pf7pcAcYoPv1aZYfp4re5qw==
   optionalDependencies:
-    "@logseq/rsapi-darwin-arm64" "0.0.76"
-    "@logseq/rsapi-darwin-x64" "0.0.76"
-    "@logseq/rsapi-freebsd-x64" "0.0.76"
-    "@logseq/rsapi-linux-arm64-gnu" "0.0.76"
-    "@logseq/rsapi-linux-x64-gnu" "0.0.76"
-    "@logseq/rsapi-win32-x64-msvc" "0.0.76"
+    "@logseq/rsapi-darwin-arm64" "0.0.81"
+    "@logseq/rsapi-darwin-x64" "0.0.81"
+    "@logseq/rsapi-freebsd-x64" "0.0.81"
+    "@logseq/rsapi-linux-arm64-gnu" "0.0.81"
+    "@logseq/rsapi-linux-x64-gnu" "0.0.81"
+    "@logseq/rsapi-win32-x64-msvc" "0.0.81"
 
 "@malept/cross-spawn-promise@^1.0.0", "@malept/cross-spawn-promise@^1.1.0":
   version "1.1.1"

+ 1 - 1
tldraw/demo/package.json

@@ -4,7 +4,7 @@
   "version": "0.0.0-dev",
   "devDependencies": {
     "@babel/plugin-proposal-decorators": "^7.20.2",
-    "@swc/core": "^1.3.17",
+    "@swc/core": "^1.3.21",
     "@typescript-eslint/eslint-plugin": "^5.43.0",
     "@typescript-eslint/parser": "^5.43.0",
     "@vitejs/plugin-basic-ssl": "^0.1.2",

+ 77 - 64
tldraw/yarn.lock

@@ -1095,71 +1095,84 @@
   dependencies:
     "@babel/runtime" "^7.13.10"
 
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.17.tgz#8692a7accdadee2059da7f824e2302a3805d577b"
-  integrity sha512-l82ub46GSRRpPpvR9NkHqqskPKQAkpRAKMZNzBrY01GLzUj63XH8uAv+3N1Htpq835iekWJjGZXYONCZ1eHlcQ==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.17.tgz#4f6490bace2569a6438eab4f66e13b2ab5b41883"
-  integrity sha512-pBVrF1Ac5t6v9wd5Jqdfve7d0G3ELnjHzaEmCxV0W3ma7/pfHiGv7ZPGnXTclt0+IrMisrVoY5LM+xG1Hv+91Q==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.17.tgz#67e50a8c9bbf2c28147a6ed6b25fd3084c7e9ade"
-  integrity sha512-argIcltgNEssehO7PzXuNYbV7ubVd6YW13FhB9uNWEp/1HGSzIJEnJ4tISbZe9NA9jwI3IALAiE3vDdTdGf/XA==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.17.tgz#a9062b96abe79de5d3f22fb71cf836522833320e"
-  integrity sha512-bH0YSJd3thV1/kY5lHkeXTEcbx0HYFpIqCGJbeDvzpg38FEFSFiUw9+0VX6Yf3FKPq1DcGK/eAKYC7LeZfAzvg==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.17.tgz#6e520d2ed5944badcbb7b0b63b8de733e06d7bc2"
-  integrity sha512-sV5rfpPADmOg5YfTXLLGAzeTUjjgix29kra44EKa25Qyuwu/52OkoW4olF86qwvcQrRySWwga95EeClRhIX/zA==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.17.tgz#b19a221c2a6c50c360a4f4b6a0ba4f3974b62028"
-  integrity sha512-KbPdQSLgSjTutFsCGzjTzMCzZBiem4dEByiKxkrQmt87kLX4wLlPCy0Gppcaa6jExRcvy5co/vlf9TknuKcy4A==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.17.tgz#000fb3569946026c54507bfa31fd0518c47ed6f2"
-  integrity sha512-NDUbaJ0MbklioadPhkzQDOP8eazOn1lJmNmcmg9zNUR7GZsek1CMmJkyJ3ETXZ5gbIfVQ1hPkPm23P9vQBtCdQ==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.17.tgz#9d62c0778e293f0090b043cd9886de6eaf8d7f1c"
-  integrity sha512-fmpGG1iuKcMSDSO2ZHETlYTRel5hTwyuJ4AYbUX3/YzAE4iEnV1PI/n54wrWIdKONsPt3Pcj/UyRD3A6/ZS8rQ==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.17.tgz#fe95a598e1e378e530bb91ffb4a70180d754a88b"
-  integrity sha512-hmQovtwsKnb4D+NAKN2HYjTyNE3iXakBrQNSo1u+/KeMU+D6/+XCSdzrg7ob4olqf4yq52FXPPkLYwyDDHRO/g==
-
-"@swc/[email protected]":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.17.tgz#e778b352bbc2d5cf4f42dd48e26a62c33f110700"
-  integrity sha512-wl+L7300uFr74WWw+b+mIx9NzMQB8+LCapFc01LqDgFyUFT6HSIIM9/s3zzy5Xh8UpgnkbS0/7rMl+zC1V+nFw==
-
-"@swc/core@^1.3.17":
-  version "1.3.17"
-  resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.17.tgz#d6cc81071a28e333a6ca2d03b012303c8278a47c"
-  integrity sha512-wcjmxJqwpo9mQqnyUChyIIxC3nw2xRK07zGMS2zbcId31J+wer5PMbgy0qEqzZEeIswUmL8lBO4whM+wSAmVqA==
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.102.tgz#2bbd90a8751e6eee981f857ec3f0b6233208da37"
+  integrity sha512-CJDxA5Wd2cUMULj3bjx4GEoiYyyiyL8oIOu4Nhrs9X+tlg8DnkCm4nI57RJGP8Mf6BaXPIJkHX8yjcefK2RlDA==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.102.tgz#df16d51f45771d3c9cca8554b28a3190cdb075cf"
+  integrity sha512-X5akDkHwk6oAer49oER0qZMjNMkLH3IOZaV1m98uXIasAGyjo5WH1MKPeMLY1sY6V6TrufzwiSwD4ds571ytcg==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.102.tgz#eb71697590c56ea261fa9a4b198c45304c7ece39"
+  integrity sha512-kJH3XtZP9YQdjq/wYVBeFuiVQl4HaC4WwRrIxAHwe2OyvrwUI43dpW3LpxSggBnxXcVCXYWf36sTnv8S75o2Gw==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.102.tgz#75d72d5253d56723fa7054e1a8f313bf3d17b1a2"
+  integrity sha512-flQP2WDyCgO24WmKA1wjjTx+xfCmavUete2Kp6yrM+631IHLGnr17eu7rYJ/d4EnDBId/ytMyrnWbTVkaVrpbQ==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.102.tgz#7db86022fec57c1e06c573d45cef5e911bcc420e"
+  integrity sha512-bQEQSnC44DyoIGLw1+fNXKVGoCHi7eJOHr8BdH0y1ooy9ArskMjwobBFae3GX4T1AfnrTaejyr0FvLYIb0Zkog==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.102.tgz#298a25aa854924bedc7e4b69da52da19f84fc7a8"
+  integrity sha512-dFvnhpI478svQSxqISMt00MKTDS0e4YtIr+ioZDG/uJ/q+RpcNy3QI2KMm05Fsc8Y0d4krVtvCKWgfUMsJZXAg==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.102.tgz#1bcd911aaa88b96f3bb665b0fd84ef4d21adf886"
+  integrity sha512-+a0M3CvjeIRNA/jTCzWEDh2V+mhKGvLreHOL7J97oULZy5yg4gf7h8lQX9J8t9QLbf6fsk+0F8bVH1Ie/PbXjA==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.102.tgz#59084786364d03fa4a120bdd589a557a00caedeb"
+  integrity sha512-w76JWLjkZNOfkB25nqdWUNCbt0zJ41CnWrJPZ+LxEai3zAnb2YtgB/cCIrwxDebRuMgE9EJXRj7gDDaTEAMOOQ==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.102.tgz#27954889d940a63796d58ff7753f5f27ed381a1f"
+  integrity sha512-vlDb09HiGqKwz+2cxDS9T5/461ipUQBplvuhW+cCbzzGuPq8lll2xeyZU0N1E4Sz3MVdSPx1tJREuRvlQjrwNg==
+
+"@swc/[email protected]":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.102.tgz#477da542e6b01b3eb64476ec9a78f497a9b87807"
+  integrity sha512-E/jfSD7sShllxBwwgDPeXp1UxvIqehj/ShSUqq1pjR/IDRXngcRSXKJK92mJkNFY7suH6BcCWwzrxZgkO7sWmw==
+
+"@swc/core@^1.3.21":
+  version "1.3.102"
+  resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.102.tgz#870874bcf1d78cd7bb1bc66b31bf2b1a87c1a667"
+  integrity sha512-OAjNLY/f6QWKSDzaM3bk31A+OYHu6cPa9P/rFIx8X5d24tHXUpRiiq6/PYI6SQRjUPlB72GjsjoEU8F+ALadHg==
+  dependencies:
+    "@swc/counter" "^0.1.1"
+    "@swc/types" "^0.1.5"
   optionalDependencies:
-    "@swc/core-darwin-arm64" "1.3.17"
-    "@swc/core-darwin-x64" "1.3.17"
-    "@swc/core-linux-arm-gnueabihf" "1.3.17"
-    "@swc/core-linux-arm64-gnu" "1.3.17"
-    "@swc/core-linux-arm64-musl" "1.3.17"
-    "@swc/core-linux-x64-gnu" "1.3.17"
-    "@swc/core-linux-x64-musl" "1.3.17"
-    "@swc/core-win32-arm64-msvc" "1.3.17"
-    "@swc/core-win32-ia32-msvc" "1.3.17"
-    "@swc/core-win32-x64-msvc" "1.3.17"
+    "@swc/core-darwin-arm64" "1.3.102"
+    "@swc/core-darwin-x64" "1.3.102"
+    "@swc/core-linux-arm-gnueabihf" "1.3.102"
+    "@swc/core-linux-arm64-gnu" "1.3.102"
+    "@swc/core-linux-arm64-musl" "1.3.102"
+    "@swc/core-linux-x64-gnu" "1.3.102"
+    "@swc/core-linux-x64-musl" "1.3.102"
+    "@swc/core-win32-arm64-msvc" "1.3.102"
+    "@swc/core-win32-ia32-msvc" "1.3.102"
+    "@swc/core-win32-x64-msvc" "1.3.102"
+
+"@swc/counter@^0.1.1":
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.2.tgz#bf06d0770e47c6f1102270b744e17b934586985e"
+  integrity sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==
+
+"@swc/types@^0.1.5":
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.5.tgz#043b731d4f56a79b4897a3de1af35e75d56bc63a"
+  integrity sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==
 
 "@types/debug@^4.0.0":
   version "4.1.7"