Merge pull request #122 from luminous-devs/v2.1.4

v2.1.4
This commit is contained in:
Ren Amamiya 2023-11-26 07:22:13 +07:00 committed by GitHub
commit 619bfb8dff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 636 additions and 397 deletions

View File

@ -2,7 +2,7 @@
"name": "lume",
"description": "the communication app",
"private": true,
"version": "2.1.3",
"version": "2.1.4",
"scripts": {
"dev": "vite",
"build": "vite build",
@ -19,8 +19,8 @@
},
"dependencies": {
"@evilmartians/harmony": "^1.1.0",
"@getalby/sdk": "^2.6.0",
"@nostr-dev-kit/ndk": "^2.0.5",
"@getalby/sdk": "^2.7.0",
"@nostr-dev-kit/ndk": "^2.1.1",
"@nostr-fetch/adapter-ndk": "^0.13.1",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-avatar": "^1.0.4",
@ -32,7 +32,7 @@
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toolbar": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.7",
"@tanstack/react-query": "^5.8.4",
"@tanstack/react-query": "^5.8.7",
"@tauri-apps/api": "2.0.0-alpha.11",
"@tauri-apps/cli": "2.0.0-alpha.17",
"@tauri-apps/plugin-autostart": "2.0.0-alpha.3",
@ -80,19 +80,19 @@
"react-router-dom": "^6.20.0",
"react-string-replace": "^1.1.1",
"reactflow": "^11.10.1",
"sonner": "^1.2.2",
"sonner": "^1.2.3",
"tailwind-scrollbar": "^3.0.5",
"tauri-controls": "github:reyamir/tauri-controls",
"tippy.js": "^6.3.7",
"tiptap-markdown": "^0.8.4",
"virtua": "^0.16.6",
"virtua": "^0.16.7",
"zustand": "^4.4.6"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.10",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/html-to-text": "^9.0.4",
"@types/node": "^20.9.4",
"@types/node": "^20.10.0",
"@types/react": "^18.2.38",
"@types/react-dom": "^18.2.17",
"@types/youtube-player": "^5.5.11",

View File

@ -9,14 +9,14 @@ dependencies:
specifier: ^1.1.0
version: 1.1.0
'@getalby/sdk':
specifier: ^2.6.0
version: 2.6.0
specifier: ^2.7.0
version: 2.7.0(typescript@5.3.2)
'@nostr-dev-kit/ndk':
specifier: ^2.0.5
version: 2.0.5(typescript@5.3.2)
specifier: ^2.1.1
version: 2.1.1(typescript@5.3.2)
'@nostr-fetch/adapter-ndk':
specifier: ^0.13.1
version: 0.13.1(@nostr-dev-kit/ndk@2.0.5)(nostr-fetch@0.13.1)
version: 0.13.1(@nostr-dev-kit/ndk@2.1.1)(nostr-fetch@0.13.1)
'@radix-ui/react-alert-dialog':
specifier: ^1.0.5
version: 1.0.5(@types/react-dom@18.2.17)(@types/react@18.2.38)(react-dom@18.2.0)(react@18.2.0)
@ -48,8 +48,8 @@ dependencies:
specifier: ^1.0.7
version: 1.0.7(@types/react-dom@18.2.17)(@types/react@18.2.38)(react-dom@18.2.0)(react@18.2.0)
'@tanstack/react-query':
specifier: ^5.8.4
version: 5.8.4(react-dom@18.2.0)(react@18.2.0)
specifier: ^5.8.7
version: 5.8.7(react-dom@18.2.0)(react@18.2.0)
'@tauri-apps/api':
specifier: 2.0.0-alpha.11
version: 2.0.0-alpha.11
@ -192,8 +192,8 @@ dependencies:
specifier: ^11.10.1
version: 11.10.1(@types/react@18.2.38)(react-dom@18.2.0)(react@18.2.0)
sonner:
specifier: ^1.2.2
version: 1.2.2(react-dom@18.2.0)(react@18.2.0)
specifier: ^1.2.3
version: 1.2.3(react-dom@18.2.0)(react@18.2.0)
tailwind-scrollbar:
specifier: ^3.0.5
version: 3.0.5(tailwindcss@3.3.5)
@ -207,8 +207,8 @@ dependencies:
specifier: ^0.8.4
version: 0.8.4(@tiptap/core@2.1.12)
virtua:
specifier: ^0.16.6
version: 0.16.6(react-dom@18.2.0)(react@18.2.0)
specifier: ^0.16.7
version: 0.16.7(react-dom@18.2.0)(react@18.2.0)
zustand:
specifier: ^4.4.6
version: 4.4.6(@types/react@18.2.38)(react@18.2.0)
@ -224,8 +224,8 @@ devDependencies:
specifier: ^9.0.4
version: 9.0.4
'@types/node':
specifier: ^20.9.4
version: 20.9.4
specifier: ^20.10.0
version: 20.10.0
'@types/react':
specifier: ^18.2.38
version: 18.2.38
@ -303,7 +303,7 @@ devDependencies:
version: 5.3.2
vite:
specifier: ^4.5.0
version: 4.5.0(@types/node@20.9.4)
version: 4.5.0(@types/node@20.10.0)
vite-tsconfig-paths:
specifier: ^4.2.1
version: 4.2.1(typescript@5.3.2)(vite@4.5.0)
@ -731,13 +731,15 @@ packages:
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
dev: false
/@getalby/sdk@2.6.0:
resolution: {integrity: sha512-klD1FrpGY39QldPf00KtzIveWj0dXtgGdZH6nLWdJ0Ness7FAqy2RkgSF7JQfKJeJSFek7Ip3AL/KCT5/lZgww==}
/@getalby/sdk@2.7.0(typescript@5.3.2):
resolution: {integrity: sha512-4NoEgdjx0R8SYDmJfCAsgvuBs0w3d8wsOMGI4m0h2MVsSeCcWW93lrzCl8bRmHTF5N7EfleHwnieYwn5j9KZTA==}
engines: {node: '>=14'}
dependencies:
crypto-js: 4.2.0
events: 3.3.0
nostr-tools: 1.13.1
nostr-tools: 1.17.0(typescript@5.3.2)
transitivePeerDependencies:
- typescript
dev: false
/@humanwhocodes/config-array@0.11.13:
@ -833,17 +835,17 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
/@nostr-dev-kit/ndk@2.0.5(typescript@5.3.2):
resolution: {integrity: sha512-EvVr43y+4N9lMSZIIe5V8jFWYlKTVkMyyJfbgRaDGCGiBZAm9iy0wcO2Yi+W57awOAlvr3mjT5fAwG9RDb6HSA==}
/@nostr-dev-kit/ndk@2.1.1(typescript@5.3.2):
resolution: {integrity: sha512-sMD4re3QVpSVMzoyvJAFiftPxJBXkhjRInrK5DcjhSkkPTlJhI+oiVXCpcvCJ3PHT5PilhDgKkg3LyOvv135UQ==}
dependencies:
'@noble/hashes': 1.3.2
'@noble/secp256k1': 2.0.0
'@scure/base': 1.1.3
debug: 4.3.4
eventemitter3: 5.0.1
light-bolt11-decoder: 3.0.0
node-fetch: 3.3.2
nostr-tools: 1.17.0(typescript@5.3.2)
tseep: 1.1.3
typescript-lru-cache: 2.0.0
utf8-buffer: 1.0.0
websocket-polyfill: 0.0.3
@ -852,13 +854,13 @@ packages:
- typescript
dev: false
/@nostr-fetch/adapter-ndk@0.13.1(@nostr-dev-kit/ndk@2.0.5)(nostr-fetch@0.13.1):
/@nostr-fetch/adapter-ndk@0.13.1(@nostr-dev-kit/ndk@2.1.1)(nostr-fetch@0.13.1):
resolution: {integrity: sha512-B3xeFR/qZHOzyy68WZCL+v+OjOZHG9YBW6jEpp1b1hzogAkoqSYJfYHo55Heka/CUp8z7dteYV/tmabtTCVcPA==}
peerDependencies:
'@nostr-dev-kit/ndk': ^0.8.4
nostr-fetch: ^0.13.1
dependencies:
'@nostr-dev-kit/ndk': 2.0.5(typescript@5.3.2)
'@nostr-dev-kit/ndk': 2.1.1(typescript@5.3.2)
'@nostr-fetch/kernel': 0.13.1
nostr-fetch: 0.13.1
dev: false
@ -2005,12 +2007,12 @@ packages:
tailwindcss: 3.3.5
dev: true
/@tanstack/query-core@5.8.3:
resolution: {integrity: sha512-SWFMFtcHfttLYif6pevnnMYnBvxKf3C+MHMH7bevyYfpXpTMsLB9O6nNGBdWSoPwnZRXFNyNeVZOw25Wmdasow==}
/@tanstack/query-core@5.8.7:
resolution: {integrity: sha512-58xOSkxxZK4SGQ/uzX8MDZHLGZCkxlgkPxnfhxUOL2uchnNHyay2UVcR3mQNMgaMwH1e2l+0n+zfS7+UJ/MAJw==}
dev: false
/@tanstack/react-query@5.8.4(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-CD+AkXzg8J72JrE6ocmuBEJfGzEzu/bzkD6sFXFDDB5yji9N20JofXZlN6n0+CaPJuIi+e4YLCbGsyPFKkfNQA==}
/@tanstack/react-query@5.8.7(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-RYSSMmkhbJ7tPkf8w+MSRIXQLoUCm7DRnTLDcdf+uampupnriEsob3fVWTt9oaEj+AJWEKeCErDBdZeNcAzURQ==}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
@ -2021,7 +2023,7 @@ packages:
react-native:
optional: true
dependencies:
'@tanstack/query-core': 5.8.3
'@tanstack/query-core': 5.8.7
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
@ -2735,8 +2737,8 @@ packages:
resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==}
dev: false
/@types/node@20.9.4:
resolution: {integrity: sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==}
/@types/node@20.10.0:
resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==}
dependencies:
undici-types: 5.26.5
dev: true
@ -2920,7 +2922,7 @@ packages:
vite: ^4 || ^5
dependencies:
'@swc/core': 1.3.99
vite: 4.5.0(@types/node@20.9.4)
vite: 4.5.0(@types/node@20.10.0)
transitivePeerDependencies:
- '@swc/helpers'
dev: true
@ -3146,7 +3148,7 @@ packages:
hasBin: true
dependencies:
caniuse-lite: 1.0.30001564
electron-to-chromium: 1.4.592
electron-to-chromium: 1.4.594
node-releases: 2.0.13
update-browserslist-db: 1.0.13(browserslist@4.22.1)
dev: true
@ -3156,7 +3158,7 @@ packages:
engines: {node: '>=6.14.2'}
requiresBuild: true
dependencies:
node-gyp-build: 4.7.0
node-gyp-build: 4.7.1
dev: false
/call-bind@1.0.5:
@ -3519,8 +3521,8 @@ packages:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: true
/electron-to-chromium@1.4.592:
resolution: {integrity: sha512-D3NOkROIlF+d5ixnz7pAf3Lu/AuWpd6AYgI9O67GQXMXTcCP1gJQRotOq35eQy5Sb4hez33XH1YdTtILA7Udww==}
/electron-to-chromium@1.4.594:
resolution: {integrity: sha512-xT1HVAu5xFn7bDfkjGQi9dNpMqGchUkebwf1GL7cZN32NSwwlHRPMSDJ1KN6HkS0bWUtndbSQZqvpQftKG2uFQ==}
dev: true
/emoji-regex@9.2.2:
@ -3862,6 +3864,7 @@ packages:
/eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
dev: true
/events@3.3.0:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
@ -4757,8 +4760,8 @@ packages:
formdata-polyfill: 4.0.10
dev: false
/node-gyp-build@4.7.0:
resolution: {integrity: sha512-PbZERfeFdrHQOOXiAKOY0VPbykZy90ndPKk0d+CFDegTKmWp1VgOTz2xACVbr1BjCWxrQp68CXtvNsveFhqDJg==}
/node-gyp-build@4.7.1:
resolution: {integrity: sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==}
hasBin: true
dev: false
@ -4781,16 +4784,6 @@ packages:
'@nostr-fetch/kernel': 0.13.1
dev: false
/nostr-tools@1.13.1:
resolution: {integrity: sha512-DTwpbxTH1/ar+afWd4gmVdpHH8CF290kdaxi00Llra88SHE6e38XuyzlRABVTcrBaceLMnoDdHmV3x16MoEFJg==}
dependencies:
'@noble/curves': 1.1.0
'@noble/hashes': 1.3.1
'@scure/base': 1.1.1
'@scure/bip32': 1.3.1
'@scure/bip39': 1.2.1
dev: false
/nostr-tools@1.17.0(typescript@5.3.2):
resolution: {integrity: sha512-LZmR8GEWKZeElbFV5Xte75dOeE9EFUW/QLI1Ncn3JKn0kFddDKEfBbFN8Mu4TMs+L4HR/WTPha2l+PPuRnJcMw==}
peerDependencies:
@ -5672,8 +5665,8 @@ packages:
is-fullwidth-code-point: 4.0.0
dev: true
/sonner@1.2.2(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-EHxYBr5tLDQW4CqosTsX95/Qd5oxjDeQN/EbKBZcjdNp4Hjs6snXB6Lmu1kTL27M3su0oG9DxkllfvX+aSoI4Q==}
/sonner@1.2.3(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-LMr155izOFA8hudzuUVQT0H93VqmcF9ODP475YjjC/4INESYWN1/ioC5SYRG20jmDmwuQDR8ugP7y6ELghT6JQ==}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
@ -5915,6 +5908,10 @@ packages:
typescript: 5.3.2
dev: true
/tseep@1.1.3:
resolution: {integrity: sha512-deBIcIlXUMlr3xaN0UEochqjU/zXGaZGPqHPd1rxo4w6DklBdRM6WQQtsk7bekIF+qY6QTeen3nE6OA7BxL9rg==}
dev: false
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: false
@ -6084,7 +6081,7 @@ packages:
engines: {node: '>=6.14.2'}
requiresBuild: true
dependencies:
node-gyp-build: 4.7.0
node-gyp-build: 4.7.1
dev: false
/utf8-buffer@1.0.0:
@ -6095,8 +6092,8 @@ packages:
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
/virtua@0.16.6(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-I2vFlh7sCUTK4nVZzPj2IhgGRFtNVrVQD2nrpFPedotjcLjeE3Z9cJslGsU4Go2y65kBymwqT19Hwkycs4IFVQ==}
/virtua@0.16.7(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-n7fzGHm88lY+ZlYadqrWV/7uiwAxg58na1+LSnEnVZdVFH2EJVsF3QgAA9sP9J2/OeNhxHd6nhgVKNEslWSOMA==}
peerDependencies:
react: '>=16.14.0'
react-dom: '>=16.14.0'
@ -6116,13 +6113,13 @@ packages:
debug: 4.3.4
globrex: 0.1.2
tsconfck: 2.1.2(typescript@5.3.2)
vite: 4.5.0(@types/node@20.9.4)
vite: 4.5.0(@types/node@20.10.0)
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/vite@4.5.0(@types/node@20.9.4):
/vite@4.5.0(@types/node@20.10.0):
resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
@ -6150,7 +6147,7 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 20.9.4
'@types/node': 20.10.0
esbuild: 0.18.20
postcss: 8.4.31
rollup: 3.29.4

