mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-04 19:15:33 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5526696357 | |||
| 5be0292536 |
+1
-1
@@ -5,7 +5,7 @@ rustflags = ["-C", "target-feature=+crt-static"]
|
|||||||
[target.'cfg(target_os = "linux")']
|
[target.'cfg(target_os = "linux")']
|
||||||
rustflags = ["-C", "link-args=-Wl,--warn-unresolved-symbols"]
|
rustflags = ["-C", "link-args=-Wl,--warn-unresolved-symbols"]
|
||||||
[target.'cfg(target_os = "macos")']
|
[target.'cfg(target_os = "macos")']
|
||||||
rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup,-no_fixup_chains", "-C", "link-args=-all_load", "-C", "link-args=-weak_framework ScreenCaptureKit"]
|
rustflags = ["-C", "link-args=-all_load", "-C", "link-args=-weak_framework ScreenCaptureKit"]
|
||||||
# https://sourceware.org/bugzilla/show_bug.cgi?id=21032
|
# https://sourceware.org/bugzilla/show_bug.cgi?id=21032
|
||||||
# https://sourceware.org/bugzilla/show_bug.cgi?id=21031
|
# https://sourceware.org/bugzilla/show_bug.cgi?id=21031
|
||||||
# https://github.com/rust-lang/rust/issues/134820
|
# https://github.com/rust-lang/rust/issues/134820
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis
|
image: redis
|
||||||
container_name: affine_redis
|
container_name: redis
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ['CMD', 'redis-cli', '--raw', 'incr', 'ping']
|
test: ['CMD', 'redis-cli', '--raw', 'incr', 'ping']
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -54,7 +54,7 @@ services:
|
|||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:16
|
image: postgres:16
|
||||||
container_name: affine_postgres
|
container_name: postgres
|
||||||
volumes:
|
volumes:
|
||||||
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -200,6 +200,11 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Configuration for mailer module",
|
"description": "Configuration for mailer module",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether enabled mail service.\n@default false",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"SMTP.host": {
|
"SMTP.host": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Host of the email server (e.g. smtp.gmail.com)\n@default \"\"\n@environment `MAILER_HOST`",
|
"description": "Host of the email server (e.g. smtp.gmail.com)\n@default \"\"\n@environment `MAILER_HOST`",
|
||||||
@@ -507,7 +512,8 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "A recognizable name for the server. Will be shown when connected with AFFiNE Desktop.\n@default undefined"
|
"description": "A recognizable name for the server. Will be shown when connected with AFFiNE Desktop.\n@default \"AFFiNE Cloud\"",
|
||||||
|
"default": "AFFiNE Cloud"
|
||||||
},
|
},
|
||||||
"externalUrl": {
|
"externalUrl": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -531,7 +537,7 @@
|
|||||||
},
|
},
|
||||||
"path": {
|
"path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Subpath where the server get deployed if there is one.(e.g. /affine)\n@default \"\"\n@environment `AFFINE_SERVER_SUB_PATH`",
|
"description": "Subpath where the server get deployed if there is.\n@default \"\"\n@environment `AFFINE_SERVER_SUB_PATH`",
|
||||||
"default": ""
|
"default": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,43 +218,7 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: test-results-e2e-bs-${{ matrix.shard }}
|
name: test-results-e2e-legacy-bs-${{ matrix.shard }}
|
||||||
path: ./test-results
|
|
||||||
if-no-files-found: ignore
|
|
||||||
|
|
||||||
e2e-blocksuite-cross-browser-test:
|
|
||||||
name: E2E BlockSuite Cross Browser Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: optimize_ci
|
|
||||||
if: needs.optimize_ci.outputs.skip == 'false'
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
shard: [1, 2]
|
|
||||||
browser: ['chromium', 'firefox', 'webkit']
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: ./.github/actions/setup-node
|
|
||||||
with:
|
|
||||||
playwright-install: true
|
|
||||||
playwright-platform: ${{ matrix.browser }}
|
|
||||||
electron-install: false
|
|
||||||
full-cache: true
|
|
||||||
|
|
||||||
- name: Run playground build
|
|
||||||
run: yarn workspace @blocksuite/playground build
|
|
||||||
|
|
||||||
- name: Run playwright tests
|
|
||||||
env:
|
|
||||||
BROWSER: ${{ matrix.browser }}
|
|
||||||
run: yarn workspace @affine-test/blocksuite test "cross-platform/" --forbid-only --shard=${{ matrix.shard }}/${{ strategy.job-total }}
|
|
||||||
|
|
||||||
- name: Upload test results
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: test-results-e2e-bs-cross-browser-${{ matrix.browser }}-${{ matrix.shard }}
|
|
||||||
path: ./test-results
|
path: ./test-results
|
||||||
if-no-files-found: ignore
|
if-no-files-found: ignore
|
||||||
|
|
||||||
@@ -1177,7 +1141,6 @@ jobs:
|
|||||||
- check-yarn-binary
|
- check-yarn-binary
|
||||||
- e2e-test
|
- e2e-test
|
||||||
- e2e-blocksuite-test
|
- e2e-blocksuite-test
|
||||||
- e2e-blocksuite-cross-browser-test
|
|
||||||
- e2e-mobile-test
|
- e2e-mobile-test
|
||||||
- unit-test
|
- unit-test
|
||||||
- build-native
|
- build-native
|
||||||
|
|||||||
@@ -85,6 +85,3 @@ packages/frontend/core/public/static/templates
|
|||||||
af
|
af
|
||||||
af.cmd
|
af.cmd
|
||||||
*.resolved
|
*.resolved
|
||||||
|
|
||||||
# playwright
|
|
||||||
storageState.json
|
|
||||||
|
|||||||
Vendored
+4
-1
@@ -29,7 +29,10 @@
|
|||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug AFFiNE Web",
|
"name": "Debug AFFiNE Web",
|
||||||
"url": "http://localhost:8080"
|
"url": "http://localhost:8080",
|
||||||
|
"sourceMapPathOverrides": {
|
||||||
|
"webpack://affine/blocksuite/*": "${workspaceFolder}/blocksuite/*"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+169
-169
File diff suppressed because one or more lines are too long
+1
-1
@@ -12,4 +12,4 @@ npmPublishAccess: public
|
|||||||
|
|
||||||
npmPublishRegistry: "https://registry.npmjs.org"
|
npmPublishRegistry: "https://registry.npmjs.org"
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-4.9.1.cjs
|
yarnPath: .yarn/releases/yarn-4.9.0.cjs
|
||||||
|
|||||||
Generated
+60
-53
@@ -79,7 +79,6 @@ dependencies = [
|
|||||||
"block2",
|
"block2",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"coreaudio-rs",
|
"coreaudio-rs",
|
||||||
"criterion2",
|
|
||||||
"dispatch2",
|
"dispatch2",
|
||||||
"libc",
|
"libc",
|
||||||
"napi",
|
"napi",
|
||||||
@@ -287,9 +286,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.98"
|
version = "1.0.97"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arbitrary"
|
name = "arbitrary"
|
||||||
@@ -514,9 +513,9 @@ checksum = "4848ed5727d39a7573551c205bcb1ccd88c8cad4ed2c80f62e2316f208196b8d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "1.12.0"
|
version = "1.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata 0.4.9",
|
"regex-automata 0.4.9",
|
||||||
@@ -602,9 +601,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.19"
|
version = "1.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
@@ -720,9 +719,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.36"
|
version = "4.5.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
|
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -730,9 +729,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.36"
|
version = "4.5.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
|
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -1208,9 +1207,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.11"
|
version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
@@ -1358,9 +1357,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "four-char-code"
|
name = "four-char-code"
|
||||||
version = "2.3.0"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42da99970737c0150e3c5cd1cdc510735a2511739f5c3aa3c6bfc9f31441488d"
|
checksum = "c661315fd366b2a1f970df7b7cb1a28d2678d49ef4872f7dcc19b4a83150f20b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fs-err"
|
name = "fs-err"
|
||||||
@@ -1530,9 +1529,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
version = "2.6.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
|
checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"crunchy",
|
"crunchy",
|
||||||
@@ -1845,9 +1844,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.9.0"
|
version = "2.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
@@ -1976,9 +1975,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.172"
|
version = "0.2.171"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
@@ -1987,7 +1986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2019,9 +2018,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.9.4"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
@@ -2185,9 +2184,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.8"
|
version = "0.8.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler2",
|
"adler2",
|
||||||
]
|
]
|
||||||
@@ -2561,7 +2560,7 @@ checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "pdf-extract"
|
name = "pdf-extract"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
source = "git+https://github.com/toeverything/pdf-extract?branch=darksky%2Fimprove-font-decoding#e74beed894e1b8dc228c2bf078ed92814b27759f"
|
source = "git+https://github.com/toeverything/pdf-extract#49ef7d2aec5bb495467a40082cd9717e849ee29a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adobe-cmap-parser",
|
"adobe-cmap-parser",
|
||||||
"cff-parser",
|
"cff-parser",
|
||||||
@@ -2897,9 +2896,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.11"
|
version = "0.5.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
]
|
]
|
||||||
@@ -3090,9 +3089,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.26"
|
version = "0.23.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
|
checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ring",
|
"ring",
|
||||||
@@ -3102,6 +3101,15 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pemfile"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||||
|
dependencies = [
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
@@ -3179,9 +3187,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scroll_derive"
|
name = "scroll_derive"
|
||||||
version = "0.12.1"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
|
checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3331,9 +3339,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.15.0"
|
version = "1.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -3385,9 +3393,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx"
|
name = "sqlx"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14e22987355fbf8cfb813a0cf8cd97b1b4ec834b94dbd759a9e8679d41fabe83"
|
checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"sqlx-macros",
|
"sqlx-macros",
|
||||||
@@ -3398,11 +3406,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-core"
|
name = "sqlx-core"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55c4720d7d4cd3d5b00f61d03751c685ad09c33ae8290c8a2c11335e0604300b"
|
checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
@@ -3421,6 +3428,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"rustls",
|
"rustls",
|
||||||
|
"rustls-pemfile",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
@@ -3435,9 +3443,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-macros"
|
name = "sqlx-macros"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "175147fcb75f353ac7675509bc58abb2cb291caf0fd24a3623b8f7e3eb0a754b"
|
checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3448,9 +3456,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-macros-core"
|
name = "sqlx-macros-core"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1cde983058e53bfa75998e1982086c5efe3c370f3250bf0357e344fa3352e32b"
|
checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"either",
|
"either",
|
||||||
@@ -3474,9 +3482,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-mysql"
|
name = "sqlx-mysql"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "847d2e5393a4f39e47e4f36cab419709bc2b83cbe4223c60e86e1471655be333"
|
checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -3517,9 +3525,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-postgres"
|
name = "sqlx-postgres"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc35947a541b9e0a2e3d85da444f1c4137c13040267141b208395a0d0ca4659f"
|
checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -3555,9 +3563,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-sqlite"
|
name = "sqlx-sqlite"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c48291dac4e5ed32da0927a0b981788be65674aeb62666d19873ab4289febde"
|
checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -3573,7 +3581,6 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"thiserror 2.0.12",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
@@ -5051,9 +5058,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.6"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
|
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ objc2-foundation = "0.3"
|
|||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
path-ext = "0.1.1"
|
path-ext = "0.1.1"
|
||||||
pdf-extract = { git = "https://github.com/toeverything/pdf-extract", branch = "darksky/improve-font-decoding" }
|
pdf-extract = { git = "https://github.com/toeverything/pdf-extract" }
|
||||||
rand = "0.9"
|
rand = "0.9"
|
||||||
rayon = "1.10"
|
rayon = "1.10"
|
||||||
readability = { version = "0.3.0", default-features = false }
|
readability = { version = "0.3.0", default-features = false }
|
||||||
|
|||||||
@@ -55,8 +55,6 @@
|
|||||||
"@blocksuite/affine-widget-edgeless-auto-connect": "workspace:*",
|
"@blocksuite/affine-widget-edgeless-auto-connect": "workspace:*",
|
||||||
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
|
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
|
||||||
"@blocksuite/affine-widget-frame-title": "workspace:*",
|
"@blocksuite/affine-widget-frame-title": "workspace:*",
|
||||||
"@blocksuite/affine-widget-keyboard-toolbar": "workspace:*",
|
|
||||||
"@blocksuite/affine-widget-linked-doc": "workspace:*",
|
|
||||||
"@blocksuite/affine-widget-remote-selection": "workspace:*",
|
"@blocksuite/affine-widget-remote-selection": "workspace:*",
|
||||||
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*",
|
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*",
|
||||||
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
||||||
@@ -117,12 +115,10 @@
|
|||||||
"./widgets/edgeless-auto-connect": "./src/widgets/edgeless-auto-connect.ts",
|
"./widgets/edgeless-auto-connect": "./src/widgets/edgeless-auto-connect.ts",
|
||||||
"./widgets/edgeless-toolbar": "./src/widgets/edgeless-toolbar.ts",
|
"./widgets/edgeless-toolbar": "./src/widgets/edgeless-toolbar.ts",
|
||||||
"./widgets/frame-title": "./src/widgets/frame-title.ts",
|
"./widgets/frame-title": "./src/widgets/frame-title.ts",
|
||||||
"./widgets/linked-doc": "./src/widgets/linked-doc.ts",
|
|
||||||
"./widgets/remote-selection": "./src/widgets/remote-selection.ts",
|
"./widgets/remote-selection": "./src/widgets/remote-selection.ts",
|
||||||
"./widgets/scroll-anchoring": "./src/widgets/scroll-anchoring.ts",
|
"./widgets/scroll-anchoring": "./src/widgets/scroll-anchoring.ts",
|
||||||
"./widgets/slash-menu": "./src/widgets/slash-menu.ts",
|
"./widgets/slash-menu": "./src/widgets/slash-menu.ts",
|
||||||
"./widgets/toolbar": "./src/widgets/toolbar.ts",
|
"./widgets/toolbar": "./src/widgets/toolbar.ts",
|
||||||
"./widgets/keyboard-toolbar": "./src/widgets/keyboard-toolbar.ts",
|
|
||||||
"./fragments/doc-title": "./src/fragments/doc-title.ts",
|
"./fragments/doc-title": "./src/fragments/doc-title.ts",
|
||||||
"./fragments/frame-panel": "./src/fragments/frame-panel.ts",
|
"./fragments/frame-panel": "./src/fragments/frame-panel.ts",
|
||||||
"./fragments/outline": "./src/fragments/outline.ts",
|
"./fragments/outline": "./src/fragments/outline.ts",
|
||||||
|
|||||||
@@ -2448,262 +2448,203 @@ World!
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('markdown to snapshot', () => {
|
describe('markdown to snapshot', () => {
|
||||||
describe('code', () => {
|
test('code', async () => {
|
||||||
test('markdown code block', async () => {
|
const markdown = '```python\nimport this\n```\n';
|
||||||
const markdown = '```python\nimport this\n```\n';
|
|
||||||
|
|
||||||
const blockSnapshot: BlockSnapshot = {
|
const blockSnapshot: BlockSnapshot = {
|
||||||
type: 'block',
|
type: 'block',
|
||||||
id: 'matchesReplaceMap[0]',
|
id: 'matchesReplaceMap[0]',
|
||||||
flavour: 'affine:note',
|
flavour: 'affine:note',
|
||||||
props: {
|
props: {
|
||||||
xywh: '[0,0,800,95]',
|
xywh: '[0,0,800,95]',
|
||||||
background: DefaultTheme.noteBackgrounColor,
|
background: DefaultTheme.noteBackgrounColor,
|
||||||
index: 'a0',
|
index: 'a0',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
displayMode: NoteDisplayMode.DocAndEdgeless,
|
displayMode: NoteDisplayMode.DocAndEdgeless,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'block',
|
||||||
|
id: 'matchesReplaceMap[1]',
|
||||||
|
flavour: 'affine:code',
|
||||||
|
props: {
|
||||||
|
language: 'python',
|
||||||
|
wrap: false,
|
||||||
|
text: {
|
||||||
|
'$blocksuite:internal:text$': true,
|
||||||
|
delta: [
|
||||||
|
{
|
||||||
|
insert: 'import this',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [],
|
||||||
},
|
},
|
||||||
children: [
|
],
|
||||||
{
|
};
|
||||||
type: 'block',
|
|
||||||
id: 'matchesReplaceMap[1]',
|
|
||||||
flavour: 'affine:code',
|
|
||||||
props: {
|
|
||||||
language: 'python',
|
|
||||||
wrap: false,
|
|
||||||
text: {
|
|
||||||
'$blocksuite:internal:text$': true,
|
|
||||||
delta: [
|
|
||||||
{
|
|
||||||
insert: 'import this',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
||||||
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
|
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
|
||||||
file: markdown,
|
file: markdown,
|
||||||
});
|
|
||||||
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
|
|
||||||
});
|
});
|
||||||
|
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
|
||||||
|
});
|
||||||
|
|
||||||
test('code with indentation 1 - slice', async () => {
|
test('code with indentation 1 - slice', async () => {
|
||||||
const markdown = '```python\n import this\n```';
|
const markdown = '```python\n import this\n```';
|
||||||
|
|
||||||
const sliceSnapshot: SliceSnapshot = {
|
const sliceSnapshot: SliceSnapshot = {
|
||||||
type: 'slice',
|
type: 'slice',
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: 'block',
|
type: 'block',
|
||||||
id: 'matchesReplaceMap[0]',
|
id: 'matchesReplaceMap[0]',
|
||||||
flavour: 'affine:note',
|
flavour: 'affine:note',
|
||||||
props: {
|
props: {
|
||||||
xywh: '[0,0,800,95]',
|
xywh: '[0,0,800,95]',
|
||||||
background: DefaultTheme.noteBackgrounColor,
|
background: DefaultTheme.noteBackgrounColor,
|
||||||
index: 'a0',
|
index: 'a0',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
displayMode: 'both',
|
displayMode: 'both',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: 'block',
|
type: 'block',
|
||||||
id: 'matchesReplaceMap[1]',
|
id: 'matchesReplaceMap[1]',
|
||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language: 'python',
|
language: 'python',
|
||||||
wrap: false,
|
wrap: false,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
delta: [
|
delta: [
|
||||||
{
|
{
|
||||||
insert: ' import this',
|
insert: ' import this',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
|
||||||
},
|
},
|
||||||
children: [],
|
|
||||||
},
|
},
|
||||||
],
|
children: [],
|
||||||
},
|
|
||||||
],
|
|
||||||
workspaceId: '',
|
|
||||||
pageId: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
|
||||||
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
|
|
||||||
file: markdown,
|
|
||||||
workspaceId: '',
|
|
||||||
pageId: '',
|
|
||||||
});
|
|
||||||
expect(nanoidReplacement(rawSliceSnapshot!)).toEqual(sliceSnapshot);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('code with indentation 2 - slice', async () => {
|
|
||||||
const markdown = '````python\n```python\n import this\n```\n````';
|
|
||||||
|
|
||||||
const sliceSnapshot: SliceSnapshot = {
|
|
||||||
type: 'slice',
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
type: 'block',
|
|
||||||
id: 'matchesReplaceMap[0]',
|
|
||||||
flavour: 'affine:note',
|
|
||||||
props: {
|
|
||||||
xywh: '[0,0,800,95]',
|
|
||||||
background: DefaultTheme.noteBackgrounColor,
|
|
||||||
index: 'a0',
|
|
||||||
hidden: false,
|
|
||||||
displayMode: 'both',
|
|
||||||
},
|
},
|
||||||
children: [
|
],
|
||||||
{
|
|
||||||
type: 'block',
|
|
||||||
id: 'matchesReplaceMap[1]',
|
|
||||||
flavour: 'affine:code',
|
|
||||||
props: {
|
|
||||||
language: 'python',
|
|
||||||
wrap: false,
|
|
||||||
text: {
|
|
||||||
'$blocksuite:internal:text$': true,
|
|
||||||
delta: [
|
|
||||||
{
|
|
||||||
insert: '```python\n import this\n```',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
workspaceId: '',
|
|
||||||
pageId: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
|
||||||
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
|
|
||||||
file: markdown,
|
|
||||||
workspaceId: '',
|
|
||||||
pageId: '',
|
|
||||||
});
|
|
||||||
expect(nanoidReplacement(rawSliceSnapshot!)).toEqual(sliceSnapshot);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('code with indentation 3 - slice', async () => {
|
|
||||||
const markdown = '~~~~python\n````python\n import this\n````\n~~~~';
|
|
||||||
|
|
||||||
const sliceSnapshot: SliceSnapshot = {
|
|
||||||
type: 'slice',
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
type: 'block',
|
|
||||||
id: 'matchesReplaceMap[0]',
|
|
||||||
flavour: 'affine:note',
|
|
||||||
props: {
|
|
||||||
xywh: '[0,0,800,95]',
|
|
||||||
background: DefaultTheme.noteBackgrounColor,
|
|
||||||
index: 'a0',
|
|
||||||
hidden: false,
|
|
||||||
displayMode: 'both',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: 'block',
|
|
||||||
id: 'matchesReplaceMap[1]',
|
|
||||||
flavour: 'affine:code',
|
|
||||||
props: {
|
|
||||||
language: 'python',
|
|
||||||
wrap: false,
|
|
||||||
text: {
|
|
||||||
'$blocksuite:internal:text$': true,
|
|
||||||
delta: [
|
|
||||||
{
|
|
||||||
insert: '````python\n import this\n````',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
workspaceId: '',
|
|
||||||
pageId: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
|
||||||
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
|
|
||||||
file: markdown,
|
|
||||||
workspaceId: '',
|
|
||||||
pageId: '',
|
|
||||||
});
|
|
||||||
expect(nanoidReplacement(rawSliceSnapshot!)).toEqual(sliceSnapshot);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('html block import as code block', async () => {
|
|
||||||
const markdown = `<div class="container">
|
|
||||||
<header>
|
|
||||||
<h1>Welcome to My Page</h1>
|
|
||||||
<nav>
|
|
||||||
<ul>
|
|
||||||
<li><a href="#home">Home</a></li>
|
|
||||||
<li><a href="#about">About</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<main>
|
|
||||||
<p>This is a sample HTML content</p>
|
|
||||||
</main>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
const blockSnapshot: BlockSnapshot = {
|
|
||||||
type: 'block',
|
|
||||||
id: 'matchesReplaceMap[0]',
|
|
||||||
flavour: 'affine:note',
|
|
||||||
props: {
|
|
||||||
xywh: '[0,0,800,95]',
|
|
||||||
background: DefaultTheme.noteBackgrounColor,
|
|
||||||
index: 'a0',
|
|
||||||
hidden: false,
|
|
||||||
displayMode: NoteDisplayMode.DocAndEdgeless,
|
|
||||||
},
|
},
|
||||||
children: [
|
],
|
||||||
{
|
workspaceId: '',
|
||||||
type: 'block',
|
pageId: '',
|
||||||
id: 'matchesReplaceMap[1]',
|
};
|
||||||
flavour: 'affine:code',
|
|
||||||
props: {
|
|
||||||
language: 'html',
|
|
||||||
wrap: false,
|
|
||||||
text: {
|
|
||||||
'$blocksuite:internal:text$': true,
|
|
||||||
delta: [
|
|
||||||
{
|
|
||||||
insert:
|
|
||||||
'<div class="container">\n <header>\n <h1>Welcome to My Page</h1>\n <nav>\n <ul>\n <li><a href="#home">Home</a></li>\n <li><a href="#about">About</a></li>\n </ul>\n </nav>\n </header>\n <main>\n <p>This is a sample HTML content</p>\n </main>\n</div>',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
||||||
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
|
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
|
||||||
file: markdown,
|
file: markdown,
|
||||||
});
|
workspaceId: '',
|
||||||
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
|
pageId: '',
|
||||||
});
|
});
|
||||||
|
expect(nanoidReplacement(rawSliceSnapshot!)).toEqual(sliceSnapshot);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('code with indentation 2 - slice', async () => {
|
||||||
|
const markdown = '````python\n```python\n import this\n```\n````';
|
||||||
|
|
||||||
|
const sliceSnapshot: SliceSnapshot = {
|
||||||
|
type: 'slice',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'block',
|
||||||
|
id: 'matchesReplaceMap[0]',
|
||||||
|
flavour: 'affine:note',
|
||||||
|
props: {
|
||||||
|
xywh: '[0,0,800,95]',
|
||||||
|
background: DefaultTheme.noteBackgrounColor,
|
||||||
|
index: 'a0',
|
||||||
|
hidden: false,
|
||||||
|
displayMode: 'both',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'block',
|
||||||
|
id: 'matchesReplaceMap[1]',
|
||||||
|
flavour: 'affine:code',
|
||||||
|
props: {
|
||||||
|
language: 'python',
|
||||||
|
wrap: false,
|
||||||
|
text: {
|
||||||
|
'$blocksuite:internal:text$': true,
|
||||||
|
delta: [
|
||||||
|
{
|
||||||
|
insert: '```python\n import this\n```',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
workspaceId: '',
|
||||||
|
pageId: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
||||||
|
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
|
||||||
|
file: markdown,
|
||||||
|
workspaceId: '',
|
||||||
|
pageId: '',
|
||||||
|
});
|
||||||
|
expect(nanoidReplacement(rawSliceSnapshot!)).toEqual(sliceSnapshot);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('code with indentation 3 - slice', async () => {
|
||||||
|
const markdown = '~~~~python\n````python\n import this\n````\n~~~~';
|
||||||
|
|
||||||
|
const sliceSnapshot: SliceSnapshot = {
|
||||||
|
type: 'slice',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'block',
|
||||||
|
id: 'matchesReplaceMap[0]',
|
||||||
|
flavour: 'affine:note',
|
||||||
|
props: {
|
||||||
|
xywh: '[0,0,800,95]',
|
||||||
|
background: DefaultTheme.noteBackgrounColor,
|
||||||
|
index: 'a0',
|
||||||
|
hidden: false,
|
||||||
|
displayMode: 'both',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'block',
|
||||||
|
id: 'matchesReplaceMap[1]',
|
||||||
|
flavour: 'affine:code',
|
||||||
|
props: {
|
||||||
|
language: 'python',
|
||||||
|
wrap: false,
|
||||||
|
text: {
|
||||||
|
'$blocksuite:internal:text$': true,
|
||||||
|
delta: [
|
||||||
|
{
|
||||||
|
insert: '````python\n import this\n````',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
workspaceId: '',
|
||||||
|
pageId: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
||||||
|
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
|
||||||
|
file: markdown,
|
||||||
|
workspaceId: '',
|
||||||
|
pageId: '',
|
||||||
|
});
|
||||||
|
expect(nanoidReplacement(rawSliceSnapshot!)).toEqual(sliceSnapshot);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('paragraph', async () => {
|
test('paragraph', async () => {
|
||||||
@@ -3697,6 +3638,48 @@ bbb
|
|||||||
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
|
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('html tag', async () => {
|
||||||
|
const markdown = `<aaa>\n`;
|
||||||
|
|
||||||
|
const blockSnapshot: BlockSnapshot = {
|
||||||
|
type: 'block',
|
||||||
|
id: 'matchesReplaceMap[0]',
|
||||||
|
flavour: 'affine:note',
|
||||||
|
props: {
|
||||||
|
xywh: '[0,0,800,95]',
|
||||||
|
background: DefaultTheme.noteBackgrounColor,
|
||||||
|
index: 'a0',
|
||||||
|
hidden: false,
|
||||||
|
displayMode: NoteDisplayMode.DocAndEdgeless,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'block',
|
||||||
|
id: 'matchesReplaceMap[1]',
|
||||||
|
flavour: 'affine:paragraph',
|
||||||
|
props: {
|
||||||
|
text: {
|
||||||
|
'$blocksuite:internal:text$': true,
|
||||||
|
delta: [
|
||||||
|
{
|
||||||
|
insert: '<aaa>',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
children: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
||||||
|
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
|
||||||
|
file: markdown,
|
||||||
|
});
|
||||||
|
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
|
||||||
|
});
|
||||||
|
|
||||||
describe('inline latex', () => {
|
describe('inline latex', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['dollar sign syntax', 'inline $E=mc^2$ latex\n'],
|
['dollar sign syntax', 'inline $E=mc^2$ latex\n'],
|
||||||
@@ -4108,55 +4091,4 @@ hhh
|
|||||||
});
|
});
|
||||||
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
|
expect(nanoidReplacement(rawBlockSnapshot)).toEqual(blockSnapshot);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not wrap url with angle brackets if it is not a url', async () => {
|
|
||||||
const markdown = 'prompt: How many people will live in the world in 2040?';
|
|
||||||
const sliceSnapshot: SliceSnapshot = {
|
|
||||||
type: 'slice',
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
type: 'block',
|
|
||||||
id: 'matchesReplaceMap[0]',
|
|
||||||
flavour: 'affine:note',
|
|
||||||
props: {
|
|
||||||
xywh: '[0,0,800,95]',
|
|
||||||
background: DefaultTheme.noteBackgrounColor,
|
|
||||||
index: 'a0',
|
|
||||||
hidden: false,
|
|
||||||
displayMode: NoteDisplayMode.DocAndEdgeless,
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: 'block',
|
|
||||||
id: 'matchesReplaceMap[1]',
|
|
||||||
flavour: 'affine:paragraph',
|
|
||||||
props: {
|
|
||||||
type: 'text',
|
|
||||||
text: {
|
|
||||||
'$blocksuite:internal:text$': true,
|
|
||||||
delta: [
|
|
||||||
{
|
|
||||||
insert:
|
|
||||||
'prompt: How many people will live in the world in 2040?',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
workspaceId: '',
|
|
||||||
pageId: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
const mdAdapter = new MarkdownAdapter(createJob(), provider);
|
|
||||||
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
|
|
||||||
file: markdown,
|
|
||||||
workspaceId: '',
|
|
||||||
pageId: '',
|
|
||||||
});
|
|
||||||
expect(nanoidReplacement(rawSliceSnapshot!)).toEqual(sliceSnapshot);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export * from '@blocksuite/affine-widget-keyboard-toolbar';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from '@blocksuite/affine-widget-linked-doc';
|
|
||||||
@@ -52,8 +52,6 @@
|
|||||||
{ "path": "../widgets/edgeless-auto-connect" },
|
{ "path": "../widgets/edgeless-auto-connect" },
|
||||||
{ "path": "../widgets/edgeless-toolbar" },
|
{ "path": "../widgets/edgeless-toolbar" },
|
||||||
{ "path": "../widgets/frame-title" },
|
{ "path": "../widgets/frame-title" },
|
||||||
{ "path": "../widgets/keyboard-toolbar" },
|
|
||||||
{ "path": "../widgets/linked-doc" },
|
|
||||||
{ "path": "../widgets/remote-selection" },
|
{ "path": "../widgets/remote-selection" },
|
||||||
{ "path": "../widgets/scroll-anchoring" },
|
{ "path": "../widgets/scroll-anchoring" },
|
||||||
{ "path": "../widgets/slash-menu" },
|
{ "path": "../widgets/slash-menu" },
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { checkAttachmentBlob, downloadAttachmentBlob } from './utils';
|
|||||||
|
|
||||||
@Peekable({
|
@Peekable({
|
||||||
enableOn: ({ model }: AttachmentBlockComponent) => {
|
enableOn: ({ model }: AttachmentBlockComponent) => {
|
||||||
return !model.doc.readonly && model.props.type.endsWith('pdf');
|
return model.props.type.endsWith('pdf');
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export class AttachmentBlockComponent extends CaptionedBlockComponent<AttachmentBlockModel> {
|
export class AttachmentBlockComponent extends CaptionedBlockComponent<AttachmentBlockModel> {
|
||||||
|
|||||||
@@ -146,20 +146,17 @@ const embedConfig: AttachmentEmbedConfig[] = [
|
|||||||
// More options: https://tinytip.co/tips/html-pdf-params/
|
// More options: https://tinytip.co/tips/html-pdf-params/
|
||||||
// https://chromium.googlesource.com/chromium/src/+/refs/tags/121.0.6153.1/chrome/browser/resources/pdf/open_pdf_params_parser.ts
|
// https://chromium.googlesource.com/chromium/src/+/refs/tags/121.0.6153.1/chrome/browser/resources/pdf/open_pdf_params_parser.ts
|
||||||
const parameters = '#toolbar=0';
|
const parameters = '#toolbar=0';
|
||||||
return html`
|
return html`<iframe
|
||||||
<iframe
|
style="width: 100%; color-scheme: auto;"
|
||||||
style="width: 100%; color-scheme: auto;"
|
height="480"
|
||||||
height="480"
|
src=${blobUrl + parameters}
|
||||||
src=${blobUrl + parameters}
|
loading="lazy"
|
||||||
loading="lazy"
|
scrolling="no"
|
||||||
scrolling="no"
|
frameborder="no"
|
||||||
frameborder="no"
|
allowTransparency
|
||||||
allowTransparency
|
allowfullscreen
|
||||||
allowfullscreen
|
type="application/pdf"
|
||||||
type="application/pdf"
|
></iframe>`;
|
||||||
></iframe>
|
|
||||||
<div class="affine-attachment-embed-event-mask"></div>
|
|
||||||
`;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -136,9 +136,4 @@ export const styles = css`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.affine-attachment-embed-event-mask {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -81,10 +81,21 @@ export class BookmarkCard extends SignalWatcher(
|
|||||||
const theme = this.bookmark.std.get(ThemeProvider).theme;
|
const theme = this.bookmark.std.get(ThemeProvider).theme;
|
||||||
const { LoadingIcon, EmbedCardBannerIcon } = getEmbedCardIcons(theme);
|
const { LoadingIcon, EmbedCardBannerIcon } = getEmbedCardIcons(theme);
|
||||||
|
|
||||||
|
const titleIconType =
|
||||||
|
!icon?.split('.').pop() || icon?.split('.').pop() === 'svg'
|
||||||
|
? 'svg+xml'
|
||||||
|
: icon?.split('.').pop();
|
||||||
|
|
||||||
const titleIcon = this.loading
|
const titleIcon = this.loading
|
||||||
? LoadingIcon
|
? LoadingIcon
|
||||||
: icon
|
: icon
|
||||||
? html`<img src=${icon} alt="icon" />`
|
? html`<object
|
||||||
|
type="image/${titleIconType}"
|
||||||
|
data=${icon}
|
||||||
|
draggable="false"
|
||||||
|
>
|
||||||
|
${WebIcon16}
|
||||||
|
</object>`
|
||||||
: WebIcon16;
|
: WebIcon16;
|
||||||
|
|
||||||
const descriptionText = this.loading
|
const descriptionText = this.loading
|
||||||
@@ -97,7 +108,9 @@ export class BookmarkCard extends SignalWatcher(
|
|||||||
|
|
||||||
const bannerImage =
|
const bannerImage =
|
||||||
!this.loading && image
|
!this.loading && image
|
||||||
? html`<img src=${image} alt="banner" />`
|
? html`<object type="image/webp" data=${image} draggable="false">
|
||||||
|
${EmbedCardBannerIcon}
|
||||||
|
</object>`
|
||||||
: EmbedCardBannerIcon;
|
: EmbedCardBannerIcon;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
|||||||
@@ -21,21 +21,16 @@ export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockM
|
|||||||
|
|
||||||
.affine-callout-block-container {
|
.affine-callout-block-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 5px 10px;
|
padding: 12px 16px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background-color: ${unsafeCSSVarV2('block/callout/background/grey')};
|
background-color: ${unsafeCSSVarV2('block/callout/background/grey')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.affine-callout-emoji-container {
|
.affine-callout-emoji-container {
|
||||||
margin-right: 10px;
|
margin-right: 12px;
|
||||||
margin-top: 14px;
|
margin-top: 10px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
}
|
||||||
.affine-callout-emoji:hover {
|
.affine-callout-emoji:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -45,7 +40,6 @@ export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockM
|
|||||||
.affine-callout-children {
|
.affine-callout-children {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding-left: 10px;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blocksuite/affine-components": "workspace:*",
|
"@blocksuite/affine-components": "workspace:*",
|
||||||
"@blocksuite/affine-gfx-turbo-renderer": "workspace:*",
|
|
||||||
"@blocksuite/affine-inline-latex": "workspace:*",
|
"@blocksuite/affine-inline-latex": "workspace:*",
|
||||||
"@blocksuite/affine-inline-link": "workspace:*",
|
"@blocksuite/affine-inline-link": "workspace:*",
|
||||||
"@blocksuite/affine-inline-preset": "workspace:*",
|
"@blocksuite/affine-inline-preset": "workspace:*",
|
||||||
@@ -36,8 +35,7 @@
|
|||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./effects": "./src/effects.ts",
|
"./effects": "./src/effects.ts"
|
||||||
"./turbo-painter": "./src/turbo/code-painter.worker.ts"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"src",
|
"src",
|
||||||
|
|||||||
@@ -3,51 +3,25 @@ import {
|
|||||||
BlockMarkdownAdapterExtension,
|
BlockMarkdownAdapterExtension,
|
||||||
type BlockMarkdownAdapterMatcher,
|
type BlockMarkdownAdapterMatcher,
|
||||||
CODE_BLOCK_WRAP_KEY,
|
CODE_BLOCK_WRAP_KEY,
|
||||||
IN_PARAGRAPH_NODE_CONTEXT_KEY,
|
|
||||||
type MarkdownAST,
|
type MarkdownAST,
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { nanoid } from '@blocksuite/store';
|
import { nanoid } from '@blocksuite/store';
|
||||||
import type { Code, Html } from 'mdast';
|
import type { Code } from 'mdast';
|
||||||
|
|
||||||
const isCodeNode = (node: MarkdownAST): node is Code => node.type === 'code';
|
const isCodeNode = (node: MarkdownAST): node is Code => node.type === 'code';
|
||||||
const isHtmlNode = (node: MarkdownAST): node is Html => node.type === 'html';
|
|
||||||
|
|
||||||
const isCodeOrHtmlNode = (node: MarkdownAST): node is Code | Html =>
|
|
||||||
isCodeNode(node) || isHtmlNode(node);
|
|
||||||
|
|
||||||
export const codeBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
export const codeBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
||||||
flavour: CodeBlockSchema.model.flavour,
|
flavour: CodeBlockSchema.model.flavour,
|
||||||
toMatch: o => isCodeOrHtmlNode(o.node),
|
toMatch: o => isCodeNode(o.node),
|
||||||
fromMatch: o => o.node.flavour === 'affine:code',
|
fromMatch: o => o.node.flavour === 'affine:code',
|
||||||
toBlockSnapshot: {
|
toBlockSnapshot: {
|
||||||
enter: (o, context) => {
|
enter: (o, context) => {
|
||||||
if (!isCodeOrHtmlNode(o.node)) {
|
if (!isCodeNode(o.node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { walkerContext, configs } = context;
|
const { walkerContext, configs } = context;
|
||||||
const wrap = configs.get(CODE_BLOCK_WRAP_KEY) === 'true';
|
const wrap = configs.get(CODE_BLOCK_WRAP_KEY) === 'true';
|
||||||
let language = 'plain text';
|
|
||||||
switch (o.node.type) {
|
|
||||||
case 'code': {
|
|
||||||
if (o.node.lang) {
|
|
||||||
language = o.node.lang;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'html': {
|
|
||||||
const inParagraphNode = !!walkerContext.getGlobalContext(
|
|
||||||
IN_PARAGRAPH_NODE_CONTEXT_KEY
|
|
||||||
);
|
|
||||||
// only handle top level html node
|
|
||||||
if (inParagraphNode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
language = 'html';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
walkerContext
|
walkerContext
|
||||||
.openNode(
|
.openNode(
|
||||||
{
|
{
|
||||||
@@ -55,7 +29,7 @@ export const codeBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
|||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
flavour: 'affine:code',
|
flavour: 'affine:code',
|
||||||
props: {
|
props: {
|
||||||
language,
|
language: o.node.lang ?? 'Plain Text',
|
||||||
wrap,
|
wrap,
|
||||||
text: {
|
text: {
|
||||||
'$blocksuite:internal:text$': true,
|
'$blocksuite:internal:text$': true,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {
|
|||||||
type MarkdownAdapterPreprocessor,
|
type MarkdownAdapterPreprocessor,
|
||||||
MarkdownPreprocessorExtension,
|
MarkdownPreprocessorExtension,
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
import { isValidUrl } from '@blocksuite/affine-shared/utils';
|
|
||||||
|
|
||||||
const codePreprocessor: MarkdownAdapterPreprocessor = {
|
const codePreprocessor: MarkdownAdapterPreprocessor = {
|
||||||
name: 'code',
|
name: 'code',
|
||||||
@@ -54,9 +53,14 @@ const codePreprocessor: MarkdownAdapterPreprocessor = {
|
|||||||
//
|
//
|
||||||
// eg. /MuawcBMT1Mzvoar09-_66?mode=page&blockIds=rL2_GXbtLU2SsJVfCSmh_
|
// eg. /MuawcBMT1Mzvoar09-_66?mode=page&blockIds=rL2_GXbtLU2SsJVfCSmh_
|
||||||
// https://www.markdownguide.org/basic-syntax/#urls-and-email-addresses
|
// https://www.markdownguide.org/basic-syntax/#urls-and-email-addresses
|
||||||
const valid = isValidUrl(trimmedLine);
|
try {
|
||||||
if (valid) {
|
const valid =
|
||||||
return `<${trimmedLine}>`;
|
URL.canParse?.(trimmedLine) ?? Boolean(new URL(trimmedLine));
|
||||||
|
if (valid) {
|
||||||
|
return `<${trimmedLine}>`;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
import { deleteTextCommand } from '@blocksuite/affine-inline-preset';
|
|
||||||
import {
|
|
||||||
HtmlAdapter,
|
|
||||||
pasteMiddleware,
|
|
||||||
PlainTextAdapter,
|
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
|
||||||
import {
|
|
||||||
getBlockIndexCommand,
|
|
||||||
getBlockSelectionsCommand,
|
|
||||||
getTextSelectionCommand,
|
|
||||||
} from '@blocksuite/affine-shared/commands';
|
|
||||||
import { type Container, createIdentifier } from '@blocksuite/global/di';
|
|
||||||
import { DisposableGroup } from '@blocksuite/global/disposable';
|
|
||||||
import {
|
|
||||||
type BlockStdScope,
|
|
||||||
Clipboard,
|
|
||||||
type ClipboardAdapterConfig,
|
|
||||||
LifeCycleWatcher,
|
|
||||||
LifeCycleWatcherIdentifier,
|
|
||||||
StdIdentifier,
|
|
||||||
type UIEventHandler,
|
|
||||||
} from '@blocksuite/std';
|
|
||||||
import type { ExtensionType } from '@blocksuite/store';
|
|
||||||
|
|
||||||
export const CodeClipboardAdapterConfigIdentifier =
|
|
||||||
createIdentifier<ClipboardAdapterConfig>('code-clipboard-adapter-config');
|
|
||||||
|
|
||||||
export function CodeClipboardAdapterConfigExtension(
|
|
||||||
config: ClipboardAdapterConfig
|
|
||||||
): ExtensionType {
|
|
||||||
return {
|
|
||||||
setup: di => {
|
|
||||||
di.addImpl(
|
|
||||||
CodeClipboardAdapterConfigIdentifier(config.mimeType),
|
|
||||||
() => config
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const PlainTextClipboardConfig = CodeClipboardAdapterConfigExtension({
|
|
||||||
mimeType: 'text/plain',
|
|
||||||
adapter: PlainTextAdapter,
|
|
||||||
priority: 90,
|
|
||||||
});
|
|
||||||
|
|
||||||
const HtmlClipboardConfig = CodeClipboardAdapterConfigExtension({
|
|
||||||
mimeType: 'text/html',
|
|
||||||
adapter: HtmlAdapter,
|
|
||||||
priority: 80,
|
|
||||||
});
|
|
||||||
|
|
||||||
export class CodeBlockClipboard extends Clipboard {
|
|
||||||
static override readonly key = 'code-block-clipboard';
|
|
||||||
|
|
||||||
override get _adapters() {
|
|
||||||
const adapterConfigs = this.std.provider.getAll(
|
|
||||||
CodeClipboardAdapterConfigIdentifier
|
|
||||||
);
|
|
||||||
return Array.from(adapterConfigs.values());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CodeBlockClipboardController extends LifeCycleWatcher {
|
|
||||||
static override key = 'code-block-clipboard-controller';
|
|
||||||
|
|
||||||
private readonly _disposables = new DisposableGroup();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
std: BlockStdScope,
|
|
||||||
readonly clipboard: CodeBlockClipboard
|
|
||||||
) {
|
|
||||||
super(std);
|
|
||||||
}
|
|
||||||
|
|
||||||
static override setup(di: Container) {
|
|
||||||
di.add(
|
|
||||||
this as unknown as {
|
|
||||||
new (
|
|
||||||
std: BlockStdScope,
|
|
||||||
clipboard: CodeBlockClipboard
|
|
||||||
): CodeBlockClipboardController;
|
|
||||||
},
|
|
||||||
[StdIdentifier, CodeBlockClipboard]
|
|
||||||
);
|
|
||||||
di.addImpl(LifeCycleWatcherIdentifier(this.key), provider =>
|
|
||||||
provider.get(this)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected _init = () => {
|
|
||||||
const paste = pasteMiddleware(this.std);
|
|
||||||
this.clipboard.use(paste);
|
|
||||||
|
|
||||||
this._disposables.add({
|
|
||||||
dispose: () => {
|
|
||||||
this.clipboard.unuse(paste);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onPaste: UIEventHandler = ctx => {
|
|
||||||
const e = ctx.get('clipboardState').raw;
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
this.std.store.captureSync();
|
|
||||||
this.std.command
|
|
||||||
.chain()
|
|
||||||
.try(cmd => [
|
|
||||||
cmd.pipe(getTextSelectionCommand).pipe((ctx, next) => {
|
|
||||||
const textSelection = ctx.currentTextSelection;
|
|
||||||
if (!textSelection) return;
|
|
||||||
const end = textSelection.to ?? textSelection.from;
|
|
||||||
next({ currentSelectionPath: end.blockId });
|
|
||||||
}),
|
|
||||||
cmd.pipe(getBlockSelectionsCommand).pipe((ctx, next) => {
|
|
||||||
const currentBlockSelections = ctx.currentBlockSelections;
|
|
||||||
if (!currentBlockSelections) return;
|
|
||||||
const blockSelection = currentBlockSelections.at(-1);
|
|
||||||
if (!blockSelection) return;
|
|
||||||
next({ currentSelectionPath: blockSelection.blockId });
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
.pipe(getBlockIndexCommand)
|
|
||||||
.try(cmd => [cmd.pipe(getTextSelectionCommand).pipe(deleteTextCommand)])
|
|
||||||
.pipe((ctx, next) => {
|
|
||||||
if (!ctx.parentBlock) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.clipboard
|
|
||||||
.paste(
|
|
||||||
e,
|
|
||||||
this.std.store,
|
|
||||||
ctx.parentBlock.model.id,
|
|
||||||
ctx.blockIndex ? ctx.blockIndex + 1 : 1
|
|
||||||
)
|
|
||||||
.catch(console.error);
|
|
||||||
|
|
||||||
return next();
|
|
||||||
})
|
|
||||||
.run();
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
override mounted() {
|
|
||||||
this._init();
|
|
||||||
|
|
||||||
// add paste event listener for code block
|
|
||||||
const subscription = this.std.view.viewUpdated.subscribe(
|
|
||||||
({ type, method, view }) => {
|
|
||||||
if (type !== 'block' || view.model.flavour !== 'affine:code') return;
|
|
||||||
|
|
||||||
if (method === 'add') {
|
|
||||||
view.handleEvent('paste', this.onPaste);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this._disposables.add(subscription);
|
|
||||||
}
|
|
||||||
|
|
||||||
override unmounted() {
|
|
||||||
this._disposables.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCodeClipboardExtensions(): ExtensionType[] {
|
|
||||||
return [
|
|
||||||
PlainTextClipboardConfig,
|
|
||||||
HtmlClipboardConfig,
|
|
||||||
CodeBlockClipboard,
|
|
||||||
CodeBlockClipboardController,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ import type { ExtensionType } from '@blocksuite/store';
|
|||||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||||
|
|
||||||
import { CodeBlockAdapterExtensions } from './adapters/extension.js';
|
import { CodeBlockAdapterExtensions } from './adapters/extension.js';
|
||||||
import { getCodeClipboardExtensions } from './clipboard/index.js';
|
|
||||||
import {
|
import {
|
||||||
CodeBlockInlineManagerExtension,
|
CodeBlockInlineManagerExtension,
|
||||||
CodeBlockUnitSpecExtension,
|
CodeBlockUnitSpecExtension,
|
||||||
@@ -34,5 +33,4 @@ export const CodeBlockSpec: ExtensionType[] = [
|
|||||||
CodeBlockAdapterExtensions,
|
CodeBlockAdapterExtensions,
|
||||||
SlashMenuConfigExtension('affine:code', codeSlashMenuConfig),
|
SlashMenuConfigExtension('affine:code', codeSlashMenuConfig),
|
||||||
CodeKeymapExtension,
|
CodeKeymapExtension,
|
||||||
...getCodeClipboardExtensions(),
|
|
||||||
].flat();
|
].flat();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
|
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
|
||||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||||
import { ShadowlessElement } from '@blocksuite/std';
|
import { ShadowlessElement } from '@blocksuite/std';
|
||||||
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline';
|
import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
@@ -111,7 +111,7 @@ export class AffineCodeUnit extends ShadowlessElement {
|
|||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
insert: ZERO_WIDTH_SPACE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
export * from './adapters';
|
export * from './adapters';
|
||||||
export * from './clipboard';
|
|
||||||
export * from './code-block';
|
export * from './code-block';
|
||||||
export * from './code-block-config';
|
export * from './code-block-config';
|
||||||
export * from './code-block-spec';
|
export * from './code-block-spec';
|
||||||
export * from './code-toolbar';
|
export * from './code-toolbar';
|
||||||
export * from './turbo/code-layout-handler';
|
|
||||||
export * from './turbo/code-painter.worker';
|
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
import type { Rect } from '@blocksuite/affine-gfx-turbo-renderer';
|
|
||||||
import {
|
|
||||||
BlockLayoutHandlerExtension,
|
|
||||||
BlockLayoutHandlersIdentifier,
|
|
||||||
} from '@blocksuite/affine-gfx-turbo-renderer';
|
|
||||||
import type { Container } from '@blocksuite/global/di';
|
|
||||||
import type { EditorHost, GfxBlockComponent } from '@blocksuite/std';
|
|
||||||
import { clientToModelCoord, type ViewportRecord } from '@blocksuite/std/gfx';
|
|
||||||
import type { BlockModel } from '@blocksuite/store';
|
|
||||||
|
|
||||||
import type { CodeLayout } from './code-painter.worker';
|
|
||||||
|
|
||||||
export class CodeLayoutHandlerExtension extends BlockLayoutHandlerExtension<CodeLayout> {
|
|
||||||
readonly blockType = 'affine:code';
|
|
||||||
|
|
||||||
static override setup(di: Container) {
|
|
||||||
di.addImpl(
|
|
||||||
BlockLayoutHandlersIdentifier('code'),
|
|
||||||
CodeLayoutHandlerExtension
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
override queryLayout(
|
|
||||||
model: BlockModel,
|
|
||||||
host: EditorHost,
|
|
||||||
viewportRecord: ViewportRecord
|
|
||||||
): CodeLayout | null {
|
|
||||||
const component = host.std.view.getBlock(model.id) as GfxBlockComponent;
|
|
||||||
if (!component) return null;
|
|
||||||
|
|
||||||
const codeBlockElement = component.querySelector(
|
|
||||||
'.affine-code-block-container'
|
|
||||||
);
|
|
||||||
if (!codeBlockElement) return null;
|
|
||||||
|
|
||||||
const { zoom, viewScale } = viewportRecord;
|
|
||||||
const codeLayout: CodeLayout = {
|
|
||||||
type: 'affine:code',
|
|
||||||
blockId: model.id,
|
|
||||||
rect: { x: 0, y: 0, w: 0, h: 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the bounding rect of the code block
|
|
||||||
const clientRect = codeBlockElement.getBoundingClientRect();
|
|
||||||
if (!clientRect) return null;
|
|
||||||
|
|
||||||
// Convert client coordinates to model coordinates
|
|
||||||
const [modelX, modelY] = clientToModelCoord(viewportRecord, [
|
|
||||||
clientRect.x,
|
|
||||||
clientRect.y,
|
|
||||||
]);
|
|
||||||
|
|
||||||
codeLayout.rect = {
|
|
||||||
x: modelX,
|
|
||||||
y: modelY,
|
|
||||||
w: clientRect.width / zoom / viewScale,
|
|
||||||
h: clientRect.height / zoom / viewScale,
|
|
||||||
};
|
|
||||||
|
|
||||||
return codeLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateBound(layout: CodeLayout) {
|
|
||||||
const rect: Rect = layout.rect;
|
|
||||||
|
|
||||||
return {
|
|
||||||
rect,
|
|
||||||
subRects: [rect],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
import type {
|
|
||||||
BlockLayout,
|
|
||||||
BlockLayoutPainter,
|
|
||||||
WorkerToHostMessage,
|
|
||||||
} from '@blocksuite/affine-gfx-turbo-renderer';
|
|
||||||
import { BlockLayoutPainterExtension } from '@blocksuite/affine-gfx-turbo-renderer/painter';
|
|
||||||
|
|
||||||
export interface CodeLayout extends BlockLayout {
|
|
||||||
type: 'affine:code';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isCodeLayout(layout: BlockLayout): layout is CodeLayout {
|
|
||||||
return layout.type === 'affine:code';
|
|
||||||
}
|
|
||||||
|
|
||||||
class CodeLayoutPainter implements BlockLayoutPainter {
|
|
||||||
paint(
|
|
||||||
ctx: OffscreenCanvasRenderingContext2D,
|
|
||||||
layout: BlockLayout,
|
|
||||||
layoutBaseX: number,
|
|
||||||
layoutBaseY: number
|
|
||||||
): void {
|
|
||||||
if (!isCodeLayout(layout)) {
|
|
||||||
const message: WorkerToHostMessage = {
|
|
||||||
type: 'paintError',
|
|
||||||
error: 'Invalid layout format',
|
|
||||||
blockType: 'affine:code',
|
|
||||||
};
|
|
||||||
self.postMessage(message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the layout dimensions
|
|
||||||
const x = layout.rect.x - layoutBaseX;
|
|
||||||
const y = layout.rect.y - layoutBaseY;
|
|
||||||
const width = layout.rect.w;
|
|
||||||
const height = layout.rect.h;
|
|
||||||
|
|
||||||
// Simple white rectangle for now
|
|
||||||
ctx.fillStyle = 'white';
|
|
||||||
ctx.fillRect(x, y, width, height);
|
|
||||||
|
|
||||||
// Add a border to visualize the code block
|
|
||||||
ctx.strokeStyle = 'rgba(0, 0, 0, 0.1)';
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.strokeRect(x, y, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CodeLayoutPainterExtension = BlockLayoutPainterExtension(
|
|
||||||
'affine:code',
|
|
||||||
CodeLayoutPainter
|
|
||||||
);
|
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
"include": ["./src"],
|
"include": ["./src"],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../components" },
|
{ "path": "../../components" },
|
||||||
{ "path": "../../gfx/turbo-renderer" },
|
|
||||||
{ "path": "../../inlines/latex" },
|
{ "path": "../../inlines/latex" },
|
||||||
{ "path": "../../inlines/link" },
|
{ "path": "../../inlines/link" },
|
||||||
{ "path": "../../inlines/preset" },
|
{ "path": "../../inlines/preset" },
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
override onSelected(context: SelectedContext): void | boolean {
|
override onSelected(context: SelectedContext) {
|
||||||
const { selected, multiSelect, event: e } = context;
|
const { selected, multiSelect, event: e } = context;
|
||||||
const { editing } = this.gfx.selection;
|
const { editing } = this.gfx.selection;
|
||||||
const alreadySelected = this.gfx.selection.has(this.model.id);
|
const alreadySelected = this.gfx.selection.has(this.model.id);
|
||||||
@@ -318,7 +318,7 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent<EdgelessTextBl
|
|||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
} else {
|
} else {
|
||||||
return super.onSelected(context);
|
super.onSelected(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type {
|
|||||||
EmbedGithubStyles,
|
EmbedGithubStyles,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import { ThemeProvider } from '@blocksuite/affine-shared/services';
|
import { ThemeProvider } from '@blocksuite/affine-shared/services';
|
||||||
import { BlockSelection, isGfxBlockComponent } from '@blocksuite/std';
|
import { BlockSelection } from '@blocksuite/std';
|
||||||
import { html, nothing } from 'lit';
|
import { html, nothing } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { classMap } from 'lit/directives/class-map.js';
|
import { classMap } from 'lit/directives/class-map.js';
|
||||||
@@ -166,16 +166,16 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent<
|
|||||||
'affine-embed-github-block': true,
|
'affine-embed-github-block': true,
|
||||||
loading,
|
loading,
|
||||||
[style]: true,
|
[style]: true,
|
||||||
edgeless: isGfxBlockComponent(this),
|
|
||||||
selected: this.selected$.value,
|
selected: this.selected$.value,
|
||||||
})}
|
})}
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
// transform: `scale(${this._scale})`,
|
transform: `scale(${this._scale})`,
|
||||||
transformOrigin: '0 0 ',
|
transformOrigin: '0 0 ',
|
||||||
})}
|
})}
|
||||||
@click=${this._handleClick}
|
@click=${this._handleClick}
|
||||||
@dblclick=${this._handleDoubleClick}
|
@dblclick=${this._handleDoubleClick}
|
||||||
>
|
>
|
||||||
|
<div class="affine-embed-github-banner">${bannerImage}</div>
|
||||||
<div class="affine-embed-github-content">
|
<div class="affine-embed-github-content">
|
||||||
<div class="affine-embed-github-content-title">
|
<div class="affine-embed-github-content-title">
|
||||||
<div class="affine-embed-github-content-title-icons">
|
<div class="affine-embed-github-content-title-icons">
|
||||||
@@ -260,7 +260,6 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent<
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="affine-embed-github-banner">${bannerImage}</div>
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ export const styles = css`
|
|||||||
opacity: var(--add, 1);
|
opacity: var(--add, 1);
|
||||||
background: var(--affine-background-primary-color);
|
background: var(--affine-background-primary-color);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.affine-embed-github-content {
|
.affine-embed-github-content {
|
||||||
@@ -276,7 +275,7 @@ export const styles = css`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.affine-embed-github-block.vertical {
|
.affine-embed-github-block.vertical {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column;
|
||||||
|
|
||||||
.affine-embed-github-content {
|
.affine-embed-github-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -384,8 +383,7 @@ export const styles = css`
|
|||||||
.affine-embed-github-content {
|
.affine-embed-github-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.affine-embed-github-banner {
|
||||||
.affine-embed-github-block:not(.edgeless) .affine-embed-github-banner {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -209,9 +209,9 @@ export class EmbedIframeErrorCard extends WithDisposable(LitElement) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _handleRetry = async (e: MouseEvent) => {
|
private readonly _handleRetry = (e: MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const success = await this.onRetry();
|
this.onRetry();
|
||||||
|
|
||||||
// track retry event
|
// track retry event
|
||||||
this.telemetryService?.track('ReloadLink', {
|
this.telemetryService?.track('ReloadLink', {
|
||||||
@@ -220,7 +220,6 @@ export class EmbedIframeErrorCard extends WithDisposable(LitElement) {
|
|||||||
segment: 'editor',
|
segment: 'editor',
|
||||||
module: 'embed block',
|
module: 'embed block',
|
||||||
control: 'reload button',
|
control: 'reload button',
|
||||||
result: success ? 'success' : 'failure',
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -302,7 +301,7 @@ export class EmbedIframeErrorCard extends WithDisposable(LitElement) {
|
|||||||
accessor error: Error | null = null;
|
accessor error: Error | null = null;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor onRetry!: () => Promise<boolean>;
|
accessor onRetry!: () => void;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor model!: EmbedIframeBlockModel;
|
accessor model!: EmbedIframeBlockModel;
|
||||||
|
|||||||
+1
-1
@@ -78,7 +78,7 @@ export class EmbedIframeLinkEditPopup extends SignalWatcher(
|
|||||||
segment: 'editor',
|
segment: 'editor',
|
||||||
module: 'embed block',
|
module: 'embed block',
|
||||||
control: 'edit button',
|
control: 'edit button',
|
||||||
result: status,
|
other: status,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -228,7 +228,7 @@ export class EmbedIframeLinkInputPopup extends EmbedIframeLinkInputBase {
|
|||||||
segment: this.options?.telemetrySegment ?? 'editor',
|
segment: this.options?.telemetrySegment ?? 'editor',
|
||||||
module: 'embed block',
|
module: 'embed block',
|
||||||
control: 'confirm embed link',
|
control: 'confirm embed link',
|
||||||
result: status,
|
other: status,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -299,19 +299,12 @@ export const builtinToolbarConfig = {
|
|||||||
icon: ResetIcon(),
|
icon: ResetIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockByType(EmbedIframeBlockComponent);
|
const component = ctx.getCurrentBlockByType(EmbedIframeBlockComponent);
|
||||||
component
|
component?.refreshData().catch(console.error);
|
||||||
?.refreshData()
|
|
||||||
.then(success => {
|
ctx.track('ReloadLink', {
|
||||||
ctx.track('ReloadLink', {
|
...trackBaseProps,
|
||||||
type: 'embed iframe block',
|
control: 'reload link',
|
||||||
page: 'doc editor',
|
});
|
||||||
segment: 'doc',
|
|
||||||
module: 'toolbar',
|
|
||||||
control: 'reload link',
|
|
||||||
result: success ? 'success' : 'failure',
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export class EmbedIframeBlockComponent extends CaptionedBlockComponent<EmbedIfra
|
|||||||
const { url } = this.model.props;
|
const { url } = this.model.props;
|
||||||
if (!url) {
|
if (!url) {
|
||||||
this.status$.value = 'idle';
|
this.status$.value = 'idle';
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set loading status
|
// set loading status
|
||||||
@@ -188,13 +188,11 @@ export class EmbedIframeBlockComponent extends CaptionedBlockComponent<EmbedIfra
|
|||||||
|
|
||||||
// set success status
|
// set success status
|
||||||
this.status$.value = 'success';
|
this.status$.value = 'success';
|
||||||
return true;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// set error status
|
// set error status
|
||||||
this.status$.value = 'error';
|
this.status$.value = 'error';
|
||||||
this.error$.value = err instanceof Error ? err : new Error(String(err));
|
this.error$.value = err instanceof Error ? err : new Error(String(err));
|
||||||
console.error('Failed to refresh iframe data:', err);
|
console.error('Failed to refresh iframe data:', err);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,7 +284,7 @@ export class EmbedIframeBlockComponent extends CaptionedBlockComponent<EmbedIfra
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly _handleRetry = async () => {
|
private readonly _handleRetry = async () => {
|
||||||
return await this.refreshData();
|
await this.refreshData();
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _renderIframe = () => {
|
private readonly _renderIframe = () => {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
|
import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
|
||||||
import { insertContent } from '@blocksuite/affine-rich-text';
|
import {
|
||||||
|
getInlineEditorByModel,
|
||||||
|
insertContent,
|
||||||
|
} from '@blocksuite/affine-rich-text';
|
||||||
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
||||||
import { createDefaultDoc } from '@blocksuite/affine-shared/utils';
|
import { createDefaultDoc } from '@blocksuite/affine-shared/utils';
|
||||||
import {
|
import {
|
||||||
@@ -65,7 +68,22 @@ const linkedDocSlashMenuConfig: SlashMenuConfig = {
|
|||||||
if (!linkedDocWidget) return;
|
if (!linkedDocWidget) return;
|
||||||
// TODO(@L-Sun): make linked-doc-widget as extension
|
// TODO(@L-Sun): make linked-doc-widget as extension
|
||||||
// @ts-expect-error same as above
|
// @ts-expect-error same as above
|
||||||
linkedDocWidget.show({ addTriggerKey: true });
|
const triggerKey = linkedDocWidget.config.triggerKeys[0];
|
||||||
|
|
||||||
|
insertContent(std, model, triggerKey);
|
||||||
|
|
||||||
|
const inlineEditor = getInlineEditorByModel(std, model);
|
||||||
|
if (inlineEditor) {
|
||||||
|
// Wait for range to be updated
|
||||||
|
const subscription = inlineEditor.slots.inlineRangeSync.subscribe(
|
||||||
|
() => {
|
||||||
|
// TODO(@L-Sun): make linked-doc-widget as extension
|
||||||
|
subscription.unsubscribe();
|
||||||
|
// @ts-expect-error same as above
|
||||||
|
linkedDocWidget.show({ addTriggerKey: true });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
DocDisplayMetaProvider,
|
DocDisplayMetaProvider,
|
||||||
EditorSettingProvider,
|
|
||||||
FeatureFlagService,
|
|
||||||
type LinkEventType,
|
type LinkEventType,
|
||||||
type OpenDocMode,
|
type OpenDocMode,
|
||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
@@ -35,7 +33,7 @@ import {
|
|||||||
ExpandFullIcon,
|
ExpandFullIcon,
|
||||||
OpenInNewIcon,
|
OpenInNewIcon,
|
||||||
} from '@blocksuite/icons/lit';
|
} from '@blocksuite/icons/lit';
|
||||||
import { BlockFlavourIdentifier, isGfxBlockComponent } from '@blocksuite/std';
|
import { BlockFlavourIdentifier } from '@blocksuite/std';
|
||||||
import { type ExtensionType, Slice } from '@blocksuite/store';
|
import { type ExtensionType, Slice } from '@blocksuite/store';
|
||||||
import { computed, signal } from '@preact/signals-core';
|
import { computed, signal } from '@preact/signals-core';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
@@ -215,20 +213,6 @@ const conversionsActionGroup = {
|
|||||||
},
|
},
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const block = ctx.getCurrentBlockByType(EmbedLinkedDocBlockComponent);
|
const block = ctx.getCurrentBlockByType(EmbedLinkedDocBlockComponent);
|
||||||
|
|
||||||
if (
|
|
||||||
ctx.std
|
|
||||||
.get(FeatureFlagService)
|
|
||||||
.getFlag('enable_embed_doc_with_alias') &&
|
|
||||||
isGfxBlockComponent(block)
|
|
||||||
) {
|
|
||||||
const editorSetting = ctx.std.getOptional(EditorSettingProvider);
|
|
||||||
editorSetting?.set?.(
|
|
||||||
'docDropCanvasPreferView',
|
|
||||||
'affine:embed-synced-doc'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
block?.convertToEmbed();
|
block?.convertToEmbed();
|
||||||
|
|
||||||
ctx.track('SelectedView', {
|
ctx.track('SelectedView', {
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import { EditorChevronDown } from '@blocksuite/affine-components/toolbar';
|
|||||||
import { EmbedSyncedDocModel } from '@blocksuite/affine-model';
|
import { EmbedSyncedDocModel } from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
EditorSettingProvider,
|
|
||||||
FeatureFlagService,
|
|
||||||
type LinkEventType,
|
type LinkEventType,
|
||||||
type OpenDocMode,
|
type OpenDocMode,
|
||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
@@ -23,7 +21,7 @@ import {
|
|||||||
ExpandFullIcon,
|
ExpandFullIcon,
|
||||||
OpenInNewIcon,
|
OpenInNewIcon,
|
||||||
} from '@blocksuite/icons/lit';
|
} from '@blocksuite/icons/lit';
|
||||||
import { BlockFlavourIdentifier, isGfxBlockComponent } from '@blocksuite/std';
|
import { BlockFlavourIdentifier } from '@blocksuite/std';
|
||||||
import { type ExtensionType, Slice } from '@blocksuite/store';
|
import { type ExtensionType, Slice } from '@blocksuite/store';
|
||||||
import { computed, signal } from '@preact/signals-core';
|
import { computed, signal } from '@preact/signals-core';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
@@ -32,6 +30,7 @@ import { keyed } from 'lit/directives/keyed.js';
|
|||||||
import { repeat } from 'lit/directives/repeat.js';
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
|
|
||||||
import { EmbedSyncedDocBlockComponent } from '../embed-synced-doc-block';
|
import { EmbedSyncedDocBlockComponent } from '../embed-synced-doc-block';
|
||||||
|
|
||||||
const trackBaseProps = {
|
const trackBaseProps = {
|
||||||
category: 'linked doc',
|
category: 'linked doc',
|
||||||
type: 'embed view',
|
type: 'embed view',
|
||||||
@@ -143,19 +142,6 @@ const conversionsActionGroup = {
|
|||||||
label: 'Card view',
|
label: 'Card view',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const block = ctx.getCurrentBlockByType(EmbedSyncedDocBlockComponent);
|
const block = ctx.getCurrentBlockByType(EmbedSyncedDocBlockComponent);
|
||||||
if (
|
|
||||||
ctx.std
|
|
||||||
.get(FeatureFlagService)
|
|
||||||
.getFlag('enable_embed_doc_with_alias') &&
|
|
||||||
isGfxBlockComponent(block)
|
|
||||||
) {
|
|
||||||
const editorSetting = ctx.std.getOptional(EditorSettingProvider);
|
|
||||||
editorSetting?.set?.(
|
|
||||||
'docDropCanvasPreferView',
|
|
||||||
'affine:embed-linked-doc'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
block?.convertToCard();
|
block?.convertToCard();
|
||||||
|
|
||||||
ctx.track('SelectedView', {
|
ctx.track('SelectedView', {
|
||||||
|
|||||||
@@ -117,9 +117,9 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
|||||||
const nextDepth = this.depth + 1;
|
const nextDepth = this.depth + 1;
|
||||||
const previewSpecBuilder = SpecProvider._.getSpec(name);
|
const previewSpecBuilder = SpecProvider._.getSpec(name);
|
||||||
const currentDisposables = this.disposables;
|
const currentDisposables = this.disposables;
|
||||||
const editorSetting = this.std.getOptional(EditorSettingProvider) ?? {
|
const editorSetting =
|
||||||
setting$: signal(GeneralSettingSchema.parse({})),
|
this.std.getOptional(EditorSettingProvider) ??
|
||||||
};
|
signal(GeneralSettingSchema.parse({}));
|
||||||
|
|
||||||
class EmbedSyncedDocWatcher extends LifeCycleWatcher {
|
class EmbedSyncedDocWatcher extends LifeCycleWatcher {
|
||||||
static override key = 'embed-synced-doc-watcher';
|
static override key = 'embed-synced-doc-watcher';
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export class FrameBlockComponent extends GfxBlockComponent<FrameBlockModel> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
override onSelected(context: SelectedContext): boolean | void {
|
override onSelected(context: SelectedContext): void {
|
||||||
const { x, y } = context.position;
|
const { x, y } = context.position;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -63,10 +63,10 @@ export class FrameBlockComponent extends GfxBlockComponent<FrameBlockModel> {
|
|||||||
// otherwise if the frame has title, then ignore it because in this case the frame cannot be selected by frame body
|
// otherwise if the frame has title, then ignore it because in this case the frame cannot be selected by frame body
|
||||||
this.model.props.title.length)
|
this.model.props.title.length)
|
||||||
) {
|
) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onSelected(context);
|
super.onSelected(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
override renderGfxBlock() {
|
override renderGfxBlock() {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ const builtinSurfaceToolbarConfig = {
|
|||||||
|
|
||||||
ctx.store.addBlock(
|
ctx.store.addBlock(
|
||||||
SurfaceRefBlockSchema.model.flavour,
|
SurfaceRefBlockSchema.model.flavour,
|
||||||
{ reference: frameId, refFlavour: FrameBlockSchema.model.flavour },
|
{ reference: frameId, refFlavour: NoteBlockSchema.model.flavour },
|
||||||
lastNoteId
|
lastNoteId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
"@blocksuite/affine-block-note": "workspace:*",
|
"@blocksuite/affine-block-note": "workspace:*",
|
||||||
"@blocksuite/affine-block-surface": "workspace:*",
|
"@blocksuite/affine-block-surface": "workspace:*",
|
||||||
"@blocksuite/affine-components": "workspace:*",
|
"@blocksuite/affine-components": "workspace:*",
|
||||||
"@blocksuite/affine-gfx-turbo-renderer": "workspace:*",
|
|
||||||
"@blocksuite/affine-model": "workspace:*",
|
"@blocksuite/affine-model": "workspace:*",
|
||||||
"@blocksuite/affine-shared": "workspace:*",
|
"@blocksuite/affine-shared": "workspace:*",
|
||||||
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
||||||
@@ -33,8 +32,7 @@
|
|||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./effects": "./src/effects.ts",
|
"./effects": "./src/effects.ts"
|
||||||
"./turbo-painter": "./src/turbo/image-painter.worker.ts"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"src",
|
"src",
|
||||||
|
|||||||
@@ -7,7 +7,5 @@ export { ImageProxyService } from './image-proxy-service';
|
|||||||
export * from './image-service';
|
export * from './image-service';
|
||||||
export * from './image-spec';
|
export * from './image-spec';
|
||||||
export * from './styles';
|
export * from './styles';
|
||||||
export * from './turbo/image-layout-handler';
|
|
||||||
export * from './turbo/image-painter.worker';
|
|
||||||
export { addImages, downloadImageBlob, uploadBlobForImage } from './utils';
|
export { addImages, downloadImageBlob, uploadBlobForImage } from './utils';
|
||||||
export { ImageSelection } from '@blocksuite/affine-shared/selection';
|
export { ImageSelection } from '@blocksuite/affine-shared/selection';
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
import type { Rect } from '@blocksuite/affine-gfx-turbo-renderer';
|
|
||||||
import {
|
|
||||||
BlockLayoutHandlerExtension,
|
|
||||||
BlockLayoutHandlersIdentifier,
|
|
||||||
} from '@blocksuite/affine-gfx-turbo-renderer';
|
|
||||||
import type { Container } from '@blocksuite/global/di';
|
|
||||||
import type { EditorHost, GfxBlockComponent } from '@blocksuite/std';
|
|
||||||
import { clientToModelCoord, type ViewportRecord } from '@blocksuite/std/gfx';
|
|
||||||
import type { BlockModel } from '@blocksuite/store';
|
|
||||||
|
|
||||||
import type { ImageLayout } from './image-painter.worker';
|
|
||||||
|
|
||||||
export class ImageLayoutHandlerExtension extends BlockLayoutHandlerExtension<ImageLayout> {
|
|
||||||
readonly blockType = 'affine:image';
|
|
||||||
|
|
||||||
static override setup(di: Container) {
|
|
||||||
di.addImpl(
|
|
||||||
BlockLayoutHandlersIdentifier('image'),
|
|
||||||
ImageLayoutHandlerExtension
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
override queryLayout(
|
|
||||||
model: BlockModel,
|
|
||||||
host: EditorHost,
|
|
||||||
viewportRecord: ViewportRecord
|
|
||||||
): ImageLayout | null {
|
|
||||||
const component = host.std.view.getBlock(model.id) as GfxBlockComponent;
|
|
||||||
if (!component) return null;
|
|
||||||
|
|
||||||
const imageContainer = component.querySelector('.affine-image-container');
|
|
||||||
if (!imageContainer) return null;
|
|
||||||
|
|
||||||
const resizableImg = component.querySelector(
|
|
||||||
'.resizable-img'
|
|
||||||
) as HTMLElement;
|
|
||||||
if (!resizableImg) return null;
|
|
||||||
|
|
||||||
const { zoom, viewScale } = viewportRecord;
|
|
||||||
const rect = resizableImg.getBoundingClientRect();
|
|
||||||
|
|
||||||
const [modelX, modelY] = clientToModelCoord(viewportRecord, [
|
|
||||||
rect.x,
|
|
||||||
rect.y,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const imageLayout: ImageLayout = {
|
|
||||||
type: 'affine:image',
|
|
||||||
blockId: model.id,
|
|
||||||
rect: {
|
|
||||||
x: modelX,
|
|
||||||
y: modelY,
|
|
||||||
w: rect.width / zoom / viewScale,
|
|
||||||
h: rect.height / zoom / viewScale,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return imageLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateBound(layout: ImageLayout) {
|
|
||||||
const rect: Rect = layout.rect;
|
|
||||||
|
|
||||||
return {
|
|
||||||
rect,
|
|
||||||
subRects: [rect],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import type {
|
|
||||||
BlockLayout,
|
|
||||||
BlockLayoutPainter,
|
|
||||||
} from '@blocksuite/affine-gfx-turbo-renderer';
|
|
||||||
import { BlockLayoutPainterExtension } from '@blocksuite/affine-gfx-turbo-renderer/painter';
|
|
||||||
|
|
||||||
export interface ImageLayout extends BlockLayout {
|
|
||||||
type: 'affine:image';
|
|
||||||
rect: {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
w: number;
|
|
||||||
h: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function isImageLayout(layout: BlockLayout): layout is ImageLayout {
|
|
||||||
return layout.type === 'affine:image';
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImageLayoutPainter implements BlockLayoutPainter {
|
|
||||||
paint(
|
|
||||||
ctx: OffscreenCanvasRenderingContext2D,
|
|
||||||
layout: BlockLayout,
|
|
||||||
layoutBaseX: number,
|
|
||||||
layoutBaseY: number
|
|
||||||
): void {
|
|
||||||
if (!isImageLayout(layout)) {
|
|
||||||
console.warn(
|
|
||||||
'Expected image layout but received different format:',
|
|
||||||
layout
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, just paint a white rectangle
|
|
||||||
const x = layout.rect.x - layoutBaseX;
|
|
||||||
const y = layout.rect.y - layoutBaseY;
|
|
||||||
const width = layout.rect.w;
|
|
||||||
const height = layout.rect.h;
|
|
||||||
|
|
||||||
// Draw a white rectangle with border
|
|
||||||
ctx.fillStyle = 'white';
|
|
||||||
ctx.fillRect(x, y, width, height);
|
|
||||||
|
|
||||||
// Add a border
|
|
||||||
ctx.strokeStyle = '#e0e0e0';
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.strokeRect(x, y, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ImageLayoutPainterExtension = BlockLayoutPainterExtension(
|
|
||||||
'affine:image',
|
|
||||||
ImageLayoutPainter
|
|
||||||
);
|
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
{ "path": "../note" },
|
{ "path": "../note" },
|
||||||
{ "path": "../surface" },
|
{ "path": "../surface" },
|
||||||
{ "path": "../../components" },
|
{ "path": "../../components" },
|
||||||
{ "path": "../../gfx/turbo-renderer" },
|
|
||||||
{ "path": "../../model" },
|
{ "path": "../../model" },
|
||||||
{ "path": "../../shared" },
|
{ "path": "../../shared" },
|
||||||
{ "path": "../../widgets/slash-menu" },
|
{ "path": "../../widgets/slash-menu" },
|
||||||
|
|||||||
@@ -2,14 +2,18 @@ import { ParagraphBlockSchema } from '@blocksuite/affine-model';
|
|||||||
import {
|
import {
|
||||||
BlockMarkdownAdapterExtension,
|
BlockMarkdownAdapterExtension,
|
||||||
type BlockMarkdownAdapterMatcher,
|
type BlockMarkdownAdapterMatcher,
|
||||||
IN_PARAGRAPH_NODE_CONTEXT_KEY,
|
|
||||||
type MarkdownAST,
|
type MarkdownAST,
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { nanoid } from '@blocksuite/store';
|
import { nanoid } from '@blocksuite/store';
|
||||||
import type { Heading } from 'mdast';
|
import type { Heading } from 'mdast';
|
||||||
|
|
||||||
const PARAGRAPH_MDAST_TYPE = new Set(['paragraph', 'heading', 'blockquote']);
|
const PARAGRAPH_MDAST_TYPE = new Set([
|
||||||
|
'paragraph',
|
||||||
|
'html',
|
||||||
|
'heading',
|
||||||
|
'blockquote',
|
||||||
|
]);
|
||||||
|
|
||||||
const isParagraphMDASTType = (node: MarkdownAST) =>
|
const isParagraphMDASTType = (node: MarkdownAST) =>
|
||||||
PARAGRAPH_MDAST_TYPE.has(node.type);
|
PARAGRAPH_MDAST_TYPE.has(node.type);
|
||||||
@@ -23,8 +27,32 @@ export const paragraphBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher =
|
|||||||
enter: (o, context) => {
|
enter: (o, context) => {
|
||||||
const { walkerContext, deltaConverter } = context;
|
const { walkerContext, deltaConverter } = context;
|
||||||
switch (o.node.type) {
|
switch (o.node.type) {
|
||||||
|
case 'html': {
|
||||||
|
walkerContext
|
||||||
|
.openNode(
|
||||||
|
{
|
||||||
|
type: 'block',
|
||||||
|
id: nanoid(),
|
||||||
|
flavour: 'affine:paragraph',
|
||||||
|
props: {
|
||||||
|
type: 'text',
|
||||||
|
text: {
|
||||||
|
'$blocksuite:internal:text$': true,
|
||||||
|
delta: [
|
||||||
|
{
|
||||||
|
insert: o.node.value,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [],
|
||||||
|
},
|
||||||
|
'children'
|
||||||
|
)
|
||||||
|
.closeNode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'paragraph': {
|
case 'paragraph': {
|
||||||
walkerContext.setGlobalContext(IN_PARAGRAPH_NODE_CONTEXT_KEY, true);
|
|
||||||
walkerContext
|
walkerContext
|
||||||
.openNode(
|
.openNode(
|
||||||
{
|
{
|
||||||
@@ -43,6 +71,7 @@ export const paragraphBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher =
|
|||||||
'children'
|
'children'
|
||||||
)
|
)
|
||||||
.closeNode();
|
.closeNode();
|
||||||
|
walkerContext.skipAllChildren();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'heading': {
|
case 'heading': {
|
||||||
@@ -90,12 +119,6 @@ export const paragraphBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave: (o, context) => {
|
|
||||||
if (o.node.type === 'paragraph') {
|
|
||||||
const { walkerContext } = context;
|
|
||||||
walkerContext.setGlobalContext(IN_PARAGRAPH_NODE_CONTEXT_KEY, false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
fromBlockSnapshot: {
|
fromBlockSnapshot: {
|
||||||
enter: (o, context) => {
|
enter: (o, context) => {
|
||||||
|
|||||||
@@ -46,8 +46,6 @@
|
|||||||
"@blocksuite/affine-widget-edgeless-auto-connect": "workspace:*",
|
"@blocksuite/affine-widget-edgeless-auto-connect": "workspace:*",
|
||||||
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
|
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
|
||||||
"@blocksuite/affine-widget-frame-title": "workspace:*",
|
"@blocksuite/affine-widget-frame-title": "workspace:*",
|
||||||
"@blocksuite/affine-widget-keyboard-toolbar": "workspace:*",
|
|
||||||
"@blocksuite/affine-widget-linked-doc": "workspace:*",
|
|
||||||
"@blocksuite/affine-widget-remote-selection": "workspace:*",
|
"@blocksuite/affine-widget-remote-selection": "workspace:*",
|
||||||
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*",
|
"@blocksuite/affine-widget-scroll-anchoring": "workspace:*",
|
||||||
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
||||||
|
|||||||
@@ -34,12 +34,6 @@ const NotionClipboardConfig = ClipboardAdapterConfigExtension({
|
|||||||
priority: 95,
|
priority: 95,
|
||||||
});
|
});
|
||||||
|
|
||||||
const HtmlClipboardConfig = ClipboardAdapterConfigExtension({
|
|
||||||
mimeType: 'text/html',
|
|
||||||
adapter: HtmlAdapter,
|
|
||||||
priority: 90,
|
|
||||||
});
|
|
||||||
|
|
||||||
const imageClipboardConfigs = [
|
const imageClipboardConfigs = [
|
||||||
'image/apng',
|
'image/apng',
|
||||||
'image/avif',
|
'image/avif',
|
||||||
@@ -52,14 +46,20 @@ const imageClipboardConfigs = [
|
|||||||
return ClipboardAdapterConfigExtension({
|
return ClipboardAdapterConfigExtension({
|
||||||
mimeType,
|
mimeType,
|
||||||
adapter: ImageAdapter,
|
adapter: ImageAdapter,
|
||||||
priority: 80,
|
priority: 85,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const PlainTextClipboardConfig = ClipboardAdapterConfigExtension({
|
const PlainTextClipboardConfig = ClipboardAdapterConfigExtension({
|
||||||
mimeType: 'text/plain',
|
mimeType: 'text/plain',
|
||||||
adapter: MixTextAdapter,
|
adapter: MixTextAdapter,
|
||||||
priority: 70,
|
priority: 80,
|
||||||
|
});
|
||||||
|
|
||||||
|
const HtmlClipboardConfig = ClipboardAdapterConfigExtension({
|
||||||
|
mimeType: 'text/html',
|
||||||
|
adapter: HtmlAdapter,
|
||||||
|
priority: 75,
|
||||||
});
|
});
|
||||||
|
|
||||||
const AttachmentClipboardConfig = ClipboardAdapterConfigExtension({
|
const AttachmentClipboardConfig = ClipboardAdapterConfigExtension({
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import {
|
|||||||
ToolbarRegistryExtension,
|
ToolbarRegistryExtension,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { dragHandleWidget } from '@blocksuite/affine-widget-drag-handle';
|
import { dragHandleWidget } from '@blocksuite/affine-widget-drag-handle';
|
||||||
import { linkedDocWidget } from '@blocksuite/affine-widget-linked-doc';
|
|
||||||
import { docRemoteSelectionWidget } from '@blocksuite/affine-widget-remote-selection';
|
import { docRemoteSelectionWidget } from '@blocksuite/affine-widget-remote-selection';
|
||||||
import { scrollAnchoringWidget } from '@blocksuite/affine-widget-scroll-anchoring';
|
import { scrollAnchoringWidget } from '@blocksuite/affine-widget-scroll-anchoring';
|
||||||
import { SlashMenuExtension } from '@blocksuite/affine-widget-slash-menu';
|
import { SlashMenuExtension } from '@blocksuite/affine-widget-slash-menu';
|
||||||
@@ -45,7 +44,7 @@ import { RootBlockAdapterExtensions } from '../adapters/extension';
|
|||||||
import { clipboardConfigs } from '../clipboard';
|
import { clipboardConfigs } from '../clipboard';
|
||||||
import { builtinToolbarConfig } from '../configs/toolbar';
|
import { builtinToolbarConfig } from '../configs/toolbar';
|
||||||
import { fallbackKeymap } from '../keyboard/keymap';
|
import { fallbackKeymap } from '../keyboard/keymap';
|
||||||
import { viewportOverlayWidget } from './widgets';
|
import { linkedDocWidget, modalWidget, viewportOverlayWidget } from './widgets';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Why do we add these extensions into CommonSpecs?
|
* Why do we add these extensions into CommonSpecs?
|
||||||
@@ -84,6 +83,7 @@ export const CommonSpecs: ExtensionType[] = [
|
|||||||
...clipboardConfigs,
|
...clipboardConfigs,
|
||||||
...EdgelessElementViews,
|
...EdgelessElementViews,
|
||||||
...EdgelessElementRendererExtension,
|
...EdgelessElementRendererExtension,
|
||||||
|
modalWidget,
|
||||||
SlashMenuExtension,
|
SlashMenuExtension,
|
||||||
linkedDocWidget,
|
linkedDocWidget,
|
||||||
dragHandleWidget,
|
dragHandleWidget,
|
||||||
|
|||||||
@@ -1,8 +1,20 @@
|
|||||||
import { WidgetViewExtension } from '@blocksuite/std';
|
import { WidgetViewExtension } from '@blocksuite/std';
|
||||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||||
|
|
||||||
|
import { AFFINE_LINKED_DOC_WIDGET } from '../widgets/linked-doc/config.js';
|
||||||
|
import { AFFINE_MODAL_WIDGET } from '../widgets/modal/modal.js';
|
||||||
import { AFFINE_VIEWPORT_OVERLAY_WIDGET } from '../widgets/viewport-overlay/viewport-overlay.js';
|
import { AFFINE_VIEWPORT_OVERLAY_WIDGET } from '../widgets/viewport-overlay/viewport-overlay.js';
|
||||||
|
|
||||||
|
export const modalWidget = WidgetViewExtension(
|
||||||
|
'affine:page',
|
||||||
|
AFFINE_MODAL_WIDGET,
|
||||||
|
literal`${unsafeStatic(AFFINE_MODAL_WIDGET)}`
|
||||||
|
);
|
||||||
|
export const linkedDocWidget = WidgetViewExtension(
|
||||||
|
'affine:page',
|
||||||
|
AFFINE_LINKED_DOC_WIDGET,
|
||||||
|
literal`${unsafeStatic(AFFINE_LINKED_DOC_WIDGET)}`
|
||||||
|
);
|
||||||
export const viewportOverlayWidget = WidgetViewExtension(
|
export const viewportOverlayWidget = WidgetViewExtension(
|
||||||
'affine:page',
|
'affine:page',
|
||||||
AFFINE_VIEWPORT_OVERLAY_WIDGET,
|
AFFINE_VIEWPORT_OVERLAY_WIDGET,
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
} from '@blocksuite/affine-block-embed';
|
} from '@blocksuite/affine-block-embed';
|
||||||
import { updateBlockType } from '@blocksuite/affine-block-note';
|
import { updateBlockType } from '@blocksuite/affine-block-note';
|
||||||
import { toast } from '@blocksuite/affine-components/toast';
|
import { toast } from '@blocksuite/affine-components/toast';
|
||||||
import { EditorChevronDown } from '@blocksuite/affine-components/toolbar';
|
|
||||||
import {
|
import {
|
||||||
deleteTextCommand,
|
deleteTextCommand,
|
||||||
formatBlockCommand,
|
formatBlockCommand,
|
||||||
@@ -41,6 +40,7 @@ import { ActionPlacement } from '@blocksuite/affine-shared/services';
|
|||||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||||
import { tableViewMeta } from '@blocksuite/data-view/view-presets';
|
import { tableViewMeta } from '@blocksuite/data-view/view-presets';
|
||||||
import {
|
import {
|
||||||
|
ArrowDownSmallIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
DatabaseTableViewIcon,
|
DatabaseTableViewIcon,
|
||||||
DeleteIcon,
|
DeleteIcon,
|
||||||
@@ -94,7 +94,7 @@ const conversionsActionGroup = {
|
|||||||
aria-label="Conversions"
|
aria-label="Conversions"
|
||||||
.tooltip="${'Turn into'}"
|
.tooltip="${'Turn into'}"
|
||||||
>
|
>
|
||||||
${conversion.icon} ${EditorChevronDown}
|
${conversion.icon} ${ArrowDownSmallIcon()}
|
||||||
</editor-icon-button>
|
</editor-icon-button>
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -88,9 +88,6 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
|
|||||||
p: () => {
|
p: () => {
|
||||||
this._setEdgelessTool('brush');
|
this._setEdgelessTool('brush');
|
||||||
},
|
},
|
||||||
'Shift-p': () => {
|
|
||||||
this._setEdgelessTool('highlighter');
|
|
||||||
},
|
|
||||||
e: () => {
|
e: () => {
|
||||||
this._setEdgelessTool('eraser');
|
this._setEdgelessTool('eraser');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import { css, html } from 'lit';
|
|||||||
import { query } from 'lit/decorators.js';
|
import { query } from 'lit/decorators.js';
|
||||||
import { repeat } from 'lit/directives/repeat.js';
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
|
|
||||||
|
import type { EdgelessRootBlockWidgetName } from '../types.js';
|
||||||
import type { EdgelessSelectedRectWidget } from './components/rects/edgeless-selected-rect.js';
|
import type { EdgelessSelectedRectWidget } from './components/rects/edgeless-selected-rect.js';
|
||||||
import { EdgelessPageKeyboardManager } from './edgeless-keyboard.js';
|
import { EdgelessPageKeyboardManager } from './edgeless-keyboard.js';
|
||||||
import type { EdgelessRootService } from './edgeless-root-service.js';
|
import type { EdgelessRootService } from './edgeless-root-service.js';
|
||||||
@@ -52,7 +53,8 @@ import { isCanvasElement } from './utils/query.js';
|
|||||||
|
|
||||||
export class EdgelessRootBlockComponent extends BlockComponent<
|
export class EdgelessRootBlockComponent extends BlockComponent<
|
||||||
RootBlockModel,
|
RootBlockModel,
|
||||||
EdgelessRootService
|
EdgelessRootService,
|
||||||
|
EdgelessRootBlockWidgetName
|
||||||
> {
|
> {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
affine-edgeless-root {
|
affine-edgeless-root {
|
||||||
@@ -349,7 +351,7 @@ export class EdgelessRootBlockComponent extends BlockComponent<
|
|||||||
private _initWheelEvent() {
|
private _initWheelEvent() {
|
||||||
this._disposables.add(
|
this._disposables.add(
|
||||||
this.dispatcher.add('wheel', ctx => {
|
this.dispatcher.add('wheel', ctx => {
|
||||||
const config = this.std.getOptional(EditorSettingProvider)?.setting$;
|
const config = this.std.getOptional(EditorSettingProvider);
|
||||||
const state = ctx.get('defaultState');
|
const state = ctx.get('defaultState');
|
||||||
const e = state.event as WheelEvent;
|
const e = state.event as WheelEvent;
|
||||||
const edgelessScrollZoom = config?.peek().edgelessScrollZoom ?? false;
|
const edgelessScrollZoom = config?.peek().edgelessScrollZoom ?? false;
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ import { css, html } from 'lit';
|
|||||||
import { query, state } from 'lit/decorators.js';
|
import { query, state } from 'lit/decorators.js';
|
||||||
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
|
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
|
||||||
|
|
||||||
|
import type { EdgelessRootBlockWidgetName } from '../types.js';
|
||||||
import type { EdgelessRootService } from './edgeless-root-service.js';
|
import type { EdgelessRootService } from './edgeless-root-service.js';
|
||||||
import { isCanvasElement } from './utils/query.js';
|
import { isCanvasElement } from './utils/query.js';
|
||||||
|
|
||||||
export class EdgelessRootPreviewBlockComponent extends BlockComponent<
|
export class EdgelessRootPreviewBlockComponent extends BlockComponent<
|
||||||
RootBlockModel,
|
RootBlockModel,
|
||||||
EdgelessRootService
|
EdgelessRootService,
|
||||||
|
EdgelessRootBlockWidgetName
|
||||||
> {
|
> {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
affine-edgeless-root-preview {
|
affine-edgeless-root-preview {
|
||||||
@@ -169,7 +171,7 @@ export class EdgelessRootPreviewBlockComponent extends BlockComponent<
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get _disableScheduleUpdate() {
|
private get _disableScheduleUpdate() {
|
||||||
const editorSetting = this.std.getOptional(EditorSettingProvider)?.setting$;
|
const editorSetting = this.std.getOptional(EditorSettingProvider);
|
||||||
|
|
||||||
return editorSetting?.peek().edgelessDisableScheduleUpdate ?? false;
|
return editorSetting?.peek().edgelessDisableScheduleUpdate ?? false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
type SurfaceBlockModel,
|
type SurfaceBlockModel,
|
||||||
type SurfaceContext,
|
type SurfaceContext,
|
||||||
} from '@blocksuite/affine-block-surface';
|
} from '@blocksuite/affine-block-surface';
|
||||||
|
import { TemplateJob } from '@blocksuite/affine-gfx-template';
|
||||||
import {
|
import {
|
||||||
type ConnectorElementModel,
|
type ConnectorElementModel,
|
||||||
RootBlockSchema,
|
RootBlockSchema,
|
||||||
@@ -38,6 +39,8 @@ export class EdgelessRootService extends RootService implements SurfaceContext {
|
|||||||
|
|
||||||
private readonly _surface: SurfaceBlockModel;
|
private readonly _surface: SurfaceBlockModel;
|
||||||
|
|
||||||
|
TemplateJob = TemplateJob;
|
||||||
|
|
||||||
get blocks(): GfxBlockElementModel[] {
|
get blocks(): GfxBlockElementModel[] {
|
||||||
return this.layer.blocks;
|
return this.layer.blocks;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import { effects as gfxShapeEffects } from '@blocksuite/affine-gfx-shape/effects
|
|||||||
import { effects as gfxTemplateEffects } from '@blocksuite/affine-gfx-template/effects';
|
import { effects as gfxTemplateEffects } from '@blocksuite/affine-gfx-template/effects';
|
||||||
import { effects as gfxCanvasTextEffects } from '@blocksuite/affine-gfx-text/effects';
|
import { effects as gfxCanvasTextEffects } from '@blocksuite/affine-gfx-text/effects';
|
||||||
import { effects as widgetEdgelessToolbarEffects } from '@blocksuite/affine-widget-edgeless-toolbar/effects';
|
import { effects as widgetEdgelessToolbarEffects } from '@blocksuite/affine-widget-edgeless-toolbar/effects';
|
||||||
import { effects as widgetMobileToolbarEffects } from '@blocksuite/affine-widget-keyboard-toolbar/effects';
|
|
||||||
import { effects as widgetLinkedDocEffects } from '@blocksuite/affine-widget-linked-doc/effects';
|
|
||||||
|
|
||||||
import { EdgelessAutoCompletePanel } from './edgeless/components/auto-complete/auto-complete-panel.js';
|
import { EdgelessAutoCompletePanel } from './edgeless/components/auto-complete/auto-complete-panel.js';
|
||||||
import { EdgelessAutoComplete } from './edgeless/components/auto-complete/edgeless-auto-complete.js';
|
import { EdgelessAutoComplete } from './edgeless/components/auto-complete/edgeless-auto-complete.js';
|
||||||
@@ -29,6 +27,7 @@ import { ToolbarArrowUpIcon } from './edgeless/components/toolbar/common/toolbar
|
|||||||
import { EdgelessDefaultToolButton } from './edgeless/components/toolbar/default/default-tool-button.js';
|
import { EdgelessDefaultToolButton } from './edgeless/components/toolbar/default/default-tool-button.js';
|
||||||
import { EdgelessLinkToolButton } from './edgeless/components/toolbar/link/link-tool-button.js';
|
import { EdgelessLinkToolButton } from './edgeless/components/toolbar/link/link-tool-button.js';
|
||||||
import {
|
import {
|
||||||
|
AffineModalWidget,
|
||||||
EdgelessRootBlockComponent,
|
EdgelessRootBlockComponent,
|
||||||
EdgelessRootPreviewBlockComponent,
|
EdgelessRootPreviewBlockComponent,
|
||||||
PageRootBlockComponent,
|
PageRootBlockComponent,
|
||||||
@@ -44,6 +43,11 @@ import {
|
|||||||
} from './widgets/edgeless-zoom-toolbar/index.js';
|
} from './widgets/edgeless-zoom-toolbar/index.js';
|
||||||
import { ZoomBarToggleButton } from './widgets/edgeless-zoom-toolbar/zoom-bar-toggle-button.js';
|
import { ZoomBarToggleButton } from './widgets/edgeless-zoom-toolbar/zoom-bar-toggle-button.js';
|
||||||
import { EdgelessZoomToolbar } from './widgets/edgeless-zoom-toolbar/zoom-toolbar.js';
|
import { EdgelessZoomToolbar } from './widgets/edgeless-zoom-toolbar/zoom-toolbar.js';
|
||||||
|
import { effects as widgetMobileToolbarEffects } from './widgets/keyboard-toolbar/effects.js';
|
||||||
|
import { effects as widgetLinkedDocEffects } from './widgets/linked-doc/effects.js';
|
||||||
|
import { Loader } from './widgets/linked-doc/import-doc/loader.js';
|
||||||
|
import { AffineCustomModal } from './widgets/modal/custom-modal.js';
|
||||||
|
import { AFFINE_MODAL_WIDGET } from './widgets/modal/modal.js';
|
||||||
import {
|
import {
|
||||||
AFFINE_PAGE_DRAGGING_AREA_WIDGET,
|
AFFINE_PAGE_DRAGGING_AREA_WIDGET,
|
||||||
AffinePageDraggingAreaWidget,
|
AffinePageDraggingAreaWidget,
|
||||||
@@ -89,6 +93,7 @@ function registerGfxEffects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function registerWidgets() {
|
function registerWidgets() {
|
||||||
|
customElements.define(AFFINE_MODAL_WIDGET, AffineModalWidget);
|
||||||
customElements.define(
|
customElements.define(
|
||||||
AFFINE_PAGE_DRAGGING_AREA_WIDGET,
|
AFFINE_PAGE_DRAGGING_AREA_WIDGET,
|
||||||
AffinePageDraggingAreaWidget
|
AffinePageDraggingAreaWidget
|
||||||
@@ -119,6 +124,12 @@ function registerEdgelessToolbarComponents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function registerMiscComponents() {
|
function registerMiscComponents() {
|
||||||
|
// Modal and menu components
|
||||||
|
customElements.define('affine-custom-modal', AffineCustomModal);
|
||||||
|
|
||||||
|
// Loading and preview components
|
||||||
|
customElements.define('loader-element', Loader);
|
||||||
|
|
||||||
// Toolbar and UI components
|
// Toolbar and UI components
|
||||||
customElements.define('edgeless-zoom-toolbar', EdgelessZoomToolbar);
|
customElements.define('edgeless-zoom-toolbar', EdgelessZoomToolbar);
|
||||||
customElements.define('zoom-bar-toggle-button', ZoomBarToggleButton);
|
customElements.define('zoom-bar-toggle-button', ZoomBarToggleButton);
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ export * from './page/page-root-block.js';
|
|||||||
export { PageRootService } from './page/page-root-service.js';
|
export { PageRootService } from './page/page-root-service.js';
|
||||||
export * from './page/page-root-spec.js';
|
export * from './page/page-root-spec.js';
|
||||||
export * from './preview/preview-root-block.js';
|
export * from './preview/preview-root-block.js';
|
||||||
|
export * from './root-config.js';
|
||||||
export { RootService } from './root-service.js';
|
export { RootService } from './root-service.js';
|
||||||
|
export * from './transformers/index.js';
|
||||||
export * from './types.js';
|
export * from './types.js';
|
||||||
export * from './utils/index.js';
|
export * from './utils/index.js';
|
||||||
export * from './widgets/index.js';
|
export * from './widgets/index.js';
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { css, html } from 'lit';
|
|||||||
import { query } from 'lit/decorators.js';
|
import { query } from 'lit/decorators.js';
|
||||||
import { repeat } from 'lit/directives/repeat.js';
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
|
|
||||||
|
import type { PageRootBlockWidgetName } from '../index.js';
|
||||||
import { PageKeyboardManager } from '../keyboard/keyboard-manager.js';
|
import { PageKeyboardManager } from '../keyboard/keyboard-manager.js';
|
||||||
import type { PageRootService } from './page-root-service.js';
|
import type { PageRootService } from './page-root-service.js';
|
||||||
|
|
||||||
@@ -51,7 +52,8 @@ function testClickOnBlankArea(
|
|||||||
|
|
||||||
export class PageRootBlockComponent extends BlockComponent<
|
export class PageRootBlockComponent extends BlockComponent<
|
||||||
RootBlockModel,
|
RootBlockModel,
|
||||||
PageRootService
|
PageRootService,
|
||||||
|
PageRootBlockWidgetName
|
||||||
> {
|
> {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
editor-host:has(> affine-page-root, * > affine-page-root) {
|
editor-host:has(> affine-page-root, * > affine-page-root) {
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
import { ViewportElementExtension } from '@blocksuite/affine-shared/services';
|
import { ViewportElementExtension } from '@blocksuite/affine-shared/services';
|
||||||
import { keyboardToolbarWidget } from '@blocksuite/affine-widget-keyboard-toolbar';
|
|
||||||
import { IS_MOBILE } from '@blocksuite/global/env';
|
|
||||||
import { BlockViewExtension, WidgetViewExtension } from '@blocksuite/std';
|
import { BlockViewExtension, WidgetViewExtension } from '@blocksuite/std';
|
||||||
import type { ExtensionType } from '@blocksuite/store';
|
import type { ExtensionType } from '@blocksuite/store';
|
||||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||||
|
|
||||||
import { PageClipboard } from '../clipboard/page-clipboard.js';
|
import { PageClipboard } from '../clipboard/page-clipboard.js';
|
||||||
import { CommonSpecs } from '../common-specs/index.js';
|
import { CommonSpecs } from '../common-specs/index.js';
|
||||||
|
import { AFFINE_KEYBOARD_TOOLBAR_WIDGET } from '../widgets/keyboard-toolbar/index.js';
|
||||||
import { AFFINE_PAGE_DRAGGING_AREA_WIDGET } from '../widgets/page-dragging-area/page-dragging-area.js';
|
import { AFFINE_PAGE_DRAGGING_AREA_WIDGET } from '../widgets/page-dragging-area/page-dragging-area.js';
|
||||||
import { PageRootService } from './page-root-service.js';
|
import { PageRootService } from './page-root-service.js';
|
||||||
|
|
||||||
|
export const keyboardToolbarWidget = WidgetViewExtension(
|
||||||
|
'affine:page',
|
||||||
|
AFFINE_KEYBOARD_TOOLBAR_WIDGET,
|
||||||
|
literal`${unsafeStatic(AFFINE_KEYBOARD_TOOLBAR_WIDGET)}`
|
||||||
|
);
|
||||||
|
|
||||||
export const pageDraggingAreaWidget = WidgetViewExtension(
|
export const pageDraggingAreaWidget = WidgetViewExtension(
|
||||||
'affine:page',
|
'affine:page',
|
||||||
AFFINE_PAGE_DRAGGING_AREA_WIDGET,
|
AFFINE_PAGE_DRAGGING_AREA_WIDGET,
|
||||||
@@ -26,7 +31,7 @@ const PageCommonExtension: ExtensionType[] = [
|
|||||||
export const PageRootBlockSpec: ExtensionType[] = [
|
export const PageRootBlockSpec: ExtensionType[] = [
|
||||||
...PageCommonExtension,
|
...PageCommonExtension,
|
||||||
BlockViewExtension('affine:page', literal`affine-page-root`),
|
BlockViewExtension('affine:page', literal`affine-page-root`),
|
||||||
IS_MOBILE ? [keyboardToolbarWidget] : [],
|
keyboardToolbarWidget,
|
||||||
PageClipboard,
|
PageClipboard,
|
||||||
].flat();
|
].flat();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ConfigExtensionFactory } from '@blocksuite/std';
|
||||||
|
|
||||||
|
import type { KeyboardToolbarConfig } from './widgets/keyboard-toolbar/config.js';
|
||||||
|
import type { LinkedWidgetConfig } from './widgets/linked-doc/index.js';
|
||||||
|
|
||||||
|
export interface RootBlockConfig {
|
||||||
|
linkedWidget?: Partial<LinkedWidgetConfig>;
|
||||||
|
keyboardToolbar?: Partial<KeyboardToolbarConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RootBlockConfigExtension =
|
||||||
|
ConfigExtensionFactory<RootBlockConfig>('affine:root-block');
|
||||||
@@ -1,6 +1,48 @@
|
|||||||
import { RootBlockSchema } from '@blocksuite/affine-model';
|
import { RootBlockSchema } from '@blocksuite/affine-model';
|
||||||
|
import {
|
||||||
|
getBlockSelectionsCommand,
|
||||||
|
getImageSelectionsCommand,
|
||||||
|
getSelectedBlocksCommand,
|
||||||
|
getTextSelectionCommand,
|
||||||
|
} from '@blocksuite/affine-shared/commands';
|
||||||
|
import type { BlockComponent } from '@blocksuite/std';
|
||||||
import { BlockService } from '@blocksuite/std';
|
import { BlockService } from '@blocksuite/std';
|
||||||
|
|
||||||
|
import type { RootBlockComponent } from './types.js';
|
||||||
|
|
||||||
export abstract class RootService extends BlockService {
|
export abstract class RootService extends BlockService {
|
||||||
static override readonly flavour = RootBlockSchema.model.flavour;
|
static override readonly flavour = RootBlockSchema.model.flavour;
|
||||||
|
|
||||||
|
get selectedBlocks() {
|
||||||
|
let result: BlockComponent[] = [];
|
||||||
|
this.std.command
|
||||||
|
.chain()
|
||||||
|
.tryAll(chain => [
|
||||||
|
chain.pipe(getTextSelectionCommand),
|
||||||
|
chain.pipe(getImageSelectionsCommand),
|
||||||
|
chain.pipe(getBlockSelectionsCommand),
|
||||||
|
])
|
||||||
|
.pipe(getSelectedBlocksCommand)
|
||||||
|
.pipe(({ selectedBlocks }) => {
|
||||||
|
if (!selectedBlocks) return;
|
||||||
|
result = selectedBlocks;
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
get selectedModels() {
|
||||||
|
return this.selectedBlocks.map(block => block.model);
|
||||||
|
}
|
||||||
|
|
||||||
|
get viewportElement() {
|
||||||
|
const rootId = this.std.store.root?.id;
|
||||||
|
if (!rootId) return null;
|
||||||
|
const rootComponent = this.std.view.getBlock(
|
||||||
|
rootId
|
||||||
|
) as RootBlockComponent | null;
|
||||||
|
if (!rootComponent) return null;
|
||||||
|
const viewportElement = rootComponent.viewportElement;
|
||||||
|
return viewportElement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ import { sha } from '@blocksuite/global/utils';
|
|||||||
import type { DocSnapshot, Schema, Store, Workspace } from '@blocksuite/store';
|
import type { DocSnapshot, Schema, Store, Workspace } from '@blocksuite/store';
|
||||||
import { extMimeMap, getAssetName, Transformer } from '@blocksuite/store';
|
import { extMimeMap, getAssetName, Transformer } from '@blocksuite/store';
|
||||||
|
|
||||||
import { download, Unzip, Zip } from './utils.js';
|
import { download, Unzip, Zip } from '../transformers/utils.js';
|
||||||
|
|
||||||
async function exportDocs(
|
async function exportDocs(
|
||||||
collection: Workspace,
|
collection: Workspace,
|
||||||
@@ -1,5 +1,40 @@
|
|||||||
|
import type { AFFINE_DRAG_HANDLE_WIDGET } from '@blocksuite/affine-widget-drag-handle';
|
||||||
|
import type { AFFINE_FRAME_TITLE_WIDGET } from '@blocksuite/affine-widget-frame-title';
|
||||||
|
import type {
|
||||||
|
AFFINE_DOC_REMOTE_SELECTION_WIDGET,
|
||||||
|
AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET,
|
||||||
|
} from '@blocksuite/affine-widget-remote-selection';
|
||||||
|
import type { AFFINE_SLASH_MENU_WIDGET } from '@blocksuite/affine-widget-slash-menu';
|
||||||
|
|
||||||
import type { EdgelessRootBlockComponent } from './edgeless/edgeless-root-block.js';
|
import type { EdgelessRootBlockComponent } from './edgeless/edgeless-root-block.js';
|
||||||
import type { PageRootBlockComponent } from './page/page-root-block.js';
|
import type { PageRootBlockComponent } from './page/page-root-block.js';
|
||||||
|
import type { AFFINE_EDGELESS_ZOOM_TOOLBAR_WIDGET } from './widgets/edgeless-zoom-toolbar/index.js';
|
||||||
|
import type { AFFINE_KEYBOARD_TOOLBAR_WIDGET } from './widgets/index.js';
|
||||||
|
import type { AFFINE_LINKED_DOC_WIDGET } from './widgets/linked-doc/config.js';
|
||||||
|
import type { AFFINE_MODAL_WIDGET } from './widgets/modal/modal.js';
|
||||||
|
import type { AFFINE_PAGE_DRAGGING_AREA_WIDGET } from './widgets/page-dragging-area/page-dragging-area.js';
|
||||||
|
import type { AFFINE_VIEWPORT_OVERLAY_WIDGET } from './widgets/viewport-overlay/viewport-overlay.js';
|
||||||
|
|
||||||
|
export type PageRootBlockWidgetName =
|
||||||
|
| typeof AFFINE_KEYBOARD_TOOLBAR_WIDGET
|
||||||
|
| typeof AFFINE_MODAL_WIDGET
|
||||||
|
| typeof AFFINE_SLASH_MENU_WIDGET
|
||||||
|
| typeof AFFINE_LINKED_DOC_WIDGET
|
||||||
|
| typeof AFFINE_PAGE_DRAGGING_AREA_WIDGET
|
||||||
|
| typeof AFFINE_DRAG_HANDLE_WIDGET
|
||||||
|
| typeof AFFINE_DOC_REMOTE_SELECTION_WIDGET
|
||||||
|
| typeof AFFINE_VIEWPORT_OVERLAY_WIDGET;
|
||||||
|
|
||||||
|
export type EdgelessRootBlockWidgetName =
|
||||||
|
| typeof AFFINE_MODAL_WIDGET
|
||||||
|
| typeof AFFINE_SLASH_MENU_WIDGET
|
||||||
|
| typeof AFFINE_LINKED_DOC_WIDGET
|
||||||
|
| typeof AFFINE_DRAG_HANDLE_WIDGET
|
||||||
|
| typeof AFFINE_DOC_REMOTE_SELECTION_WIDGET
|
||||||
|
| typeof AFFINE_EDGELESS_REMOTE_SELECTION_WIDGET
|
||||||
|
| typeof AFFINE_EDGELESS_ZOOM_TOOLBAR_WIDGET
|
||||||
|
| typeof AFFINE_VIEWPORT_OVERLAY_WIDGET
|
||||||
|
| typeof AFFINE_FRAME_TITLE_WIDGET;
|
||||||
|
|
||||||
export type RootBlockComponent =
|
export type RootBlockComponent =
|
||||||
| PageRootBlockComponent
|
| PageRootBlockComponent
|
||||||
|
|||||||
@@ -1,4 +1,18 @@
|
|||||||
export { AffineEdgelessZoomToolbarWidget } from './edgeless-zoom-toolbar/index.js';
|
export { AffineEdgelessZoomToolbarWidget } from './edgeless-zoom-toolbar/index.js';
|
||||||
|
export * from './keyboard-toolbar/index.js';
|
||||||
|
export {
|
||||||
|
type LinkedMenuAction,
|
||||||
|
type LinkedMenuGroup,
|
||||||
|
type LinkedMenuItem,
|
||||||
|
type LinkedWidgetConfig,
|
||||||
|
LinkedWidgetUtils,
|
||||||
|
} from './linked-doc/config.js';
|
||||||
|
export {
|
||||||
|
// It's used in the AFFiNE!
|
||||||
|
showImportModal,
|
||||||
|
} from './linked-doc/import-doc/index.js';
|
||||||
|
export { AffineLinkedDocWidget } from './linked-doc/index.js';
|
||||||
|
export { AffineModalWidget } from './modal/modal.js';
|
||||||
export { AffinePageDraggingAreaWidget } from './page-dragging-area/page-dragging-area.js';
|
export { AffinePageDraggingAreaWidget } from './page-dragging-area/page-dragging-area.js';
|
||||||
export * from './viewport-overlay/viewport-overlay.js';
|
export * from './viewport-overlay/viewport-overlay.js';
|
||||||
export { AffineFrameTitleWidget } from '@blocksuite/affine-widget-frame-title';
|
export { AffineFrameTitleWidget } from '@blocksuite/affine-widget-frame-title';
|
||||||
|
|||||||
+41
-19
@@ -34,7 +34,10 @@ import {
|
|||||||
toggleUnderline,
|
toggleUnderline,
|
||||||
} from '@blocksuite/affine-inline-preset';
|
} from '@blocksuite/affine-inline-preset';
|
||||||
import type { FrameBlockModel } from '@blocksuite/affine-model';
|
import type { FrameBlockModel } from '@blocksuite/affine-model';
|
||||||
import { insertContent } from '@blocksuite/affine-rich-text';
|
import {
|
||||||
|
getInlineEditorByModel,
|
||||||
|
insertContent,
|
||||||
|
} from '@blocksuite/affine-rich-text';
|
||||||
import {
|
import {
|
||||||
copySelectedModelsCommand,
|
copySelectedModelsCommand,
|
||||||
deleteSelectedModelsCommand,
|
deleteSelectedModelsCommand,
|
||||||
@@ -52,7 +55,6 @@ import {
|
|||||||
openFileOrFiles,
|
openFileOrFiles,
|
||||||
type Signal,
|
type Signal,
|
||||||
} from '@blocksuite/affine-shared/utils';
|
} from '@blocksuite/affine-shared/utils';
|
||||||
import type { AffineLinkedDocWidget } from '@blocksuite/affine-widget-linked-doc';
|
|
||||||
import { viewPresets } from '@blocksuite/data-view/view-presets';
|
import { viewPresets } from '@blocksuite/data-view/view-presets';
|
||||||
import { assertType } from '@blocksuite/global/utils';
|
import { assertType } from '@blocksuite/global/utils';
|
||||||
import {
|
import {
|
||||||
@@ -97,15 +99,13 @@ import {
|
|||||||
YesterdayIcon,
|
YesterdayIcon,
|
||||||
YoutubeDuotoneIcon,
|
YoutubeDuotoneIcon,
|
||||||
} from '@blocksuite/icons/lit';
|
} from '@blocksuite/icons/lit';
|
||||||
import {
|
import type { BlockStdScope } from '@blocksuite/std';
|
||||||
type BlockComponent,
|
|
||||||
type BlockStdScope,
|
|
||||||
ConfigExtensionFactory,
|
|
||||||
} from '@blocksuite/std';
|
|
||||||
import { computed } from '@preact/signals-core';
|
import { computed } from '@preact/signals-core';
|
||||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
import type { TemplateResult } from 'lit';
|
import type { TemplateResult } from 'lit';
|
||||||
|
|
||||||
|
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
|
||||||
|
import type { AffineLinkedDocWidget } from '../linked-doc/index.js';
|
||||||
import {
|
import {
|
||||||
FigmaDuotoneIcon,
|
FigmaDuotoneIcon,
|
||||||
HeadingIcon,
|
HeadingIcon,
|
||||||
@@ -159,7 +159,7 @@ export type KeyboardSubToolbarConfig = {
|
|||||||
|
|
||||||
export type KeyboardToolbarContext = {
|
export type KeyboardToolbarContext = {
|
||||||
std: BlockStdScope;
|
std: BlockStdScope;
|
||||||
rootComponent: BlockComponent;
|
rootComponent: PageRootBlockComponent;
|
||||||
/**
|
/**
|
||||||
* Close tool bar, and blur the focus if blur is true, default is false
|
* Close tool bar, and blur the focus if blur is true, default is false
|
||||||
*/
|
*/
|
||||||
@@ -348,11 +348,35 @@ const pageToolGroup: KeyboardToolPanelGroup = {
|
|||||||
);
|
);
|
||||||
if (!linkedDocWidget) return;
|
if (!linkedDocWidget) return;
|
||||||
assertType<AffineLinkedDocWidget>(linkedDocWidget);
|
assertType<AffineLinkedDocWidget>(linkedDocWidget);
|
||||||
linkedDocWidget.show({
|
|
||||||
mode: 'mobile',
|
const triggerKey = linkedDocWidget.config.triggerKeys[0];
|
||||||
addTriggerKey: true,
|
|
||||||
});
|
std.command
|
||||||
closeToolPanel();
|
.chain()
|
||||||
|
.pipe(getSelectedModelsCommand)
|
||||||
|
.pipe(ctx => {
|
||||||
|
const { selectedModels } = ctx;
|
||||||
|
if (!selectedModels?.length) return;
|
||||||
|
|
||||||
|
const currentModel = selectedModels[0];
|
||||||
|
insertContent(std, currentModel, triggerKey);
|
||||||
|
|
||||||
|
const inlineEditor = getInlineEditorByModel(std, currentModel);
|
||||||
|
// Wait for range to be updated
|
||||||
|
if (inlineEditor) {
|
||||||
|
const subscription = inlineEditor.slots.inlineRangeSync.subscribe(
|
||||||
|
() => {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
linkedDocWidget.show({
|
||||||
|
mode: 'mobile',
|
||||||
|
addTriggerKey: true,
|
||||||
|
});
|
||||||
|
closeToolPanel();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -404,7 +428,8 @@ const contentMediaToolGroup: KeyboardToolPanelGroup = {
|
|||||||
{
|
{
|
||||||
name: 'Attachment',
|
name: 'Attachment',
|
||||||
icon: AttachmentIcon(),
|
icon: AttachmentIcon(),
|
||||||
showWhen: () => false,
|
showWhen: ({ std }) =>
|
||||||
|
std.store.schema.flavourSchemaMap.has('affine:attachment'),
|
||||||
action: async ({ std }) => {
|
action: async ({ std }) => {
|
||||||
const [_, { selectedModels }] = std.command.exec(
|
const [_, { selectedModels }] = std.command.exec(
|
||||||
getSelectedModelsCommand
|
getSelectedModelsCommand
|
||||||
@@ -1004,7 +1029,8 @@ export const defaultKeyboardToolbarConfig: KeyboardToolbarConfig = {
|
|||||||
{
|
{
|
||||||
name: 'Attachment',
|
name: 'Attachment',
|
||||||
icon: AttachmentIcon(),
|
icon: AttachmentIcon(),
|
||||||
showWhen: () => false,
|
showWhen: ({ std }) =>
|
||||||
|
std.store.schema.flavourSchemaMap.has('affine:attachment'),
|
||||||
action: async ({ std }) => {
|
action: async ({ std }) => {
|
||||||
const [_, { selectedModels }] = std.command.exec(
|
const [_, { selectedModels }] = std.command.exec(
|
||||||
getSelectedModelsCommand
|
getSelectedModelsCommand
|
||||||
@@ -1129,7 +1155,3 @@ export const defaultKeyboardToolbarConfig: KeyboardToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KeyboardToolbarConfigExtension = ConfigExtensionFactory<
|
|
||||||
Partial<KeyboardToolbarConfig>
|
|
||||||
>('affine:keyboard-toolbar');
|
|
||||||
+21
-33
@@ -2,20 +2,18 @@ import { getDocTitleByEditorHost } from '@blocksuite/affine-fragment-doc-title';
|
|||||||
import type { RootBlockModel } from '@blocksuite/affine-model';
|
import type { RootBlockModel } from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
FeatureFlagService,
|
FeatureFlagService,
|
||||||
isVirtualKeyboardProviderWithAction,
|
|
||||||
VirtualKeyboardProvider,
|
VirtualKeyboardProvider,
|
||||||
type VirtualKeyboardProviderWithAction,
|
type VirtualKeyboardProviderWithAction,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { IS_MOBILE } from '@blocksuite/global/env';
|
import { IS_MOBILE } from '@blocksuite/global/env';
|
||||||
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/std';
|
import { WidgetComponent } from '@blocksuite/std';
|
||||||
import { effect, signal } from '@preact/signals-core';
|
import { effect, signal } from '@preact/signals-core';
|
||||||
import { html, nothing } from 'lit';
|
import { html, nothing } from 'lit';
|
||||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
|
||||||
|
|
||||||
import {
|
import { RootBlockConfigExtension } from '../../root-config.js';
|
||||||
defaultKeyboardToolbarConfig,
|
import { defaultKeyboardToolbarConfig } from './config.js';
|
||||||
KeyboardToolbarConfigExtension,
|
|
||||||
} from './config.js';
|
export * from './config.js';
|
||||||
|
|
||||||
export const AFFINE_KEYBOARD_TOOLBAR_WIDGET = 'affine-keyboard-toolbar-widget';
|
export const AFFINE_KEYBOARD_TOOLBAR_WIDGET = 'affine-keyboard-toolbar-widget';
|
||||||
|
|
||||||
@@ -36,10 +34,7 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
|
|||||||
|
|
||||||
private _initialInputMode: string = '';
|
private _initialInputMode: string = '';
|
||||||
|
|
||||||
get keyboard(): VirtualKeyboardProviderWithAction & { fallback?: boolean } {
|
get keyboard(): VirtualKeyboardProviderWithAction {
|
||||||
const provider = this.std.get(VirtualKeyboardProvider);
|
|
||||||
if (isVirtualKeyboardProviderWithAction(provider)) return provider;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// fallback keyboard actions
|
// fallback keyboard actions
|
||||||
show: () => {
|
show: () => {
|
||||||
@@ -54,7 +49,7 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
|
|||||||
rootComponent.inputMode = 'none';
|
rootComponent.inputMode = 'none';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
...provider,
|
...this.std.get(VirtualKeyboardProvider),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +60,8 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
|
|||||||
get config() {
|
get config() {
|
||||||
return {
|
return {
|
||||||
...defaultKeyboardToolbarConfig,
|
...defaultKeyboardToolbarConfig,
|
||||||
...this.std.getOptional(KeyboardToolbarConfigExtension.identifier),
|
...this.std.getOptional(RootBlockConfigExtension.identifier)
|
||||||
|
?.keyboardToolbar,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +70,10 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
|
|||||||
|
|
||||||
const rootComponent = this.block?.rootComponent;
|
const rootComponent = this.block?.rootComponent;
|
||||||
if (rootComponent) {
|
if (rootComponent) {
|
||||||
|
this._initialInputMode = rootComponent.inputMode;
|
||||||
|
this.disposables.add(() => {
|
||||||
|
rootComponent.inputMode = this._initialInputMode;
|
||||||
|
});
|
||||||
this.disposables.addFromEvent(rootComponent, 'focus', () => {
|
this.disposables.addFromEvent(rootComponent, 'focus', () => {
|
||||||
this._show$.value = true;
|
this._show$.value = true;
|
||||||
});
|
});
|
||||||
@@ -81,20 +81,14 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
|
|||||||
this._show$.value = false;
|
this._show$.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.keyboard.fallback) {
|
this.disposables.add(
|
||||||
this._initialInputMode = rootComponent.inputMode;
|
effect(() => {
|
||||||
this.disposables.add(() => {
|
// recover input mode when keyboard toolbar is hidden
|
||||||
rootComponent.inputMode = this._initialInputMode;
|
if (!this._show$.value) {
|
||||||
});
|
rootComponent.inputMode = this._initialInputMode;
|
||||||
this.disposables.add(
|
}
|
||||||
effect(() => {
|
})
|
||||||
// recover input mode when keyboard toolbar is hidden
|
);
|
||||||
if (!this._show$.value) {
|
|
||||||
rootComponent.inputMode = this._initialInputMode;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._docTitle) {
|
if (this._docTitle) {
|
||||||
@@ -134,12 +128,6 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent<RootBlockModel>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const keyboardToolbarWidget = WidgetViewExtension(
|
|
||||||
'affine:page',
|
|
||||||
AFFINE_KEYBOARD_TOOLBAR_WIDGET,
|
|
||||||
literal`${unsafeStatic(AFFINE_KEYBOARD_TOOLBAR_WIDGET)}`
|
|
||||||
);
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
[AFFINE_KEYBOARD_TOOLBAR_WIDGET]: AffineKeyboardToolbarWidget;
|
[AFFINE_KEYBOARD_TOOLBAR_WIDGET]: AffineKeyboardToolbarWidget;
|
||||||
+6
-14
@@ -3,7 +3,6 @@ import { type VirtualKeyboardProviderWithAction } from '@blocksuite/affine-share
|
|||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
||||||
import { ArrowLeftBigIcon, KeyboardIcon } from '@blocksuite/icons/lit';
|
import { ArrowLeftBigIcon, KeyboardIcon } from '@blocksuite/icons/lit';
|
||||||
import {
|
import {
|
||||||
BlockComponent,
|
|
||||||
PropTypes,
|
PropTypes,
|
||||||
requiredProperties,
|
requiredProperties,
|
||||||
ShadowlessElement,
|
ShadowlessElement,
|
||||||
@@ -15,6 +14,7 @@ import { repeat } from 'lit/directives/repeat.js';
|
|||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
import { when } from 'lit/directives/when.js';
|
import { when } from 'lit/directives/when.js';
|
||||||
|
|
||||||
|
import { PageRootBlockComponent } from '../../page/page-root-block';
|
||||||
import type {
|
import type {
|
||||||
KeyboardIconType,
|
KeyboardIconType,
|
||||||
KeyboardToolbarConfig,
|
KeyboardToolbarConfig,
|
||||||
@@ -34,7 +34,7 @@ export const AFFINE_KEYBOARD_TOOLBAR = 'affine-keyboard-toolbar';
|
|||||||
|
|
||||||
@requiredProperties({
|
@requiredProperties({
|
||||||
config: PropTypes.object,
|
config: PropTypes.object,
|
||||||
rootComponent: PropTypes.instanceOf(BlockComponent),
|
rootComponent: PropTypes.instanceOf(PageRootBlockComponent),
|
||||||
})
|
})
|
||||||
export class AffineKeyboardToolbar extends SignalWatcher(
|
export class AffineKeyboardToolbar extends SignalWatcher(
|
||||||
WithDisposable(ShadowlessElement)
|
WithDisposable(ShadowlessElement)
|
||||||
@@ -55,8 +55,10 @@ export class AffineKeyboardToolbar extends SignalWatcher(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly _closeToolPanel = () => {
|
private readonly _closeToolPanel = () => {
|
||||||
|
if (!this.panelOpened) return;
|
||||||
|
|
||||||
this._currentPanelIndex$.value = -1;
|
this._currentPanelIndex$.value = -1;
|
||||||
if (!this.keyboard.visible$.peek()) this.keyboard.show();
|
this.keyboard.show();
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _currentPanelIndex$ = signal(-1);
|
private readonly _currentPanelIndex$ = signal(-1);
|
||||||
@@ -253,16 +255,6 @@ export class AffineKeyboardToolbar extends SignalWatcher(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.disposables.add(
|
|
||||||
effect(() => {
|
|
||||||
// sometime the keyboard will auto show when user click into different paragraph in Android,
|
|
||||||
// so we need to close the tool panel explicitly when the keyboard is visible
|
|
||||||
if (this.keyboard.visible$.value) {
|
|
||||||
this._closeToolPanel();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
this._watchAutoShow();
|
this._watchAutoShow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,5 +330,5 @@ export class AffineKeyboardToolbar extends SignalWatcher(
|
|||||||
accessor config!: KeyboardToolbarConfig;
|
accessor config!: KeyboardToolbarConfig;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor rootComponent!: BlockComponent;
|
accessor rootComponent!: PageRootBlockComponent;
|
||||||
}
|
}
|
||||||
+66
-80
@@ -16,12 +16,7 @@ import {
|
|||||||
isFuzzyMatch,
|
isFuzzyMatch,
|
||||||
type Signal,
|
type Signal,
|
||||||
} from '@blocksuite/affine-shared/utils';
|
} from '@blocksuite/affine-shared/utils';
|
||||||
import { IS_MOBILE } from '@blocksuite/global/env';
|
import type { BlockStdScope, EditorHost } from '@blocksuite/std';
|
||||||
import {
|
|
||||||
type BlockStdScope,
|
|
||||||
ConfigExtensionFactory,
|
|
||||||
type EditorHost,
|
|
||||||
} from '@blocksuite/std';
|
|
||||||
import type { InlineRange } from '@blocksuite/std/inline';
|
import type { InlineRange } from '@blocksuite/std/inline';
|
||||||
import type { TemplateResult } from 'lit';
|
import type { TemplateResult } from 'lit';
|
||||||
|
|
||||||
@@ -112,7 +107,6 @@ export type LinkedDocContext = {
|
|||||||
std: BlockStdScope;
|
std: BlockStdScope;
|
||||||
inlineEditor: AffineInlineEditor;
|
inlineEditor: AffineInlineEditor;
|
||||||
startRange: InlineRange;
|
startRange: InlineRange;
|
||||||
startNativeRange: Range;
|
|
||||||
triggerKey: string;
|
triggerKey: string;
|
||||||
config: LinkedWidgetConfig;
|
config: LinkedWidgetConfig;
|
||||||
close: () => void;
|
close: () => void;
|
||||||
@@ -177,77 +171,73 @@ export function createNewDocMenuGroup(
|
|||||||
docName.slice(0, DISPLAY_NAME_LENGTH) +
|
docName.slice(0, DISPLAY_NAME_LENGTH) +
|
||||||
(docName.length > DISPLAY_NAME_LENGTH ? '..' : '');
|
(docName.length > DISPLAY_NAME_LENGTH ? '..' : '');
|
||||||
|
|
||||||
const items: LinkedMenuItem[] = [
|
|
||||||
{
|
|
||||||
key: 'create',
|
|
||||||
name: `Create "${displayDocName}" doc`,
|
|
||||||
icon: NewDocIcon,
|
|
||||||
action: () => {
|
|
||||||
abort();
|
|
||||||
const docName = query;
|
|
||||||
const newDoc = createDefaultDoc(doc.workspace, {
|
|
||||||
title: docName,
|
|
||||||
});
|
|
||||||
insertLinkedNode({
|
|
||||||
inlineEditor,
|
|
||||||
docId: newDoc.id,
|
|
||||||
});
|
|
||||||
const telemetryService = editorHost.std.getOptional(TelemetryProvider);
|
|
||||||
telemetryService?.track('LinkedDocCreated', {
|
|
||||||
control: 'new doc',
|
|
||||||
module: 'inline @',
|
|
||||||
type: 'doc',
|
|
||||||
other: 'new doc',
|
|
||||||
});
|
|
||||||
telemetryService?.track('DocCreated', {
|
|
||||||
control: 'new doc',
|
|
||||||
module: 'inline @',
|
|
||||||
type: 'doc',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!IS_MOBILE) {
|
|
||||||
items.push({
|
|
||||||
key: 'import',
|
|
||||||
name: 'Import',
|
|
||||||
icon: ImportIcon,
|
|
||||||
action: () => {
|
|
||||||
abort();
|
|
||||||
const onSuccess = (
|
|
||||||
docIds: string[],
|
|
||||||
options: {
|
|
||||||
importedCount: number;
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
toast(
|
|
||||||
editorHost,
|
|
||||||
`Successfully imported ${options.importedCount} Doc${options.importedCount > 1 ? 's' : ''}.`
|
|
||||||
);
|
|
||||||
for (const docId of docIds) {
|
|
||||||
insertLinkedNode({
|
|
||||||
inlineEditor,
|
|
||||||
docId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onFail = (message: string) => {
|
|
||||||
toast(editorHost, message);
|
|
||||||
};
|
|
||||||
showImportModal({
|
|
||||||
collection: doc.workspace,
|
|
||||||
schema: doc.schema,
|
|
||||||
onSuccess,
|
|
||||||
onFail,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'New Doc',
|
name: 'New Doc',
|
||||||
items,
|
items: [
|
||||||
|
{
|
||||||
|
key: 'create',
|
||||||
|
name: `Create "${displayDocName}" doc`,
|
||||||
|
icon: NewDocIcon,
|
||||||
|
action: () => {
|
||||||
|
abort();
|
||||||
|
const docName = query;
|
||||||
|
const newDoc = createDefaultDoc(doc.workspace, {
|
||||||
|
title: docName,
|
||||||
|
});
|
||||||
|
insertLinkedNode({
|
||||||
|
inlineEditor,
|
||||||
|
docId: newDoc.id,
|
||||||
|
});
|
||||||
|
const telemetryService =
|
||||||
|
editorHost.std.getOptional(TelemetryProvider);
|
||||||
|
telemetryService?.track('LinkedDocCreated', {
|
||||||
|
control: 'new doc',
|
||||||
|
module: 'inline @',
|
||||||
|
type: 'doc',
|
||||||
|
other: 'new doc',
|
||||||
|
});
|
||||||
|
telemetryService?.track('DocCreated', {
|
||||||
|
control: 'new doc',
|
||||||
|
module: 'inline @',
|
||||||
|
type: 'doc',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'import',
|
||||||
|
name: 'Import',
|
||||||
|
icon: ImportIcon,
|
||||||
|
action: () => {
|
||||||
|
abort();
|
||||||
|
const onSuccess = (
|
||||||
|
docIds: string[],
|
||||||
|
options: {
|
||||||
|
importedCount: number;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
toast(
|
||||||
|
editorHost,
|
||||||
|
`Successfully imported ${options.importedCount} Doc${options.importedCount > 1 ? 's' : ''}.`
|
||||||
|
);
|
||||||
|
for (const docId of docIds) {
|
||||||
|
insertLinkedNode({
|
||||||
|
inlineEditor,
|
||||||
|
docId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onFail = (message: string) => {
|
||||||
|
toast(editorHost, message);
|
||||||
|
};
|
||||||
|
showImportModal({
|
||||||
|
collection: doc.workspace,
|
||||||
|
schema: doc.schema,
|
||||||
|
onSuccess,
|
||||||
|
onFail,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +260,3 @@ export const LinkedWidgetUtils = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const AFFINE_LINKED_DOC_WIDGET = 'affine-linked-doc-widget';
|
export const AFFINE_LINKED_DOC_WIDGET = 'affine-linked-doc-widget';
|
||||||
|
|
||||||
export const LinkedWidgetConfigExtension = ConfigExtensionFactory<
|
|
||||||
Partial<LinkedWidgetConfig>
|
|
||||||
>('affine:widget-linked-doc');
|
|
||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
import { AFFINE_LINKED_DOC_WIDGET } from './config.js';
|
import { AFFINE_LINKED_DOC_WIDGET } from './config.js';
|
||||||
import { ImportDoc } from './import-doc/import-doc.js';
|
import { ImportDoc } from './import-doc/import-doc.js';
|
||||||
import { Loader } from './import-doc/loader.js';
|
|
||||||
import { AffineLinkedDocWidget } from './index.js';
|
import { AffineLinkedDocWidget } from './index.js';
|
||||||
import { LinkedDocPopover } from './linked-doc-popover.js';
|
import { LinkedDocPopover } from './linked-doc-popover.js';
|
||||||
import { AffineMobileLinkedDocMenu } from './mobile-linked-doc-menu.js';
|
import { AffineMobileLinkedDocMenu } from './mobile-linked-doc-menu.js';
|
||||||
@@ -9,9 +8,9 @@ export function effects() {
|
|||||||
customElements.define('affine-linked-doc-popover', LinkedDocPopover);
|
customElements.define('affine-linked-doc-popover', LinkedDocPopover);
|
||||||
customElements.define(AFFINE_LINKED_DOC_WIDGET, AffineLinkedDocWidget);
|
customElements.define(AFFINE_LINKED_DOC_WIDGET, AffineLinkedDocWidget);
|
||||||
customElements.define('import-doc', ImportDoc);
|
customElements.define('import-doc', ImportDoc);
|
||||||
|
|
||||||
customElements.define(
|
customElements.define(
|
||||||
'affine-mobile-linked-doc-menu',
|
'affine-mobile-linked-doc-menu',
|
||||||
AffineMobileLinkedDocMenu
|
AffineMobileLinkedDocMenu
|
||||||
);
|
);
|
||||||
customElements.define('loader-element', Loader);
|
|
||||||
}
|
}
|
||||||
+3
-3
@@ -12,9 +12,9 @@ import type { Schema, Workspace } from '@blocksuite/store';
|
|||||||
import { html, LitElement, type PropertyValues } from 'lit';
|
import { html, LitElement, type PropertyValues } from 'lit';
|
||||||
import { query, state } from 'lit/decorators.js';
|
import { query, state } from 'lit/decorators.js';
|
||||||
|
|
||||||
import { HtmlTransformer } from '../transformers/html.js';
|
import { HtmlTransformer } from '../../../transformers/html.js';
|
||||||
import { MarkdownTransformer } from '../transformers/markdown.js';
|
import { MarkdownTransformer } from '../../../transformers/markdown.js';
|
||||||
import { NotionHtmlTransformer } from '../transformers/notion-html.js';
|
import { NotionHtmlTransformer } from '../../../transformers/notion-html.js';
|
||||||
import { styles } from './styles.js';
|
import { styles } from './styles.js';
|
||||||
|
|
||||||
export type OnSuccessHandler = (
|
export type OnSuccessHandler = (
|
||||||
+22
-43
@@ -7,11 +7,7 @@ import { FeatureFlagService } from '@blocksuite/affine-shared/services';
|
|||||||
import { getViewportElement } from '@blocksuite/affine-shared/utils';
|
import { getViewportElement } from '@blocksuite/affine-shared/utils';
|
||||||
import { IS_MOBILE } from '@blocksuite/global/env';
|
import { IS_MOBILE } from '@blocksuite/global/env';
|
||||||
import type { BlockComponent } from '@blocksuite/std';
|
import type { BlockComponent } from '@blocksuite/std';
|
||||||
import {
|
import { BLOCK_ID_ATTR, WidgetComponent } from '@blocksuite/std';
|
||||||
BLOCK_ID_ATTR,
|
|
||||||
WidgetComponent,
|
|
||||||
WidgetViewExtension,
|
|
||||||
} from '@blocksuite/std';
|
|
||||||
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
|
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
|
||||||
import {
|
import {
|
||||||
INLINE_ROOT_ATTR,
|
INLINE_ROOT_ATTR,
|
||||||
@@ -23,18 +19,22 @@ import { html, nothing } from 'lit';
|
|||||||
import { choose } from 'lit/directives/choose.js';
|
import { choose } from 'lit/directives/choose.js';
|
||||||
import { repeat } from 'lit/directives/repeat.js';
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
|
||||||
|
|
||||||
|
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
|
||||||
|
import { RootBlockConfigExtension } from '../../root-config.js';
|
||||||
import {
|
import {
|
||||||
AFFINE_LINKED_DOC_WIDGET,
|
type AFFINE_LINKED_DOC_WIDGET,
|
||||||
getMenus,
|
getMenus,
|
||||||
type LinkedDocContext,
|
type LinkedDocContext,
|
||||||
type LinkedWidgetConfig,
|
type LinkedWidgetConfig,
|
||||||
LinkedWidgetConfigExtension,
|
|
||||||
} from './config.js';
|
} from './config.js';
|
||||||
import { linkedDocWidgetStyles } from './styles.js';
|
import { linkedDocWidgetStyles } from './styles.js';
|
||||||
|
export { type LinkedWidgetConfig } from './config.js';
|
||||||
|
|
||||||
export class AffineLinkedDocWidget extends WidgetComponent<RootBlockModel> {
|
export class AffineLinkedDocWidget extends WidgetComponent<
|
||||||
|
RootBlockModel,
|
||||||
|
PageRootBlockComponent
|
||||||
|
> {
|
||||||
static override styles = linkedDocWidgetStyles;
|
static override styles = linkedDocWidgetStyles;
|
||||||
|
|
||||||
private _context: LinkedDocContext | null = null;
|
private _context: LinkedDocContext | null = null;
|
||||||
@@ -43,19 +43,6 @@ export class AffineLinkedDocWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
|
|
||||||
private readonly _mode$ = signal<'desktop' | 'mobile' | 'none'>('none');
|
private readonly _mode$ = signal<'desktop' | 'mobile' | 'none'>('none');
|
||||||
|
|
||||||
private _addTriggerKey(inlineEditor: InlineEditor, triggerKey: string) {
|
|
||||||
const inlineRange = inlineEditor.getInlineRange();
|
|
||||||
if (!inlineRange) return;
|
|
||||||
inlineEditor.insertText(
|
|
||||||
{ index: inlineRange.index, length: 0 },
|
|
||||||
triggerKey
|
|
||||||
);
|
|
||||||
inlineEditor.setInlineRange({
|
|
||||||
index: inlineRange.index + triggerKey.length,
|
|
||||||
length: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateInputRects() {
|
private _updateInputRects() {
|
||||||
if (!this._context) return;
|
if (!this._context) return;
|
||||||
const { inlineEditor, startRange, triggerKey } = this._context;
|
const { inlineEditor, startRange, triggerKey } = this._context;
|
||||||
@@ -230,7 +217,8 @@ export class AffineLinkedDocWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
scrollContainer: getViewportElement(this.std.host) ?? window,
|
scrollContainer: getViewportElement(this.std.host) ?? window,
|
||||||
scrollTopOffset: 46,
|
scrollTopOffset: 46,
|
||||||
},
|
},
|
||||||
...this.std.getOptional(LinkedWidgetConfigExtension.identifier),
|
...this.std.getOptional(RootBlockConfigExtension.identifier)
|
||||||
|
?.linkedWidget,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,30 +259,27 @@ export class AffineLinkedDocWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
inlineEditor = props.inlineEditor;
|
inlineEditor = props.inlineEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const inlineRange = inlineEditor.getInlineRange();
|
||||||
|
if (!inlineRange) return;
|
||||||
|
|
||||||
if (addTriggerKey) {
|
if (addTriggerKey) {
|
||||||
this._addTriggerKey(inlineEditor, primaryTriggerKey);
|
inlineEditor.insertText(
|
||||||
// we need to wait the range sync to get the correct startNativeRange
|
{ index: inlineRange.index, length: 0 },
|
||||||
const subscription = inlineEditor.slots.inlineRangeSync.subscribe(() => {
|
primaryTriggerKey
|
||||||
this.show({ ...props, addTriggerKey: false });
|
);
|
||||||
subscription.unsubscribe();
|
inlineEditor.setInlineRange({
|
||||||
|
index: inlineRange.index + primaryTriggerKey.length,
|
||||||
|
length: 0,
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const startRange = inlineEditor.getInlineRange();
|
|
||||||
if (!startRange) return;
|
|
||||||
|
|
||||||
const startNativeRange = inlineEditor.getNativeRange();
|
|
||||||
if (!startNativeRange) return;
|
|
||||||
|
|
||||||
const disposable = inlineEditor.slots.renderComplete.subscribe(() => {
|
const disposable = inlineEditor.slots.renderComplete.subscribe(() => {
|
||||||
this._updateInputRects();
|
this._updateInputRects();
|
||||||
});
|
});
|
||||||
this._context = {
|
this._context = {
|
||||||
std: this.std,
|
std: this.std,
|
||||||
inlineEditor,
|
inlineEditor,
|
||||||
startRange,
|
startRange: inlineRange,
|
||||||
startNativeRange,
|
|
||||||
triggerKey: primaryTriggerKey,
|
triggerKey: primaryTriggerKey,
|
||||||
config: this.config,
|
config: this.config,
|
||||||
close: () => {
|
close: () => {
|
||||||
@@ -331,12 +316,6 @@ export class AffineLinkedDocWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const linkedDocWidget = WidgetViewExtension(
|
|
||||||
'affine:page',
|
|
||||||
AFFINE_LINKED_DOC_WIDGET,
|
|
||||||
literal`${unsafeStatic(AFFINE_LINKED_DOC_WIDGET)}`
|
|
||||||
);
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
[AFFINE_LINKED_DOC_WIDGET]: AffineLinkedDocWidget;
|
[AFFINE_LINKED_DOC_WIDGET]: AffineLinkedDocWidget;
|
||||||
+8
-9
@@ -7,6 +7,7 @@ import {
|
|||||||
import { unsafeCSSVar } from '@blocksuite/affine-shared/theme';
|
import { unsafeCSSVar } from '@blocksuite/affine-shared/theme';
|
||||||
import {
|
import {
|
||||||
createKeydownObserver,
|
createKeydownObserver,
|
||||||
|
getCurrentNativeRange,
|
||||||
getPopperPosition,
|
getPopperPosition,
|
||||||
getViewportElement,
|
getViewportElement,
|
||||||
} from '@blocksuite/affine-shared/utils';
|
} from '@blocksuite/affine-shared/utils';
|
||||||
@@ -159,15 +160,11 @@ export class LinkedDocPopover extends SignalWatcher(
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
this._updateLinkedDocGroup().catch(console.error);
|
this._updateLinkedDocGroup().catch(console.error);
|
||||||
this._disposables.addFromEvent(this, 'pointerdown', e => {
|
this._disposables.addFromEvent(this, 'mousedown', e => {
|
||||||
// Prevent input from losing focus
|
// Prevent input from losing focus
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
this._disposables.addFromEvent(this, 'mousedown', e => {
|
this._disposables.addFromEvent(window, 'mousedown', e => {
|
||||||
// Prevent input from losing focus in electron
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
this._disposables.addFromEvent(window, 'pointerdown', e => {
|
|
||||||
if (e.target === this) return;
|
if (e.target === this) return;
|
||||||
// We don't clear the query when clicking outside the popover
|
// We don't clear the query when clicking outside the popover
|
||||||
this.context.close();
|
this.context.close();
|
||||||
@@ -249,7 +246,6 @@ export class LinkedDocPopover extends SignalWatcher(
|
|||||||
override disconnectedCallback() {
|
override disconnectedCallback() {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
this._menusItemsEffectCleanup();
|
this._menusItemsEffectCleanup();
|
||||||
this._updateLinkedDocGroupAbortController?.abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
@@ -284,7 +280,7 @@ export class LinkedDocPopover extends SignalWatcher(
|
|||||||
return html`
|
return html`
|
||||||
<div class="divider" ?hidden=${idx === 0}></div>
|
<div class="divider" ?hidden=${idx === 0}></div>
|
||||||
<div class="group-title">
|
<div class="group-title">
|
||||||
<div class="group-title-text">${group.name}</div>
|
${group.name}
|
||||||
${group.isLoading
|
${group.isLoading
|
||||||
? html`<span class="loading-icon">${LoadingIcon}</span>`
|
? html`<span class="loading-icon">${LoadingIcon}</span>`
|
||||||
: nothing}
|
: nothing}
|
||||||
@@ -342,8 +338,11 @@ export class LinkedDocPopover extends SignalWatcher(
|
|||||||
|
|
||||||
override willUpdate() {
|
override willUpdate() {
|
||||||
if (!this.hasUpdated) {
|
if (!this.hasUpdated) {
|
||||||
|
const curRange = getCurrentNativeRange();
|
||||||
|
if (!curRange) return;
|
||||||
|
|
||||||
const updatePosition = throttle(() => {
|
const updatePosition = throttle(() => {
|
||||||
this._position = getPopperPosition(this, this.context.startNativeRange);
|
this._position = getPopperPosition(this, curRange);
|
||||||
}, 10);
|
}, 10);
|
||||||
|
|
||||||
this.disposables.addFromEvent(window, 'resize', updatePosition);
|
this.disposables.addFromEvent(window, 'resize', updatePosition);
|
||||||
+48
-8
@@ -3,7 +3,10 @@ import {
|
|||||||
getTextContentFromInlineRange,
|
getTextContentFromInlineRange,
|
||||||
} from '@blocksuite/affine-rich-text';
|
} from '@blocksuite/affine-rich-text';
|
||||||
import { VirtualKeyboardProvider } from '@blocksuite/affine-shared/services';
|
import { VirtualKeyboardProvider } from '@blocksuite/affine-shared/services';
|
||||||
import { getViewportElement } from '@blocksuite/affine-shared/utils';
|
import {
|
||||||
|
createKeydownObserver,
|
||||||
|
getViewportElement,
|
||||||
|
} from '@blocksuite/affine-shared/utils';
|
||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
||||||
import { MoreHorizontalIcon } from '@blocksuite/icons/lit';
|
import { MoreHorizontalIcon } from '@blocksuite/icons/lit';
|
||||||
import { PropTypes, requiredProperties } from '@blocksuite/std';
|
import { PropTypes, requiredProperties } from '@blocksuite/std';
|
||||||
@@ -13,6 +16,7 @@ import { property } from 'lit/decorators.js';
|
|||||||
import { join } from 'lit/directives/join.js';
|
import { join } from 'lit/directives/join.js';
|
||||||
import { repeat } from 'lit/directives/repeat.js';
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
|
|
||||||
|
import { PageRootBlockComponent } from '../../index.js';
|
||||||
import type {
|
import type {
|
||||||
LinkedDocContext,
|
LinkedDocContext,
|
||||||
LinkedMenuGroup,
|
LinkedMenuGroup,
|
||||||
@@ -25,6 +29,7 @@ export const AFFINE_MOBILE_LINKED_DOC_MENU = 'affine-mobile-linked-doc-menu';
|
|||||||
|
|
||||||
@requiredProperties({
|
@requiredProperties({
|
||||||
context: PropTypes.object,
|
context: PropTypes.object,
|
||||||
|
rootComponent: PropTypes.instanceOf(PageRootBlockComponent),
|
||||||
})
|
})
|
||||||
export class AffineMobileLinkedDocMenu extends SignalWatcher(
|
export class AffineMobileLinkedDocMenu extends SignalWatcher(
|
||||||
WithDisposable(LitElement)
|
WithDisposable(LitElement)
|
||||||
@@ -33,6 +38,8 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
|
|||||||
|
|
||||||
private readonly _expand = new Set<string>();
|
private readonly _expand = new Set<string>();
|
||||||
|
|
||||||
|
private _firstActionItem: LinkedMenuItem | null = null;
|
||||||
|
|
||||||
private readonly _linkedDocGroup$ = signal<LinkedMenuGroup[]>([]);
|
private readonly _linkedDocGroup$ = signal<LinkedMenuGroup[]>([]);
|
||||||
|
|
||||||
private readonly _renderGroup = (group: LinkedMenuGroup) => {
|
private readonly _renderGroup = (group: LinkedMenuGroup) => {
|
||||||
@@ -182,14 +189,42 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
|
|||||||
const keydownObserverAbortController = new AbortController();
|
const keydownObserverAbortController = new AbortController();
|
||||||
this._disposables.add(() => keydownObserverAbortController.abort());
|
this._disposables.add(() => keydownObserverAbortController.abort());
|
||||||
|
|
||||||
// we need use beforeinput because the event.key of keypress event usually is `Unidentified` in Android
|
createKeydownObserver({
|
||||||
this.disposables.addFromEvent(eventSource, 'beforeinput', () => {
|
target: eventSource,
|
||||||
const curRange = inlineEditor.getInlineRange();
|
signal: keydownObserverAbortController.signal,
|
||||||
if (curRange && curRange.index < this.context.startRange.index) {
|
onInput: isComposition => {
|
||||||
|
if (isComposition) {
|
||||||
|
this._updateLinkedDocGroup().catch(console.error);
|
||||||
|
} else {
|
||||||
|
const subscription = inlineEditor.slots.renderComplete.subscribe(
|
||||||
|
() => {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
this._updateLinkedDocGroup().catch(console.error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDelete: () => {
|
||||||
|
const subscription = inlineEditor.slots.renderComplete.subscribe(
|
||||||
|
() => {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
const curRange = inlineEditor.getInlineRange();
|
||||||
|
|
||||||
|
if (!this.context.startRange || !curRange) return;
|
||||||
|
|
||||||
|
if (curRange.index < this.context.startRange.index) {
|
||||||
|
this.context.close();
|
||||||
|
}
|
||||||
|
this._updateLinkedDocGroup().catch(console.error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onConfirm: () => {
|
||||||
|
this._firstActionItem?.action()?.catch(console.error);
|
||||||
|
},
|
||||||
|
onAbort: () => {
|
||||||
this.context.close();
|
this.context.close();
|
||||||
return;
|
},
|
||||||
}
|
|
||||||
this._updateLinkedDocGroup().catch(console.error);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,6 +239,8 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
|
|||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._firstActionItem = resolveSignal(groups[0].items)[0];
|
||||||
|
|
||||||
this.style.bottom = `${this.keyboard.height$.value}px`;
|
this.style.bottom = `${this.keyboard.height$.value}px`;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
@@ -213,4 +250,7 @@ export class AffineMobileLinkedDocMenu extends SignalWatcher(
|
|||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor context!: LinkedDocContext;
|
accessor context!: LinkedDocContext;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor rootComponent!: PageRootBlockComponent;
|
||||||
}
|
}
|
||||||
-7
@@ -52,13 +52,6 @@ export const linkedDocPopoverStyles = css`
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
max-width: 240px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.linked-doc-popover .group-title .group-title-text {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.linked-doc-popover .group-title .loading-icon {
|
.linked-doc-popover .group-title .loading-icon {
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import { css, html, LitElement, nothing } from 'lit';
|
||||||
|
import { ref } from 'lit/directives/ref.js';
|
||||||
|
import { repeat } from 'lit/directives/repeat.js';
|
||||||
|
|
||||||
|
type ModalButton = {
|
||||||
|
text: string;
|
||||||
|
type?: 'primary';
|
||||||
|
onClick: () => Promise<void> | void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ModalOptions = {
|
||||||
|
footer: null | ModalButton[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export class AffineCustomModal extends LitElement {
|
||||||
|
static override styles = css`
|
||||||
|
:host {
|
||||||
|
z-index: calc(var(--affine-z-index-modal) + 3);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-background {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--affine-background-modal-color);
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-window {
|
||||||
|
width: 70%;
|
||||||
|
min-width: 500px;
|
||||||
|
height: 80%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
background-color: var(--affine-background-overlay-panel-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: var(--affine-shadow-3);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-main {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 24px;
|
||||||
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .button {
|
||||||
|
align-items: center;
|
||||||
|
background: var(--affine-white);
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: var(--affine-border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--affine-text-primary-color);
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-flex;
|
||||||
|
font-size: var(--affine-font-sm);
|
||||||
|
font-weight: 500;
|
||||||
|
justify-content: center;
|
||||||
|
outline: 0;
|
||||||
|
padding: 12px 18px;
|
||||||
|
touch-action: manipulation;
|
||||||
|
transition: all 0.3s;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .primary {
|
||||||
|
background: var(--affine-primary-color);
|
||||||
|
border-color: var(--affine-black-10);
|
||||||
|
box-shadow: var(--affine-button-inner-shadow);
|
||||||
|
color: var(--affine-pure-white);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
onOpen!: (div: HTMLDivElement) => void;
|
||||||
|
|
||||||
|
options!: ModalOptions;
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
modalRef(modal: Element | undefined) {
|
||||||
|
if (modal) this.onOpen?.(modal as HTMLDivElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
override render() {
|
||||||
|
const { options } = this;
|
||||||
|
|
||||||
|
return html`<div class="modal-background">
|
||||||
|
<div class="modal-window">
|
||||||
|
<div class="modal-main" ${ref(this.modalRef)}></div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
${options.footer
|
||||||
|
? repeat(
|
||||||
|
options.footer,
|
||||||
|
button => button.text,
|
||||||
|
button => html`
|
||||||
|
<button
|
||||||
|
class="button ${button.type ?? ''}"
|
||||||
|
@click=${button.onClick}
|
||||||
|
>
|
||||||
|
${button.text}
|
||||||
|
</button>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
: nothing}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateModalOption = ModalOptions & {
|
||||||
|
entry: (div: HTMLDivElement) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createCustomModal(
|
||||||
|
options: CreateModalOption,
|
||||||
|
container: HTMLElement = document.body
|
||||||
|
) {
|
||||||
|
const modal = new AffineCustomModal();
|
||||||
|
|
||||||
|
modal.onOpen = options.entry;
|
||||||
|
modal.options = options;
|
||||||
|
|
||||||
|
container.append(modal);
|
||||||
|
|
||||||
|
return modal;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { WidgetComponent } from '@blocksuite/std';
|
||||||
|
import { nothing } from 'lit';
|
||||||
|
|
||||||
|
import { createCustomModal } from './custom-modal.js';
|
||||||
|
|
||||||
|
export const AFFINE_MODAL_WIDGET = 'affine-modal-widget';
|
||||||
|
|
||||||
|
export class AffineModalWidget extends WidgetComponent {
|
||||||
|
open(options: Parameters<typeof createCustomModal>[0]) {
|
||||||
|
return createCustomModal(options, this.ownerDocument.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
override render() {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
[AFFINE_MODAL_WIDGET]: AffineModalWidget;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,8 +43,6 @@
|
|||||||
{ "path": "../../widgets/edgeless-auto-connect" },
|
{ "path": "../../widgets/edgeless-auto-connect" },
|
||||||
{ "path": "../../widgets/edgeless-toolbar" },
|
{ "path": "../../widgets/edgeless-toolbar" },
|
||||||
{ "path": "../../widgets/frame-title" },
|
{ "path": "../../widgets/frame-title" },
|
||||||
{ "path": "../../widgets/keyboard-toolbar" },
|
|
||||||
{ "path": "../../widgets/linked-doc" },
|
|
||||||
{ "path": "../../widgets/remote-selection" },
|
{ "path": "../../widgets/remote-selection" },
|
||||||
{ "path": "../../widgets/scroll-anchoring" },
|
{ "path": "../../widgets/scroll-anchoring" },
|
||||||
{ "path": "../../widgets/slash-menu" },
|
{ "path": "../../widgets/slash-menu" },
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ export const calcCustomButtonStyle = (
|
|||||||
return { '--b': b, '--c': c };
|
return { '--b': b, '--c': c };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color.startsWith('--')) {
|
if (color.startsWith('---')) {
|
||||||
if (!color.endsWith('transparent')) {
|
if (!color.endsWith('transparent')) {
|
||||||
b = 'var(--affine-background-overlay-panel-color)';
|
b = 'var(--affine-background-overlay-panel-color)';
|
||||||
c = keepColor(
|
c = keepColor(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { css, html, LitElement } from 'lit';
|
import { css, html, LitElement } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { repeat } from 'lit-html/directives/repeat.js';
|
|
||||||
|
|
||||||
export class TooltipContentWithShortcut extends LitElement {
|
export class TooltipContentWithShortcut extends LitElement {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
@@ -10,10 +9,6 @@ export class TooltipContentWithShortcut extends LitElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
.tooltip__shortcuts {
|
|
||||||
display: flex;
|
|
||||||
gap: 2px;
|
|
||||||
}
|
|
||||||
.tooltip__shortcut {
|
.tooltip__shortcut {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -33,30 +28,19 @@ export class TooltipContentWithShortcut extends LitElement {
|
|||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
}
|
}
|
||||||
.tooltip__label {
|
.tooltip__label {
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
get shortcuts() {
|
|
||||||
let shortcut = this.shortcut;
|
|
||||||
if (!shortcut) return [];
|
|
||||||
return shortcut.split(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
const { tip, shortcuts, postfix } = this;
|
const { tip, shortcut, postfix } = this;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="tooltip-with-shortcut">
|
<div class="tooltip-with-shortcut">
|
||||||
<span class="tooltip__label">${tip}</span>
|
<span class="tooltip__label">${tip}</span>
|
||||||
<div class="tooltip__shortcuts">
|
${shortcut
|
||||||
${repeat(
|
? html`<span class="tooltip__shortcut">${shortcut}</span>`
|
||||||
shortcuts,
|
: ''}
|
||||||
shortcut => html`<span class="tooltip__shortcut">${shortcut}</span>`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
${postfix ? html`<span class="tooltip__postfix">${postfix}</span>` : ''}
|
${postfix ? html`<span class="tooltip__postfix">${postfix}</span>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ export const cardPreview = style({
|
|||||||
borderRadius: '4px',
|
borderRadius: '4px',
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
|
':hover': {
|
||||||
|
background: cssVarV2('layer/background/hoverOverlay'),
|
||||||
|
},
|
||||||
selectors: {
|
selectors: {
|
||||||
[`${outlineCard}[data-sortable="true"] &:hover`]: {
|
|
||||||
background: cssVarV2('layer/background/hoverOverlay'),
|
|
||||||
},
|
|
||||||
[`${outlineCard}[data-status="selected"] &`]: {
|
[`${outlineCard}[data-status="selected"] &`]: {
|
||||||
background: cssVarV2('layer/background/hoverOverlay'),
|
background: cssVarV2('layer/background/hoverOverlay'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVar } from '@toeverything/theme';
|
||||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
import { globalStyle, style } from '@vanilla-extract/css';
|
import { style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
export const outlineBlockPreview = style({
|
export const outlineBlockPreview = style({
|
||||||
fontFamily: cssVar('fontFamily'),
|
fontFamily: cssVar('fontFamily'),
|
||||||
@@ -108,11 +108,6 @@ export const linkedDocPreviewUnavailable = style({
|
|||||||
color: cssVarV2('text/disable'),
|
color: cssVarV2('text/disable'),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const linkedDocPreviewAvailable = style({});
|
|
||||||
globalStyle(`${linkedDocPreviewAvailable} > svg`, {
|
|
||||||
marginBottom: '0.1em',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const linkedDocTextUnavailable = style({
|
export const linkedDocTextUnavailable = style({
|
||||||
color: cssVarV2('text/disable'),
|
color: cssVarV2('text/disable'),
|
||||||
textDecoration: 'line-through',
|
textDecoration: 'line-through',
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user