Compare commits

..

11 Commits

Author SHA1 Message Date
zzj3720
06b84330a9 feat: add icon picker functionality to callout block
- Add IconData type import to callout-model.ts
- Implement icon picker component in callout-block.ts
- Copy renderUniLit function to avoid external dependencies
- Integrate icon picker directly in renderBlock for testing
- Remove unused IconPickerServiceIdentifier import
2025-09-26 23:59:30 +08:00
zzj3720
5147e2c62d fix: remove unused ThemeExtensionIdentifier import 2025-09-26 18:41:42 +08:00
zzj3720
03e8e7143d Merge canary branch with callout background color feature 2025-09-26 15:02:08 +08:00
zzj3720
5e8691367d feat(callout): add formatbar with background color selection
- Add background property to CalloutBlockModel with default white color
- Implement dynamic background color rendering in CalloutBlockComponent
- Create toolbar configuration with color palette for background selection
- Register toolbar extension in CalloutViewExtension
- Support all note background colors with visual feedback for current selection
- Maintain consistency with other block formatbar implementations
2025-09-24 23:56:57 +08:00
3720
e3d88ab3f2 Merge branch 'canary' into fix/callout-delete-merge 2025-09-19 21:58:05 +08:00
zzj3720
61e40c7523 fix(callout): adjust callout styling and slash menu behavior
update callout block margins and spacing
add debug logs for slash menu disableWhen checks
remove slash menu disable test and update paragraph count assertions
2025-09-19 20:16:08 +08:00
zzj3720
cdb721d6a6 Merge branch 'fix/callout-delete-merge' of github.com:toeverything/AFFiNE into fix/callout-delete-merge 2025-09-17 19:43:06 +08:00
zzj3720
c89680cb55 refactor(callout): rename variable for clarity in callout keymap
The variable `calloutBlock` was being assigned directly from `std.store.getBlock`, which could be confusing. Renamed to `parentBlock` first to better reflect its purpose before assignment to `calloutBlock`.
2025-09-17 19:42:38 +08:00
3720
0256fdb2af Merge branch 'canary' into fix/callout-delete-merge 2025-09-17 19:18:45 +08:00
zzj3720
a4711aad61 fix: improve callout block functionality and slash menu configuration 2025-09-17 19:16:03 +08:00
zzj3720
6d97c5a393 fix(callout): fix text merging issue when deleting callout sub-blocks
- Fix text content disappearing after deleting callout sub-blocks
- Properly clone text content before deletion to prevent data loss
- Ensure text merges correctly to previous block with formatting preserved
- Improve cursor positioning after merge operation
2025-09-17 18:55:03 +08:00
369 changed files with 4317 additions and 13565 deletions

View File