177
src-tauri/Cargo.lock generated
View File

@ -183,12 +183,12 @@ dependencies = [
[[package]]
name = "async-channel"
version = "2.1.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e"
checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
dependencies = [
"concurrent-queue",
"event-listener 3.1.0",
"event-listener 4.0.0",
"event-listener-strategy",
"futures-core",
"pin-project-lite",
@ -196,11 +196,11 @@ dependencies = [
[[package]]
name = "async-executor"
version = "1.7.2"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc5ea910c42e5ab19012bab31f53cb4d63d54c3a27730f9a833a88efcf4bb52d"
checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c"
dependencies = [
"async-lock 3.1.1",
"async-lock 3.1.2",
"async-task",
"concurrent-queue",
"fastrand 2.0.1",
@ -242,22 +242,21 @@ dependencies = [
[[package]]
name = "async-io"
version = "2.2.0"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ed9d5715c2d329bf1b4da8d60455b99b187f27ba726df2883799af9af60997"
checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff"
dependencies = [
"async-lock 3.1.1",
"async-lock 3.1.2",
"cfg-if",
"concurrent-queue",
"futures-io",
"futures-lite 2.0.1",
"parking",
"polling 3.3.0",
"polling 3.3.1",
"rustix 0.38.25",
"slab",
"tracing",
"waker-fn",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -271,11 +270,11 @@ dependencies = [
[[package]]
name = "async-lock"
version = "3.1.1"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "655b9c7fe787d3b25cc0f804a1a8401790f0c5bc395beb5a64dc77d8de079105"
checksum = "dea8b3453dd7cc96711834b75400d671b73e3656975fa68d9f277163b7f7e316"
dependencies = [
"event-listener 3.1.0",
"event-listener 4.0.0",
"event-listener-strategy",
"pin-project-lite",
]
@ -314,7 +313,7 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5"
dependencies = [
"async-io 2.2.0",
"async-io 2.2.1",
"async-lock 2.8.0",
"atomic-waker",
"cfg-if",
@ -381,6 +380,16 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "atomic-write-file"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c232177ba50b16fe7a4588495bd474a62a9e45a8e4ca6fd7d0b7ac29d164631e"
dependencies = [
"nix 0.26.4",
"rand 0.8.5",
]
[[package]]
name = "auto-launch"
version = "0.5.0"
@ -501,7 +510,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
dependencies = [
"async-channel",
"async-lock 3.1.1",
"async-lock 3.1.2",
"async-task",
"fastrand 2.0.1",
"futures-io",
@ -1108,9 +1117,9 @@ dependencies = [
[[package]]
name = "data-url"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41b319d1b62ffbd002e057f36bebd1f42b9f97927c9577461d855f3513c4289f"
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
[[package]]
name = "der"
@ -1368,12 +1377,23 @@ dependencies = [
]
[[package]]
name = "event-listener-strategy"
version = "0.3.0"
name = "event-listener"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160"
checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae"
dependencies = [
"event-listener 3.1.0",
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener-strategy"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
dependencies = [
"event-listener 4.0.0",
"pin-project-lite",
]
@ -1511,9 +1531,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
name = "form_urlencoded"
version = "1.2.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
"percent-encoding",
]
@ -1818,9 +1838,9 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.28.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "gio"
@ -2259,9 +2279,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.4.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
@ -2575,9 +2595,9 @@ dependencies = [
[[package]]
name = "libsqlite3-sys"
version = "0.26.0"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716"
dependencies = [
"cc",
"pkg-config",
@ -2660,7 +2680,7 @@ dependencies = [
[[package]]
name = "lume"
version = "2.1.3"
version = "2.1.4"
dependencies = [
"keyring",
"serde",
@ -2941,6 +2961,7 @@ dependencies = [
"cfg-if",
"libc",
"memoffset 0.7.1",
"pin-utils",
]
[[package]]
@ -3180,9 +3201,9 @@ dependencies = [
[[package]]
name = "openssl"
version = "0.10.59"
version = "0.10.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
@ -3221,9 +3242,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.95"
version = "0.9.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
dependencies = [
"cc",
"libc",
@ -3369,9 +3390,9 @@ dependencies = [
[[package]]
name = "percent-encoding"
version = "2.3.0"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "phf"
@ -3602,16 +3623,16 @@ dependencies = [
[[package]]
name = "polling"
version = "3.3.0"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531"
checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e"
dependencies = [
"cfg-if",
"concurrent-queue",
"pin-project-lite",
"rustix 0.38.25",
"tracing",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -4470,9 +4491,9 @@ dependencies = [
[[package]]
name = "sqlx"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e50c216e3624ec8e7ecd14c6a6a6370aad6ee5d8cfc3ab30b5162eeeef2ed33"
checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
dependencies = [
"sqlx-core",
"sqlx-macros",
@ -4483,9 +4504,9 @@ dependencies = [
[[package]]
name = "sqlx-cli"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e80bc07dfc7f258db72ae5d72d793aa87943690fc1b2afc87b4cabf87035bac0"
checksum = "1b941ddc37071bb01d001ec479885a493021f1ca39142d754a05a780a77fff99"
dependencies = [
"anyhow",
"async-trait",
@ -4508,9 +4529,9 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d"
checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
dependencies = [
"ahash",
"atoi",
@ -4549,9 +4570,9 @@ dependencies = [
[[package]]
name = "sqlx-macros"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a793bb3ba331ec8359c1853bd39eed32cdd7baaf22c35ccf5c92a7e8d1189ec"
checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
dependencies = [
"proc-macro2",
"quote",
@ -4562,10 +4583,11 @@ dependencies = [
[[package]]
name = "sqlx-macros-core"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a4ee1e104e00dedb6aa5ffdd1343107b0a4702e862a84320ee7cc74782d96fc"
checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
dependencies = [
"atomic-write-file",
"dotenvy",
"either",
"heck",
@ -4588,9 +4610,9 @@ dependencies = [
[[package]]
name = "sqlx-mysql"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db"
checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
dependencies = [
"atoi",
"base64",
@ -4631,9 +4653,9 @@ dependencies = [
[[package]]
name = "sqlx-postgres"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624"
checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
dependencies = [
"atoi",
"base64",
@ -4671,9 +4693,9 @@ dependencies = [
[[package]]
name = "sqlx-sqlite"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59dc83cf45d89c555a577694534fcd1b55c545a816c816ce51f20bbe56a4f3f"
checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
dependencies = [
"atoi",
"flume",
@ -4690,6 +4712,7 @@ dependencies = [
"time",
"tracing",
"url",
"urlencoding",
]
[[package]]
@ -5033,7 +5056,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-autostart"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"auto-launch",
"log",
@ -5046,7 +5069,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-cli"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"clap",
"log",
@ -5059,7 +5082,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-clipboard-manager"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"arboard",
"log",
@ -5073,7 +5096,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-dialog"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"glib 0.16.9",
"log",
@ -5090,7 +5113,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-fs"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"anyhow",
"glob",
@ -5103,7 +5126,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-http"
version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"data-url",
"glob",
@ -5120,7 +5143,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-notification"
version = "2.0.0-alpha.5"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"log",
"notify-rust",
@ -5138,7 +5161,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-os"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"gethostname 0.4.3",
"log",
@ -5154,7 +5177,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-process"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"tauri",
]
@ -5162,7 +5185,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-shell"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"encoding_rs",
"log",
@ -5179,7 +5202,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-sql"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"futures-core",
"log",
@ -5195,7 +5218,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-store"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"log",
"serde",
@ -5223,7 +5246,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-updater"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"base64",
"dirs-next",
@ -5249,7 +5272,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-upload"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"futures-util",
"log",
@ -5266,7 +5289,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-window-state"
version = "2.0.0-alpha.4"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#445c1e6cb6971ef644a08d1224fc689923be301b"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#f49b391f10515db4465da32d839c5cc43ebdb3d3"
dependencies = [
"bincode",
"bitflags 2.4.1",
@ -5783,9 +5806,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "url"
version = "2.4.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [
"form_urlencoded",
"idna",
@ -5793,6 +5816,12 @@ dependencies = [
"serde",
]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "utf-8"
version = "0.7.6"

View File

@ -1,6 +1,6 @@
[package]
name = "lume"
version = "2.1.3"
version = "2.1.4"
description = "the communication app"
authors = ["Ren Amamiya"]
license = "GPL-3.0"

View File

@ -9,7 +9,7 @@
},
"package": {
"productName": "Lume",
"version": "2.1.3"
"version": "2.1.4"
},
"plugins": {
"fs": {

View File

@ -21,7 +21,7 @@ export function OutboxModel() {
<div className="rounded-xl bg-neutral-100 p-3 text-neutral-800 dark:bg-neutral-900 dark:text-neutral-200">
<div className="flex items-start justify-between gap-2">
<div>
<h5 className="font-semibold">Enable Outbox (experiment)</h5>
<h5 className="font-semibold">Enable Outbox</h5>
<p className="text-sm">
When you request information about a user, Lume will automatically query the
user&apos;s outbox relays and subsequent queries will favour using those

View File

@ -13,21 +13,13 @@ export function FollowList() {
queryKey: ['follows'],
queryFn: async () => {
const user = ndk.getUser({ pubkey: db.account.pubkey });
const follows = await user.follows();
const followsAsArr = [];
follows.forEach((user) => {
followsAsArr.push(user.pubkey);
});
const follows = [...(await user.follows())].map((user) => user.pubkey);
// update db
await db.updateAccount('follows', JSON.stringify(followsAsArr));
await db.updateAccount('circles', JSON.stringify(followsAsArr));
await db.updateAccount('follows', JSON.stringify(follows));
db.account.follows = follows;
db.account.follows = followsAsArr;
db.account.circles = followsAsArr;
return followsAsArr;
return follows;
},
refetchOnWindowFocus: false,
});

View File

@ -44,7 +44,8 @@ export function ImportAccountScreen() {
try {
const pubkey = nip19.decode(npub.split('#')[0]).data as string;
const localSigner = NDKPrivateKeySigner.generate();
await db.secureSave(pubkey + '-bunker', localSigner.privateKey);
await db.createSetting('nsecbunker', '1');
await db.secureSave(pubkey + '-nsecbunker', localSigner.privateKey);
const remoteSigner = new NDKNip46Signer(ndk, npub, localSigner);
// await remoteSigner.blockUntilReady();

View File

@ -2,7 +2,6 @@ import { useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { AllowNotification } from '@app/auth/components/features/allowNotification';
import { Circle } from '@app/auth/components/features/enableCircle';
import { OutboxModel } from '@app/auth/components/features/enableOutbox';
import { FavoriteHashtag } from '@app/auth/components/features/favoriteHashtag';
import { FollowList } from '@app/auth/components/features/followList';
@ -41,7 +40,6 @@ export function OnboardingListScreen() {
<div className="flex flex-col gap-3">
{newuser ? <SuggestFollow /> : <FollowList />}
<FavoriteHashtag />
<Circle />
<OutboxModel />
<AllowNotification />
<button

View File

@ -4,7 +4,7 @@ import Image from '@tiptap/extension-image';
import Placeholder from '@tiptap/extension-placeholder';
import { EditorContent, FloatingMenu, useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import { useMemo, useState } from 'react';
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { toast } from 'sonner';
import { twMerge } from 'tailwind-merge';
@ -27,12 +27,14 @@ import {
export function NewArticleScreen() {
const { ndk } = useNDK();
const [height, setHeight] = useState(0);
const [loading, setLoading] = useState(false);
const [title, setTitle] = useState('');
const [summary, setSummary] = useState({ open: false, content: '' });
const [cover, setCover] = useState('');
const navigate = useNavigate();
const containerRef = useRef(null);
const ident = useMemo(() => String(Date.now()), []);
const editor = useEditor({
extensions: [
@ -113,123 +115,133 @@ export function NewArticleScreen() {
}
};
useLayoutEffect(() => {
setHeight(containerRef.current.clientHeight);
}, []);
return (
<div className="flex h-full flex-col justify-between">
<div className="flex flex-col gap-4">
{cover ? (
<img
src={cover}
alt="post cover"
className="h-72 w-full rounded-lg object-cover"
/>
) : null}
<div className="group flex justify-between gap-2">
<input
name="title"
className="h-9 flex-1 border-none bg-transparent text-2xl font-semibold text-neutral-900 shadow-none outline-none placeholder:text-neutral-400 dark:text-neutral-100 dark:placeholder:text-neutral-600"
placeholder="Untitled"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<div
className={twMerge(
'inline-flex shrink-0 gap-2 group-hover:inline-flex',
title.length > 0 ? '' : 'hidden'
)}
>
<ArticleCoverUploader setCover={setCover} />
<button
type="button"
onClick={() => setSummary((prev) => ({ ...prev, open: !prev.open }))}
className="inline-flex h-9 w-max items-center gap-2 rounded-lg bg-neutral-100 px-2.5 text-sm font-medium hover:bg-neutral-200 dark:bg-neutral-800 dark:hover:bg-neutral-800"
<div className="flex flex-1 flex-col justify-between">
<div className="flex-1 overflow-y-auto">
<div
className="flex flex-col gap-4"
ref={containerRef}
style={{ height: `${height}px` }}
>
{cover ? (
<img
src={cover}
alt="post cover"
className="h-72 w-full rounded-lg object-cover"
/>
) : null}
<div className="group flex justify-between gap-2">
<input
name="title"
className="h-9 flex-1 border-none bg-transparent text-2xl font-semibold text-neutral-900 shadow-none outline-none placeholder:text-neutral-400 dark:text-neutral-100 dark:placeholder:text-neutral-600"
placeholder="Untitled"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<div
className={twMerge(
'inline-flex shrink-0 gap-2 group-hover:inline-flex',
title.length > 0 ? '' : 'hidden'
)}
>
<ThreadsIcon className="h-4 w-4" />
Add summary
</button>
</div>
</div>
{summary.open ? (
<div className="flex gap-3">
<div className="h-16 w-1 shrink-0 rounded-full bg-neutral-200 dark:bg-neutral-800" />
<div className="flex-1">
<textarea
className="h-16 w-full border-none bg-transparent px-1 py-1 text-neutral-900 shadow-none outline-none placeholder:text-neutral-400 dark:text-neutral-100 dark:placeholder:text-neutral-600"
placeholder="A brief summary of your article"
value={summary.content}
onChange={(e) =>
setSummary((prev) => ({ ...prev, content: e.target.value }))
}
/>
<ArticleCoverUploader setCover={setCover} />
<button
type="button"
onClick={() => setSummary((prev) => ({ ...prev, open: !prev.open }))}
className="inline-flex h-9 w-max items-center gap-2 rounded-lg bg-neutral-100 px-2.5 text-sm font-medium hover:bg-neutral-200 dark:bg-neutral-800 dark:hover:bg-neutral-800"
>
<ThreadsIcon className="h-4 w-4" />
Add summary
</button>
</div>
</div>
) : null}
<div>
{editor && (
<FloatingMenu
{summary.open ? (
<div className="flex gap-3">
<div className="h-16 w-1 shrink-0 rounded-full bg-neutral-200 dark:bg-neutral-800" />
<div className="flex-1">
<textarea
className="h-16 w-full border-none bg-transparent px-1 py-1 text-neutral-900 shadow-none outline-none placeholder:text-neutral-400 dark:text-neutral-100 dark:placeholder:text-neutral-600"
placeholder="A brief summary of your article"
value={summary.content}
onChange={(e) =>
setSummary((prev) => ({ ...prev, content: e.target.value }))
}
/>
</div>
</div>
) : null}
<div>
{editor && (
<FloatingMenu
editor={editor}
tippyOptions={{ duration: 100 }}
className="ml-36 inline-flex h-10 items-center gap-1 rounded-lg border border-neutral-200 bg-neutral-100 px-px dark:border-neutral-800 dark:bg-neutral-900"
>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('heading', { level: 1 })
? 'bg-white shadow dark:bg-black'
: ''
)}
>
<Heading1Icon className="h-5 w-5" />
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('heading', { level: 2 })
? 'bg-white shadow dark:bg-black'
: ''
)}
>
<Heading2Icon className="h-5 w-5" />
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('heading', { level: 3 })
? 'bg-white shadow dark:bg-black'
: ''
)}
>
<Heading3Icon className="h-5 w-5" />
</button>
<button
onClick={() => editor.chain().focus().toggleBold().run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('bold') ? 'bg-white shadow dark:bg-black' : ''
)}
>
<BoldIcon className="h-5 w-5" />
</button>
<button
onClick={() => editor.chain().focus().toggleItalic().run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('italic') ? 'bg-white shadow dark:bg-black' : ''
)}
>
<ItalicIcon className="h-5 w-5" />
</button>
</FloatingMenu>
)}
<EditorContent
editor={editor}
tippyOptions={{ duration: 100 }}
className="ml-36 inline-flex h-10 items-center gap-1 rounded-lg border border-neutral-200 bg-neutral-100 px-px dark:border-neutral-800 dark:bg-neutral-900"
>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('heading', { level: 1 })
? 'bg-white shadow dark:bg-black'
: ''
)}
>
<Heading1Icon className="h-5 w-5" />
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('heading', { level: 2 })
? 'bg-white shadow dark:bg-black'
: ''
)}
>
<Heading2Icon className="h-5 w-5" />
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('heading', { level: 3 })
? 'bg-white shadow dark:bg-black'
: ''
)}
>
<Heading3Icon className="h-5 w-5" />
</button>
<button
onClick={() => editor.chain().focus().toggleBold().run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('bold') ? 'bg-white shadow dark:bg-black' : ''
)}
>
<BoldIcon className="h-5 w-5" />
</button>
<button
onClick={() => editor.chain().focus().toggleItalic().run()}
className={twMerge(
'inline-flex h-9 w-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-50 dark:text-neutral-100 dark:hover:bg-neutral-950',
editor.isActive('italic') ? 'bg-white shadow dark:bg-black' : ''
)}
>
<ItalicIcon className="h-5 w-5" />
</button>
</FloatingMenu>
)}
<EditorContent
editor={editor}
spellCheck="false"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
/>
spellCheck="false"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
/>
</div>
</div>
</div>
<div>

View File

@ -2,3 +2,4 @@ export * from './articleCoverUploader';
export * from './mediaUploader';
export * from './mentionPopup';
export * from './mentionPopupItem';
export * from './mentionList';

View File

@ -0,0 +1,104 @@
import * as Avatar from '@radix-ui/react-avatar';
import { minidenticon } from 'minidenticons';
import { Ref, forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { twMerge } from 'tailwind-merge';
import { NDKCacheUserProfile } from '@utils/types';
type MentionListRef = {
onKeyDown: (props: { event: Event }) => boolean;
};
const List = (
props: {
items: NDKCacheUserProfile[];
command: (arg0: { id: string }) => void;
},
ref: Ref<unknown>
) => {
const [selectedIndex, setSelectedIndex] = useState(0);
const selectItem = (index) => {
const item = props.items[index];
if (item) {
props.command({ id: item.pubkey });
}
};
const upHandler = () => {
setSelectedIndex((selectedIndex + props.items.length - 1) % props.items.length);
};
const downHandler = () => {
setSelectedIndex((selectedIndex + 1) % props.items.length);
};
const enterHandler = () => {
selectItem(selectedIndex);
};
useEffect(() => setSelectedIndex(0), [props.items]);
useImperativeHandle(ref, () => ({
onKeyDown: ({ event }) => {
if (event.key === 'ArrowUp') {
upHandler();
return true;
}
if (event.key === 'ArrowDown') {
downHandler();
return true;
}
if (event.key === 'Enter') {
enterHandler();
return true;
}
return false;
},
}));
return (
<div className="flex w-[200px] flex-col overflow-y-auto rounded-lg border border-neutral-200 bg-neutral-50 p-2 shadow-lg shadow-neutral-500/20 dark:border-neutral-800 dark:bg-neutral-950 dark:shadow-neutral-300/50">
{props.items.length ? (
props.items.map((item, index) => (
<button
key={index}
onClick={() => selectItem(index)}
className={twMerge(
'inline-flex h-11 items-center gap-2 rounded-md px-2',
index === selectedIndex ? 'bg-neutral-100 dark:bg-neutral-900' : ''
)}
>
<Avatar.Root className="h-8 w-8 shrink-0">
<Avatar.Image
src={item.image}
alt={item.name}
loading="lazy"
decoding="async"
className="h-8 w-8 rounded-md"
/>
<Avatar.Fallback delayMs={150}>
<img
src={
'data:image/svg+xml;utf8,' +
encodeURIComponent(minidenticon(item.name, 90, 50))
}
alt={item.name}
className="h-8 w-8 rounded-md bg-black dark:bg-white"
/>
</Avatar.Fallback>
</Avatar.Root>
<h5 className="max-w-[150px] truncate text-sm font-medium">{item.name}</h5>
</button>
))
) : (
<div className="text-center text-sm font-medium">No result</div>
)}
</div>
);
};
export const MentionList = forwardRef<MentionListRef>(List);

View File

@ -1,11 +1,13 @@
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import CharacterCount from '@tiptap/extension-character-count';
import Image from '@tiptap/extension-image';
import Mention from '@tiptap/extension-mention';
import Placeholder from '@tiptap/extension-placeholder';
import { EditorContent, useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import { convert } from 'html-to-text';
import { useEffect, useState } from 'react';
import { nip19 } from 'nostr-tools';
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { toast } from 'sonner';
@ -18,16 +20,20 @@ import { MentionNote } from '@shared/notes';
import { WIDGET_KIND } from '@stores/constants';
import { useSuggestion } from '@utils/hooks/useSuggestion';
import { useWidget } from '@utils/hooks/useWidget';
export function NewPostScreen() {
const { ndk } = useNDK();
const { addWidget } = useWidget();
const { suggestion } = useSuggestion();
const [loading, setLoading] = useState(false);
const [height, setHeight] = useState(0);
const [searchParams, setSearchParams] = useSearchParams();
const navigate = useNavigate();
const containerRef = useRef(null);
const editor = useEditor({
extensions: [
StarterKit.configure(),
@ -39,6 +45,14 @@ export function NewPostScreen() {
},
}),
CharacterCount.configure(),
Mention.configure({
suggestion,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
renderLabel({ options, node }) {
const npub = nip19.npubEncode(node.attrs.id);
return `nostr:${npub}`;
},
}),
],
content: JSON.parse(localStorage.getItem('editor-post') || '{}'),
editorProps: {
@ -115,34 +129,40 @@ export function NewPostScreen() {
}
};
useLayoutEffect(() => {
setHeight(containerRef.current.clientHeight);
}, []);
useEffect(() => {
if (editor) editor.commands.focus('end');
}, [editor]);
return (
<div className="flex h-full flex-col justify-between">
<div>
<EditorContent
editor={editor}
spellCheck="false"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
/>
{searchParams.get('replyTo') && (
<div className="relative max-w-lg">
<MentionNote id={searchParams.get('replyTo')} editing />
<button
type="button"
onClick={() => setSearchParams({})}
className="absolute right-3 top-3 inline-flex h-6 w-6 items-center justify-center rounded bg-neutral-200 px-2 dark:bg-neutral-800"
>
<CancelIcon className="h-5 w-5" />
</button>
</div>
)}
<div className="flex flex-1 flex-col gap-4">
<div className="flex-1 overflow-y-auto">
<div ref={containerRef} style={{ height: `${height}px` }}>
<EditorContent
editor={editor}
spellCheck="false"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
/>
{searchParams.get('replyTo') && (
<div className="relative max-w-lg">
<MentionNote id={searchParams.get('replyTo')} editing />
<button
type="button"
onClick={() => setSearchParams({})}
className="absolute right-3 top-3 inline-flex h-6 w-6 items-center justify-center rounded bg-neutral-200 px-2 dark:bg-neutral-800"
>
<CancelIcon className="h-5 w-5" />
</button>
</div>
)}
</div>
</div>
<div className="flex h-16 w-full items-center justify-between border-t border-neutral-100 dark:border-neutral-900">
<div className="inline-flex h-16 w-full items-center justify-between border-t border-neutral-100 bg-neutral-50 dark:border-neutral-900 dark:bg-neutral-950">
<span className="text-sm font-medium tabular-nums text-neutral-600 dark:text-neutral-400">
{editor?.storage?.characterCount.characters()} characters
</span>

View File

@ -21,8 +21,8 @@ export function UserProfile({ pubkey }: { pubkey: string }) {
const { user } = useProfile(pubkey);
const [followed, setFollowed] = useState(false);
const navigate = useNavigate();
const navigate = useNavigate();
const svgURI =
'data:image/svg+xml;utf8,' + encodeURIComponent(minidenticon(pubkey, 90, 50));
@ -78,9 +78,9 @@ export function UserProfile({ pubkey }: { pubkey: string }) {
return (
<>
<div className="h-56 w-full overflow-hidden rounded-tl-lg">
{user.banner ? (
{user?.banner ? (
<img
src={user.banner}
src={user?.banner}
alt="user banner"
className="h-full w-full rounded-tl-lg object-cover"
/>
@ -112,10 +112,10 @@ export function UserProfile({ pubkey }: { pubkey: string }) {
<h5 className="text-center text-xl font-semibold text-neutral-900 dark:text-neutral-100">
{user.name || user.display_name || user.displayName || 'No name'}
</h5>
{user.nip05 ? (
{user?.nip05 ? (
<NIP05
pubkey={pubkey}
nip05={user?.nip05}
nip05={user.nip05}
className="text-neutral-600 dark:text-neutral-400"
/>
) : (
@ -125,7 +125,7 @@ export function UserProfile({ pubkey }: { pubkey: string }) {
)}
</div>
<div className="flex flex-col gap-6">
{user.about || user.bio ? (
{user?.about || user?.bio ? (
<p className="mt-2 max-w-[500px] select-text break-words text-center text-neutral-900 dark:text-neutral-100">
{user.about || user.bio}
</p>

View File

@ -61,29 +61,26 @@ export const NDKInstance = () => {
}
}
async function getSigner(instance: NDK) {
if (!db.account) return null;
const localSignerPrivkey = await db.secureLoad(db.account.pubkey + '-bunker');
const userPrivkey = await db.secureLoad(db.account.pubkey);
async function getSigner(nsecbunker?: boolean) {
if (!db.account) return;
// NIP-46 Signer
if (localSignerPrivkey) {
if (nsecbunker) {
const localSignerPrivkey = await db.secureLoad(db.account.pubkey + '-nsecbunker');
const localSigner = new NDKPrivateKeySigner(localSignerPrivkey);
const remoteSigner = new NDKNip46Signer(instance, db.account.id, localSigner);
// await remoteSigner.blockUntilReady();
return remoteSigner;
return new NDKNip46Signer(ndk, db.account.id, localSigner);
}
// Privkey Signer
if (userPrivkey) {
return new NDKPrivateKeySigner(userPrivkey);
}
// Private key Signer
const userPrivkey = await db.secureLoad(db.account.pubkey);
return new NDKPrivateKeySigner(userPrivkey);
}
async function initNDK() {
const outboxSetting = await db.getSettingValue('outbox');
const bunkerSetting = await db.getSettingValue('nsecbunker');
const signer = await getSigner(!!parseInt(bunkerSetting));
const explicitRelayUrls = await getExplicitRelays();
const tauriAdapter = new NDKCacheAdapterTauri(db);
@ -91,34 +88,23 @@ export const NDKInstance = () => {
explicitRelayUrls,
cacheAdapter: tauriAdapter,
outboxRelayUrls: ['wss://purplepag.es'],
enableOutboxModel: outboxSetting === '1',
blacklistRelayUrls: [],
enableOutboxModel: !!parseInt(outboxSetting),
});
instance.signer = signer;
try {
// connect
await instance.connect(2000);
// add signer
const signer = await getSigner(instance);
instance.signer = signer;
// update account's metadata
if (db.account) {
const circleSetting = await db.getSettingValue('circles');
const user = instance.getUser({ pubkey: db.account.pubkey });
const follows = await user.follows();
const follows = [...(await user.follows())].map((user) => user.pubkey);
const relayList = await user.relayList();
const followsAsArr = [];
follows.forEach((user) => {
followsAsArr.push(user.pubkey);
});
// update user's follows
await db.updateAccount('follows', JSON.stringify(followsAsArr));
if (circleSetting !== '1')
await db.updateAccount('circles', JSON.stringify(followsAsArr));
await db.updateAccount('follows', JSON.stringify(follows));
// update user's relay list
if (relayList) {

View File

@ -12,6 +12,7 @@ import type {
NDKCacheEvent,
NDKCacheEventTag,
NDKCacheUser,
NDKCacheUserProfile,
Relays,
Widget,
} from '@utils/types';
@ -52,6 +53,20 @@ export class LumeStorage {
return await invoke('secure_remove', { key });
}
public async getAllCacheUsers() {
const results: Array<NDKCacheUser> = await this.db.select(
'SELECT * FROM ndk_users ORDER BY createdAt DESC;'
);
if (!results.length) return [];
const users: NDKCacheUserProfile[] = results.map((item) => ({
pubkey: item.pubkey,
...JSON.parse(item.profile as string),
}));
return users;
}
public async getCacheUser(pubkey: string) {
const results: Array<NDKCacheUser> = await this.db.select(
'SELECT * FROM ndk_users WHERE pubkey = $1 ORDER BY pubkey DESC LIMIT 1;',
@ -423,7 +438,7 @@ export class LumeStorage {
[relay, this.account.id]
);
if (existRelays.length > 0) return false;
if (!existRelays.length) return;
return await this.db.execute(
'INSERT OR IGNORE INTO relays (account_id, relay, purpose) VALUES ($1, $2, $3);',
@ -436,7 +451,7 @@ export class LumeStorage {
}
public async createSetting(key: string, value: string) {
const currentSetting = await this.getSettingValue(key);
const currentSetting = await this.checkSettingValue(key);
if (!currentSetting)
return await this.db.execute(
@ -460,12 +475,21 @@ export class LumeStorage {
return results;
}
public async checkSettingValue(key: string) {
const results: { key: string; value: string }[] = await this.db.select(
'SELECT * FROM settings WHERE key = $1 ORDER BY id DESC LIMIT 1;',
[key]
);
if (!results.length) return false;
return results[0].value;
}
public async getSettingValue(key: string) {
const results: { key: string; value: string }[] = await this.db.select(
'SELECT * FROM settings WHERE key = $1 ORDER BY id DESC LIMIT 1;',
[key]
);
if (results.length < 1) return null;
if (!results.length) return '0';
return results[0].value;
}

View File

@ -15,65 +15,62 @@ export function NewLayout() {
{db.platform !== 'macos' ? (
<WindowTitlebar />
) : (
<div data-tauri-drag-region className="h-9" />
<div data-tauri-drag-region className="h-9 shrink-0" />
)}
<div data-tauri-drag-region className="h-6" />
<div className="flex h-full min-h-0 w-full">
<div className="container mx-auto grid grid-cols-8 px-4">
<div className="col-span-1">
<Link
to="/"
className="inline-flex h-10 w-10 items-center justify-center rounded-lg bg-neutral-100 hover:bg-neutral-200 dark:bg-neutral-900"
>
<ArrowLeftIcon className="h-5 w-5" />
</Link>
</div>
<div className="relative col-span-6 flex flex-col">
<div className="mb-8 flex h-10 shrink-0 items-center gap-3">
{location.pathname !== '/new/privkey' ? (
<div className="flex h-10 items-center gap-2 rounded-lg bg-neutral-100 px-0.5 dark:bg-neutral-800">
<NavLink
to="/new/"
className={({ isActive }) =>
twMerge(
'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
)
}
>
Post
</NavLink>
<NavLink
to="/new/article"
className={({ isActive }) =>
twMerge(
'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
)
}
>
Article
</NavLink>
<NavLink
to="/new/file"
className={({ isActive }) =>
twMerge(
'inline-flex h-9 w-28 items-center justify-center rounded-lg text-sm font-medium',
isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
)
}
>
File Sharing
</NavLink>
</div>
) : null}
</div>
<div className="h-full min-h-0 w-full">
<Outlet />
</div>
</div>
<div className="col-span-1" />
<div data-tauri-drag-region className="h-4 shrink-0" />
<div className="container mx-auto grid flex-1 grid-cols-8 px-4">
<div className="col-span-1">
<Link
to="/"
className="inline-flex h-10 w-10 items-center justify-center rounded-lg bg-neutral-100 hover:bg-neutral-200 dark:bg-neutral-900"
>
<ArrowLeftIcon className="h-5 w-5" />
</Link>
</div>
<div className="col-span-6 flex flex-col">
<div className="mb-8 flex h-10 shrink-0 items-center gap-3">
{location.pathname !== '/new/privkey' ? (
<div className="flex h-10 items-center gap-2 rounded-lg bg-neutral-100 px-0.5 dark:bg-neutral-800">
<NavLink
to="/new/"
end
className={({ isActive }) =>
twMerge(
'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
)
}
>
Post
</NavLink>
<NavLink
to="/new/article"
className={({ isActive }) =>
twMerge(
'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
)
}
>
Article
</NavLink>
<NavLink
to="/new/file"
className={({ isActive }) =>
twMerge(
'inline-flex h-9 w-28 items-center justify-center rounded-lg text-sm font-medium',
isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
)
}
>
File Sharing
</NavLink>
</div>
) : null}
</div>
<Outlet />
</div>
<div className="col-span-1" />
</div>
</div>
);

View File

@ -39,7 +39,6 @@ export const NIP05 = memo(function NIP05({
if (!res.ok) throw new Error(`Failed to fetch NIP-05 service: ${nip05}`);
const data: NIP05 = await res.json();
if (data.names) {
if (data.names[localPath] !== pubkey) return false;
return true;

View File

@ -33,13 +33,13 @@ export function TitleBar({
<div className="col-span-1 flex justify-center">
{id === '9999' ? (
<div className="isolate flex -space-x-2">
{db.account.circles
{db.account.follows
?.slice(0, 8)
.map((item) => <User key={item} pubkey={item} variant="ministacked" />)}
{db.account.circles?.length > 8 ? (
{db.account.follows?.length > 8 ? (
<div className="inline-flex h-6 w-6 items-center justify-center rounded-full bg-neutral-300 text-neutral-900 ring-1 ring-white dark:bg-neutral-700 dark:text-neutral-100 dark:ring-black">
<span className="text-[8px] font-medium">
+{db.account.circles?.length - 8}
+{db.account.follows?.length - 8}
</span>
</div>
) : null}

View File

@ -222,7 +222,7 @@ export const User = memo(function User({
{user?.name || user?.display_name || user?.displayName}
</h3>
<p className="max-w-[10rem] truncate text-sm text-neutral-900 dark:text-neutral-100/70">
{user?.nip05 || user?.username || displayNpub(pubkey, 16)}
{user?.username || displayNpub(pubkey, 16)}
</p>
</div>
</div>
@ -551,7 +551,7 @@ export const User = memo(function User({
{user?.nip05 ? (
<NIP05
pubkey={pubkey}
nip05={user?.nip05}
nip05={user.nip05}
className="max-w-[15rem] truncate text-sm text-neutral-500 dark:text-neutral-300"
/>
) : (

View File

@ -40,7 +40,7 @@ export function ArticleWidget({ widget }: { widget: Widget }) {
} else {
filter = {
kinds: [NDKKind.Article],
authors: db.account.circles,
authors: db.account.follows,
};
}

View File

@ -40,7 +40,7 @@ export function FileWidget({ widget }: { widget: Widget }) {
} else {
filter = {
kinds: [1063],
authors: db.account.circles,
authors: db.account.follows,
};
}

View File

@ -39,7 +39,7 @@ export function NewsfeedWidget() {
relayUrls,
{
kinds: [NDKKind.Text, NDKKind.Repost],
authors: db.account.circles,
authors: db.account.follows,
},
FETCH_LIMIT,
{ asOf: pageParam === 0 ? undefined : pageParam, abortSignal: signal }

View File

@ -96,7 +96,7 @@ export function AddGroupFeeds({ currentWidgetId }: { currentWidgetId: string })
Users
</span>
<div className="flex h-[420px] flex-col overflow-y-auto rounded-xl bg-neutral-100 py-2 dark:bg-neutral-900">
{db.account.circles.map((item: string) => (
{db.account.follows.map((item: string) => (
<button
key={item}
type="button"

View File

@ -30,12 +30,12 @@ export function LiveUpdater({ status }: { status: QueryStatus }) {
useEffect(() => {
let sub: NDKSubscription = undefined;
if (status === 'success' && db.account && db.account.circles.length > 0) {
if (status === 'success' && db.account && db.account.follows.length > 0) {
queryClient.fetchQuery({ queryKey: ['notification'] });
const filter: NDKFilter = {
kinds: [NDKKind.Text, NDKKind.Repost],
authors: db.account.circles,
authors: db.account.follows,
since: Math.floor(Date.now() / 1000),
};

View File

@ -1,6 +1,5 @@
export const FULL_RELAYS = [
'wss://relay.damus.io',
'wss://relayable.org',
'wss://relay.nostr.band/all',
'wss://nostr.mutinywallet.com',
];

View File

@ -0,0 +1,76 @@
import { MentionOptions } from '@tiptap/extension-mention';
import { ReactRenderer } from '@tiptap/react';
import tippy from 'tippy.js';
import { MentionList } from '@app/new/components';
import { useStorage } from '@libs/storage/provider';
export function useSuggestion() {
const { db } = useStorage();
const suggestion: MentionOptions['suggestion'] = {
items: async ({ query }) => {
const users = await db.getAllCacheUsers();
return users
.filter((item) => item.name.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5);
},
render: () => {
let component;
let popup;
return {
onStart: (props) => {
component = new ReactRenderer(MentionList, {
props,
editor: props.editor,
});
if (!props.clientRect) {
return;
}
popup = tippy('body', {
getReferenceClientRect: props.clientRect,
appendTo: () => document.body,
content: component.element,
showOnCreate: true,
interactive: true,
trigger: 'manual',
placement: 'bottom-start',
});
},
onUpdate(props) {
component.updateProps(props);
if (!props.clientRect) {
return;
}
popup[0].setProps({
getReferenceClientRect: props.clientRect,
});
},
onKeyDown(props) {
if (props.event.key === 'Escape') {
popup[0].hide();
return true;
}
return component.ref?.onKeyDown(props);
},
onExit() {
popup[0].destroy();
component.destroy();
},
};
},
};
return { suggestion };
}

View File

@ -122,6 +122,10 @@ export interface NDKCacheUser {
createdAt: number;
}
export interface NDKCacheUserProfile extends NDKUserProfile {
pubkey: string;
}
export interface NDKCacheEvent {
id: string;
pubkey: string;