@@ -5,14 +5,7 @@ rustflags = ["-C", "target-feature=+crt-static"]
[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-args=-Wl,--warn-unresolved-symbols"]
[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=-Wl,-undefined,dynamic_lookup,-no_fixup_chains", "-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=21031
# https://github.com/rust-lang/rust/issues/134820

View File

@@ -2,8 +2,6 @@ version: '3.8'
services:
app:
security_opt:
- no-new-privileges:true
image: mcr.microsoft.com/devcontainers/base:bookworm
volumes:
- ../..:/workspaces:cached

View File

@@ -222,12 +222,12 @@
},
"SMTP.sender": {
"type": "string",
"description": "Sender of all the emails (e.g. \"AFFiNE Self Hosted <noreply@example.com>\")\n@default \"AFFiNE Self Hosted <noreply@example.com>\"\n@environment `MAILER_SENDER`",
"default": "AFFiNE Self Hosted <noreply@example.com>"
"description": "Sender of all the emails (e.g. \"AFFiNE Team <noreply@affine.pro>\")\n@default \"\"\n@environment `MAILER_SENDER`",
"default": ""
},
"SMTP.ignoreTLS": {
"type": "boolean",
"description": "Whether ignore email server's TLS certificate verification. Enable it for self-signed certificates.\n@default false\n@environment `MAILER_IGNORE_TLS`",
"description": "Whether ignore email server's TSL certification verification. Enable it for self-signed certificates.\n@default false\n@environment `MAILER_IGNORE_TLS`",
"default": false
},
"fallbackDomains": {
@@ -262,12 +262,12 @@
},
"fallbackSMTP.sender": {
"type": "string",
"description": "Sender of all the emails (e.g. \"AFFiNE Self Hosted <noreply@example.com>\")\n@default \"\"",
"description": "Sender of all the emails (e.g. \"AFFiNE Team <noreply@affine.pro>\")\n@default \"\"",
"default": ""
},
"fallbackSMTP.ignoreTLS": {
"type": "boolean",
"description": "Whether ignore email server's TLS certificate verification. Enable it for self-signed certificates.\n@default false",
"description": "Whether ignore email server's TSL certification verification. Enable it for self-signed certificates.\n@default false",
"default": false
}
}
@@ -684,7 +684,7 @@
},
"scenarios": {
"type": "object",
"description": "Use custom models in scenarios and override default settings.\n@default {\"override_enabled\":false,\"scenarios\":{\"audio_transcribing\":\"gemini-2.5-flash\",\"chat\":\"gemini-2.5-flash\",\"embedding\":\"gemini-embedding-001\",\"image\":\"gpt-image-1\",\"rerank\":\"gpt-4.1\",\"coding\":\"claude-sonnet-4-5@20250929\",\"complex_text_generation\":\"gpt-4o-2024-08-06\",\"quick_decision_making\":\"gpt-5-mini\",\"quick_text_generation\":\"gemini-2.5-flash\",\"polish_and_summarize\":\"gemini-2.5-flash\"}}",
"description": "Use custom models in scenarios and override default settings.\n@default {\"override_enabled\":false,\"scenarios\":{\"audio_transcribing\":\"gemini-2.5-flash\",\"chat\":\"gemini-2.5-flash\",\"embedding\":\"gemini-embedding-001\",\"image\":\"gpt-image-1\",\"rerank\":\"gpt-4.1\",\"coding\":\"claude-sonnet-4@20250514\",\"complex_text_generation\":\"gpt-4o-2024-08-06\",\"quick_decision_making\":\"gpt-5-mini\",\"quick_text_generation\":\"gemini-2.5-flash\",\"polish_and_summarize\":\"gemini-2.5-flash\"}}",
"default": {
"override_enabled": false,
"scenarios": {
@@ -693,7 +693,7 @@
"embedding": "gemini-embedding-001",
"image": "gpt-image-1",
"rerank": "gpt-4.1",
"coding": "claude-sonnet-4-5@20250929",
"coding": "claude-sonnet-4@20250514",
"complex_text_generation": "gpt-4o-2024-08-06",
"quick_decision_making": "gpt-5-mini",
"quick_text_generation": "gemini-2.5-flash",

View File

@@ -3,4 +3,4 @@ name: affine
description: AFFiNE cloud chart
type: application
version: 0.0.0
appVersion: "0.25.5"
appVersion: "0.22.4"

View File

@@ -3,7 +3,7 @@ name: doc
description: AFFiNE doc server
type: application
version: 0.0.0
appVersion: "0.25.5"
appVersion: "0.22.4"
dependencies:
- name: gcloud-sql-proxy
version: 0.0.0

View File

@@ -3,7 +3,7 @@ name: graphql
description: AFFiNE GraphQL server
type: application
version: 0.0.0
appVersion: "0.25.5"
appVersion: "0.22.4"
dependencies:
- name: gcloud-sql-proxy
version: 0.0.0

View File

@@ -3,7 +3,7 @@ name: renderer
description: AFFiNE renderer server
type: application
version: 0.0.0
appVersion: "0.25.5"
appVersion: "0.22.4"
dependencies:
- name: gcloud-sql-proxy
version: 0.0.0

View File

@@ -3,7 +3,7 @@ name: sync
description: AFFiNE Sync Server
type: application
version: 0.0.0
appVersion: "0.25.5"
appVersion: "0.22.4"
dependencies:
- name: gcloud-sql-proxy
version: 0.0.0

View File

@@ -19,7 +19,7 @@ env:
APP_NAME: affine
AFFINE_ENV: dev
COVERAGE: true
MACOSX_DEPLOYMENT_TARGET: '11.6'
MACOSX_DEPLOYMENT_TARGET: '10.13'
DEPLOYMENT_TYPE: affine
AFFINE_INDEXER_ENABLED: true

View File

@@ -25,7 +25,7 @@ env:
RELEASE_VERSION: ${{ inputs.app-version }}
DEBUG: 'affine:*,napi:*'
APP_NAME: affine
MACOSX_DEPLOYMENT_TARGET: '11.6'
MACOSX_DEPLOYMENT_TARGET: '10.13'
jobs:
before-make:
@@ -165,7 +165,7 @@ jobs:
mv packages/frontend/apps/electron/out/*/make/zip/linux/${{ matrix.spec.arch }}/*.zip ./builds/affine-${{ env.RELEASE_VERSION }}-${{ env.BUILD_TYPE }}-linux-${{ matrix.spec.arch }}.zip
mv packages/frontend/apps/electron/out/*/make/*.AppImage ./builds/affine-${{ env.RELEASE_VERSION }}-${{ env.BUILD_TYPE }}-linux-${{ matrix.spec.arch }}.appimage
mv packages/frontend/apps/electron/out/*/make/deb/${{ matrix.spec.arch }}/*.deb ./builds/affine-${{ env.RELEASE_VERSION }}-${{ env.BUILD_TYPE }}-linux-${{ matrix.spec.arch }}.deb
# mv packages/frontend/apps/electron/out/*/make/flatpak/*/*.flatpak ./builds/affine-${{ env.RELEASE_VERSION }}-${{ env.BUILD_TYPE }}-linux-${{ matrix.spec.arch }}.flatpak
mv packages/frontend/apps/electron/out/*/make/flatpak/*/*.flatpak ./builds/affine-${{ env.RELEASE_VERSION }}-${{ env.BUILD_TYPE }}-linux-${{ matrix.spec.arch }}.flatpak
- uses: actions/attest-build-provenance@v2
if: ${{ matrix.spec.platform == 'darwin' }}
@@ -466,4 +466,6 @@ jobs:
draft: ${{ inputs.build-type == 'stable' }}
prerelease: ${{ inputs.build-type != 'stable' }}
tag_name: v${{ env.RELEASE_VERSION}}
files: ./release/*
files: |
./release/*
./release/.env.example

3
.gitignore vendored
View File

@@ -33,9 +33,6 @@ node_modules
!.vscode/launch.template.json
!.vscode/extensions.json
# Kiro
.kiro
# misc
/.sass-cache
/connect.lock

View File

@@ -1,7 +1,7 @@
exclude = ["node_modules/**/*.toml", "target/**/*.toml"]
include = ["./*.toml", "./packages/**/*.toml"]
# https://taplo.tamasfe.dev/configuration/formatter-options.html
[formatting]
align_entries = true
indent_tables = true
reorder_keys = true
align_entries = true
column_width = 180
reorder_arrays = true
reorder_keys = true

193
Cargo.lock generated
View File

@@ -40,7 +40,6 @@ dependencies = [
name = "affine_common"
version = "0.1.0"
dependencies = [
"assert-json-diff",
"cc",
"chrono",
"criterion2",
@@ -51,7 +50,6 @@ dependencies = [
"rand 0.9.1",
"rayon",
"readability",
"serde",
"serde_json",
"sha3",
"strum_macros",
@@ -71,7 +69,6 @@ dependencies = [
"tree-sitter-scala",
"tree-sitter-typescript",
"url",
"y-octo",
]
[[package]]
@@ -164,9 +161,7 @@ dependencies = [
"affine_common",
"chrono",
"file-format",
"infer",
"mimalloc",
"mp4parse",
"napi",
"napi-build",
"napi-derive",
@@ -445,6 +440,12 @@ dependencies = [
"num-traits",
]
[[package]]
name = "atomic_refcell"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c"
[[package]]
name = "auto_enums"
version = "0.8.7"
@@ -573,12 +574,15 @@ dependencies = [
]
[[package]]
name = "bitreader"
version = "0.3.11"
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "886559b1e163d56c765bc3a985febb4eee8009f625244511d8ee3c432e08c066"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"cfg-if",
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
@@ -1478,15 +1482,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
[[package]]
name = "fallible_collections"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a88c69768c0a15262df21899142bc6df9b9b823546d4b4b9a7bc2d6c448ec6fd"
dependencies = [
"hashbrown 0.13.2",
]
[[package]]
name = "fancy-regex"
version = "0.13.0"
@@ -1509,9 +1504,9 @@ dependencies = [
[[package]]
name = "file-format"
version = "0.28.0"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eab8aa2fba5f39f494000a22f44bf3c755b7d7f8ffad3f36c6d507893074159"
checksum = "e7ef3d5e8ae27277c8285ac43ed153158178ef0f79567f32024ca8140a0c7cd8"
[[package]]
name = "flate2"
@@ -1597,6 +1592,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futf"
version = "0.1.5"
@@ -1703,6 +1704,19 @@ dependencies = [
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.2.16"
@@ -1786,20 +1800,15 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "hashbrown"
@@ -1904,7 +1913,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.61.2",
"windows-core 0.57.0",
]
[[package]]
@@ -2217,6 +2226,16 @@ dependencies = [
"cpufeatures",
]
[[package]]
name = "lasso"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb"
dependencies = [
"dashmap",
"hashbrown 0.14.5",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
@@ -2474,20 +2493,6 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "mp4parse"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63a35203d3c6ce92d5251c77520acb2e57108c88728695aa883f70023624c570"
dependencies = [
"bitreader",
"byteorder",
"fallible_collections",
"log",
"num-traits",
"static_assertions",
]
[[package]]
name = "nanoid"
version = "0.4.0"
@@ -3232,6 +3237,25 @@ version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc",
]
[[package]]
name = "rand"
version = "0.8.5"
@@ -3253,6 +3277,16 @@ dependencies = [
"rand_core 0.9.3",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core 0.5.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
@@ -3273,6 +3307,15 @@ dependencies = [
"rand_core 0.9.3",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_core"
version = "0.6.4"
@@ -3301,6 +3344,15 @@ dependencies = [
"rand 0.9.1",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_xorshift"
version = "0.3.0"
@@ -4382,6 +4434,12 @@ dependencies = [
"syn 2.0.101",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tempfile"
version = "3.20.0"
@@ -5097,6 +5155,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@@ -5701,6 +5765,15 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]]
name = "xml5ever"
version = "0.17.0"
@@ -5726,8 +5799,10 @@ dependencies = [
"arbitrary",
"assert-json-diff",
"async-lock",
"bitvec",
"byteorder",
"criterion",
"lasso",
"lib0",
"log",
"loom",
@@ -5744,7 +5819,7 @@ dependencies = [
"serde_json",
"smol_str",
"thiserror 2.0.12",
"yrs",
"yrs 0.23.4",
]
[[package]]
@@ -5774,7 +5849,18 @@ dependencies = [
"rand_chacha 0.9.0",
"regex",
"y-octo",
"yrs",
"y-sync",
"yrs 0.23.4",
]
[[package]]
name = "y-sync"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e3675a497cde881a71e7e5c2ae1d087dfc7733ddece9b24a9a61408e969d3b"
dependencies = [
"thiserror 1.0.69",
"yrs 0.17.4",
]
[[package]]
@@ -5801,6 +5887,21 @@ dependencies = [
"synstructure",
]
[[package]]
name = "yrs"
version = "0.17.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4830316bfee4bec0044fe34a001cda783506d5c4c0852f8433c6041dfbfce51"
dependencies = [
"atomic_refcell",
"rand 0.7.3",
"serde",
"serde_json",
"smallstr",
"smallvec",
"thiserror 1.0.69",
]
[[package]]
name = "yrs"
version = "0.23.4"

View File

@@ -13,122 +13,108 @@ members = [
]
resolver = "3"
[workspace.package]
edition = "2024"
[workspace.package]
edition = "2024"
[workspace.dependencies]
affine_common = { path = "./packages/common/native" }
affine_nbstore = { path = "./packages/frontend/native/nbstore" }
ahash = "0.8"
anyhow = "1"
arbitrary = { version = "1.3", features = ["derive"] }
assert-json-diff = "2.0"
async-lock = { version = "3.4.0", features = ["loom"] }
base64-simd = "0.8"
bitvec = "1.0"
block2 = "0.6"
byteorder = "1.5"
chrono = "0.4"
clap = { version = "4.4", features = ["derive"] }
core-foundation = "0.10"
coreaudio-rs = "0.12"
cpal = "0.15"
criterion = { version = "0.5", features = ["html_reports"] }
criterion2 = { version = "3", default-features = false }
crossbeam-channel = "0.5"
dispatch2 = "0.3"
docx-parser = { git = "https://github.com/toeverything/docx-parser" }
dotenvy = "0.15"
file-format = { version = "0.28", features = ["reader"] }
homedir = "0.3"
infer = { version = "0.19.0" }
lasso = { version = "0.7", features = ["multi-threaded"] }
lib0 = { version = "0.16", features = ["lib0-serde"] }
libc = "0.2"
log = "0.4"
loom = { version = "0.7", features = ["checkpoint"] }
mimalloc = "0.1"
mp4parse = "0.17"
nanoid = "0.4"
napi = { version = "3.0.0-beta.3", features = [
"async",
"chrono_date",
"error_anyhow",
"napi9",
"serde",
] }
napi-build = { version = "2" }
napi-derive = { version = "3.0.0-beta.3" }
nom = "8"
notify = { version = "8", features = ["serde"] }
objc2 = "0.6"
objc2-foundation = "0.3"
once_cell = "1"
ordered-float = "5"
parking_lot = "0.12"
path-ext = "0.1.2"
pdf-extract = { git = "https://github.com/toeverything/pdf-extract", branch = "darksky/improve-font-decoding" }
phf = { version = "0.11", features = ["macros"] }
proptest = "1.3"
proptest-derive = "0.5"
rand = "0.9"
rand_chacha = "0.9"
rand_distr = "0.5"
rayon = "1.10"
readability = { version = "0.3.0", default-features = false }
regex = "1.10"
rubato = "0.16"
screencapturekit = "0.3"
serde = "1"
serde_json = "1"
sha3 = "0.10"
smol_str = "0.3"
sqlx = { version = "0.8", default-features = false, features = [
"chrono",
"macros",
"migrate",
"runtime-tokio",
"sqlite",
"tls-rustls",
] }
strum_macros = "0.27.0"
symphonia = { version = "0.5", features = ["all", "opt-simd"] }
text-splitter = "0.27"
thiserror = "2"
tiktoken-rs = "0.7"
tokio = "1.45"
tree-sitter = { version = "0.25" }
tree-sitter-c = { version = "0.24" }
tree-sitter-c-sharp = { version = "0.23" }
tree-sitter-cpp = { version = "0.23" }
tree-sitter-go = { version = "0.23" }
tree-sitter-java = { version = "0.23" }
tree-sitter-javascript = { version = "0.23" }
tree-sitter-kotlin-ng = { version = "1.1" }
tree-sitter-python = { version = "0.23" }
tree-sitter-rust = { version = "0.24" }
tree-sitter-scala = { version = "0.24" }
tree-sitter-typescript = { version = "0.23" }
uniffi = "0.29"
url = { version = "2.5" }
uuid = "1.8"
v_htmlescape = "0.15"
windows = { version = "0.61", features = [
"Win32_Devices_FunctionDiscovery",
"Win32_Foundation",
"Win32_Media_Audio",
"Win32_System_Com",
"Win32_System_Com_StructuredStorage",
"Win32_System_Diagnostics_ToolHelp",
"Win32_System_ProcessStatus",
"Win32_System_Threading",
"Win32_System_Variant",
"Win32_UI_Shell_PropertiesSystem",
] }
windows-core = { version = "0.61" }
y-octo = { path = "./packages/common/y-octo/core" }
y-sync = { version = "0.4" }
yrs = "0.23.0"
[workspace.dependencies]
affine_common = { path = "./packages/common/native" }
affine_nbstore = { path = "./packages/frontend/native/nbstore" }
ahash = "0.8"
anyhow = "1"
arbitrary = { version = "1.3", features = ["derive"] }
assert-json-diff = "2.0"
async-lock = { version = "3.4.0", features = ["loom"] }
base64-simd = "0.8"
bitvec = "1.0"
block2 = "0.6"
byteorder = "1.5"
cpal = "0.15"
chrono = "0.4"
clap = { version = "4.4", features = ["derive"] }
core-foundation = "0.10"
coreaudio-rs = "0.12"
criterion = { version = "0.5", features = ["html_reports"] }
criterion2 = { version = "3", default-features = false }
crossbeam-channel = "0.5"
dispatch2 = "0.3"
docx-parser = { git = "https://github.com/toeverything/docx-parser" }
dotenvy = "0.15"
file-format = { version = "0.26", features = ["reader"] }
homedir = "0.3"
infer = { version = "0.19.0" }
lasso = { version = "0.7", features = ["multi-threaded"] }
lib0 = { version = "0.16", features = ["lib0-serde"] }
libc = "0.2"
log = "0.4"
loom = { version = "0.7", features = ["checkpoint"] }
mimalloc = "0.1"
nanoid = "0.4"
napi = { version = "3.0.0-beta.3", features = ["async", "chrono_date", "error_anyhow", "napi9", "serde"] }
napi-build = { version = "2" }
napi-derive = { version = "3.0.0-beta.3" }
nom = "8"
notify = { version = "8", features = ["serde"] }
objc2 = "0.6"
objc2-foundation = "0.3"
once_cell = "1"
ordered-float = "5"
parking_lot = "0.12"
path-ext = "0.1.2"
pdf-extract = { git = "https://github.com/toeverything/pdf-extract", branch = "darksky/improve-font-decoding" }
phf = { version = "0.11", features = ["macros"] }
proptest = "1.3"
proptest-derive = "0.5"
rand = "0.9"
rand_chacha = "0.9"
rand_distr = "0.5"
rayon = "1.10"
readability = { version = "0.3.0", default-features = false }
regex = "1.10"
rubato = "0.16"
screencapturekit = "0.3"
serde = "1"
serde_json = "1"
sha3 = "0.10"
smol_str = "0.3"
sqlx = { version = "0.8", default-features = false, features = ["chrono", "macros", "migrate", "runtime-tokio", "sqlite", "tls-rustls"] }
strum_macros = "0.27.0"
symphonia = { version = "0.5", features = ["all", "opt-simd"] }
text-splitter = "0.27"
thiserror = "2"
tiktoken-rs = "0.7"
tokio = "1.45"
tree-sitter = { version = "0.25" }
tree-sitter-c = { version = "0.24" }
tree-sitter-c-sharp = { version = "0.23" }
tree-sitter-cpp = { version = "0.23" }
tree-sitter-go = { version = "0.23" }
tree-sitter-java = { version = "0.23" }
tree-sitter-javascript = { version = "0.23" }
tree-sitter-kotlin-ng = { version = "1.1" }
tree-sitter-python = { version = "0.23" }
tree-sitter-rust = { version = "0.24" }
tree-sitter-scala = { version = "0.24" }
tree-sitter-typescript = { version = "0.23" }
uniffi = "0.29"
url = { version = "2.5" }
uuid = "1.8"
v_htmlescape = "0.15"
windows = { version = "0.61", features = [
"Win32_Devices_FunctionDiscovery",
"Win32_UI_Shell_PropertiesSystem",
"Win32_Media_Audio",
"Win32_System_Variant",
"Win32_System_Com_StructuredStorage",
"Win32_System_Threading",
"Win32_System_ProcessStatus",
"Win32_Foundation",
"Win32_System_Com",
"Win32_System_Diagnostics_ToolHelp",
] }
windows-core = { version = "0.61" }
y-octo = { path = "./packages/common/y-octo/core" }
y-sync = { version = "0.4" }
yrs = "0.23.0"
[profile.dev.package.sqlx-macros]
opt-level = 3
@@ -139,6 +125,6 @@ lto = true
opt-level = 3
strip = "symbols"
# android uniffi bindgen requires symbols
[profile.release.package.affine_mobile_native]
strip = "none"
# android uniffi bindgen requires symbols
[profile.release.package.affine_mobile_native]
strip = "none"

View File

@@ -6,7 +6,7 @@
<br>
</h1>
<a href="https://affine.pro/download">
<img alt="affine logo" src="https://cdn.affine.pro/Github_hero_image2.png" style="width: 100%">
<img alt="affine logo" src="https://cdn.affine.pro/Github_hero_image1.png" style="width: 100%">
</a>
<br/>
<p align="center">

View File

@@ -6,12 +6,12 @@ We recommend users to always use the latest major version. Security updates will
| Version | Supported |
| --------------- | ------------------ |
| 0.24.x (stable) | :white_check_mark: |
| < 0.24.x | :x: |
| 0.17.x (stable) | :white_check_mark: |
| < 0.17.x | :x: |
## Reporting a Vulnerability
We welcome you to provide us with bug reports via and email at [security@toeverything.info](mailto:security@toeverything.info) or submit directly on [GitHub](https://github.com/toeverything/AFFiNE/security), **we encourage you to submit the relevant information directly via GitHub**. We expect your report to contain at least the following for us to evaluate and reproduce:
We welcome you to provide us with bug reports via and email at [security@toeverything.info](mailto:security@toeverything.info). We expect your report to contain at least the following for us to evaluate and reproduce:
1. Using platform and version, for example:
@@ -22,6 +22,8 @@ We welcome you to provide us with bug reports via and email at [security@toevery
3. Your classification or analysis of the vulnerability (optional)
Since we are an open source project, we also welcome you to provide corresponding fix PRs, we will determine specific rewards based on the evaluation results.
Since we are an open source project, we also welcome you to provide corresponding fix PRs.
We will provide bounties for vulnerabilities involving user information leakage, permission leakage, and unauthorized code execution. For other types of vulnerabilities, we will determine specific rewards based on the evaluation results.
If the vulnerability is caused by a library we depend on, we encourage you to submit a security report to the corresponding dependent library at the same time to benefit more users.

View File

@@ -296,7 +296,7 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5",
"version": "0.22.4",
"devDependencies": {
"@vanilla-extract/vite-plugin": "^5.0.0",
"msw": "^2.8.4",

View File

@@ -41,5 +41,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -45,5 +45,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -10,6 +10,7 @@
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@affine/component": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-ext-loader": "workspace:*",
"@blocksuite/affine-inline-preset": "workspace:*",
@@ -22,7 +23,6 @@
"@blocksuite/std": "workspace:*",
"@blocksuite/store": "workspace:*",
"@emoji-mart/data": "^1.2.1",
"@emotion/css": "^11.13.5",
"@floating-ui/dom": "^1.6.10",
"@lit/context": "^1.1.2",
"@preact/signals-core": "^1.8.0",
@@ -45,5 +45,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -1,56 +0,0 @@
import { css } from '@emotion/css';
export const calloutHostStyles = css({
display: 'block',
margin: '8px 0',
});
export const calloutBlockContainerStyles = css({
display: 'flex',
alignItems: 'flex-start',
padding: '5px 10px',
borderRadius: '8px',
});
export const calloutEmojiContainerStyles = css({
userSelect: 'none',
fontSize: '1.2em',
width: '24px',
height: '24px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
// marginTop is dynamically set by JavaScript based on first child's height
marginBottom: '10px',
flexShrink: 0,
position: 'relative',
});
export const calloutEmojiStyles = css({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
':hover': {
cursor: 'pointer',
opacity: 0.7,
},
});
export const calloutChildrenStyles = css({
flex: 1,
minWidth: 0,
paddingLeft: '10px',
});
export const iconPickerContainerStyles = css({
position: 'absolute',
top: '100%',
left: 0,
zIndex: 1000,
background: 'white',
border: '1px solid #ccc',
borderRadius: '8px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
width: '390px',
height: '400px',
});

View File

@@ -1,13 +1,6 @@
import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption';
import {
createPopup,
popupTargetFromElement,
} from '@blocksuite/affine-components/context-menu';
import { DefaultInlineManagerExtension } from '@blocksuite/affine-inline-preset';
import {
type CalloutBlockModel,
ParagraphBlockModel,
} from '@blocksuite/affine-model';
import { type CalloutBlockModel, DefaultTheme } from '@blocksuite/affine-model';
import { focusTextModel } from '@blocksuite/affine-rich-text';
import { EDGELESS_TOP_CONTENTEDITABLE_SELECTOR } from '@blocksuite/affine-shared/consts';
import {
@@ -15,24 +8,15 @@ import {
type IconData,
IconPickerServiceIdentifier,
IconType,
ThemeProvider,
} from '@blocksuite/affine-shared/services';
import type { UniComponent } from '@blocksuite/affine-shared/types';
import * as icons from '@blocksuite/icons/lit';
import type { BlockComponent } from '@blocksuite/std';
import { type Signal } from '@preact/signals-core';
import { cssVarV2 } from '@toeverything/theme/v2';
import { type Signal, signal } from '@preact/signals-core';
import type { TemplateResult } from 'lit';
import { html } from 'lit';
import { css, html } from 'lit';
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
import {
calloutBlockContainerStyles,
calloutChildrenStyles,
calloutEmojiContainerStyles,
calloutEmojiStyles,
calloutHostStyles,
} from './callout-block-styles.js';
import { IconPickerWrapper } from './icon-picker-wrapper.js';
// Copy of renderUniLit and UniLit from affine-data-view
export const renderUniLit = <Props, Expose extends NonNullable<unknown>>(
uni: UniComponent<Props, Expose> | undefined,
@@ -51,8 +35,9 @@ export const renderUniLit = <Props, Expose extends NonNullable<unknown>>(
></uni-lit>`;
};
const getIcon = (icon?: IconData) => {
console.log(icon);
if (!icon) {
return null;
return '💡';
}
if (icon.type === IconType.Emoji) {
return icon.unicode;
@@ -62,64 +47,85 @@ const getIcon = (icon?: IconData) => {
icons as Record<string, (props: { style: string }) => TemplateResult>
)[`${icon.name}Icon`]?.({ style: `color:${icon.color}` });
}
return null;
return '💡';
};
export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockModel> {
private _popupCloseHandler: (() => void) | null = null;
override connectedCallback() {
super.connectedCallback();
this.classList.add(calloutHostStyles);
}
private _getEmojiMarginTop(): string {
if (this.model.children.length === 0) {
return '10px';
static override styles = css`
:host {
display: block;
margin: 8px 0;
}
const firstChild = this.model.children[0];
const flavour = firstChild.flavour;
const marginTopMap: Record<string, string> = {
'affine:paragraph:h1': '23px',
'affine:paragraph:h2': '20px',
'affine:paragraph:h3': '16px',
'affine:paragraph:h4': '15px',
'affine:paragraph:h5': '14px',
'affine:paragraph:h6': '13px',
};
// For heading blocks, use the type to determine margin
if (flavour === 'affine:paragraph') {
const paragraph = firstChild as ParagraphBlockModel;
const type = paragraph.props.type$.value;
const key = `${flavour}:${type}`;
return marginTopMap[key] || '10px';
.affine-callout-block-container {
display: flex;
align-items: flex-start;
padding: 5px 10px;
border-radius: 8px;
}
// Default for all other block types
return '10px';
}
private _closeIconPicker() {
if (this._popupCloseHandler) {
this._popupCloseHandler();
this._popupCloseHandler = null;
.affine-callout-emoji-container {
user-select: none;
font-size: 1.2em;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
margin-bottom: 10px;
flex-shrink: 0;
position: relative;
}
.affine-callout-emoji {
display: flex;
align-items: center;
justify-content: center;
}
.affine-callout-emoji:hover {
cursor: pointer;
opacity: 0.7;
}
.affine-callout-children {
flex: 1;
min-width: 0;
padding-left: 10px;
}
.icon-picker-container {
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
background: white;
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
width: 300px;
height: 400px;
}
`;
private readonly showIconPicker$ = signal(false);
private _closeEmojiMenu() {
this.showIconPicker$.value = false;
}
private _toggleIconPicker(event: MouseEvent) {
// If popup is already open, close it
if (this._popupCloseHandler) {
this._closeIconPicker();
return;
private _toggleIconPicker() {
this.showIconPicker$.value = !this.showIconPicker$.value;
}
private _renderIconPicker() {
if (!this.showIconPicker$.value) {
return html``;
}
// Get IconPickerService from the framework
const iconPickerService = this.std.getOptional(IconPickerServiceIdentifier);
if (!iconPickerService) {
console.warn('IconPickerService not found');
return;
return html``;
}
// Get the uni-component from the service
@@ -129,31 +135,23 @@ export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockM
const props = {
onSelect: (iconData?: IconData) => {
this.model.props.icon$.value = iconData;
this._closeIconPicker(); // Close the picker after selection
this._closeEmojiMenu(); // Close the picker after selection
},
onClose: () => {
this._closeIconPicker();
this._closeEmojiMenu();
},
};
// Create IconPickerWrapper instance
const wrapper = new IconPickerWrapper();
wrapper.iconPickerComponent = iconPickerComponent;
wrapper.props = props;
wrapper.style.position = 'absolute';
wrapper.style.backgroundColor = cssVarV2.layer.background.overlayPanel;
wrapper.style.boxShadow = 'var(--affine-menu-shadow)';
wrapper.style.borderRadius = '8px';
// Create popup target from the clicked element
const target = popupTargetFromElement(event.currentTarget as HTMLElement);
// Create popup
this._popupCloseHandler = createPopup(target, wrapper, {
onClose: () => {
this._popupCloseHandler = null;
},
});
return html`
<div
@click=${(e: MouseEvent) => {
e.stopPropagation();
}}
class="icon-picker-container"
>
${renderUniLit(iconPickerComponent, props)}
</div>
`;
}
private readonly _handleBlockClick = (event: MouseEvent) => {
@@ -166,13 +164,6 @@ export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockM
return;
}
// If there's no icon, open icon picker on click
const icon = this.model.props.icon$.value;
if (!icon) {
this._toggleIconPicker(event);
return;
}
// Only handle clicks when there are no children
if (this.model.children.length > 0) {
return;
@@ -215,38 +206,33 @@ export class CalloutBlockComponent extends CaptionedBlockComponent<CalloutBlockM
override renderBlock() {
const icon = this.model.props.icon$.value;
const backgroundColorName = this.model.props.backgroundColorName$.value;
const backgroundColor = (
cssVarV2.block.callout.background as Record<string, string>
)[backgroundColorName ?? ''];
const background = this.model.props.background$.value;
const iconContent = getIcon(icon);
const themeProvider = this.std.get(ThemeProvider);
const theme = themeProvider.theme$.value;
const backgroundColor = themeProvider.generateColorProperty(
background || DefaultTheme.NoteBackgroundColorMap.White,
DefaultTheme.NoteBackgroundColorMap.White,
theme
);
return html`
<div
class="${calloutBlockContainerStyles}"
class="affine-callout-block-container"
@click=${this._handleBlockClick}
style=${styleMap({
backgroundColor: backgroundColor ?? 'transparent',
backgroundColor: backgroundColor,
})}
>
${iconContent
? html`
<div
@click=${this._toggleIconPicker}
contenteditable="false"
class="${calloutEmojiContainerStyles}"
style=${styleMap({
marginTop: this._getEmojiMarginTop(),
})}
>
<span class="${calloutEmojiStyles}" data-testid="callout-emoji"
>${iconContent}</span
>
</div>
`
: ''}
<div class="${calloutChildrenStyles}">
<div
@click=${this._toggleIconPicker}
contenteditable="false"
class="affine-callout-emoji-container"
>
<span class="affine-callout-emoji">${getIcon(icon)}</span>
${this._renderIconPicker()}
</div>
<div class="affine-callout-children">
${this.renderChildren(this.model)}
</div>
</div>

View File

@@ -1,4 +1,5 @@
import { focusBlockEnd } from '@blocksuite/affine-shared/commands';
import { FeatureFlagService } from '@blocksuite/affine-shared/services';
import { isInsideBlockByFlavour } from '@blocksuite/affine-shared/utils';
import { type SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { FontIcon } from '@blocksuite/icons/lit';
@@ -17,11 +18,10 @@ export const calloutSlashMenuConfig: SlashMenuConfig = {
},
searchAlias: ['callout'],
group: '0_Basic@9',
when: ({ model }) => {
return !isInsideBlockByFlavour(
model.store,
model,
'affine:edgeless-text'
when: ({ std, model }) => {
return (
std.get(FeatureFlagService).getFlag('enable_callout') &&
!isInsideBlockByFlavour(model.store, model, 'affine:edgeless-text')
);
},
action: ({ model, std }) => {

View File

@@ -1,28 +1,18 @@
import {
createPopup,
popupTargetFromElement,
} from '@blocksuite/affine-components/context-menu';
import { EditorChevronDown } from '@blocksuite/affine-components/toolbar';
import { CalloutBlockModel } from '@blocksuite/affine-model';
import { CalloutBlockModel, DefaultTheme } from '@blocksuite/affine-model';
import {
ActionPlacement,
type IconData,
IconPickerServiceIdentifier,
type ToolbarAction,
type ToolbarActionGroup,
type ToolbarModuleConfig,
ToolbarModuleExtension,
} from '@blocksuite/affine-shared/services';
import { DeleteIcon, PaletteIcon, SmileIcon } from '@blocksuite/icons/lit';
import { PaletteIcon } from '@blocksuite/icons/lit';
import { BlockFlavourIdentifier } from '@blocksuite/std';
import type { ExtensionType } from '@blocksuite/store';
import { cssVarV2 } from '@toeverything/theme/v2';
import { html } from 'lit';
import { repeat } from 'lit/directives/repeat.js';
import { styleMap } from 'lit/directives/style-map.js';
import { IconPickerWrapper } from '../icon-picker-wrapper.js';
const colors = [
'default',
'red',
@@ -48,7 +38,27 @@ const backgroundColorAction = {
if (!model) return null;
const updateBackground = (color: string) => {
ctx.store.updateBlock(model, { backgroundColorName: color });
// Map text highlight colors to note background colors
const colorMap: Record<
string,
keyof typeof DefaultTheme.NoteBackgroundColorMap | null
> = {
default: null,
red: 'Red',
orange: 'Orange',
yellow: 'Yellow',
green: 'Green',
teal: 'Green', // Map teal to green as it's not available in NoteBackgroundColorMap
blue: 'Blue',
purple: 'Purple',
grey: 'White', // Map grey to white as it's the closest available
};
const mappedColor = colorMap[color];
const backgroundValue = mappedColor
? DefaultTheme.NoteBackgroundColorMap[mappedColor]
: null;
ctx.store.updateBlock(model, { background: backgroundValue });
};
return html`
@@ -93,102 +103,12 @@ const backgroundColorAction = {
},
} satisfies ToolbarAction;
const iconPickerAction = {
id: 'icon-picker',
label: 'Icon Picker',
tooltip: 'Change icon',
icon: SmileIcon(),
run() {
// This will be handled by the content function
},
content(ctx) {
const model = ctx.getCurrentModelByType(CalloutBlockModel);
if (!model) return null;
const handleIconPickerClick = (event: MouseEvent) => {
// Get IconPickerService from the framework
const iconPickerService = ctx.std.getOptional(
IconPickerServiceIdentifier
);
if (!iconPickerService) {
console.warn('IconPickerService not found');
return;
}
// Get the uni-component from the service
const iconPickerComponent = iconPickerService.iconPickerComponent;
// Create props for the icon picker
const props = {
onSelect: (iconData?: IconData) => {
// When iconData is undefined (delete icon), set icon to undefined
ctx.store.updateBlock(model, { icon: iconData });
closeHandler(); // Close the picker after selection
},
onClose: () => {
closeHandler();
},
};
// Create IconPickerWrapper instance
const wrapper = new IconPickerWrapper();
wrapper.iconPickerComponent = iconPickerComponent;
wrapper.props = props;
wrapper.style.position = 'absolute';
wrapper.style.backgroundColor = cssVarV2.layer.background.overlayPanel;
wrapper.style.boxShadow = 'var(--affine-menu-shadow)';
wrapper.style.borderRadius = '8px';
// Create popup target from the clicked element
const target = popupTargetFromElement(event.currentTarget as HTMLElement);
// Create popup
const closeHandler = createPopup(target, wrapper, {
onClose: () => {
// Cleanup if needed
},
});
};
return html`
<editor-icon-button
aria-label="icon-picker"
.tooltip=${'Change Icon'}
@click=${handleIconPickerClick}
>
${SmileIcon()} ${EditorChevronDown}
</editor-icon-button>
`;
},
} satisfies ToolbarAction;
const builtinToolbarConfig = {
actions: [
{
id: 'style',
actions: [backgroundColorAction],
} satisfies ToolbarActionGroup<ToolbarAction>,
{
id: 'icon',
actions: [iconPickerAction],
} satisfies ToolbarActionGroup<ToolbarAction>,
{
placement: ActionPlacement.More,
id: 'c.delete',
label: 'Delete',
icon: DeleteIcon(),
variant: 'destructive',
run(ctx) {
const model = ctx.getCurrentModelByType(CalloutBlockModel);
if (!model) return;
ctx.store.deleteBlock(model);
// Clears
ctx.select('note');
ctx.reset();
},
} satisfies ToolbarAction,
],
} as const satisfies ToolbarModuleConfig;

View File

@@ -1,14 +1,11 @@
import { CalloutBlockComponent } from './callout-block';
import { IconPickerWrapper } from './icon-picker-wrapper';
export function effects() {
customElements.define('affine-callout', CalloutBlockComponent);
customElements.define('icon-picker-wrapper', IconPickerWrapper);
}
declare global {
interface HTMLElementTagNameMap {
'affine-callout': CalloutBlockComponent;
'icon-picker-wrapper': IconPickerWrapper;
}
}

View File

@@ -1,52 +0,0 @@
import type { IconData } from '@blocksuite/affine-shared/services';
import type { UniComponent } from '@blocksuite/affine-shared/types';
import { ShadowlessElement } from '@blocksuite/std';
import { type Signal } from '@preact/signals-core';
import { html, type TemplateResult } from 'lit';
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
// Copy of renderUniLit from callout-block.ts
const renderUniLit = <Props, Expose extends NonNullable<unknown>>(
uni: UniComponent<Props, Expose> | undefined,
props?: Props,
options?: {
ref?: Signal<Expose | undefined>;
style?: Readonly<StyleInfo>;
class?: string;
}
): TemplateResult => {
return html` <uni-lit
.uni="${uni}"
.props="${props}"
.ref="${options?.ref}"
style=${options?.style ? styleMap(options?.style) : ''}
></uni-lit>`;
};
export interface IconPickerWrapperProps {
onSelect?: (iconData?: IconData) => void;
onClose?: () => void;
}
export class IconPickerWrapper extends ShadowlessElement {
iconPickerComponent?: UniComponent<IconPickerWrapperProps, any>;
props?: IconPickerWrapperProps;
constructor() {
super();
}
override render() {
if (!this.iconPickerComponent) {
return html``;
}
return renderUniLit(this.iconPickerComponent, this.props);
}
}
declare global {
interface HTMLElementTagNameMap {
'icon-picker-wrapper': IconPickerWrapper;
}
}

View File

@@ -48,5 +48,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -42,5 +42,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -48,5 +48,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -176,7 +176,7 @@ export class DatabaseTitle extends SignalWatcher(
private readonly isFocus$ = signal(false);
private onPressEnterKey() {
this.input.blur();
this.dataViewLogic.addRow?.('start');
}
get readonly$() {

View File

@@ -39,5 +39,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -43,5 +43,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -49,5 +49,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -323,8 +323,7 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent<EmbedLinke
private readonly _renderEmbedView = () => {
const linkedDoc = this.linkedDoc;
const trash = linkedDoc?.meta?.trash;
const isDeleted = trash || !linkedDoc;
const isDeleted = !linkedDoc;
const isLoading = this._loading;
const isError = this.isError;
const isEmpty = this._isDocEmpty() && this.isBannerEmpty;
@@ -522,6 +521,11 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent<EmbedLinke
);
this._setDocUpdatedAt();
this.disposables.add(
this.store.workspace.slots.docListUpdated.subscribe(() => {
this._setDocUpdatedAt();
})
);
if (this._referenceToNode) {
this._linkedDocMode = this.model.props.params?.mode ?? 'page';
@@ -550,13 +554,6 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent<EmbedLinke
})
);
this.disposables.add(
this.store.workspace.slots.docListUpdated.subscribe(() => {
this._setDocUpdatedAt();
this.refreshData();
})
);
this._trackCitationDeleteEvent();
}

View File

@@ -56,9 +56,6 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
// Caches total bounds, includes all blocks and elements.
private _cachedBounds: Bound | null = null;
private _hasRenderedSyncedView = false;
private _hasInitedFitEffect = false;
private readonly _initEdgelessFitEffect = () => {
const fitToContent = () => {
if (this.isPageMode) return;
@@ -360,14 +357,10 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
};
refreshData = () => {
this._load()
.then(() => {
this._isEmptySyncedDoc = isEmptyDoc(this.syncedDoc, this.editorMode);
})
.catch(e => {
console.error(e);
this._error = true;
});
this._load().catch(e => {
console.error(e);
this._error = true;
});
};
title$ = computed(() => {
@@ -452,8 +445,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
this._cycle = false;
const syncedDoc = this.syncedDoc;
const trash = syncedDoc?.meta?.trash;
if (trash || !syncedDoc) {
if (!syncedDoc) {
this._deleted = true;
this._loading = false;
return;
@@ -529,7 +521,6 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
this.disposables.add(
this.store.workspace.slots.docListUpdated.subscribe(() => {
this._setDocUpdatedAt();
this.refreshData();
})
);
@@ -561,6 +552,8 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
this._selectBlock();
}
});
this._initEdgelessFitEffect();
}
override renderBlock() {
@@ -588,21 +581,12 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
);
}
!this._hasRenderedSyncedView && (this._hasRenderedSyncedView = true);
return this._renderSyncedView();
}
override updated(changedProperties: PropertyValues) {
super.updated(changedProperties);
this.syncedDocCard?.requestUpdate();
if (!this._hasInitedFitEffect && this._hasRenderedSyncedView) {
/* Register the resizeObserver AFTER syncdView viewport's own resizeObserver
* so that viewport.onResize() use up-to-date boundingClientRect values */
this._hasInitedFitEffect = true;
this._initEdgelessFitEffect();
}
}
@state()

View File

@@ -49,5 +49,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -44,5 +44,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -44,5 +44,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -1,5 +1,4 @@
import { updateBlockAlign } from '@blocksuite/affine-block-note';
import { ImageBlockModel, TextAlign } from '@blocksuite/affine-model';
import { ImageBlockModel } from '@blocksuite/affine-model';
import {
ActionPlacement,
blockCommentToolbarButton,
@@ -13,9 +12,6 @@ import {
DeleteIcon,
DownloadIcon,
DuplicateIcon,
TextAlignCenterIcon,
TextAlignLeftIcon,
TextAlignRightIcon,
} from '@blocksuite/icons/lit';
import { BlockFlavourIdentifier } from '@blocksuite/std';
import type { ExtensionType } from '@blocksuite/store';
@@ -55,55 +51,7 @@ const builtinToolbarConfig = {
},
},
{
id: 'c.1.align-left',
tooltip: 'Align left',
icon: TextAlignLeftIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
if (block) {
ctx.chain
.pipe(updateBlockAlign, {
textAlign: TextAlign.Left,
selectedBlocks: [block],
})
.run();
}
},
},
{
id: 'c.2.align-center',
tooltip: 'Align center',
icon: TextAlignCenterIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
if (block) {
ctx.chain
.pipe(updateBlockAlign, {
textAlign: TextAlign.Center,
selectedBlocks: [block],
})
.run();
}
},
},
{
id: 'c.3.align-right',
tooltip: 'Align right',
icon: TextAlignRightIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
if (block) {
ctx.chain
.pipe(updateBlockAlign, {
textAlign: TextAlign.Right,
selectedBlocks: [block],
})
.run();
}
},
},
{
id: 'd.comment',
id: 'c.comment',
...blockCommentToolbarButton,
},
{

View File

@@ -143,15 +143,6 @@ export class ImageBlockComponent extends CaptionedBlockComponent<ImageBlockModel
width: '100%',
});
const alignItemsStyleMap = styleMap({
alignItems:
this.model.props.textAlign$.value === 'left'
? 'flex-start'
: this.model.props.textAlign$.value === 'right'
? 'flex-end'
: undefined,
});
const resovledState = this.resourceController.resolveStateWith({
loadingIcon: LoadingIcon({
strokeColor: cssVarV2('button/pureWhiteText'),
@@ -171,7 +162,6 @@ export class ImageBlockComponent extends CaptionedBlockComponent<ImageBlockModel
html`<affine-page-image
.block=${this}
.state=${resovledState}
style="${alignItemsStyleMap}"
></affine-page-image>`,
() =>
html`<affine-image-fallback-card

View File

@@ -46,5 +46,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -46,5 +46,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -150,10 +150,6 @@ export class ListBlockComponent extends CaptionedBlockComponent<ListBlockModel>
const listIcon = getListIcon(model, !collapsed, _onClickIcon);
const textAlignStyle = styleMap({
textAlign: this.model.props.textAlign$?.value,
});
const children = html`<div
class="affine-block-children-container"
style=${styleMap({
@@ -165,7 +161,7 @@ export class ListBlockComponent extends CaptionedBlockComponent<ListBlockModel>
</div>`;
return html`
<div class=${'affine-list-block-container'} style="${textAlignStyle}">
<div class=${'affine-list-block-container'}>
<div
class=${classMap({
'affine-list-rich-text-wrapper': true,

View File

@@ -49,5 +49,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -8,4 +8,3 @@ export { indentBlock } from './indent-block.js';
export { indentBlocks } from './indent-blocks.js';
export { selectBlock } from './select-block.js';
export { selectBlocksBetween } from './select-blocks-between.js';
export { updateBlockAlign } from './update-block-align.js';

View File

@@ -1,53 +0,0 @@
import type { TextAlign } from '@blocksuite/affine-model';
import {
getBlockSelectionsCommand,
getImageSelectionsCommand,
getSelectedBlocksCommand,
getTextSelectionCommand,
} from '@blocksuite/affine-shared/commands';
import {
type BlockComponent,
type Command,
TextSelection,
} from '@blocksuite/std';
type UpdateBlockAlignConfig = {
textAlign: TextAlign;
selectedBlocks?: BlockComponent[];
};
export const updateBlockAlign: Command<UpdateBlockAlignConfig> = (
ctx,
next
) => {
let { std, textAlign, selectedBlocks } = ctx;
if (!selectedBlocks) {
const [result, ctx] = std.command
.chain()
.tryAll(chain => [
chain.pipe(getTextSelectionCommand),
chain.pipe(getBlockSelectionsCommand),
chain.pipe(getImageSelectionsCommand),
])
.pipe(getSelectedBlocksCommand, { types: ['text', 'block', 'image'] })
.run();
if (result) {
selectedBlocks = ctx.selectedBlocks;
}
}
if (!selectedBlocks || selectedBlocks.length === 0) return false;
selectedBlocks.forEach(block => {
std.store.updateBlock(block.model, { textAlign });
});
const selectionManager = std.host.selection;
const textSelection = selectionManager.find(TextSelection);
if (!textSelection) {
return false;
}
selectionManager.setGroup('note', [textSelection]);
return next();
};

View File

@@ -4,15 +4,9 @@ import {
textFormatConfigs,
} from '@blocksuite/affine-inline-preset';
import {
type TextAlignConfig,
textAlignConfigs,
type TextConversionConfig,
textConversionConfigs,
} from '@blocksuite/affine-rich-text';
import {
getSelectedModelsCommand,
getTextSelectionCommand,
} from '@blocksuite/affine-shared/commands';
import { isInsideBlockByFlavour } from '@blocksuite/affine-shared/utils';
import {
type SlashMenuActionItem,
@@ -23,7 +17,7 @@ import {
import { HeadingsIcon } from '@blocksuite/icons/lit';
import { BlockSelection } from '@blocksuite/std';
import { updateBlockAlign, updateBlockType } from '../commands';
import { updateBlockType } from '../commands';
import { tooltips } from './tooltips';
let basicIndex = 0;
@@ -66,10 +60,6 @@ const noteSlashMenuConfig: SlashMenuConfig = {
createConversionItem(config, `1_List@${index++}`)
),
...textAlignConfigs.map((config, index) =>
createAlignItem(config, `2_Align@${index++}`)
),
...textFormatConfigs
.filter(i => !['Code', 'Link'].includes(i.name))
.map((config, index) =>
@@ -99,26 +89,6 @@ function createConversionItem(
};
}
function createAlignItem(
config: TextAlignConfig,
group?: SlashMenuItem['group']
): SlashMenuActionItem {
const { textAlign, name, icon } = config;
return {
name,
group,
icon,
action: ({ std }) => {
std.command
.chain()
.pipe(getTextSelectionCommand)
.pipe(getSelectedModelsCommand, { types: ['text'] })
.pipe(updateBlockAlign, { textAlign })
.run();
},
};
}
function createTextFormatItem(
config: TextFormatConfig,
group?: SlashMenuItem['group']

View File

@@ -5,10 +5,7 @@ import {
NoteBlockSchema,
ParagraphBlockModel,
} from '@blocksuite/affine-model';
import {
textAlignConfigs,
textConversionConfigs,
} from '@blocksuite/affine-rich-text';
import { textConversionConfigs } from '@blocksuite/affine-rich-text';
import {
focusBlockEnd,
focusBlockStart,
@@ -39,7 +36,6 @@ import {
indentBlocks,
selectBlock,
selectBlocksBetween,
updateBlockAlign,
updateBlockType,
} from './commands';
import { moveBlockConfigs } from './move-block';
@@ -161,36 +157,6 @@ class NoteKeymap {
);
};
private readonly _bindTextAlignHotKey = () => {
return textAlignConfigs.reduce(
(acc, item) => {
const keymap = item.hotkey!.reduce(
(acc, key) => {
return {
...acc,
[key]: ctx => {
ctx.get('defaultState').event.preventDefault();
const [result] = this._std.command
.chain()
.pipe(updateBlockAlign, { textAlign: item.textAlign })
.run();
return result;
},
};
},
{} as Record<string, UIEventHandler>
);
return {
...acc,
...keymap,
};
},
{} as Record<string, UIEventHandler>
);
};
private _focusBlock: BlockComponent | null = null;
private readonly _getClosestNoteByBlockId = (blockId: string) => {
@@ -602,7 +568,6 @@ class NoteKeymap {
...this._bindMoveBlockHotKey(),
...this._bindQuickActionHotKey(),
...this._bindTextConversionHotKey(),
...this._bindTextAlignHotKey(),
Tab: ctx => {
const [success] = this.std.command.exec(indentBlocks);

View File

@@ -42,5 +42,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -264,10 +264,6 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
`;
}
const textAlignStyle = styleMap({
textAlign: this.model.props.textAlign$?.value,
});
const children = html`<div
class="affine-block-children-container"
style=${styleMap({
@@ -292,7 +288,6 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
'affine-paragraph-block-container': true,
'highlight-comment': this.isCommentHighlighted,
})}
style="${textAlignStyle}"
data-has-collapsed-siblings="${collapsedSiblings.length > 0}"
>
<div

View File

@@ -46,7 +46,7 @@
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.16",
"@types/lodash-es": "^4.17.12",
"dompurify": "^3.3.0",
"dompurify": "^3.2.4",
"html2canvas": "^1.4.1",
"lit": "^3.2.0",
"lodash-es": "^4.17.21",
@@ -67,5 +67,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -8,10 +8,7 @@ import {
notifyDocCreated,
promptDocTitle,
} from '@blocksuite/affine-block-embed';
import {
updateBlockAlign,
updateBlockType,
} from '@blocksuite/affine-block-note';
import { updateBlockType } from '@blocksuite/affine-block-note';
import type { HighlightType } from '@blocksuite/affine-components/highlight-dropdown-menu';
import { toast } from '@blocksuite/affine-components/toast';
import { EditorChevronDown } from '@blocksuite/affine-components/toolbar';
@@ -26,12 +23,8 @@ import {
import {
EmbedLinkedDocBlockSchema,
EmbedSyncedDocBlockSchema,
type TextAlign,
} from '@blocksuite/affine-model';
import {
textAlignConfigs,
textConversionConfigs,
} from '@blocksuite/affine-rich-text';
import { textConversionConfigs } from '@blocksuite/affine-rich-text';
import {
copySelectedModelsCommand,
deleteSelectedModelsCommand,
@@ -53,7 +46,6 @@ import {
ActionPlacement,
blockCommentToolbarButton,
} from '@blocksuite/affine-shared/services';
import { getMostCommonValue } from '@blocksuite/affine-shared/utils';
import { tableViewMeta } from '@blocksuite/data-view/view-presets';
import {
CopyIcon,
@@ -138,64 +130,6 @@ const conversionsActionGroup = {
},
} as const satisfies ToolbarActionGenerator;
const alignActionGroup = {
id: 'b.align',
when: ({ chain }) => isFormatSupported(chain).run()[0],
generate({ chain }) {
const [ok, { selectedModels = [] }] = chain
.tryAll(chain => [
chain.pipe(getTextSelectionCommand),
chain.pipe(getBlockSelectionsCommand),
])
.pipe(getSelectedModelsCommand, { types: ['text', 'block'] })
.run();
if (!ok) return null;
const alignment =
textAlignConfigs.find(
({ textAlign }) =>
textAlign ===
getMostCommonValue(
selectedModels.map(
({ props }) => props as { textAlign?: TextAlign }
),
'textAlign'
)
) ?? textAlignConfigs[0];
const update = (textAlign: TextAlign) => {
chain.pipe(updateBlockAlign, { textAlign }).run();
};
return {
content: html`
<editor-menu-button
.contentPadding="${'8px'}"
.button=${html`
<editor-icon-button aria-label="Align" .tooltip="${'Align'}">
${alignment.icon} ${EditorChevronDown}
</editor-icon-button>
`}
>
<div data-size="large" data-orientation="vertical">
${repeat(
textAlignConfigs,
item => item.name,
({ textAlign, name, icon }) => html`
<editor-menu-action
aria-label=${name}
@click=${() => update(textAlign)}
>
${icon}<span class="label">${name}</span>
</editor-menu-action>
`
)}
</div>
</editor-menu-button>
`,
};
},
} as const satisfies ToolbarActionGenerator;
const inlineTextActionGroup = {
id: 'b.inline-text',
when: ({ chain }) => isFormatSupported(chain).run()[0],
@@ -357,7 +291,6 @@ const turnIntoLinkedDoc = {
export const builtinToolbarConfig = {
actions: [
conversionsActionGroup,
alignActionGroup,
inlineTextActionGroup,
highlightActionGroup,
turnIntoDatabase,

View File

@@ -45,5 +45,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -46,5 +46,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -113,7 +113,7 @@ export class CanvasRenderer {
* It is not recommended to set width and height to 100%.
*/
private _canvasSizeUpdater(dpr = window.devicePixelRatio) {
const { width, height, viewScale } = this.viewport;
const { width, height } = this.viewport;
const actualWidth = Math.ceil(width * dpr);
const actualHeight = Math.ceil(height * dpr);
@@ -124,8 +124,6 @@ export class CanvasRenderer {
update(canvas: HTMLCanvasElement) {
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
canvas.style.transform = `scale(${1 / viewScale})`;
canvas.style.transformOrigin = `top left`;
canvas.width = actualWidth;
canvas.height = actualHeight;
},

View File

@@ -42,5 +42,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -144,16 +144,6 @@ export class TableBlockComponent extends CaptionedBlockComponent<TableBlockModel
style=${styleMap({
paddingLeft: `${virtualPadding}px`,
paddingRight: `${virtualPadding}px`,
marginLeft:
!this.model.props.textAlign$.value ||
this.model.props.textAlign$?.value === 'left'
? undefined
: 'auto',
marginRight:
!this.model.props.textAlign$.value ||
this.model.props.textAlign$?.value === 'right'
? undefined
: 'auto',
width: 'max-content',
})}
>

View File

@@ -82,5 +82,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -229,9 +229,9 @@ export class DatePicker extends WithDisposable(LitElement) {
private _modeDecade(offset: number) {
this._yearCursor = clamp(
this._yearCursor + offset,
this._minYear,
this._maxYear
this._maxYear,
this._yearCursor + offset
);
this._getYearMatrix();
}

View File

@@ -46,5 +46,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -1,36 +0,0 @@
import { describe, expect, test } from 'vitest';
import { mobileEffects } from '../view-presets/table/mobile/effect.js';
import type { MobileTableGroup } from '../view-presets/table/mobile/group.js';
import { pcEffects } from '../view-presets/table/pc/effect.js';
import type { TableGroup } from '../view-presets/table/pc/group.js';
/** @vitest-environment happy-dom */
describe('TableGroup', () => {
test('toggle collapse on pc', () => {
pcEffects();
const group = document.createElement(
'affine-data-view-table-group'
) as TableGroup;
expect(group.collapsed$.value).toBe(false);
(group as any)._toggleCollapse();
expect(group.collapsed$.value).toBe(true);
(group as any)._toggleCollapse();
expect(group.collapsed$.value).toBe(false);
});
test('toggle collapse on mobile', () => {
mobileEffects();
const group = document.createElement(
'mobile-table-group'
) as MobileTableGroup;
expect(group.collapsed$.value).toBe(false);
(group as any)._toggleCollapse();
expect(group.collapsed$.value).toBe(true);
(group as any)._toggleCollapse();
expect(group.collapsed$.value).toBe(false);
});
});

View File

@@ -26,10 +26,13 @@ const GroupTitleMobile = (
const type = groupData.tType;
if (!type) return nothing;
const icon = html` <uni-lit
class="group-header-icon"
.uni="${groupData.property.icon}"
></uni-lit>`;
const icon =
groupData.value == null
? ''
: html` <uni-lit
class="group-header-icon"
.uni="${groupData.property.icon}"
></uni-lit>`;
const props: GroupRenderProps = {
group: groupData,
readonly: ops.readonly,
@@ -123,10 +126,13 @@ export const GroupTitle = (
const type = groupData.tType;
if (!type) return nothing;
const icon = html` <uni-lit
class="group-header-icon"
.uni="${groupData.property.icon}"
></uni-lit>`;
const icon =
groupData.value == null
? ''
: html` <uni-lit
class="group-header-icon"
.uni="${groupData.property.icon}"
></uni-lit>`;
const props: GroupRenderProps = {
group: groupData,
readonly: ops.readonly,

View File

@@ -1,44 +0,0 @@
/**
* Shared utility for managing table group collapsed state in sessionStorage.
* Used by both PC and mobile table group implementations.
*/
/**
* Gets the collapsed state for a specific table group from sessionStorage.
* @param viewId - The ID of the table view
* @param groupKey - The key of the group
* @returns The collapsed state as a boolean, or false if not found or invalid
*/
export function getCollapsedState(viewId: string, groupKey: string): boolean {
try {
const value = sessionStorage.getItem(
`affine:table-group:${viewId}:${groupKey}:collapsed`
);
if (!value) return false;
const parsed = JSON.parse(value);
return typeof parsed === 'boolean' ? parsed : false;
} catch {
return false;
}
}
/**
* Sets the collapsed state for a specific table group in sessionStorage.
* @param viewId - The ID of the table view
* @param groupKey - The key of the group
* @param collapsed - The collapsed state to store
*/
export function setCollapsedState(
viewId: string,
groupKey: string,
collapsed: boolean
): void {
try {
sessionStorage.setItem(
`affine:table-group:${viewId}:${groupKey}:collapsed`,
JSON.stringify(collapsed)
);
} catch {
// ignore
}
}

View File

@@ -4,22 +4,16 @@ import {
popupTargetFromElement,
} from '@blocksuite/affine-components/context-menu';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
import {
PlusIcon,
ToggleDownIcon,
ToggleRightIcon,
} from '@blocksuite/icons/lit';
import { PlusIcon } from '@blocksuite/icons/lit';
import { ShadowlessElement } from '@blocksuite/std';
import { signal } from '@preact/signals-core';
import { cssVarV2 } from '@toeverything/theme/v2';
import { css, html, nothing, unsafeCSS } from 'lit';
import { css, html, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { GroupTitle } from '../../../core/group-by/group-title.js';
import type { Group } from '../../../core/group-by/trait.js';
import type { Row } from '../../../core/index.js';
import { getCollapsedState, setCollapsedState } from '../collapsed-state.js';
import { LEFT_TOOL_BAR_WIDTH } from '../consts.js';
import type { MobileTableViewUILogic } from './table-view-ui-logic.js';
@@ -48,28 +42,6 @@ const styles = css`
line-height: 20px;
color: var(--affine-text-secondary-color);
}
.group-toggle-btn {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
cursor: pointer;
transition: background-color 150ms cubic-bezier(0.42, 0, 1, 1);
}
.group-toggle-btn:hover {
background: var(--affine-hover-color);
}
.group-toggle-btn svg {
width: 16px;
height: 16px;
flex-shrink: 0;
user-select: none;
}
`;
export class MobileTableGroup extends SignalWatcher(
@@ -77,29 +49,6 @@ export class MobileTableGroup extends SignalWatcher(
) {
static override styles = styles;
collapsed$ = signal(false);
private storageLoaded = false;
private _loadCollapsedState() {
if (this.storageLoaded) return;
this.storageLoaded = true;
const view = this.tableViewLogic?.view;
if (!view) return;
const value = getCollapsedState(view.id, this.group?.key ?? 'all');
this.collapsed$.value = value;
}
private readonly _toggleCollapse = (e?: MouseEvent) => {
e?.stopPropagation();
const next = !this.collapsed$.value;
this.collapsed$.value = next;
const view = this.tableViewLogic?.view;
if (view) {
setCollapsedState(view.id, this.group?.key ?? 'all', next);
}
};
private readonly clickAddRow = () => {
this.view.rowAdd('end', this.group?.key);
this.requestUpdate();
@@ -144,27 +93,6 @@ export class MobileTableGroup extends SignalWatcher(
<div
style="position: sticky;left: 0;width: max-content;padding: 6px 0;margin-bottom: 4px;display:flex;align-items:center;gap: 12px;max-width: 400px"
>
<div
class=${`group-toggle-btn ${this.collapsed$.value ? '' : 'expanded'}`}
role="button"
aria-expanded=${this.collapsed$.value ? 'false' : 'true'}
aria-label=${this.collapsed$.value
? 'Expand group'
: 'Collapse group'}
tabindex="0"
@click=${this._toggleCollapse}
@keydown=${(e: KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this._toggleCollapse();
}
}}
>
${this.collapsed$.value
? ToggleRightIcon({ width: '16px', height: '16px' })
: ToggleDownIcon({ width: '16px', height: '16px' })}
</div>
${GroupTitle(this.group, {
readonly: this.view.readonly$.value,
clickAdd: this.clickAddRowInStart,
@@ -181,6 +109,7 @@ export class MobileTableGroup extends SignalWatcher(
private renderRows(rows: Row[]) {
return html`
<mobile-table-header
.renderGroupHeader="${this.renderGroupHeader}"
.tableViewManager="${this.view}"
></mobile-table-header>
<div class="mobile-affine-table-body">
@@ -215,26 +144,8 @@ export class MobileTableGroup extends SignalWatcher(
`;
}
override willUpdate(changed: Map<PropertyKey, unknown>): void {
super.willUpdate(changed);
if (
!this.storageLoaded &&
(changed.has('group') || changed.has('tableViewLogic'))
) {
this._loadCollapsedState();
}
}
override connectedCallback(): void {
super.connectedCallback();
this._loadCollapsedState();
}
override render() {
return html`
${this.collapsed$.value ? this.renderGroupHeader() : nothing}
${this.collapsed$.value ? nothing : this.renderRows(this.rows)}
`;
return this.renderRows(this.rows);
}
@property({ attribute: false })

View File

@@ -57,12 +57,12 @@ const styles = css`
margin-inline: 5px;
}
.stats-cell .label {
.label {
text-transform: uppercase;
color: var(--affine-text-secondary-color);
}
.stats-cell .value {
.value {
color: var(--affine-text-primary-color);
}
`;

View File

@@ -4,15 +4,11 @@ import {
popupTargetFromElement,
} from '@blocksuite/affine-components/context-menu';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
import {
PlusIcon,
ToggleDownIcon,
ToggleRightIcon,
} from '@blocksuite/icons/lit';
import { PlusIcon } from '@blocksuite/icons/lit';
import { ShadowlessElement } from '@blocksuite/std';
import { effect, signal } from '@preact/signals-core';
import { effect } from '@preact/signals-core';
import { cssVarV2 } from '@toeverything/theme/v2';
import { css, html, nothing, unsafeCSS } from 'lit';
import { css, html, unsafeCSS } from 'lit';
import { property, query } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
@@ -22,7 +18,6 @@ import type { Row } from '../../../core/index.js';
import { createDndContext } from '../../../core/utils/wc-dnd/dnd-context.js';
import { defaultActivators } from '../../../core/utils/wc-dnd/sensors/index.js';
import { linearMove } from '../../../core/utils/wc-dnd/utils/linear-move.js';
import { getCollapsedState, setCollapsedState } from '../collapsed-state.js';
import { LEFT_TOOL_BAR_WIDTH } from '../consts.js';
import { TableViewAreaSelection } from '../selection';
import { DataViewColumnPreview } from './header/column-renderer.js';
@@ -35,12 +30,6 @@ const styles = css`
opacity: 1;
}
affine-data-view-table-group {
margin-top: 4px;
padding-top: 4px;
border-top: 1px solid var(--affine-border-color);
}
.data-view-table-group-add-row {
display: flex;
width: 100%;
@@ -53,10 +42,6 @@ const styles = css`
border-bottom: 1px solid ${unsafeCSS(cssVarV2.layer.insideBorder.border)};
}
.affine-data-view-table-group:hover svg {
fill: var(--affine-icon-color);
}
@media print {
.data-view-table-group-add-row {
display: none;
@@ -75,28 +60,6 @@ const styles = css`
line-height: 20px;
color: var(--affine-text-secondary-color);
}
.group-toggle-btn {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
cursor: pointer;
transition: background-color 150ms cubic-bezier(0.42, 0, 1, 1);
}
.group-toggle-btn:hover {
background: var(--affine-hover-color);
}
.group-toggle-btn svg {
width: 16px;
height: 16px;
flex-shrink: 0;
user-select: none;
}
`;
export class TableGroup extends SignalWatcher(
@@ -104,29 +67,6 @@ export class TableGroup extends SignalWatcher(
) {
static override styles = styles;
collapsed$ = signal(false);
private storageLoaded = false;
private _loadCollapsedState() {
if (this.storageLoaded) return;
this.storageLoaded = true;
const view = this.tableViewLogic?.view;
if (!view) return;
const value = getCollapsedState(view.id, this.group?.key ?? 'all');
this.collapsed$.value = value;
}
private readonly _toggleCollapse = (e?: MouseEvent) => {
e?.stopPropagation();
const next = !this.collapsed$.value;
this.collapsed$.value = next;
const view = this.tableViewLogic?.view;
if (view) {
setCollapsedState(view.id, this.group?.key ?? 'all', next);
}
};
private readonly clickAddRow = () => {
this.view.rowAdd('end', this.group?.key);
const selectionController = this.tableViewLogic.selectionController;
@@ -197,32 +137,10 @@ export class TableGroup extends SignalWatcher(
if (!this.group) {
return null;
}
return html`
<div
style="position: sticky;left: 0;width: max-content;padding: 6px 0;margin-bottom: 4px;display:flex;align-items:center;gap: 8px;max-width: 400px"
style="position: sticky;left: 0;width: max-content;padding: 6px 0;margin-bottom: 4px;display:flex;align-items:center;gap: 12px;max-width: 400px"
>
<div
class=${`group-toggle-btn ${this.collapsed$.value ? '' : 'expanded'}`}
role="button"
aria-expanded=${this.collapsed$.value ? 'false' : 'true'}
aria-label=${this.collapsed$.value
? 'Expand group'
: 'Collapse group'}
tabindex="0"
@click=${this._toggleCollapse}
@keydown=${(e: KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this._toggleCollapse();
}
}}
>
${this.collapsed$.value
? ToggleRightIcon({ width: '16px', height: '16px' })
: ToggleDownIcon({ width: '16px', height: '16px' })}
</div>
${GroupTitle(this.group, {
readonly: this.view.readonly$.value,
clickAdd: this.clickAddRowInStart,
@@ -326,8 +244,8 @@ export class TableGroup extends SignalWatcher(
private renderRows(rows: Row[]) {
return html`
<affine-database-column-header
.renderGroupHeader=${this.renderGroupHeader}
.tableViewLogic=${this.tableViewLogic}
.renderGroupHeader="${this.renderGroupHeader}"
.tableViewLogic="${this.tableViewLogic}"
></affine-database-column-header>
<div class="affine-database-block-rows">
${repeat(
@@ -366,27 +284,13 @@ export class TableGroup extends SignalWatcher(
`;
}
override willUpdate(changed: Map<PropertyKey, unknown>): void {
super.willUpdate(changed);
if (
!this.storageLoaded &&
(changed.has('group') || changed.has('tableViewLogic'))
) {
this._loadCollapsedState();
}
}
override connectedCallback(): void {
super.connectedCallback();
this._loadCollapsedState();
this.showIndicator();
}
override render() {
return html`
${this.collapsed$.value ? this.renderGroupHeader() : nothing}
${this.collapsed$.value ? nothing : this.renderRows(this.rows)}
`;
return this.renderRows(this.rows);
}
@query('.affine-database-block-rows')

View File

@@ -57,12 +57,12 @@ const styles = css`
margin-inline: 5px;
}
.stats-cell .label {
.label {
text-transform: uppercase;
color: var(--affine-text-secondary-color);
}
.stats-cell .value {
.value {
color: var(--affine-text-primary-color);
}
`;

View File

@@ -26,5 +26,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -42,5 +42,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -35,5 +35,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -40,5 +40,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -19,16 +19,16 @@ const DOC_BLOCK_CHILD_PADDING = 24;
export class DocTitle extends WithDisposable(ShadowlessElement) {
static override styles = css`
.doc-title-container {
font-size: 40px;
line-height: 50px;
font-weight: 700;
}
.doc-icon-container,
.doc-title-container {
box-sizing: border-box;
font-family: var(--affine-font-family);
font-size: var(--affine-font-base);
line-height: var(--affine-line-height);
color: var(--affine-text-primary-color);
font-size: 40px;
line-height: 50px;
font-weight: 700;
outline: none;
resize: none;
border: 0;
@@ -47,10 +47,6 @@ export class DocTitle extends WithDisposable(ShadowlessElement) {
${DOC_BLOCK_CHILD_PADDING}px
);
}
.doc-icon-container + * .doc-title-container {
/* when doc icon exists, remove the top padding */
padding-top: 0;
}
/* Extra small devices (phones, 640px and down) */
@container viewport (width <= 640px) {

View File

@@ -42,5 +42,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -41,5 +41,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -43,5 +43,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -44,5 +44,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -44,5 +44,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -45,5 +45,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -51,5 +51,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -45,5 +45,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -42,5 +42,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -60,20 +60,12 @@ export class PanTool extends BaseTool<PanToolOption> {
return;
}
const currentTool = this.controller.currentToolOption$.peek();
const { toolType, options: originalToolOptions } = currentTool;
if (toolType?.toolName === PanTool.toolName) {
return;
}
evt.raw.preventDefault();
const selectionToRestore = this.gfx.selection.surfaceSelections.slice();
const currentTool = this.controller.currentToolOption$.peek();
const restoreToPrevious = () => {
this.gfx.selection.set(selectionToRestore);
const { toolType, options: originalToolOptions } = currentTool;
const selectionToRestore = this.gfx.selection.surfaceSelections;
if (!toolType) return;
// restore to DefaultTool if previous tool is CopilotTool
if (toolType.toolName === 'copilot') {
@@ -96,18 +88,21 @@ export class PanTool extends BaseTool<PanToolOption> {
} as RestorablePresentToolOptions;
}
this.controller.setTool(toolType, finalOptions);
this.gfx.selection.set(selectionToRestore);
};
// If in presentation mode, disable black background after middle mouse drag
if (toolType?.toolName === 'frameNavigator') {
if (currentTool.toolType?.toolName === 'frameNavigator') {
const slots = this.std.get(EdgelessLegacySlotIdentifier);
slots.navigatorSettingUpdated.next({
blackBackground: false,
});
}
this.controller.setTool(PanTool, {
panning: true,
requestAnimationFrame(() => {
this.controller.setTool(PanTool, {
panning: true,
});
});
const dispose = on(document, 'pointerup', evt => {

View File

@@ -44,5 +44,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -44,5 +44,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -43,5 +43,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -25,5 +25,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -42,5 +42,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.21.0"
}

View File

@@ -47,5 +47,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -50,5 +50,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -44,5 +44,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -42,5 +42,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -56,5 +56,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -43,5 +43,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -30,5 +30,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

View File

@@ -6,20 +6,22 @@ import {
type Text,
} from '@blocksuite/store';
import type { Color } from '../../themes/index.js';
import { DefaultTheme } from '../../themes/index.js';
import type { BlockMeta } from '../../utils/types';
export type CalloutProps = {
icon?: IconData;
text: Text;
backgroundColorName?: string;
background: Color;
} & BlockMeta;
export const CalloutBlockSchema = defineBlockSchema({
flavour: 'affine:callout',
props: (internal): CalloutProps => ({
icon: { type: 'emoji', unicode: '💡' } as IconData,
icon: undefined,
text: internal.Text(),
backgroundColorName: 'grey',
background: DefaultTheme.NoteBackgroundColorMap.White,
'meta:createdAt': undefined,
'meta:updatedAt': undefined,
'meta:createdBy': undefined,

View File

@@ -9,7 +9,6 @@ import {
defineBlockSchema,
} from '@blocksuite/store';
import type { TextAlign } from '../../consts';
import type { BlockMeta } from '../../utils/types.js';
import { ImageBlockTransformer } from './image-transformer.js';
@@ -21,7 +20,6 @@ export type ImageBlockProps = {
rotate: number;
size?: number;
comments?: Record<string, boolean>;
textAlign?: TextAlign;
} & Omit<GfxCommonBlockProps, 'scale'> &
BlockMeta;
@@ -36,7 +34,6 @@ const defaultImageProps: ImageBlockProps = {
rotate: 0,
size: -1,
comments: undefined,
textAlign: undefined,
'meta:createdAt': undefined,
'meta:createdBy': undefined,
'meta:updatedAt': undefined,

View File

@@ -5,7 +5,6 @@ import {
defineBlockSchema,
} from '@blocksuite/store';
import type { TextAlign } from '../../consts';
import type { BlockMeta } from '../../utils/types';
// `toggle` type has been deprecated, do not use it
@@ -14,7 +13,6 @@ export type ListType = 'bulleted' | 'numbered' | 'todo' | 'toggle';
export type ListProps = {
type: ListType;
text: Text;
textAlign?: TextAlign;
checked: boolean;
collapsed: boolean;
order: number | null;
@@ -27,7 +25,6 @@ export const ListBlockSchema = defineBlockSchema({
({
type: 'bulleted',
text: internal.Text(),
textAlign: undefined,
checked: false,
collapsed: false,

View File

@@ -5,7 +5,6 @@ import {
type Text,
} from '@blocksuite/store';
import type { TextAlign } from '../../consts';
import type { BlockMeta } from '../../utils/types';
export type ParagraphType =
@@ -20,7 +19,6 @@ export type ParagraphType =
export type ParagraphProps = {
type: ParagraphType;
textAlign?: TextAlign;
text: Text;
collapsed: boolean;
comments?: Record<string, boolean>;
@@ -31,7 +29,6 @@ export const ParagraphBlockSchema = defineBlockSchema({
props: (internal): ParagraphProps => ({
type: 'text',
text: internal.Text(),
textAlign: undefined,
collapsed: false,
comments: undefined,
'meta:createdAt': undefined,

View File

@@ -5,7 +5,6 @@ import {
defineBlockSchema,
} from '@blocksuite/store';
import type { TextAlign } from '../../consts';
import type { BlockMeta } from '../../utils/types';
export type TableCell = {
@@ -31,7 +30,6 @@ export interface TableBlockProps extends BlockMeta {
// key = `${rowId}:${columnId}`
cells: Record<string, TableCell>;
comments?: Record<string, boolean>;
textAlign?: TextAlign;
}
export interface TableCellSerialized {
@@ -55,7 +53,6 @@ export const TableBlockSchema = defineBlockSchema({
columns: {},
cells: {},
comments: undefined,
textAlign: undefined,
'meta:createdAt': undefined,
'meta:createdBy': undefined,
'meta:updatedAt': undefined,

View File

@@ -41,5 +41,5 @@
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.25.5"
"version": "0.22.4"
}

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