This commit is contained in:
Ren Amamiya 2023-08-03 08:56:36 +07:00
parent babcd8698e
commit ae1e84655a
71 changed files with 908 additions and 1072 deletions

View File

@ -18,14 +18,14 @@
}, },
"dependencies": { "dependencies": {
"@headlessui/react": "^1.7.16", "@headlessui/react": "^1.7.16",
"@nostr-dev-kit/ndk": "^0.7.7", "@nostr-dev-kit/ndk": "^0.8.0",
"@nostr-fetch/adapter-ndk": "^0.11.0", "@nostr-fetch/adapter-ndk": "^0.11.0",
"@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-dialog": "^1.0.4", "@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-popover": "^1.0.6", "@radix-ui/react-popover": "^1.0.6",
"@radix-ui/react-tooltip": "^1.0.6", "@radix-ui/react-tooltip": "^1.0.6",
"@tanstack/react-query": "^4.32.0", "@tanstack/react-query": "^4.32.1",
"@tanstack/react-query-devtools": "^4.32.0", "@tanstack/react-query-devtools": "^4.32.1",
"@tanstack/react-virtual": "3.0.0-beta.54", "@tanstack/react-virtual": "3.0.0-beta.54",
"@tauri-apps/api": "2.0.0-alpha.5", "@tauri-apps/api": "2.0.0-alpha.5",
"@tauri-apps/plugin-app": "github:tauri-apps/tauri-plugin-app#v2", "@tauri-apps/plugin-app": "github:tauri-apps/tauri-plugin-app#v2",
@ -58,7 +58,7 @@
"immer": "^10.0.2", "immer": "^10.0.2",
"light-bolt11-decoder": "^3.0.0", "light-bolt11-decoder": "^3.0.0",
"nostr-fetch": "^0.12.2", "nostr-fetch": "^0.12.2",
"nostr-tools": "^1.13.1", "nostr-tools": "^1.14.0",
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@ -72,7 +72,7 @@
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"tauri-controls": "^0.0.5", "tauri-controls": "^0.0.5",
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"zustand": "^4.3.9" "zustand": "^4.4.0"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/typography": "^0.5.9", "@tailwindcss/typography": "^0.5.9",
@ -105,7 +105,7 @@
"tailwind-merge": "^1.14.0", "tailwind-merge": "^1.14.0",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.3.3",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^4.4.7", "vite": "^4.4.8",
"vite-plugin-top-level-await": "^1.3.1", "vite-plugin-top-level-await": "^1.3.1",
"vite-tsconfig-paths": "^4.2.0" "vite-tsconfig-paths": "^4.2.0"
} }

View File

@ -5,11 +5,11 @@ dependencies:
specifier: ^1.7.16 specifier: ^1.7.16
version: 1.7.16(react-dom@18.2.0)(react@18.2.0) version: 1.7.16(react-dom@18.2.0)(react@18.2.0)
'@nostr-dev-kit/ndk': '@nostr-dev-kit/ndk':
specifier: ^0.7.7 specifier: ^0.8.0
version: 0.7.7(typescript@4.9.5) version: 0.8.0(typescript@4.9.5)
'@nostr-fetch/adapter-ndk': '@nostr-fetch/adapter-ndk':
specifier: ^0.11.0 specifier: ^0.11.0
version: 0.11.0(@nostr-dev-kit/ndk@0.7.7)(nostr-fetch@0.12.2) version: 0.11.0(@nostr-dev-kit/ndk@0.8.0)(nostr-fetch@0.12.2)
'@radix-ui/react-collapsible': '@radix-ui/react-collapsible':
specifier: ^1.0.3 specifier: ^1.0.3
version: 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) version: 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0)
@ -23,11 +23,11 @@ dependencies:
specifier: ^1.0.6 specifier: ^1.0.6
version: 1.0.6(@types/react-dom@18.2.7)(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) version: 1.0.6(@types/react-dom@18.2.7)(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0)
'@tanstack/react-query': '@tanstack/react-query':
specifier: ^4.32.0 specifier: ^4.32.1
version: 4.32.0(react-dom@18.2.0)(react@18.2.0) version: 4.32.1(react-dom@18.2.0)(react@18.2.0)
'@tanstack/react-query-devtools': '@tanstack/react-query-devtools':
specifier: ^4.32.0 specifier: ^4.32.1
version: 4.32.0(@tanstack/react-query@4.32.0)(react-dom@18.2.0)(react@18.2.0) version: 4.32.1(@tanstack/react-query@4.32.1)(react-dom@18.2.0)(react@18.2.0)
'@tanstack/react-virtual': '@tanstack/react-virtual':
specifier: 3.0.0-beta.54 specifier: 3.0.0-beta.54
version: 3.0.0-beta.54(react@18.2.0) version: 3.0.0-beta.54(react@18.2.0)
@ -45,7 +45,7 @@ dependencies:
version: github.com/tauri-apps/tauri-plugin-clipboard-manager/549ca993a47ae7aafff635d99fc3e6dc124b9181 version: github.com/tauri-apps/tauri-plugin-clipboard-manager/549ca993a47ae7aafff635d99fc3e6dc124b9181
'@tauri-apps/plugin-dialog': '@tauri-apps/plugin-dialog':
specifier: github:tauri-apps/tauri-plugin-dialog#v2 specifier: github:tauri-apps/tauri-plugin-dialog#v2
version: github.com/tauri-apps/tauri-plugin-dialog/80325934b699f02bea9abe4fe1311dfba793a2bb version: github.com/tauri-apps/tauri-plugin-dialog/c84cc21fbcd1cd284a4832e8021e08460cd42963
'@tauri-apps/plugin-fs': '@tauri-apps/plugin-fs':
specifier: github:tauri-apps/tauri-plugin-fs#v2 specifier: github:tauri-apps/tauri-plugin-fs#v2
version: github.com/tauri-apps/tauri-plugin-fs/60e8dec66d2582cc39ebdd7b7101e9c96c23e52a version: github.com/tauri-apps/tauri-plugin-fs/60e8dec66d2582cc39ebdd7b7101e9c96c23e52a
@ -54,10 +54,10 @@ dependencies:
version: github.com/tauri-apps/tauri-plugin-http/b23c48592e1b6f1924feb273e1754944063e4ee8 version: github.com/tauri-apps/tauri-plugin-http/b23c48592e1b6f1924feb273e1754944063e4ee8
'@tauri-apps/plugin-notification': '@tauri-apps/plugin-notification':
specifier: github:tauri-apps/tauri-plugin-notification#v2 specifier: github:tauri-apps/tauri-plugin-notification#v2
version: github.com/tauri-apps/tauri-plugin-notification/6d8c193765f7fcf97429c0106bc5699d41870cef version: github.com/tauri-apps/tauri-plugin-notification/9989c95217af5abcf847e790cb74dda485c0459a
'@tauri-apps/plugin-os': '@tauri-apps/plugin-os':
specifier: github:tauri-apps/tauri-plugin-os#v2 specifier: github:tauri-apps/tauri-plugin-os#v2
version: github.com/tauri-apps/tauri-plugin-os/d235fbf70c53812c501f1d86a6b8c790bdf6bc8b version: github.com/tauri-apps/tauri-plugin-os/a63d34fddb1bd97d6a634a1881e5cc26910e115f
'@tauri-apps/plugin-process': '@tauri-apps/plugin-process':
specifier: github:tauri-apps/tauri-plugin-process#v2 specifier: github:tauri-apps/tauri-plugin-process#v2
version: github.com/tauri-apps/tauri-plugin-process/ed3f8f78ddecc72c926239f5a10ec6ce1b8c353e version: github.com/tauri-apps/tauri-plugin-process/ed3f8f78ddecc72c926239f5a10ec6ce1b8c353e
@ -125,8 +125,8 @@ dependencies:
specifier: ^0.12.2 specifier: ^0.12.2
version: 0.12.2 version: 0.12.2
nostr-tools: nostr-tools:
specifier: ^1.13.1 specifier: ^1.14.0
version: 1.13.1 version: 1.14.0
qrcode.react: qrcode.react:
specifier: ^3.1.0 specifier: ^3.1.0
version: 3.1.0(react@18.2.0) version: 3.1.0(react@18.2.0)
@ -167,8 +167,8 @@ dependencies:
specifier: ^6.3.7 specifier: ^6.3.7
version: 6.3.7 version: 6.3.7
zustand: zustand:
specifier: ^4.3.9 specifier: ^4.4.0
version: 4.3.9(immer@10.0.2)(react@18.2.0) version: 4.4.0(@types/react@18.2.18)(immer@10.0.2)(react@18.2.0)
devDependencies: devDependencies:
'@tailwindcss/typography': '@tailwindcss/typography':
@ -203,7 +203,7 @@ devDependencies:
version: 5.62.0(eslint@8.46.0)(typescript@4.9.5) version: 5.62.0(eslint@8.46.0)(typescript@4.9.5)
'@vitejs/plugin-react-swc': '@vitejs/plugin-react-swc':
specifier: ^3.3.2 specifier: ^3.3.2
version: 3.3.2(vite@4.4.7) version: 3.3.2(vite@4.4.8)
autoprefixer: autoprefixer:
specifier: ^10.4.14 specifier: ^10.4.14
version: 10.4.14(postcss@8.4.27) version: 10.4.14(postcss@8.4.27)
@ -262,14 +262,14 @@ devDependencies:
specifier: ^4.9.5 specifier: ^4.9.5
version: 4.9.5 version: 4.9.5
vite: vite:
specifier: ^4.4.7 specifier: ^4.4.8
version: 4.4.7(@types/node@18.17.1) version: 4.4.8(@types/node@18.17.1)
vite-plugin-top-level-await: vite-plugin-top-level-await:
specifier: ^1.3.1 specifier: ^1.3.1
version: 1.3.1(vite@4.4.7) version: 1.3.1(vite@4.4.8)
vite-tsconfig-paths: vite-tsconfig-paths:
specifier: ^4.2.0 specifier: ^4.2.0
version: 4.2.0(typescript@4.9.5)(vite@4.4.7) version: 4.2.0(typescript@4.9.5)(vite@4.4.8)
packages: packages:
@ -988,8 +988,8 @@ packages:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0 fastq: 1.15.0
/@nostr-dev-kit/ndk@0.7.7(typescript@4.9.5): /@nostr-dev-kit/ndk@0.8.0(typescript@4.9.5):
resolution: {integrity: sha512-IRTW16q40zzuSBkpYpDUcZJRrbw26JTeicfZN6O/2Gw7D2w6Pe42VqFwpbcP9xOnFPEGP2eNV6SwXQ3y0tjBtw==} resolution: {integrity: sha512-SFrB7dW80kMZgquw33OUEjDpE5JJD11PsS/ET4Lxl5FtYMHP/unR61BmcIsCPhBXLm+0Pf2QqAq+N5/BYVZqEA==}
dependencies: dependencies:
'@noble/hashes': 1.3.1 '@noble/hashes': 1.3.1
'@noble/secp256k1': 2.0.0 '@noble/secp256k1': 2.0.0
@ -1006,7 +1006,7 @@ packages:
eventemitter3: 5.0.1 eventemitter3: 5.0.1
light-bolt11-decoder: 3.0.0 light-bolt11-decoder: 3.0.0
node-fetch: 3.3.2 node-fetch: 3.3.2
nostr-tools: 1.13.1 nostr-tools: 1.14.0
tsd: 0.28.1 tsd: 0.28.1
utf8-buffer: 1.0.0 utf8-buffer: 1.0.0
websocket-polyfill: 0.0.3 websocket-polyfill: 0.0.3
@ -1017,13 +1017,13 @@ packages:
- typescript - typescript
dev: false dev: false
/@nostr-fetch/adapter-ndk@0.11.0(@nostr-dev-kit/ndk@0.7.7)(nostr-fetch@0.12.2): /@nostr-fetch/adapter-ndk@0.11.0(@nostr-dev-kit/ndk@0.8.0)(nostr-fetch@0.12.2):
resolution: {integrity: sha512-Otl7SEzm9ecqyHB10bpYXBu1qpqJEnipp7dZ4qcA9LeJAtM38fnYKUD34HX0JXA9EDjtc6VS5UNZe544xC9GCg==} resolution: {integrity: sha512-Otl7SEzm9ecqyHB10bpYXBu1qpqJEnipp7dZ4qcA9LeJAtM38fnYKUD34HX0JXA9EDjtc6VS5UNZe544xC9GCg==}
peerDependencies: peerDependencies:
'@nostr-dev-kit/ndk': ^0.5.0 '@nostr-dev-kit/ndk': ^0.5.0
nostr-fetch: ^0.11.0 nostr-fetch: ^0.11.0
dependencies: dependencies:
'@nostr-dev-kit/ndk': 0.7.7(typescript@4.9.5) '@nostr-dev-kit/ndk': 0.8.0(typescript@4.9.5)
'@nostr-fetch/kernel': 0.11.0 '@nostr-fetch/kernel': 0.11.0
nostr-fetch: 0.12.2 nostr-fetch: 0.12.2
dev: false dev: false
@ -1618,8 +1618,8 @@ packages:
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
dev: false dev: false
/@swc/core-darwin-arm64@1.3.72: /@swc/core-darwin-arm64@1.3.74:
resolution: {integrity: sha512-oNSI5hVfZ+1xpj+dH1g4kQqA0VsGtqd8S9S+cDqkHZiOOVOevw9KN6dzVtmLOcPtlULVypVc0TVvsB55KdVZhQ==} resolution: {integrity: sha512-2rMV4QxM583jXcREfo0MhV3Oj5pgRSfSh/kVrB1twL2rQxOrbzkAPT/8flmygdVoL4f2F7o1EY5lKlYxEBiIKQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
@ -1627,8 +1627,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-darwin-x64@1.3.72: /@swc/core-darwin-x64@1.3.74:
resolution: {integrity: sha512-y5O/WQ1g0/VfTgeNahWIOutbdD5U2Gi703jaefdcoJo3FUx8WU108QQdbVGwGMgaqapo3iQB6Qs9paixYQAYsA==} resolution: {integrity: sha512-KKEGE1wXneYXe15fWDRM8/oekd/Q4yAuccA0vWY/7i6nOSPqWYcSDR0nRtR030ltDxWt0rk/eCTmNkrOWrKs3A==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
@ -1636,8 +1636,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-linux-arm-gnueabihf@1.3.72: /@swc/core-linux-arm-gnueabihf@1.3.74:
resolution: {integrity: sha512-05JdWcso0OomHF+7bk5MBDgI8MZ9skcQ/4nhSv5gboSgSiuBmKM15Bg3lZ5iAUwGByNj7pGkSmmd3YwTrXEB+g==} resolution: {integrity: sha512-HehH5DR6r/5fIVu7tu8ZqgrHkhSCQNewf1ztFQJgcmaQWn+H4AJERBjwkjosqh4TvUJucZv8vyRTvrFeBXaCSA==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
@ -1645,8 +1645,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-linux-arm64-gnu@1.3.72: /@swc/core-linux-arm64-gnu@1.3.74:
resolution: {integrity: sha512-8qRELJaeYshhJgqvyOeXCKqBOpai+JYdWuouMbvvDUL85j3OcZhzR+bipexEbbJKcOCdRnoYB7Qg6mjqZ0t7VA==} resolution: {integrity: sha512-+xkbCRz/wczgdknoV4NwYxbRI2dD7x/qkIFcVM2buzLCq8oWLweuV8+aL4pRqu0qDh7ZSb1jcaVTUIsySCJznA==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
@ -1654,8 +1654,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-linux-arm64-musl@1.3.72: /@swc/core-linux-arm64-musl@1.3.74:
resolution: {integrity: sha512-tOqAGZw+Pe7YrBHFrwFVyRiKqjgjzwYbJmY+UDxLrzWrZSVtC3eO2TPrp7kWmhirg40Og81BbdfRAl8ds48w0Q==} resolution: {integrity: sha512-maKFZSCD3tQznzPV7T3V+TtiWZFEFM8YrnSS5fQNNb+K9J65sL+170uTb3M7H4cFkG+9Sm5k5yCrCIutlvV48g==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
@ -1663,8 +1663,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-linux-x64-gnu@1.3.72: /@swc/core-linux-x64-gnu@1.3.74:
resolution: {integrity: sha512-U2W2xWR3s9nplGVWz376GiBlcLTgxyYKlpZPBNZk0w3OvTcjKC62gW1Pe7PUkk4NgJUnaQDBa/mb4V4Zl+GZPA==} resolution: {integrity: sha512-LEXpcShF6DLTWJSiBhMSYZkLQ27UvaQ24fCFhoIV/R3dhYaUpHmIyLPPBNC82T03lB3ONUFVwrRw6fxDJ/f00A==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
@ -1672,8 +1672,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-linux-x64-musl@1.3.72: /@swc/core-linux-x64-musl@1.3.74:
resolution: {integrity: sha512-3+2dUiZBsifKgvnFEHWdysXjInK8K+BfPBw2tTZJmq1+fZLt0rvuErYDVMLfIJnVWLCcJMnDtTXrvkFV1y/6iA==} resolution: {integrity: sha512-sxsFctbFMZEFmDE7CmYljG0dMumH8XBTwwtGr8s6z0fYAzXBGNq2AFPcmEh2np9rPWkt7pE1m0ByESD+dMkbxQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
@ -1681,8 +1681,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-win32-arm64-msvc@1.3.72: /@swc/core-win32-arm64-msvc@1.3.74:
resolution: {integrity: sha512-ndI8xZ2AId806D25xgqw2SFJ9gc/jhg21+5hA8XPq9ZL+oDiaYDztaP3ijVmZ1G5xXKD9DpgB7xmylv/f6o6GA==} resolution: {integrity: sha512-F7hY9/BjFCozA4YPFYFH5FGCyWwa44vIXHqG66F5cDwXDGFn8ZtBsYIsiPfUYcx0AeAo1ojnVWKPxokZhYNYqA==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
@ -1690,8 +1690,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-win32-ia32-msvc@1.3.72: /@swc/core-win32-ia32-msvc@1.3.74:
resolution: {integrity: sha512-F3TK8JHP3SRFjLRlzcRVZPnvvGm2CQ5/cwbIkaEq0Dla3kyctU8SiRqvtYwWCW4JuY10cUygIg93Ec/C9Lkk4g==} resolution: {integrity: sha512-qBAsiD1AlIdqED6wy3UNRHyAys9pWMUidX0LJ6mj24r/vfrzzTBAUrLJe5m7bzE+F1Rgi001avYJeEW1DLEJ+Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
@ -1699,8 +1699,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core-win32-x64-msvc@1.3.72: /@swc/core-win32-x64-msvc@1.3.74:
resolution: {integrity: sha512-FXMnIUtLl0yEmGkw+xbUg/uUPExvUxUlLSHbX7CnbSuOIHqMHzvEd9skIueLAst4bvmJ8kT1hDyAIWQcTIAJYQ==} resolution: {integrity: sha512-S3YAvvLprTnPRwQuy9Dkwubb5SRLpVK3JJsqYDbGfgj8PGQyKHZcVJ5X3nfFsoWLy3j9B/3Os2nawprRSzeC5A==}
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@ -1708,8 +1708,8 @@ packages:
dev: true dev: true
optional: true optional: true
/@swc/core@1.3.72: /@swc/core@1.3.74:
resolution: {integrity: sha512-+AKjwLH3/STfPrd7CHzB9+NG1FVT0UKJMUChuWq9sQ8b9xlV8vUeRgZXgh/EHYvNQgl/OUTQKtL6xU2yOLuEuA==} resolution: {integrity: sha512-P+MIExOTdWlfq8Heb1/NhBAke6UTckd4cRDuJoFcFMGBRvgoCMNWhnfP3FRRXPLI7GGg27dRZS+xHiqYyQmSrA==}
engines: {node: '>=10'} engines: {node: '>=10'}
requiresBuild: true requiresBuild: true
peerDependencies: peerDependencies:
@ -1718,16 +1718,16 @@ packages:
'@swc/helpers': '@swc/helpers':
optional: true optional: true
optionalDependencies: optionalDependencies:
'@swc/core-darwin-arm64': 1.3.72 '@swc/core-darwin-arm64': 1.3.74
'@swc/core-darwin-x64': 1.3.72 '@swc/core-darwin-x64': 1.3.74
'@swc/core-linux-arm-gnueabihf': 1.3.72 '@swc/core-linux-arm-gnueabihf': 1.3.74
'@swc/core-linux-arm64-gnu': 1.3.72 '@swc/core-linux-arm64-gnu': 1.3.74
'@swc/core-linux-arm64-musl': 1.3.72 '@swc/core-linux-arm64-musl': 1.3.74
'@swc/core-linux-x64-gnu': 1.3.72 '@swc/core-linux-x64-gnu': 1.3.74
'@swc/core-linux-x64-musl': 1.3.72 '@swc/core-linux-x64-musl': 1.3.74
'@swc/core-win32-arm64-msvc': 1.3.72 '@swc/core-win32-arm64-msvc': 1.3.74
'@swc/core-win32-ia32-msvc': 1.3.72 '@swc/core-win32-ia32-msvc': 1.3.74
'@swc/core-win32-x64-msvc': 1.3.72 '@swc/core-win32-x64-msvc': 1.3.74
dev: true dev: true
/@tailwindcss/typography@0.5.9(tailwindcss@3.3.3): /@tailwindcss/typography@0.5.9(tailwindcss@3.3.3):
@ -1749,27 +1749,27 @@ packages:
remove-accents: 0.4.2 remove-accents: 0.4.2
dev: false dev: false
/@tanstack/query-core@4.32.0: /@tanstack/query-core@4.32.1:
resolution: {integrity: sha512-ei4IYwL2kmlKSlCw9WgvV7PpXi0MiswVwfQRxawhJA690zWO3dU49igaQ/UMTl+Jy9jj9dK5IKAYvbX7kUvviQ==} resolution: {integrity: sha512-VEAGHboOFWN/bvf/7cCoeLQfld0AA8n0V/kfc77W+FvxnnSwJufEh6gfjqpX5bRE/DEYfYDYdNtuL3KM+lIs8Q==}
dev: false dev: false
/@tanstack/react-query-devtools@4.32.0(@tanstack/react-query@4.32.0)(react-dom@18.2.0)(react@18.2.0): /@tanstack/react-query-devtools@4.32.1(@tanstack/react-query@4.32.1)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-rOmWqzKzRmQrQULV5Ova2FGEEPT76FZA3hz8T+LFkvp3ehw9ugSZ1BosgRJ7AFCeir+5pcNvFwILy4pDK8HpRw==} resolution: {integrity: sha512-/ZgxCfGXLIXUvaIRzrNCP+C4iv1bIleNzXCjGKFZ4qKEifnv5A/SpWE2dG4SBjqXVlIkMAP82lesfoHcsOm+zg==}
peerDependencies: peerDependencies:
'@tanstack/react-query': 4.32.0 '@tanstack/react-query': 4.32.1
react: ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies: dependencies:
'@tanstack/match-sorter-utils': 8.8.4 '@tanstack/match-sorter-utils': 8.8.4
'@tanstack/react-query': 4.32.0(react-dom@18.2.0)(react@18.2.0) '@tanstack/react-query': 4.32.1(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
superjson: 1.13.1 superjson: 1.13.1
use-sync-external-store: 1.2.0(react@18.2.0) use-sync-external-store: 1.2.0(react@18.2.0)
dev: false dev: false
/@tanstack/react-query@4.32.0(react-dom@18.2.0)(react@18.2.0): /@tanstack/react-query@4.32.1(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-B8WUMcByYAH9500ENejDCATOmEZhqjtS9wsfiQ3BNa+s+yAynY8SESI8WWHhSqUmjd0pmCSFRP6BOUGSda3QXA==} resolution: {integrity: sha512-lPTfOq6bR6DorPaS018gTMd3zs8r06tlERiVY6BRP9SnDkkl4ckqeANava/jPLWrSZP+EA15loQUTmvZs6k2GA==}
peerDependencies: peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
@ -1780,7 +1780,7 @@ packages:
react-native: react-native:
optional: true optional: true
dependencies: dependencies:
'@tanstack/query-core': 4.32.0 '@tanstack/query-core': 4.32.1
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
use-sync-external-store: 1.2.0(react@18.2.0) use-sync-external-store: 1.2.0(react@18.2.0)
@ -2462,13 +2462,13 @@ packages:
'@typescript-eslint/types': 5.62.0 '@typescript-eslint/types': 5.62.0
eslint-visitor-keys: 3.4.2 eslint-visitor-keys: 3.4.2
/@vitejs/plugin-react-swc@3.3.2(vite@4.4.7): /@vitejs/plugin-react-swc@3.3.2(vite@4.4.8):
resolution: {integrity: sha512-VJFWY5sfoZerQRvJrh518h3AcQt6f/yTuWn4/TRB+dqmYU0NX1qz7qM5Wfd+gOQqUzQW4gxKqKN3KpE/P3+zrA==} resolution: {integrity: sha512-VJFWY5sfoZerQRvJrh518h3AcQt6f/yTuWn4/TRB+dqmYU0NX1qz7qM5Wfd+gOQqUzQW4gxKqKN3KpE/P3+zrA==}
peerDependencies: peerDependencies:
vite: ^4 vite: ^4
dependencies: dependencies:
'@swc/core': 1.3.72 '@swc/core': 1.3.74
vite: 4.4.7(@types/node@18.17.1) vite: 4.4.8(@types/node@18.17.1)
transitivePeerDependencies: transitivePeerDependencies:
- '@swc/helpers' - '@swc/helpers'
dev: true dev: true
@ -2758,7 +2758,7 @@ packages:
hasBin: true hasBin: true
dependencies: dependencies:
caniuse-lite: 1.0.30001518 caniuse-lite: 1.0.30001518
electron-to-chromium: 1.4.478 electron-to-chromium: 1.4.482
node-releases: 2.0.13 node-releases: 2.0.13
update-browserslist-db: 1.0.11(browserslist@4.21.10) update-browserslist-db: 1.0.11(browserslist@4.21.10)
dev: true dev: true
@ -3228,8 +3228,8 @@ packages:
/eastasianwidth@0.2.0: /eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
/electron-to-chromium@1.4.478: /electron-to-chromium@1.4.482:
resolution: {integrity: sha512-qjTA8djMXd+ruoODDFGnRCRBpID+AAfYWCyGtYTNhsuwxI19s8q19gbjKTwRS5z/LyVf5wICaIiPQGLekmbJbA==} resolution: {integrity: sha512-h+UqpfmEr1Qkk0zp7ej/jid7CXoq4m4QzW6wNTb0ELJ/BZCpA4wgUylBIMGCe621tnr4l5VmoHjdoSx2lbnNJA==}
dev: true dev: true
/emoji-regex@8.0.0: /emoji-regex@8.0.0:
@ -5385,8 +5385,8 @@ packages:
'@nostr-fetch/kernel': 0.12.2 '@nostr-fetch/kernel': 0.12.2
dev: false dev: false
/nostr-tools@1.13.1: /nostr-tools@1.14.0:
resolution: {integrity: sha512-DTwpbxTH1/ar+afWd4gmVdpHH8CF290kdaxi00Llra88SHE6e38XuyzlRABVTcrBaceLMnoDdHmV3x16MoEFJg==} resolution: {integrity: sha512-hwq2i1z5/DneXRE5Zu/TzQuKzVLcB+gOdfT9CeoiScvNw/2dWRGJvyTXIdF92d7NQ7nMcEwqVJPDytLpEpiiKw==}
dependencies: dependencies:
'@noble/curves': 1.1.0 '@noble/curves': 1.1.0
'@noble/hashes': 1.3.1 '@noble/hashes': 1.3.1
@ -6124,7 +6124,7 @@ packages:
remark-parse: 10.0.2 remark-parse: 10.0.2
remark-rehype: 10.1.0 remark-rehype: 10.1.0
space-separated-tokens: 2.0.2 space-separated-tokens: 2.0.2
style-to-object: 0.4.1 style-to-object: 0.4.2
unified: 10.1.2 unified: 10.1.2
unist-util-visit: 4.1.2 unist-util-visit: 4.1.2
vfile: 5.3.7 vfile: 5.3.7
@ -6730,8 +6730,8 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'} engines: {node: '>=8'}
/style-to-object@0.4.1: /style-to-object@0.4.2:
resolution: {integrity: sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==} resolution: {integrity: sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA==}
dependencies: dependencies:
inline-style-parser: 0.1.1 inline-style-parser: 0.1.1
dev: false dev: false
@ -6838,7 +6838,7 @@ packages:
tailwind-merge: ^1.14.0 tailwind-merge: ^1.14.0
dependencies: dependencies:
'@tauri-apps/api': 2.0.0-alpha.5 '@tauri-apps/api': 2.0.0-alpha.5
'@tauri-apps/plugin-os': github.com/tauri-apps/tauri-plugin-os/d235fbf70c53812c501f1d86a6b8c790bdf6bc8b '@tauri-apps/plugin-os': github.com/tauri-apps/tauri-plugin-os/a63d34fddb1bd97d6a634a1881e5cc26910e115f
'@tauri-apps/plugin-window': 2.0.0-alpha.0 '@tauri-apps/plugin-window': 2.0.0-alpha.0
clsx: 2.0.0 clsx: 2.0.0
react: 18.2.0 react: 18.2.0
@ -7257,21 +7257,21 @@ packages:
vfile-message: 3.1.4 vfile-message: 3.1.4
dev: false dev: false
/vite-plugin-top-level-await@1.3.1(vite@4.4.7): /vite-plugin-top-level-await@1.3.1(vite@4.4.8):
resolution: {integrity: sha512-55M1h4NAwkrpxPNOJIBzKZFihqLUzIgnElLSmPNPMR2Fn9+JHKaNg3sVX1Fq+VgvuBksQYxiD3OnwQAUu7kaPQ==} resolution: {integrity: sha512-55M1h4NAwkrpxPNOJIBzKZFihqLUzIgnElLSmPNPMR2Fn9+JHKaNg3sVX1Fq+VgvuBksQYxiD3OnwQAUu7kaPQ==}
peerDependencies: peerDependencies:
vite: '>=2.8' vite: '>=2.8'
dependencies: dependencies:
'@rollup/plugin-virtual': 3.0.1 '@rollup/plugin-virtual': 3.0.1
'@swc/core': 1.3.72 '@swc/core': 1.3.74
uuid: 9.0.0 uuid: 9.0.0
vite: 4.4.7(@types/node@18.17.1) vite: 4.4.8(@types/node@18.17.1)
transitivePeerDependencies: transitivePeerDependencies:
- '@swc/helpers' - '@swc/helpers'
- rollup - rollup
dev: true dev: true
/vite-tsconfig-paths@4.2.0(typescript@4.9.5)(vite@4.4.7): /vite-tsconfig-paths@4.2.0(typescript@4.9.5)(vite@4.4.8):
resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==} resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==}
peerDependencies: peerDependencies:
vite: '*' vite: '*'
@ -7282,14 +7282,14 @@ packages:
debug: 4.3.4 debug: 4.3.4
globrex: 0.1.2 globrex: 0.1.2
tsconfck: 2.1.2(typescript@4.9.5) tsconfck: 2.1.2(typescript@4.9.5)
vite: 4.4.7(@types/node@18.17.1) vite: 4.4.8(@types/node@18.17.1)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
- typescript - typescript
dev: true dev: true
/vite@4.4.7(@types/node@18.17.1): /vite@4.4.8(@types/node@18.17.1):
resolution: {integrity: sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==} resolution: {integrity: sha512-LONawOUUjxQridNWGQlNizfKH89qPigK36XhMI7COMGztz8KNY0JHim7/xDd71CZwGT4HtSRgI7Hy+RlhG0Gvg==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -7446,18 +7446,22 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
/zustand@4.3.9(immer@10.0.2)(react@18.2.0): /zustand@4.4.0(@types/react@18.2.18)(immer@10.0.2)(react@18.2.0):
resolution: {integrity: sha512-Tat5r8jOMG1Vcsj8uldMyqYKC5IZvQif8zetmLHs9WoZlntTHmIoNM8TpLRY31ExncuUvUOXehd0kvahkuHjDw==} resolution: {integrity: sha512-2dq6wq4dSxbiPTamGar0NlIG/av0wpyWZJGeQYtUOLegIUvhM2Bf86ekPlmgpUtS5uR7HyetSiktYrGsdsyZgQ==}
engines: {node: '>=12.7.0'} engines: {node: '>=12.7.0'}
peerDependencies: peerDependencies:
'@types/react': '>=16.8'
immer: '>=9.0' immer: '>=9.0'
react: '>=16.8' react: '>=16.8'
peerDependenciesMeta: peerDependenciesMeta:
'@types/react':
optional: true
immer: immer:
optional: true optional: true
react: react:
optional: true optional: true
dependencies: dependencies:
'@types/react': 18.2.18
immer: 10.0.2 immer: 10.0.2
react: 18.2.0 react: 18.2.0
use-sync-external-store: 1.2.0(react@18.2.0) use-sync-external-store: 1.2.0(react@18.2.0)
@ -7491,8 +7495,8 @@ packages:
'@tauri-apps/api': 2.0.0-alpha.5 '@tauri-apps/api': 2.0.0-alpha.5
dev: false dev: false
github.com/tauri-apps/tauri-plugin-dialog/80325934b699f02bea9abe4fe1311dfba793a2bb: github.com/tauri-apps/tauri-plugin-dialog/c84cc21fbcd1cd284a4832e8021e08460cd42963:
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-dialog/tar.gz/80325934b699f02bea9abe4fe1311dfba793a2bb} resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-dialog/tar.gz/c84cc21fbcd1cd284a4832e8021e08460cd42963}
name: '@tauri-apps/plugin-dialog' name: '@tauri-apps/plugin-dialog'
version: 2.0.0-alpha.0 version: 2.0.0-alpha.0
dependencies: dependencies:
@ -7515,16 +7519,16 @@ packages:
'@tauri-apps/api': 2.0.0-alpha.5 '@tauri-apps/api': 2.0.0-alpha.5
dev: false dev: false
github.com/tauri-apps/tauri-plugin-notification/6d8c193765f7fcf97429c0106bc5699d41870cef: github.com/tauri-apps/tauri-plugin-notification/9989c95217af5abcf847e790cb74dda485c0459a:
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-notification/tar.gz/6d8c193765f7fcf97429c0106bc5699d41870cef} resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-notification/tar.gz/9989c95217af5abcf847e790cb74dda485c0459a}
name: '@tauri-apps/plugin-notification' name: '@tauri-apps/plugin-notification'
version: 2.0.0-alpha.0 version: 2.0.0-alpha.0
dependencies: dependencies:
'@tauri-apps/api': 2.0.0-alpha.5 '@tauri-apps/api': 2.0.0-alpha.5
dev: false dev: false
github.com/tauri-apps/tauri-plugin-os/d235fbf70c53812c501f1d86a6b8c790bdf6bc8b: github.com/tauri-apps/tauri-plugin-os/a63d34fddb1bd97d6a634a1881e5cc26910e115f:
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-os/tar.gz/d235fbf70c53812c501f1d86a6b8c790bdf6bc8b} resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-os/tar.gz/a63d34fddb1bd97d6a634a1881e5cc26910e115f}
name: '@tauri-apps/plugin-os' name: '@tauri-apps/plugin-os'
version: 2.0.0-alpha.0 version: 2.0.0-alpha.0
dependencies: dependencies:

139
src-tauri/Cargo.lock generated
View File

@ -309,7 +309,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -326,7 +326,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -641,9 +641,12 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.79" version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "cesu8" name = "cesu8"
@ -757,7 +760,7 @@ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -1065,7 +1068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -1121,7 +1124,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -1132,7 +1135,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -1146,6 +1149,15 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "deranged"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "derivative" name = "derivative"
version = "2.2.0" version = "2.2.0"
@ -1346,7 +1358,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -1357,9 +1369,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.1" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [ dependencies = [
"errno-dragonfly", "errno-dragonfly",
"libc", "libc",
@ -1425,7 +1437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"rustix 0.38.4", "rustix 0.38.6",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -1515,7 +1527,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -1631,7 +1643,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -2377,7 +2389,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"rustix 0.38.4", "rustix 0.38.6",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -2579,9 +2591,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.3" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@ -3282,7 +3294,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -3844,22 +3856,22 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.4" version = "0.38.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f"
dependencies = [ dependencies = [
"bitflags 2.3.3", "bitflags 2.3.3",
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.4.3", "linux-raw-sys 0.4.5",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.21.5" version = "0.21.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
dependencies = [ dependencies = [
"ring", "ring",
"rustls-webpki", "rustls-webpki",
@ -3989,22 +4001,22 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.178" version = "1.0.180"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348" checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.178" version = "1.0.180"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b" checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -4026,7 +4038,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -4075,7 +4087,7 @@ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -4669,9 +4681,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.27" version = "2.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -4774,9 +4786,9 @@ dependencies = [
[[package]] [[package]]
name = "target-lexicon" name = "target-lexicon"
version = "0.12.10" version = "0.12.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e" checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a"
[[package]] [[package]]
name = "tauri" name = "tauri"
@ -4888,7 +4900,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-app" name = "tauri-plugin-app"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"tauri", "tauri",
] ]
@ -4896,7 +4908,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-autostart" name = "tauri-plugin-autostart"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"auto-launch", "auto-launch",
"log", "log",
@ -4909,7 +4921,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-clipboard-manager" name = "tauri-plugin-clipboard-manager"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"arboard", "arboard",
"log", "log",
@ -4923,7 +4935,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-dialog" name = "tauri-plugin-dialog"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"glib", "glib",
"log", "log",
@ -4940,7 +4952,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-fs" name = "tauri-plugin-fs"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"glob", "glob",
@ -4953,7 +4965,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-http" name = "tauri-plugin-http"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"bytes", "bytes",
"glob", "glob",
@ -4971,7 +4983,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-notification" name = "tauri-plugin-notification"
version = "2.0.0-alpha.1" version = "2.0.0-alpha.1"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"log", "log",
"notify-rust", "notify-rust",
@ -4989,7 +5001,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-os" name = "tauri-plugin-os"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"gethostname 0.4.3", "gethostname 0.4.3",
"log", "log",
@ -5005,7 +5017,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-process" name = "tauri-plugin-process"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"tauri", "tauri",
] ]
@ -5013,7 +5025,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-single-instance" name = "tauri-plugin-single-instance"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"log", "log",
"serde", "serde",
@ -5027,7 +5039,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-sql" name = "tauri-plugin-sql"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"log", "log",
@ -5043,7 +5055,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-store" name = "tauri-plugin-store"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"log", "log",
"serde", "serde",
@ -5055,7 +5067,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-stronghold" name = "tauri-plugin-stronghold"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"hex", "hex",
"iota-crypto 0.23.0", "iota-crypto 0.23.0",
@ -5071,7 +5083,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-updater" name = "tauri-plugin-updater"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"base64 0.21.2", "base64 0.21.2",
"dirs-next", "dirs-next",
@ -5098,7 +5110,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-upload" name = "tauri-plugin-upload"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
@ -5115,7 +5127,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-window" name = "tauri-plugin-window"
version = "2.0.0-alpha.0" version = "2.0.0-alpha.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#6f01bc11ab5be762d6cbe0ca924f15cdde47ce0d" source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v2#7f2e2dd5b8af2c8e7e224bed132e2b76da983818"
dependencies = [ dependencies = [
"serde", "serde",
"tauri", "tauri",
@ -5222,7 +5234,7 @@ dependencies = [
"cfg-if", "cfg-if",
"fastrand 2.0.0", "fastrand 2.0.0",
"redox_syscall 0.3.5", "redox_syscall 0.3.5",
"rustix 0.38.4", "rustix 0.38.6",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -5260,7 +5272,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -5286,10 +5298,11 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.23" version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea"
dependencies = [ dependencies = [
"deranged",
"itoa 1.0.9", "itoa 1.0.9",
"serde", "serde",
"time-core", "time-core",
@ -5304,9 +5317,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.10" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
dependencies = [ dependencies = [
"time-core", "time-core",
] ]
@ -5352,7 +5365,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -5441,7 +5454,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -5704,7 +5717,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -5738,7 +5751,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6221,9 +6234,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.1" version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11" checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -6442,7 +6455,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]

View File

@ -31,10 +31,10 @@ export function User({ pubkey, fallback }: { pubkey: string; fallback?: string }
/> />
</div> </div>
<div className="flex w-full flex-1 flex-col items-start text-start"> <div className="flex w-full flex-1 flex-col items-start text-start">
<span className="truncate font-medium leading-tight text-zinc-100"> <span className="truncate font-medium leading-tight text-white">
{user?.name || user?.displayName || user?.display_name} {user?.name || user?.displayName || user?.display_name}
</span> </span>
<span className="max-w-[15rem] truncate text-base leading-tight text-zinc-400"> <span className="max-w-[15rem] truncate text-base leading-tight text-white/50">
{user?.nip05?.toLowerCase() || shortenKey(pubkey)} {user?.nip05?.toLowerCase() || shortenKey(pubkey)}
</span> </span>
</div> </div>

View File

@ -81,25 +81,25 @@ export function CreateStep1Screen() {
return ( return (
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center"> <div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100">Save your access key!</h1> <h1 className="text-xl font-semibold text-white">Save your access key!</h1>
</div> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="text-base font-semibold text-zinc-400">Public Key</span> <span className="text-base font-semibold text-white/50">Public Key</span>
<input <input
readOnly readOnly
value={npub} value={npub}
className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400" className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="text-base font-semibold text-zinc-400">Private Key</span> <span className="text-base font-semibold text-white/50">Private Key</span>
<div className="relative"> <div className="relative">
<input <input
readOnly readOnly
type={privkeyInput} type={privkeyInput}
value={nsec} value={nsec}
className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400" className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
/> />
<button <button
type="button" type="button"
@ -110,13 +110,13 @@ export function CreateStep1Screen() {
<EyeOffIcon <EyeOffIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
) : ( ) : (
<EyeOnIcon <EyeOnIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
)} )}
</button> </button>
@ -132,13 +132,13 @@ export function CreateStep1Screen() {
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<Button preset="large" onClick={() => submit()}> <Button preset="large" onClick={() => submit()}>
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'I have saved my key, continue →' 'I have saved my key, continue →'
)} )}
</Button> </Button>
{downloaded ? ( {downloaded ? (
<span className="text-sm text-zinc-400">Saved in download folder</span> <span className="text-sm text-white/50">Saved in download folder</span>
) : ( ) : (
<Button preset="large-alt" onClick={() => download()}> <Button preset="large-alt" onClick={() => download()}>
Download Download

View File

@ -74,7 +74,7 @@ export function CreateStep2Screen() {
return ( return (
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center"> <div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100"> <h1 className="text-xl font-semibold text-white">
Set password to secure your key Set password to secure your key
</h1> </h1>
</div> </div>
@ -85,7 +85,7 @@ export function CreateStep2Screen() {
<input <input
{...register('password', { required: true })} {...register('password', { required: true })}
type={passwordInput} type={passwordInput}
className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400" className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
/> />
<button <button
type="button" type="button"
@ -96,13 +96,13 @@ export function CreateStep2Screen() {
<EyeOffIcon <EyeOffIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
) : ( ) : (
<EyeOnIcon <EyeOnIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
)} )}
</button> </button>
@ -122,10 +122,10 @@ export function CreateStep2Screen() {
<button <button
type="submit" type="submit"
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50" className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Continue →' 'Continue →'
)} )}

View File

@ -45,7 +45,7 @@ export function CreateStep3Screen() {
return ( return (
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center"> <div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100">Create your profile</h1> <h1 className="text-xl font-semibold text-white">Create your profile</h1>
</div> </div>
<div className="w-full overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900"> <div className="w-full overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<form onSubmit={handleSubmit(onSubmit)} className="mb-0 flex flex-col"> <form onSubmit={handleSubmit(onSubmit)} className="mb-0 flex flex-col">
@ -53,13 +53,13 @@ export function CreateStep3Screen() {
type={'hidden'} type={'hidden'}
{...register('picture')} {...register('picture')}
value={picture} value={picture}
className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500" className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-white/50 dark:bg-zinc-800 dark:text-white dark:shadow-black/10 dark:placeholder:text-zinc-500"
/> />
<input <input
type={'hidden'} type={'hidden'}
{...register('banner')} {...register('banner')}
value={banner} value={banner}
className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500" className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-white/50 dark:bg-zinc-800 dark:text-white dark:shadow-black/10 dark:placeholder:text-zinc-500"
/> />
<div className="relative"> <div className="relative">
<div className="relative h-44 w-full bg-zinc-800"> <div className="relative h-44 w-full bg-zinc-800">
@ -91,7 +91,7 @@ export function CreateStep3Screen() {
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="name" htmlFor="name"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Name * Name *
</label> </label>
@ -102,26 +102,26 @@ export function CreateStep3Screen() {
minLength: 4, minLength: 4,
})} })}
spellCheck={false} spellCheck={false}
className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="about" htmlFor="about"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Bio Bio
</label> </label>
<textarea <textarea
{...register('about')} {...register('about')}
spellCheck={false} spellCheck={false}
className="relative h-20 w-full resize-none rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-20 w-full resize-none rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="website" htmlFor="website"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Website Website
</label> </label>
@ -131,16 +131,16 @@ export function CreateStep3Screen() {
required: false, required: false,
})} })}
spellCheck={false} spellCheck={false}
className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<button <button
type="submit" type="submit"
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600" className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Continue →' 'Continue →'
)} )}

View File

@ -53,7 +53,7 @@ export function CreateStep4Screen() {
return ( return (
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center"> <div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100">Create your Lume ID</h1> <h1 className="text-xl font-semibold text-white">Create your Lume ID</h1>
</div> </div>
<div className="flex w-full flex-col items-center justify-center gap-4"> <div className="flex w-full flex-col items-center justify-center gap-4">
<div className="inline-flex w-full items-center justify-center gap-2 rounded-lg bg-zinc-800"> <div className="inline-flex w-full items-center justify-center gap-2 rounded-lg bg-zinc-800">
@ -65,7 +65,7 @@ export function CreateStep4Screen() {
autoCorrect="none" autoCorrect="none"
spellCheck="false" spellCheck="false"
placeholder="satoshi" placeholder="satoshi"
className="relative w-full bg-transparent py-3 pl-3.5 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative w-full bg-transparent py-3 pl-3.5 text-white !outline-none placeholder:text-zinc-500"
/> />
<span className="pr-3.5 font-semibold text-fuchsia-500">@lume.nu</span> <span className="pr-3.5 font-semibold text-fuchsia-500">@lume.nu</span>
</div> </div>
@ -75,7 +75,7 @@ export function CreateStep4Screen() {
disabled={username.length === 0} disabled={username.length === 0}
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Continue →' 'Continue →'
)} )}

View File

@ -168,13 +168,11 @@ export function CreateStep5Screen() {
return ( return (
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center"> <div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100"> <h1 className="text-xl font-semibold text-white">Personalized your newsfeed</h1>
Personalized your newsfeed
</h1>
</div> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div className="w-full overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900"> <div className="w-full overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<div className="inline-flex h-10 w-full items-center gap-1 border-b border-zinc-800 px-4 text-base font-medium text-zinc-400"> <div className="inline-flex h-10 w-full items-center gap-1 border-b border-zinc-800 px-4 text-base font-medium text-white/50">
Follow at least Follow at least
<span className="font-semibold text-fuchsia-500"> <span className="font-semibold text-fuchsia-500">
{follows.length}/10 {follows.length}/10
@ -183,7 +181,7 @@ export function CreateStep5Screen() {
</div> </div>
{status === 'loading' ? ( {status === 'loading' ? (
<div className="inline-flex h-11 w-full items-center justify-center px-4 py-2"> <div className="inline-flex h-11 w-full items-center justify-center px-4 py-2">
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
</div> </div>
) : ( ) : (
<div className="scrollbar-hide flex h-96 flex-col overflow-y-auto py-2"> <div className="scrollbar-hide flex h-96 flex-col overflow-y-auto py-2">
@ -209,10 +207,10 @@ export function CreateStep5Screen() {
<button <button
type="button" type="button"
onClick={() => submit()} onClick={() => submit()}
className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600" className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Finish →' 'Finish →'
)} )}

View File

@ -98,17 +98,17 @@ export function ImportStep1Screen() {
return ( return (
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center"> <div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100">Import your key</h1> <h1 className="text-xl font-semibold text-white">Import your key</h1>
</div> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-3"> <form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-3">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="text-base font-semibold text-zinc-400">Private key</span> <span className="text-base font-semibold text-white/50">Private key</span>
<input <input
{...register('privkey', { required: true, minLength: 32 })} {...register('privkey', { required: true, minLength: 32 })}
type={'password'} type={'password'}
placeholder="nsec or hexstring" placeholder="nsec or hexstring"
className="relative w-full rounded-lg bg-zinc-800 px-3 py-3 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative w-full rounded-lg bg-zinc-800 px-3 py-3 text-white !outline-none placeholder:text-zinc-500"
/> />
<span className="text-sm text-red-400"> <span className="text-sm text-red-400">
{errors.privkey && <p>{errors.privkey.message}</p>} {errors.privkey && <p>{errors.privkey.message}</p>}
@ -118,10 +118,10 @@ export function ImportStep1Screen() {
<button <button
type="submit" type="submit"
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600" className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Continue →' 'Continue →'
)} )}

View File

@ -74,7 +74,7 @@ export function ImportStep2Screen() {
return ( return (
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center"> <div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100"> <h1 className="text-xl font-semibold text-white">
Set password to secure your key Set password to secure your key
</h1> </h1>
</div> </div>
@ -85,7 +85,7 @@ export function ImportStep2Screen() {
<input <input
{...register('password', { required: true })} {...register('password', { required: true })}
type={passwordInput} type={passwordInput}
className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400" className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
/> />
<button <button
type="button" type="button"
@ -96,13 +96,13 @@ export function ImportStep2Screen() {
<EyeOffIcon <EyeOffIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
) : ( ) : (
<EyeOnIcon <EyeOnIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
)} )}
</button> </button>
@ -122,10 +122,10 @@ export function ImportStep2Screen() {
<button <button
type="submit" type="submit"
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50" className="inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Continue →' 'Continue →'
)} )}

View File

@ -75,7 +75,7 @@ export function ImportStep3Screen() {
<User pubkey={account.pubkey} /> <User pubkey={account.pubkey} />
<Button preset="large" onClick={() => submit()}> <Button preset="large" onClick={() => submit()}>
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Continue →' 'Continue →'
)} )}

View File

@ -92,7 +92,7 @@ export function MigrateScreen() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-8 text-center"> <div className="mb-8 text-center">
<h1 className="text-xl font-semibold text-zinc-100"> <h1 className="text-xl font-semibold text-white">
Upgrade security for your account Upgrade security for your account
</h1> </h1>
</div> </div>
@ -100,15 +100,15 @@ export function MigrateScreen() {
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div> <div>
<div className="mt-1"> <div className="mt-1">
<p className="text-sm text-zinc-400"> <p className="text-sm text-white/50">
You&apos;re using old Lume version which store your private key as You&apos;re using old Lume version which store your private key as
plaintext in database, this is huge security risk. plaintext in database, this is huge security risk.
</p> </p>
<p className="mt-2 text-sm text-zinc-400"> <p className="mt-2 text-sm text-white/50">
To secure your private key, please set a password and Lume will put your To secure your private key, please set a password and Lume will put your
private key in secure storage. private key in secure storage.
</p> </p>
<p className="mt-2 text-sm text-zinc-400"> <p className="mt-2 text-sm text-white/50">
It is not possible to start the app without applying this step, it is It is not possible to start the app without applying this step, it is
easy and fast! easy and fast!
</p> </p>
@ -124,7 +124,7 @@ export function MigrateScreen() {
{...register('password', { required: true })} {...register('password', { required: true })}
type={passwordInput} type={passwordInput}
placeholder="min. 4 characters" placeholder="min. 4 characters"
className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400" className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
/> />
<button <button
type="button" type="button"
@ -135,13 +135,13 @@ export function MigrateScreen() {
<EyeOffIcon <EyeOffIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
) : ( ) : (
<EyeOnIcon <EyeOnIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
)} )}
</button> </button>
@ -154,10 +154,10 @@ export function MigrateScreen() {
<button <button
type="submit" type="submit"
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
className="mt-3 inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50" className="mt-3 inline-flex h-11 w-full items-center justify-center rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600 disabled:pointer-events-none disabled:opacity-50"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Continue →' 'Continue →'
)} )}

View File

@ -38,7 +38,7 @@ export function OnboardingScreen() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">
<div className="mb-4 text-center"> <div className="mb-4 text-center">
<h1 className="mb-2 text-xl font-semibold text-zinc-100"> <h1 className="mb-2 text-xl font-semibold text-white">
👋 Hello, welcome you to Lume 👋 Hello, welcome you to Lume
</h1> </h1>
<p className="text-sm text-zinc-300"> <p className="text-sm text-zinc-300">
@ -54,7 +54,7 @@ export function OnboardingScreen() {
{status === 'success' && ( {status === 'success' && (
<User pubkey={account.pubkey} time={Math.floor(Date.now() / 1000)} /> <User pubkey={account.pubkey} time={Math.floor(Date.now() / 1000)} />
)} )}
<div className="-mt-6 select-text whitespace-pre-line break-words pl-[49px] text-base text-zinc-100"> <div className="-mt-6 select-text whitespace-pre-line break-words pl-[49px] text-base text-white">
<p>Running Lume, join with me #nostr #lume</p> <p>Running Lume, join with me #nostr #lume</p>
<a <a
href="https://lume.nu" href="https://lume.nu"
@ -71,12 +71,12 @@ export function OnboardingScreen() {
<button <button
type="button" type="button"
onClick={() => submit()} onClick={() => submit()}
className="inline-flex h-12 w-full items-center justify-between gap-2 rounded-lg bg-fuchsia-500 px-6 font-medium text-zinc-100 hover:bg-fuchsia-600" className="inline-flex h-12 w-full items-center justify-between gap-2 rounded-lg bg-fuchsia-500 px-6 font-medium text-white hover:bg-fuchsia-600"
> >
{loading ? ( {loading ? (
<> <>
<span className="w-5" /> <span className="w-5" />
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
<span className="w-5" /> <span className="w-5" />
</> </>
) : ( ) : (

View File

@ -12,7 +12,7 @@ export function WelcomeScreen() {
<div className="inline-flex w-full flex-col gap-3 px-10 pb-10"> <div className="inline-flex w-full flex-col gap-3 px-10 pb-10">
<Link <Link
to="/auth/import" to="/auth/import"
className="inline-flex h-12 w-full items-center justify-between gap-2 rounded-lg bg-fuchsia-500 px-6 font-medium text-zinc-100 hover:bg-fuchsia-600" className="inline-flex h-12 w-full items-center justify-between gap-2 rounded-lg bg-fuchsia-500 px-6 font-medium text-white hover:bg-fuchsia-600"
> >
<span className="w-5" /> <span className="w-5" />
<span>Login with private key</span> <span>Login with private key</span>

View File

@ -18,7 +18,7 @@ export function ChannelBlackList({ blacklist }: { blacklist: any }) {
<MuteIcon <MuteIcon
width={16} width={16}
height={16} height={16}
className="text-zinc-400 group-hover:text-zinc-100" className="text-white/50 group-hover:text-white"
/> />
</Popover.Button> </Popover.Button>
<Transition <Transition
@ -37,7 +37,7 @@ export function ChannelBlackList({ blacklist }: { blacklist: any }) {
<h3 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text font-semibold leading-none text-transparent"> <h3 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text font-semibold leading-none text-transparent">
Your muted list Your muted list
</h3> </h3>
<p className="text-base leading-tight text-zinc-400"> <p className="text-base leading-tight text-white/50">
Currently, unmute only affect locally, when you move to new client, Currently, unmute only affect locally, when you move to new client,
muted list will loaded again muted list will loaded again
</p> </p>

View File

@ -115,7 +115,7 @@ export function ChannelCreateModal() {
<PlusIcon width={12} height={12} className="text-zinc-500" /> <PlusIcon width={12} height={12} className="text-zinc-500" />
</div> </div>
<div> <div>
<h5 className="font-medium text-zinc-400">Create channel</h5> <h5 className="font-medium text-white/50">Create channel</h5>
</div> </div>
</button> </button>
<Transition appear show={isOpen} as={Fragment}> <Transition appear show={isOpen} as={Fragment}>
@ -147,7 +147,7 @@ export function ChannelCreateModal() {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Dialog.Title <Dialog.Title
as="h3" as="h3"
className="text-lg font-semibold leading-none text-zinc-100" className="text-lg font-semibold leading-none text-white"
> >
Create channel Create channel
</Dialog.Title> </Dialog.Title>
@ -159,7 +159,7 @@ export function ChannelCreateModal() {
<CancelIcon width={20} height={20} className="text-zinc-300" /> <CancelIcon width={20} height={20} className="text-zinc-300" />
</button> </button>
</div> </div>
<Dialog.Description className="text-sm leading-tight text-zinc-400"> <Dialog.Description className="text-sm leading-tight text-white/50">
Channels are freedom square, everyone can speech freely, no one can Channels are freedom square, everyone can speech freely, no one can
stop you or deceive what to speech stop you or deceive what to speech
</Dialog.Description> </Dialog.Description>
@ -174,10 +174,10 @@ export function ChannelCreateModal() {
type={'hidden'} type={'hidden'}
{...register('picture')} {...register('picture')}
value={image} value={image}
className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500" className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-white/50 dark:bg-zinc-800 dark:text-white dark:shadow-black/10 dark:placeholder:text-zinc-500"
/> />
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="text-sm font-medium uppercase tracking-wider text-zinc-400"> <span className="text-sm font-medium uppercase tracking-wider text-white/50">
Picture Picture
</span> </span>
<div className="relative inline-flex h-36 w-full items-center justify-center overflow-hidden rounded-lg border border-zinc-900 bg-zinc-950"> <div className="relative inline-flex h-36 w-full items-center justify-center overflow-hidden rounded-lg border border-zinc-900 bg-zinc-950">
@ -195,7 +195,7 @@ export function ChannelCreateModal() {
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="name" htmlFor="name"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Channel name * Channel name *
</label> </label>
@ -206,28 +206,28 @@ export function ChannelCreateModal() {
minLength: 4, minLength: 4,
})} })}
spellCheck={false} spellCheck={false}
className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="about" htmlFor="about"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Description Description
</label> </label>
<textarea <textarea
{...register('about')} {...register('about')}
spellCheck={false} spellCheck={false}
className="relative h-20 w-full resize-none rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-20 w-full resize-none rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<div className="flex h-20 items-center justify-between gap-1 rounded-lg bg-zinc-800 px-4 py-2"> <div className="flex h-20 items-center justify-between gap-1 rounded-lg bg-zinc-800 px-4 py-2">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="font-semibold leading-none text-zinc-100"> <span className="font-semibold leading-none text-white">
Encrypted Encrypted
</span> </span>
<p className="w-4/5 text-sm leading-none text-zinc-400"> <p className="w-4/5 text-sm leading-none text-white/50">
All messages are encrypted and only invited members can view and All messages are encrypted and only invited members can view and
send message send message
</p> </p>
@ -248,10 +248,10 @@ export function ChannelCreateModal() {
<button <button
type="submit" type="submit"
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full transform items-center justify-center gap-1 rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600 focus:outline-none active:translate-y-1 disabled:pointer-events-none disabled:opacity-50" className="inline-flex h-11 w-full transform items-center justify-center gap-1 rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600 focus:outline-none active:translate-y-1 disabled:pointer-events-none disabled:opacity-50"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Create channel →' 'Create channel →'
)} )}

View File

@ -12,12 +12,12 @@ export function ChannelsListItem({ data }: { data: any }) {
className={({ isActive }) => className={({ isActive }) =>
twMerge( twMerge(
'inline-flex h-9 items-center gap-2.5 rounded-md px-2.5', 'inline-flex h-9 items-center gap-2.5 rounded-md px-2.5',
isActive ? 'bg-zinc-900/50 text-zinc-100' : '' isActive ? 'bg-zinc-900/50 text-white' : ''
) )
} }
> >
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded border-t border-zinc-800/50 bg-zinc-900"> <div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded border-t border-zinc-800/50 bg-zinc-900">
<span className="text-xs text-zinc-100">#</span> <span className="text-xs text-white">#</span>
</div> </div>
<div className="inline-flex w-full items-center justify-between"> <div className="inline-flex w-full items-center justify-between">
<h5 className="truncate font-medium text-zinc-200">{channel?.name}</h5> <h5 className="truncate font-medium text-zinc-200">{channel?.name}</h5>

View File

@ -74,7 +74,7 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
<div className="flex w-full flex-col"> <div className="flex w-full flex-col">
<UserReply pubkey={replyTo.pubkey} /> <UserReply pubkey={replyTo.pubkey} />
<div className="-mt-5 pl-[38px]"> <div className="-mt-5 pl-[38px]">
<div className="text-base text-zinc-100">{replyTo.content}</div> <div className="text-base text-white">{replyTo.content}</div>
</div> </div>
</div> </div>
<button <button
@ -82,7 +82,7 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
onClick={() => stopReply()} onClick={() => stopReply()}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-800" className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-800"
> >
<CancelIcon width={12} height={12} className="text-zinc-100" /> <CancelIcon width={12} height={12} className="text-white" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -99,7 +99,7 @@ export function MessageHideButton({ id }: { id: string }) {
<CancelIcon width={20} height={20} className="text-zinc-300" /> <CancelIcon width={20} height={20} className="text-zinc-300" />
</button> </button>
</div> </div>
<Dialog.Description className="leading-tight text-zinc-400"> <Dialog.Description className="leading-tight text-white/50">
This message will be hidden from your feed. This message will be hidden from your feed.
</Dialog.Description> </Dialog.Description>
</div> </div>
@ -109,14 +109,14 @@ export function MessageHideButton({ id }: { id: string }) {
<button <button
type="button" type="button"
onClick={closeModal} onClick={closeModal}
className="inline-flex h-9 items-center justify-center rounded-md px-2 text-base font-medium text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100" className="inline-flex h-9 items-center justify-center rounded-md px-2 text-base font-medium text-white/50 hover:bg-zinc-800 hover:text-white"
> >
Cancel Cancel
</button> </button>
<button <button
type="button" type="button"
onClick={() => hideMessage()} onClick={() => hideMessage()}
className="inline-flex h-9 items-center justify-center rounded-md bg-red-500 px-2 text-base font-medium text-zinc-100 hover:bg-red-600" className="inline-flex h-9 items-center justify-center rounded-md bg-red-500 px-2 text-base font-medium text-white hover:bg-red-600"
> >
Confirm Confirm
</button> </button>

View File

@ -19,7 +19,7 @@ export function ChannelMessageItem({ data }: { data: LumeEvent }) {
<div className="flex flex-col"> <div className="flex flex-col">
<User pubkey={data.pubkey} time={data.created_at} isChat={true} /> <User pubkey={data.pubkey} time={data.created_at} isChat={true} />
<div className="-mt-[20px] pl-[49px]"> <div className="-mt-[20px] pl-[49px]">
<p className="select-text whitespace-pre-line break-words text-base text-zinc-100"> <p className="select-text whitespace-pre-line break-words text-base text-white">
{content.parsed} {content.parsed}
</p> </p>
{Array.isArray(content.images) && content.images.length ? ( {Array.isArray(content.images) && content.images.length ? (

View File

@ -99,7 +99,7 @@ export function MessageMuteButton({ pubkey }: { pubkey: string }) {
<CancelIcon width={20} height={20} className="text-zinc-300" /> <CancelIcon width={20} height={20} className="text-zinc-300" />
</button> </button>
</div> </div>
<Dialog.Description className="leading-tight text-zinc-400"> <Dialog.Description className="leading-tight text-white/50">
You will no longer see messages from this user. You will no longer see messages from this user.
</Dialog.Description> </Dialog.Description>
</div> </div>
@ -109,14 +109,14 @@ export function MessageMuteButton({ pubkey }: { pubkey: string }) {
<button <button
type="button" type="button"
onClick={closeModal} onClick={closeModal}
className="inline-flex h-9 items-center justify-center rounded-md px-2 text-base font-medium text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100" className="inline-flex h-9 items-center justify-center rounded-md px-2 text-base font-medium text-white/50 hover:bg-zinc-800 hover:text-white"
> >
Cancel Cancel
</button> </button>
<button <button
type="button" type="button"
onClick={() => muteUser()} onClick={() => muteUser()}
className="inline-flex h-9 items-center justify-center rounded-md bg-red-500 px-2 text-base font-medium text-zinc-100 hover:bg-red-600" className="inline-flex h-9 items-center justify-center rounded-md bg-red-500 px-2 text-base font-medium text-white hover:bg-red-600"
> >
Confirm Confirm
</button> </button>

View File

@ -32,10 +32,10 @@ export function ChannelMetadata({ id }: { id: string }) {
<div className="inline-flex items-center gap-1"> <div className="inline-flex items-center gap-1">
<h5 className="text-lg font-semibold leading-none">{metadata?.name}</h5> <h5 className="text-lg font-semibold leading-none">{metadata?.name}</h5>
<button type="button" onClick={() => copyNoteID()}> <button type="button" onClick={() => copyNoteID()}>
<CopyIcon width={14} height={14} className="text-zinc-400" /> <CopyIcon width={14} height={14} className="text-white/50" />
</button> </button>
</div> </div>
<p className="leading-tight text-zinc-400"> <p className="leading-tight text-white/50">
{metadata?.about || (noteID && `${noteID.substring(0, 24)}...`)} {metadata?.about || (noteID && `${noteID.substring(0, 24)}...`)}
</p> </p>
</div> </div>

View File

@ -51,10 +51,10 @@ export function MutedItem({ data }: { data: any }) {
/> />
</div> </div>
<div className="flex w-full flex-1 flex-col items-start gap-0.5 text-start"> <div className="flex w-full flex-1 flex-col items-start gap-0.5 text-start">
<span className="truncate text-base font-medium leading-none text-zinc-100"> <span className="truncate text-base font-medium leading-none text-white">
{user?.displayName || user?.name || 'Pleb'} {user?.displayName || user?.name || 'Pleb'}
</span> </span>
<span className="text-base leading-none text-zinc-400"> <span className="text-base leading-none text-white/50">
{shortenKey(data.content)} {shortenKey(data.content)}
</span> </span>
</div> </div>
@ -64,7 +64,7 @@ export function MutedItem({ data }: { data: any }) {
<button <button
type="button" type="button"
onClick={() => unmute()} onClick={() => unmute()}
className="inline-flex h-6 w-min items-center justify-center rounded px-1.5 text-base font-medium leading-none text-zinc-400 hover:bg-zinc-800 hover:text-fuchsia-500" className="inline-flex h-6 w-min items-center justify-center rounded px-1.5 text-base font-medium leading-none text-white/50 hover:bg-zinc-800 hover:text-fuchsia-500"
> >
Unmute Unmute
</button> </button>
@ -72,7 +72,7 @@ export function MutedItem({ data }: { data: any }) {
<button <button
type="button" type="button"
onClick={() => mute()} onClick={() => mute()}
className="inline-flex h-6 w-min items-center justify-center rounded px-1.5 text-base font-medium leading-none text-zinc-400 hover:bg-zinc-800 hover:text-fuchsia-500" className="inline-flex h-6 w-min items-center justify-center rounded px-1.5 text-base font-medium leading-none text-white/50 hover:bg-zinc-800 hover:text-fuchsia-500"
> >
Mute Mute
</button> </button>

View File

@ -23,7 +23,7 @@ const Header = (
<div className="w-full border-t border-zinc-800" /> <div className="w-full border-t border-zinc-800" />
</div> </div>
<div className="relative flex justify-center"> <div className="relative flex justify-center">
<div className="inline-flex items-center gap-x-1.5 rounded-full bg-zinc-900 px-3 py-1.5 text-sm font-medium text-zinc-400 shadow-sm ring-1 ring-inset ring-zinc-800"> <div className="inline-flex items-center gap-x-1.5 rounded-full bg-zinc-900 px-3 py-1.5 text-sm font-medium text-white/50 shadow-sm ring-1 ring-inset ring-zinc-800">
{getHourAgo(24, now).toLocaleDateString('en-US', { {getHourAgo(24, now).toLocaleDateString('en-US', {
weekday: 'long', weekday: 'long',
year: 'numeric', year: 'numeric',
@ -40,7 +40,7 @@ const Empty = (
<h3 className="text-base font-semibold leading-none text-white"> <h3 className="text-base font-semibold leading-none text-white">
Nothing to see here yet Nothing to see here yet
</h3> </h3>
<p className="text-base leading-none text-zinc-400"> <p className="text-base leading-none text-white/50">
Be the first to share a message in this channel. Be the first to share a message in this channel.
</p> </p>
</div> </div>
@ -102,7 +102,7 @@ export function ChannelScreen() {
data-tauri-drag-region data-tauri-drag-region
className="inline-flex h-11 w-full shrink-0 items-center justify-center border-b border-zinc-900" className="inline-flex h-11 w-full shrink-0 items-center justify-center border-b border-zinc-900"
> >
<h3 className="font-semibold text-zinc-100">Public Channel</h3> <h3 className="font-semibold text-white">Public Channel</h3>
</div> </div>
<div className="h-full w-full flex-1 p-3"> <div className="h-full w-full flex-1 p-3">
<div className="flex h-full flex-col justify-between overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900"> <div className="flex h-full flex-col justify-between overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900">

View File

@ -30,7 +30,7 @@ export function ChatMessageItem({
<div className="flex flex-col"> <div className="flex flex-col">
<User pubkey={data.sender_pubkey} time={data.created_at} isChat={true} /> <User pubkey={data.sender_pubkey} time={data.created_at} isChat={true} />
<div className="-mt-[20px] pl-[49px]"> <div className="-mt-[20px] pl-[49px]">
<p className="select-text whitespace-pre-line break-words text-base text-zinc-100"> <p className="select-text whitespace-pre-line break-words text-base text-white">
{content.parsed} {content.parsed}
</p> </p>
{content.images.length > 0 && <ImagePreview urls={content.images} />} {content.images.length > 0 && <ImagePreview urls={content.images} />}

View File

@ -43,14 +43,14 @@ export function NewMessageModal() {
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5"> <div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Dialog.Title className="text-lg font-semibold leading-none text-zinc-100"> <Dialog.Title className="text-lg font-semibold leading-none text-white">
New chat New chat
</Dialog.Title> </Dialog.Title>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10"> <Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" /> <CancelIcon className="h-4 w-4 text-white/50" />
</Dialog.Close> </Dialog.Close>
</div> </div>
<Dialog.Description className="text-sm leading-none text-zinc-400"> <Dialog.Description className="text-sm leading-none text-white/50">
All messages will be encrypted, but anyone can see who you chat All messages will be encrypted, but anyone can see who you chat
</Dialog.Description> </Dialog.Description>
</div> </div>

View File

@ -26,7 +26,7 @@ export function ChatSidebar({ pubkey }: { pubkey: string }) {
<h3 className="text-lg font-semibold leading-none"> <h3 className="text-lg font-semibold leading-none">
{user?.displayName || user?.name} {user?.displayName || user?.name}
</h3> </h3>
<h5 className="leading-none text-zinc-400"> <h5 className="leading-none text-white/50">
{user?.nip05 || shortenKey(pubkey)} {user?.nip05 || shortenKey(pubkey)}
</h5> </h5>
</div> </div>
@ -34,7 +34,7 @@ export function ChatSidebar({ pubkey }: { pubkey: string }) {
<p className="leading-tight">{user?.bio || user?.about}</p> <p className="leading-tight">{user?.bio || user?.about}</p>
<Link <Link
to={`/app/users/${pubkey}`} to={`/app/users/${pubkey}`}
className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-md bg-zinc-900 text-sm font-medium text-zinc-300 hover:bg-zinc-800 hover:text-zinc-100" className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-md bg-zinc-900 text-sm font-medium text-zinc-300 hover:bg-zinc-800 hover:text-white"
> >
View full profile View full profile
</Link> </Link>

View File

@ -42,14 +42,14 @@ export function UnknownsModal({ data }: { data: Chats[] }) {
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5"> <div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Dialog.Title className="text-lg font-semibold leading-none text-zinc-100"> <Dialog.Title className="text-lg font-semibold leading-none text-white">
{data.length} unknowns {data.length} unknowns
</Dialog.Title> </Dialog.Title>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10"> <Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" /> <CancelIcon className="h-4 w-4 text-white/50" />
</Dialog.Close> </Dialog.Close>
</div> </div>
<Dialog.Description className="text-sm leading-none text-zinc-400"> <Dialog.Description className="text-sm leading-none text-white/50">
All messages from people you not follow All messages from people you not follow
</Dialog.Description> </Dialog.Description>
</div> </div>

View File

@ -1,7 +1,9 @@
import { nip04 } from 'nostr-tools'; import { nip04 } from 'nostr-tools';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
export function useDecryptMessage(data: any, userPubkey: string, userPriv: string) { import { Chats } from '@utils/types';
export function useDecryptMessage(data: Chats, userPubkey: string, userPriv: string) {
const [content, setContent] = useState(data.content); const [content, setContent] = useState(data.content);
useEffect(() => { useEffect(() => {

View File

@ -106,7 +106,7 @@ export function ChatScreen() {
data-tauri-drag-region data-tauri-drag-region
className="inline-flex h-11 w-full shrink-0 items-center justify-center border-b border-zinc-900" className="inline-flex h-11 w-full shrink-0 items-center justify-center border-b border-zinc-900"
> >
<h3 className="font-semibold text-zinc-100">Encrypted Chat</h3> <h3 className="font-semibold text-white">Encrypted Chat</h3>
</div> </div>
<div className="h-full w-full flex-1 p-3"> <div className="h-full w-full flex-1 p-3">
<div className="flex h-full flex-col justify-between overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900"> <div className="flex h-full flex-col justify-between overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900">
@ -155,7 +155,7 @@ export function ChatScreen() {
const Empty = ( const Empty = (
<div className="absolute left-1/2 top-1/2 flex w-full -translate-x-1/2 -translate-y-1/2 transform flex-col gap-1 text-center"> <div className="absolute left-1/2 top-1/2 flex w-full -translate-x-1/2 -translate-y-1/2 transform flex-col gap-1 text-center">
<h3 className="mb-2 text-4xl">🙌</h3> <h3 className="mb-2 text-4xl">🙌</h3>
<p className="leading-none text-zinc-400"> <p className="leading-none text-white/50">
You two didn&apos;t talk yet, let&apos;s send first message You two didn&apos;t talk yet, let&apos;s send first message
</p> </p>
</div> </div>

View File

@ -118,46 +118,6 @@ export function Root() {
} }
} }
/*
async function fetchChannelMessages() {
try {
const ids = [];
const channels: any = await getChannels();
channels.forEach((channel) => {
ids.push(channel.event_id);
});
const since = lastLogin === 0 ? dateToUnix(getHourAgo(48, now.current)) : lastLogin;
const filter: NDKFilter = {
'#e': ids,
kinds: [42],
since: since,
};
const events = await prefetchEvents(ndk, filter);
events.forEach((event) => {
const channel_id = event.tags[0][1];
if (channel_id) {
createChannelMessage(
channel_id,
event.id,
event.pubkey,
event.kind,
event.content,
event.tags,
event.created_at
);
}
});
return true;
} catch (e) {
console.log('error: ', e);
}
}
*/
useEffect(() => { useEffect(() => {
async function prefetch() { async function prefetch() {
const notes = await fetchNotes(); const notes = await fetchNotes();
@ -180,12 +140,12 @@ export function Root() {
<div data-tauri-drag-region className="h-11 shrink-0" /> <div data-tauri-drag-region className="h-11 shrink-0" />
<div className="relative flex min-h-0 w-full flex-1 items-center justify-center"> <div className="relative flex min-h-0 w-full flex-1 items-center justify-center">
<div className="flex flex-col items-center justify-center gap-4"> <div className="flex flex-col items-center justify-center gap-4">
<LoaderIcon className="h-6 w-6 animate-spin text-zinc-100" /> <LoaderIcon className="h-6 w-6 animate-spin text-white" />
<div className="text-center"> <div className="text-center">
<h3 className="text-lg font-semibold leading-tight text-zinc-100"> <h3 className="text-lg font-semibold leading-tight text-white">
Prefetching data... Prefetching data...
</h3> </h3>
<p className="text-zinc-600"> <p className="text-white/50">
This may take a few seconds, please don&apos;t close app. This may take a few seconds, please don&apos;t close app.
</p> </p>
</div> </div>

View File

@ -23,36 +23,36 @@ export function AccountSettingsScreen() {
return ( return (
<div className="h-full w-full px-3 pt-12"> <div className="h-full w-full px-3 pt-12">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<h1 className="text-lg font-semibold text-zinc-100">Account</h1> <h1 className="text-lg font-semibold text-white">Account</h1>
<div className=""> <div className="">
{status === 'loading' ? ( {status === 'loading' ? (
<p>Loading...</p> <p>Loading...</p>
) : ( ) : (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label htmlFor="pubkey" className="text-base font-semibold text-zinc-400"> <label htmlFor="pubkey" className="text-base font-semibold text-white/50">
Public Key Public Key
</label> </label>
<input <input
readOnly readOnly
value={account.pubkey} value={account.pubkey}
className="relative w-2/3 rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400" className="relative w-2/3 rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label htmlFor="npub" className="text-base font-semibold text-zinc-400"> <label htmlFor="npub" className="text-base font-semibold text-white/50">
Npub Npub
</label> </label>
<input <input
readOnly readOnly
value={account.npub} value={account.npub}
className="relative w-2/3 rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400" className="relative w-2/3 rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="privkey" htmlFor="privkey"
className="text-base font-semibold text-zinc-400" className="text-base font-semibold text-white/50"
> >
Private Key Private Key
</label> </label>
@ -61,7 +61,7 @@ export function AccountSettingsScreen() {
readOnly readOnly
type={type} type={type}
value={privkey} value={privkey}
className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-zinc-100 !outline-none placeholder:text-zinc-400" className="relative w-full rounded-lg bg-zinc-800 py-3 pl-3.5 pr-11 text-white !outline-none placeholder:text-white/50"
/> />
<button <button
type="button" type="button"
@ -72,13 +72,13 @@ export function AccountSettingsScreen() {
<EyeOffIcon <EyeOffIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
) : ( ) : (
<EyeOnIcon <EyeOnIcon
width={20} width={20}
height={20} height={20}
className="text-zinc-500 group-hover:text-zinc-100" className="text-zinc-500 group-hover:text-white"
/> />
)} )}
</button> </button>

View File

@ -36,7 +36,7 @@ export function AutoStartSetting() {
<div className="inline-flex items-center justify-between px-5 py-4"> <div className="inline-flex items-center justify-between px-5 py-4">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="font-medium leading-none text-zinc-200">Auto start</span> <span className="font-medium leading-none text-zinc-200">Auto start</span>
<span className="text-sm leading-none text-zinc-400">Auto start at login</span> <span className="text-sm leading-none text-white/50">Auto start at login</span>
</div> </div>
<Switch <Switch
checked={enabled} checked={enabled}

View File

@ -20,7 +20,7 @@ export function CacheTimeSetting() {
<span className="font-medium leading-none text-zinc-200"> <span className="font-medium leading-none text-zinc-200">
Cache time (milliseconds) Cache time (milliseconds)
</span> </span>
<span className="text-sm leading-none text-zinc-400"> <span className="text-sm leading-none text-white/50">
The length of time before inactive data gets removed from the cache The length of time before inactive data gets removed from the cache
</span> </span>
</div> </div>
@ -37,7 +37,7 @@ export function CacheTimeSetting() {
onClick={() => update()} onClick={() => update()}
className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-800 font-medium hover:bg-fuchsia-500" className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-800 font-medium hover:bg-fuchsia-500"
> >
<CheckCircleIcon className="h-4 w-4 text-zinc-100" /> <CheckCircleIcon className="h-4 w-4 text-white" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -9,7 +9,7 @@ export function VersionSetting() {
<div className="inline-flex items-center justify-between px-5 py-4"> <div className="inline-flex items-center justify-between px-5 py-4">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="font-medium leading-none text-zinc-200">Version</span> <span className="font-medium leading-none text-zinc-200">Version</span>
<span className="text-sm leading-none text-zinc-400"> <span className="text-sm leading-none text-white/50">
You&apos;re using latest version You&apos;re using latest version
</span> </span>
</div> </div>
@ -19,7 +19,7 @@ export function VersionSetting() {
type="button" type="button"
className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-800 font-medium hover:bg-fuchsia-500" className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-800 font-medium hover:bg-fuchsia-500"
> >
<RefreshIcon className="h-4 w-4 text-zinc-100" /> <RefreshIcon className="h-4 w-4 text-white" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -6,7 +6,7 @@ export function GeneralSettingsScreen() {
return ( return (
<div className="h-full w-full px-3 pt-12"> <div className="h-full w-full px-3 pt-12">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<h1 className="text-lg font-semibold text-zinc-100">General</h1> <h1 className="text-lg font-semibold text-white">General</h1>
<div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900"> <div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<div className="flex h-full w-full flex-col divide-y divide-zinc-800"> <div className="flex h-full w-full flex-col divide-y divide-zinc-800">
<AutoStartSetting /> <AutoStartSetting />

View File

@ -4,7 +4,7 @@ export function ShortcutsSettingsScreen() {
return ( return (
<div className="h-full w-full px-3 pt-12"> <div className="h-full w-full px-3 pt-12">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<h1 className="text-lg font-semibold text-zinc-100">Shortcuts</h1> <h1 className="text-lg font-semibold text-white">Shortcuts</h1>
<div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900"> <div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<div className="flex h-full w-full flex-col divide-y divide-zinc-800"> <div className="flex h-full w-full flex-col divide-y divide-zinc-800">
<div className="inline-flex items-center justify-between px-5 py-4"> <div className="inline-flex items-center justify-between px-5 py-4">

View File

@ -1,13 +0,0 @@
import { AddFeedBlock } from '@app/space/components/addFeed';
import { AddHashTagBlock } from '@app/space/components/addHashtag';
import { AddImageBlock } from '@app/space/components/addImage';
export function AddBlock() {
return (
<div className="flex flex-col gap-1">
<AddImageBlock />
<AddFeedBlock />
<AddHashTagBlock />
</div>
);
}

View File

@ -1,252 +0,0 @@
import { Dialog, Transition } from '@headlessui/react';
import { Combobox } from '@headlessui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { nip19 } from 'nostr-tools';
import { Fragment, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook';
import { User } from '@app/auth/components/user';
import { createBlock } from '@libs/storage';
import { CancelIcon, CheckCircleIcon, CommandIcon, LoaderIcon } from '@shared/icons';
import { BLOCK_KINDS, DEFAULT_AVATAR } from '@stores/constants';
import { ADD_FEEDBLOCK_SHORTCUT } from '@stores/shortcuts';
import { useAccount } from '@utils/hooks/useAccount';
export function AddFeedBlock() {
const queryClient = useQueryClient();
const [loading, setLoading] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [selected, setSelected] = useState([]);
const [query, setQuery] = useState('');
const { status, account } = useAccount();
const openModal = () => {
setIsOpen(true);
};
const closeModal = () => {
setIsOpen(false);
};
useHotkeys(ADD_FEEDBLOCK_SHORTCUT, () => openModal());
const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] });
},
});
const {
register,
handleSubmit,
reset,
formState: { isDirty, isValid },
} = useForm();
const onSubmit = (data: { kind: number; title: string; content: string }) => {
setLoading(true);
selected.forEach((item, index) => {
if (item.substring(0, 4) === 'npub') {
selected[index] = nip19.decode(item).data;
}
});
// insert to database
block.mutate({
kind: BLOCK_KINDS.feed,
title: data.title,
content: JSON.stringify(selected),
});
setLoading(false);
// reset form
reset();
// close modal
closeModal();
};
return (
<>
<button
type="button"
onClick={() => openModal()}
className="inline-flex h-9 w-72 items-center justify-start gap-2.5 rounded-md px-2.5"
>
<div className="flex items-center gap-2">
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<CommandIcon width={12} height={12} className="text-white" />
</div>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<span className="text-sm leading-none text-white">F</span>
</div>
</div>
<div>
<h5 className="font-medium text-white/50">New feed block</h5>
</div>
</button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-50" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
</Transition.Child>
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title
as="h3"
className="text-lg font-semibold leading-none text-zinc-100"
>
Create feed block
</Dialog.Title>
<button
type="button"
onClick={closeModal}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
>
<CancelIcon width={14} height={14} className="text-zinc-300" />
</button>
</div>
<Dialog.Description className="text-sm leading-tight text-zinc-400">
Specific newsfeed space for people you want to keep up to date
</Dialog.Description>
</div>
</div>
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
<form
onSubmit={handleSubmit(onSubmit)}
className="mb-0 flex h-full w-full flex-col gap-4"
>
<div className="flex flex-col gap-1">
<label
htmlFor="title"
className="text-sm font-medium uppercase tracking-wider text-zinc-400"
>
Title *
</label>
<input
type={'text'}
{...register('title', {
required: true,
})}
spellCheck={false}
className="relative h-10 w-full rounded-md bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500"
/>
</div>
<div className="flex flex-col gap-1">
<span className="text-sm font-medium uppercase tracking-wider text-zinc-400">
Choose at least 1 user *
</span>
<div className="flex h-[300px] w-full flex-col overflow-y-auto overflow-x-hidden rounded-lg border-t border-zinc-700/50 bg-zinc-800">
<div className="w-full px-3 py-2">
<Combobox value={selected} onChange={setSelected} multiple>
<Combobox.Input
onChange={(event) => setQuery(event.target.value)}
spellCheck={false}
placeholder="Enter pubkey or npub..."
className="relative mb-2 h-10 w-full rounded-md bg-zinc-700 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500"
/>
<Combobox.Options static>
{query.length > 0 && (
<Combobox.Option
value={query}
className="group flex w-full items-center justify-between rounded-md px-2 py-2 hover:bg-zinc-700"
>
{({ selected }) => (
<>
<div className="flex items-center gap-2">
<img
alt={query}
src={DEFAULT_AVATAR}
className="h-11 w-11 shrink-0 rounded object-cover"
/>
<div className="inline-flex flex-col gap-1">
<span className="text-base leading-tight text-zinc-400">
{query}
</span>
</div>
</div>
{selected && (
<CheckCircleIcon className="h-4 w-4 text-green-500" />
)}
</>
)}
</Combobox.Option>
)}
{status === 'loading' ? (
<p>Loading...</p>
) : (
JSON.parse(account.follows as string).map((follow) => (
<Combobox.Option
key={follow}
value={follow}
className="group flex w-full items-center justify-between rounded-md px-2 py-2 hover:bg-zinc-700"
>
{({ selected }) => (
<>
<User pubkey={follow} />
{selected && (
<CheckCircleIcon className="h-4 w-4 text-green-500" />
)}
</>
)}
</Combobox.Option>
))
)}
</Combobox.Options>
</Combobox>
</div>
</div>
</div>
<div>
<button
type="submit"
disabled={!isDirty || !isValid}
className="shadow-button inline-flex h-11 w-full transform items-center justify-center rounded-lg bg-fuchsia-500 font-medium text-zinc-100 active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
{loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
) : (
'Confirm'
)}
</button>
</div>
</form>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
);
}

View File

@ -1,174 +0,0 @@
import { Dialog, Transition } from '@headlessui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { Fragment, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook';
import { createBlock } from '@libs/storage';
import { CancelIcon, CommandIcon, LoaderIcon } from '@shared/icons';
import { BLOCK_KINDS } from '@stores/constants';
import { ADD_HASHTAGBLOCK_SHORTCUT } from '@stores/shortcuts';
export function AddHashTagBlock() {
const queryClient = useQueryClient();
const [loading, setLoading] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const openModal = () => {
setIsOpen(true);
};
const closeModal = () => {
setIsOpen(false);
};
useHotkeys(ADD_HASHTAGBLOCK_SHORTCUT, () => openModal());
const {
register,
handleSubmit,
reset,
formState: { isDirty, isValid },
} = useForm();
const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] });
},
});
const onSubmit = async (data: { hashtag: string }) => {
setLoading(true);
// mutate
block.mutate({
kind: BLOCK_KINDS.hashtag,
title: data.hashtag,
content: data.hashtag.replace('#', ''),
});
setLoading(false);
// reset form
reset();
// close modal
closeModal();
};
return (
<>
<button
type="button"
onClick={() => openModal()}
className="inline-flex h-9 w-72 items-center justify-start gap-2.5 rounded-md px-2.5"
>
<div className="flex items-center gap-2">
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<CommandIcon width={12} height={12} className="text-white" />
</div>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<span className="text-sm leading-none text-white">T</span>
</div>
</div>
<div>
<h5 className="font-medium text-white/50">New hashtag block</h5>
</div>
</button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-50" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
</Transition.Child>
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title
as="h3"
className="text-lg font-semibold leading-none text-zinc-100"
>
Create hashtag block
</Dialog.Title>
<button
type="button"
onClick={closeModal}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
>
<CancelIcon width={14} height={14} className="text-zinc-300" />
</button>
</div>
<Dialog.Description className="text-sm leading-tight text-zinc-400">
Pin the hashtag you want to keep follow up
</Dialog.Description>
</div>
</div>
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
<form
onSubmit={handleSubmit(onSubmit)}
className="mb-0 flex h-full w-full flex-col gap-4"
>
<div className="flex flex-col gap-1">
<label
htmlFor="title"
className="text-sm font-medium uppercase tracking-wider text-zinc-400"
>
Hashtag *
</label>
<div className="after:shadow-highlight relative w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[6px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[6px] after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
<input
type={'text'}
{...register('hashtag', {
required: true,
})}
spellCheck={false}
placeholder="#"
className="shadow-input relative h-10 w-full rounded-md border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
</div>
</div>
<div>
<button
type="submit"
disabled={!isDirty || !isValid}
className="shadow-button inline-flex h-11 w-full transform items-center justify-center rounded-lg bg-fuchsia-500 font-medium text-zinc-100 active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
{loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
) : (
'Confirm'
)}
</button>
</div>
</form>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
);
}

View File

@ -1,226 +0,0 @@
import { Dialog, Transition } from '@headlessui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { Fragment, useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook';
import { createBlock } from '@libs/storage';
import { CancelIcon, CommandIcon, LoaderIcon } from '@shared/icons';
import { Image } from '@shared/image';
import { BLOCK_KINDS, DEFAULT_AVATAR } from '@stores/constants';
import { ADD_IMAGEBLOCK_SHORTCUT } from '@stores/shortcuts';
import { usePublish } from '@utils/hooks/usePublish';
import { useImageUploader } from '@utils/hooks/useUploader';
export function AddImageBlock() {
const queryClient = useQueryClient();
const upload = useImageUploader();
const { publish } = usePublish();
const [loading, setLoading] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [image, setImage] = useState('');
const tags = useRef(null);
const openModal = () => {
setIsOpen(true);
};
const closeModal = () => {
setIsOpen(false);
};
useHotkeys(ADD_IMAGEBLOCK_SHORTCUT, () => openModal());
const {
register,
handleSubmit,
reset,
setValue,
formState: { isDirty, isValid },
} = useForm();
const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] });
},
});
const uploadImage = async () => {
const image = await upload(null);
if (image.url) {
setImage(image.url);
}
};
const onSubmit = async (data: { kind: number; title: string; content: string }) => {
setLoading(true);
// publish file metedata
await publish({ content: data.title, kind: 1063, tags: tags.current });
// mutate
block.mutate({ kind: BLOCK_KINDS.image, title: data.title, content: data.content });
setLoading(false);
// reset form
reset();
// close modal
closeModal();
};
useEffect(() => {
setValue('content', image);
}, [setValue, image]);
return (
<>
<button
type="button"
onClick={() => openModal()}
className="inline-flex h-9 w-72 items-center justify-start gap-2.5 rounded-md px-2.5"
>
<div className="flex items-center gap-2">
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<CommandIcon width={12} height={12} className="text-white" />
</div>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<span className="text-sm leading-none text-white">I</span>
</div>
</div>
<div>
<h5 className="font-medium text-white/50">New image block</h5>
</div>
</button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-50" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-md" />
</Transition.Child>
<div className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<div className="h-min w-full shrink-0 border-b border-zinc-800 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title
as="h3"
className="text-lg font-semibold leading-none text-zinc-100"
>
Create image block
</Dialog.Title>
<button
type="button"
onClick={closeModal}
className="inline-flex h-5 w-5 items-center justify-center rounded hover:bg-zinc-900"
>
<CancelIcon width={14} height={14} className="text-zinc-300" />
</button>
</div>
<Dialog.Description className="text-sm leading-tight text-zinc-400">
Pin your favorite image to Space then you can view every time that
you use Lume, your image will be broadcast to Nostr Relay as well
</Dialog.Description>
</div>
</div>
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
<form
onSubmit={handleSubmit(onSubmit)}
className="mb-0 flex h-full w-full flex-col gap-4"
>
<input
type={'hidden'}
{...register('content')}
value={image}
className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
<div className="flex flex-col gap-1">
<label
htmlFor="title"
className="text-sm font-medium uppercase tracking-wider text-zinc-400"
>
Title *
</label>
<div className="after:shadow-highlight relative w-full shrink-0 overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[6px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[6px] after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20">
<input
type={'text'}
{...register('title', {
required: true,
})}
spellCheck={false}
className="shadow-input relative h-10 w-full rounded-md border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
</div>
</div>
<div className="flex flex-col gap-1">
<label
htmlFor="picture"
className="text-sm font-medium uppercase tracking-wider text-zinc-400"
>
Picture
</label>
<div className="relative inline-flex h-56 w-full items-center justify-center overflow-hidden rounded-lg border border-zinc-900 bg-zinc-950">
<Image
src={image}
fallback={DEFAULT_AVATAR}
alt="content"
className="relative z-10 h-auto max-h-[156px] w-[150px] rounded-md object-cover"
/>
<div className="absolute bottom-3 right-3 z-10">
<button
onClick={() => uploadImage()}
type="button"
className="inline-flex h-6 items-center justify-center rounded bg-zinc-900 px-3 text-sm font-medium text-zinc-300 ring-1 ring-zinc-800 hover:bg-zinc-800"
>
Upload
</button>
</div>
</div>
</div>
<div>
<button
type="submit"
disabled={!isDirty || !isValid}
className="shadow-button inline-flex h-11 w-full transform items-center justify-center rounded-lg bg-fuchsia-500 font-medium text-zinc-100 active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
{loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
) : (
'Confirm'
)}
</button>
</div>
</form>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
);
}

View File

@ -121,15 +121,15 @@ export function FeedBlock({ params }: { params: Block }) {
<div className="h-full"> <div className="h-full">
{status === 'loading' ? ( {status === 'loading' ? (
<div className="px-3 py-1.5"> <div className="px-3 py-1.5">
<div className="rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-3"> <div className="rounded-xl bg-white/10 px-3 py-3">
<NoteSkeleton /> <NoteSkeleton />
</div> </div>
</div> </div>
) : itemsVirtualizer.length === 0 ? ( ) : itemsVirtualizer.length === 0 ? (
<div className="px-3 py-1.5"> <div className="px-3 py-1.5">
<div className="rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-6"> <div className="bbg-white/10 rounded-xl px-3 py-6">
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
<p className="text-center text-sm text-zinc-300"> <p className="text-center text-sm text-white">
Not found any posts from last 48 hours Not found any posts from last 48 hours
</p> </p>
</div> </div>

View File

@ -133,15 +133,15 @@ export function FollowingBlock() {
<div className="h-full"> <div className="h-full">
{status === 'loading' ? ( {status === 'loading' ? (
<div className="px-3 py-1.5"> <div className="px-3 py-1.5">
<div className="rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-3"> <div className="rounded-xl bg-white/10 px-3 py-3">
<NoteSkeleton /> <NoteSkeleton />
</div> </div>
</div> </div>
) : itemsVirtualizer.length === 0 ? ( ) : itemsVirtualizer.length === 0 ? (
<div className="px-3 py-1.5"> <div className="px-3 py-1.5">
<div className="rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-6"> <div className="rounded-xl bg-white/10 px-3 py-6">
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
<p className="text-center text-sm text-zinc-300"> <p className="text-center text-sm text-white">
You not have any posts to see yet You not have any posts to see yet
<br /> <br />
Follow more people to have more fun. Follow more people to have more fun.

View File

@ -39,15 +39,15 @@ export function HashtagBlock({ params }: { params: Block }) {
<div className="h-full"> <div className="h-full">
{status === 'loading' ? ( {status === 'loading' ? (
<div className="px-3 py-1.5"> <div className="px-3 py-1.5">
<div className="rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 pt-3"> <div className="rounded-xl bg-white/10 px-3 pt-3">
<NoteSkeleton /> <NoteSkeleton />
</div> </div>
</div> </div>
) : itemsVirtualizer.length === 0 ? ( ) : itemsVirtualizer.length === 0 ? (
<div className="px-3 py-1.5"> <div className="px-3 py-1.5">
<div className="rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-6"> <div className="rounded-xl bg-white/10 px-3 py-6">
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
<p className="text-center text-sm text-zinc-300"> <p className="text-center text-sm text-white">
No new posts about this hashtag in 48 hours ago No new posts about this hashtag in 48 hours ago
</p> </p>
</div> </div>

View File

@ -0,0 +1,212 @@
import { Combobox } from '@headlessui/react';
import * as Dialog from '@radix-ui/react-dialog';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { nip19 } from 'nostr-tools';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook';
import { User } from '@app/auth/components/user';
import { createBlock } from '@libs/storage';
import { CancelIcon, CheckCircleIcon, CommandIcon, LoaderIcon } from '@shared/icons';
import { BLOCK_KINDS, DEFAULT_AVATAR } from '@stores/constants';
import { ADD_FEEDBLOCK_SHORTCUT } from '@stores/shortcuts';
import { useAccount } from '@utils/hooks/useAccount';
export function FeedModal() {
const queryClient = useQueryClient();
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [selected, setSelected] = useState([]);
const [query, setQuery] = useState('');
const { status, account } = useAccount();
useHotkeys(ADD_FEEDBLOCK_SHORTCUT, () => setOpen(true));
const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] });
},
});
const {
register,
handleSubmit,
reset,
formState: { isDirty, isValid },
} = useForm();
const onSubmit = (data: { kind: number; title: string; content: string }) => {
setLoading(true);
selected.forEach((item, index) => {
if (item.substring(0, 4) === 'npub') {
selected[index] = nip19.decode(item).data;
}
});
// insert to database
block.mutate({
kind: BLOCK_KINDS.feed,
title: data.title,
content: JSON.stringify(selected),
});
setLoading(false);
// reset form
reset();
// close modal
setOpen(false);
};
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger asChild>
<button
type="button"
className="inline-flex h-9 w-72 items-center justify-start gap-2.5 rounded-md px-2.5"
>
<div className="flex items-center gap-2">
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<CommandIcon className="h-3 w-3 text-white" />
</div>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<span className="text-sm leading-none text-white">F</span>
</div>
</div>
<h5 className="font-medium text-white/50">New feed block</h5>
</button>
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10">
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title className="text-lg font-semibold leading-none text-white">
Create feed block
</Dialog.Title>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" />
</Dialog.Close>
</div>
<Dialog.Description className="text-sm leading-tight text-white/50">
Specific newsfeed space for people you want to keep up to date
</Dialog.Description>
</div>
</div>
<div className="flex flex-col overflow-y-auto overflow-x-hidden px-5 pb-5 pt-2">
<form
onSubmit={handleSubmit(onSubmit)}
className="mb-0 flex h-full w-full flex-col gap-4"
>
<div className="flex flex-col gap-1">
<label
htmlFor="title"
className="text-sm font-medium uppercase tracking-wider text-white/50"
>
Title *
</label>
<input
type={'text'}
{...register('title', {
required: true,
})}
spellCheck={false}
className="relative h-11 w-full rounded-lg bg-white/10 px-3 py-2 text-white !outline-none placeholder:text-white/50"
/>
</div>
<div className="flex flex-col gap-1">
<span className="text-sm font-medium uppercase tracking-wider text-white/50">
Choose at least 1 user *
</span>
<div className="flex h-[300px] w-full flex-col overflow-y-auto overflow-x-hidden rounded-lg bg-white/10">
<div className="w-full px-3 py-2">
<Combobox value={selected} onChange={setSelected} multiple>
<Combobox.Input
onChange={(event) => setQuery(event.target.value)}
spellCheck={false}
placeholder="Enter pubkey or npub..."
className="relative mb-2 h-10 w-full rounded-md bg-white/10 px-3 py-2 text-white !outline-none placeholder:text-white/50"
/>
<Combobox.Options static>
{query.length > 0 && (
<Combobox.Option
value={query}
className="group flex w-full items-center justify-between rounded-md px-2 py-2 hover:bg-white/10"
>
{({ selected }) => (
<>
<div className="flex items-center gap-2">
<img
alt={query}
src={DEFAULT_AVATAR}
className="h-11 w-11 shrink-0 rounded object-cover"
/>
<div className="inline-flex flex-col gap-1">
<span className="text-base leading-tight text-white/50">
{query}
</span>
</div>
</div>
{selected && (
<CheckCircleIcon className="h-4 w-4 text-green-500" />
)}
</>
)}
</Combobox.Option>
)}
{status === 'loading' ? (
<p>Loading...</p>
) : (
JSON.parse(account.follows as string).map((follow) => (
<Combobox.Option
key={follow}
value={follow}
className="group flex w-full items-center justify-between rounded-md px-2 py-2 hover:bg-white/10"
>
{({ selected }) => (
<>
<User pubkey={follow} />
{selected && (
<CheckCircleIcon className="h-4 w-4 text-green-500" />
)}
</>
)}
</Combobox.Option>
))
)}
</Combobox.Options>
</Combobox>
</div>
</div>
</div>
<button
type="submit"
disabled={!isDirty || !isValid}
className="shadow-button inline-flex h-11 w-full transform items-center justify-center rounded-lg bg-fuchsia-500 font-medium text-white active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
{loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : (
'Confirm'
)}
</button>
</form>
</div>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}

View File

@ -0,0 +1,132 @@
import * as Dialog from '@radix-ui/react-dialog';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook';
import { createBlock } from '@libs/storage';
import { CancelIcon, CommandIcon, LoaderIcon } from '@shared/icons';
import { BLOCK_KINDS } from '@stores/constants';
import { ADD_HASHTAGBLOCK_SHORTCUT } from '@stores/shortcuts';
export function HashtagModal() {
const queryClient = useQueryClient();
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
useHotkeys(ADD_HASHTAGBLOCK_SHORTCUT, () => setOpen(false));
const {
register,
handleSubmit,
reset,
formState: { isDirty, isValid },
} = useForm();
const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] });
},
});
const onSubmit = async (data: { hashtag: string }) => {
setLoading(true);
// mutate
block.mutate({
kind: BLOCK_KINDS.hashtag,
title: data.hashtag,
content: data.hashtag.replace('#', ''),
});
setLoading(false);
// reset form
reset();
// close modal
setOpen(false);
};
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger asChild>
<button
type="button"
className="inline-flex h-9 w-72 items-center justify-start gap-2.5 rounded-md px-2.5"
>
<div className="flex items-center gap-2">
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<CommandIcon className="h-3 w-3 text-white" />
</div>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<span className="text-sm leading-none text-white">T</span>
</div>
</div>
<h5 className="font-medium text-white/50">New hashtag block</h5>
</button>
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10">
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title className="text-lg font-semibold leading-none text-white">
Create hashtag block
</Dialog.Title>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" />
</Dialog.Close>
</div>
<Dialog.Description className="text-sm leading-tight text-white/50">
Pin the hashtag you want to keep follow up
</Dialog.Description>
</div>
</div>
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
<form
onSubmit={handleSubmit(onSubmit)}
className="mb-0 flex h-full w-full flex-col gap-3"
>
<div className="flex flex-col gap-1">
<label
htmlFor="title"
className="text-sm font-medium uppercase tracking-wider text-white/50"
>
Hashtag *
</label>
<input
type={'text'}
{...register('hashtag', {
required: true,
})}
spellCheck={false}
placeholder="#"
className="relative h-11 w-full rounded-lg bg-white/10 px-3 py-2 text-white !outline-none placeholder:text-white/50"
/>
</div>
<button
type="submit"
disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full transform items-center justify-center rounded-lg bg-fuchsia-500 font-medium text-white active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
{loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-white" />
) : (
'Confirm'
)}
</button>
</form>
</div>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}

View File

@ -0,0 +1,184 @@
import * as Dialog from '@radix-ui/react-dialog';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook';
import { createBlock } from '@libs/storage';
import { CancelIcon, CommandIcon, LoaderIcon } from '@shared/icons';
import { Image } from '@shared/image';
import { BLOCK_KINDS, DEFAULT_AVATAR } from '@stores/constants';
import { ADD_IMAGEBLOCK_SHORTCUT } from '@stores/shortcuts';
import { usePublish } from '@utils/hooks/usePublish';
import { useImageUploader } from '@utils/hooks/useUploader';
export function ImageModal() {
const queryClient = useQueryClient();
const upload = useImageUploader();
const { publish } = usePublish();
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [image, setImage] = useState('');
const tags = useRef(null);
useHotkeys(ADD_IMAGEBLOCK_SHORTCUT, () => setOpen(false));
const {
register,
handleSubmit,
reset,
setValue,
formState: { isDirty, isValid },
} = useForm();
const block = useMutation({
mutationFn: (data: { kind: number; title: string; content: string }) => {
return createBlock(data.kind, data.title, data.content);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['blocks'] });
},
});
const uploadImage = async () => {
const image = await upload(null);
if (image.url) {
setImage(image.url);
}
};
const onSubmit = async (data: { kind: number; title: string; content: string }) => {
setLoading(true);
// publish file metedata
await publish({ content: data.title, kind: 1063, tags: tags.current });
// mutate
block.mutate({ kind: BLOCK_KINDS.image, title: data.title, content: data.content });
setLoading(false);
// reset form
reset();
// close modal
setOpen(false);
};
useEffect(() => {
setValue('content', image);
}, [setValue, image]);
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger asChild>
<button
type="button"
className="inline-flex h-9 w-72 items-center justify-start gap-2.5 rounded-md px-2.5"
>
<div className="flex items-center gap-2">
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<CommandIcon width={12} height={12} className="text-white" />
</div>
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded bg-white/10">
<span className="text-sm leading-none text-white">I</span>
</div>
</div>
<h5 className="font-medium text-white/50">New image block</h5>
</button>
</Dialog.Trigger>
<Dialog.Portal className="relative z-10">
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl" />
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
<div className="relative h-min w-full max-w-xl rounded-xl bg-white/10">
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Dialog.Title className="text-lg font-semibold leading-none text-white">
Create image block
</Dialog.Title>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" />
</Dialog.Close>
</div>
<Dialog.Description className="text-sm leading-tight text-white/50">
Pin your favorite image to Space then you can view every time that you
use Lume, your image will be broadcast to Nostr Relay as well
</Dialog.Description>
</div>
</div>
<div className="flex h-full w-full flex-col overflow-y-auto px-5 pb-5 pt-3">
<form
onSubmit={handleSubmit(onSubmit)}
className="mb-0 flex h-full w-full flex-col gap-3"
>
<input
type={'hidden'}
{...register('content')}
value={image}
className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-white/50 dark:bg-zinc-800 dark:text-white dark:shadow-black/10 dark:placeholder:text-zinc-500"
/>
<div className="flex flex-col gap-1">
<label
htmlFor="title"
className="text-sm font-medium uppercase tracking-wider text-white/50"
>
Title *
</label>
<input
type={'text'}
{...register('title', {
required: true,
})}
spellCheck={false}
className="relative h-11 w-full rounded-lg bg-white/10 px-3 py-2 text-white !outline-none placeholder:text-white/50"
/>
</div>
<div className="flex flex-col gap-1">
<label
htmlFor="picture"
className="text-sm font-medium uppercase tracking-wider text-white/50"
>
Picture
</label>
<div className="relative inline-flex h-56 w-full items-center justify-center overflow-hidden rounded-lg border border-zinc-900 bg-zinc-950">
<Image
src={image}
fallback={DEFAULT_AVATAR}
alt="content"
className="relative z-10 h-auto max-h-[156px] w-[150px] rounded-md object-cover"
/>
<div className="absolute bottom-3 right-3 z-10">
<button
onClick={() => uploadImage()}
type="button"
className="inline-flex h-6 items-center justify-center rounded bg-zinc-900 px-3 text-sm font-medium text-zinc-300 ring-1 ring-zinc-800 hover:bg-zinc-800"
>
Upload
</button>
</div>
</div>
</div>
<button
type="submit"
disabled={!isDirty || !isValid}
className="inline-flex h-11 w-full transform items-center justify-center rounded-lg bg-fuchsia-500 font-medium text-white active:translate-y-1 disabled:cursor-not-allowed disabled:opacity-30"
>
{loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-white" />
) : (
'Confirm'
)}
</button>
</form>
</div>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}

View File

@ -1,13 +1,15 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { AddBlock } from '@app/space/components/add';
import { FeedBlock } from '@app/space/components/blocks/feed'; import { FeedBlock } from '@app/space/components/blocks/feed';
import { FollowingBlock } from '@app/space/components/blocks/following'; import { FollowingBlock } from '@app/space/components/blocks/following';
import { HashtagBlock } from '@app/space/components/blocks/hashtag'; import { HashtagBlock } from '@app/space/components/blocks/hashtag';
import { ImageBlock } from '@app/space/components/blocks/image'; import { ImageBlock } from '@app/space/components/blocks/image';
import { ThreadBlock } from '@app/space/components/blocks/thread'; import { ThreadBlock } from '@app/space/components/blocks/thread';
import { UserBlock } from '@app/space/components/blocks/user'; import { UserBlock } from '@app/space/components/blocks/user';
import { FeedModal } from '@app/space/components/modals/feed';
import { HashtagModal } from '@app/space/components/modals/hashtag';
import { ImageModal } from '@app/space/components/modals/image';
import { getBlocks } from '@libs/storage'; import { getBlocks } from '@libs/storage';
@ -76,13 +78,15 @@ export function SpaceScreen() {
className="group flex h-11 w-full items-center justify-between overflow-hidden px-3" className="group flex h-11 w-full items-center justify-between overflow-hidden px-3"
/> />
<div className="flex w-full flex-1 items-center justify-center p-3"> <div className="flex w-full flex-1 items-center justify-center p-3">
<LoaderIcon className="h-5 w-5 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-5 w-5 animate-spin text-white" />
</div> </div>
</div> </div>
)} )}
<div className="flex w-[350px] shrink-0 flex-col"> <div className="flex w-[350px] shrink-0 flex-col">
<div className="inline-flex h-full w-full items-center justify-center"> <div className="inline-flex h-full w-full flex-col items-center justify-center gap-1">
<AddBlock /> <FeedModal />
<ImageModal />
<HashtagModal />
</div> </div>
</div> </div>
<div className="w-[250px] shrink-0" /> <div className="w-[250px] shrink-0" />

View File

@ -113,7 +113,7 @@ export function UserProfile({ pubkey }: { pubkey: string }) {
</div> </div>
</div> </div>
<div className="flex flex-col gap-8"> <div className="flex flex-col gap-8">
<p className="mt-2 max-w-[500px] select-text break-words text-zinc-100"> <p className="mt-2 max-w-[500px] select-text break-words text-white">
{user?.about || user?.bio} {user?.about || user?.bio}
</p> </p>
<UserMetadata pubkey={pubkey} /> <UserMetadata pubkey={pubkey} />

View File

@ -26,9 +26,9 @@ export function AvatarUploader({ setPicture }: { setPicture: any }) {
className="inline-flex h-full w-full items-center justify-center bg-zinc-900/40" className="inline-flex h-full w-full items-center justify-center bg-zinc-900/40"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-6 w-6 animate-spin text-zinc-100" /> <LoaderIcon className="h-6 w-6 animate-spin text-white" />
) : ( ) : (
<PlusIcon className="h-6 w-6 text-zinc-100" /> <PlusIcon className="h-6 w-6 text-white" />
)} )}
</button> </button>
); );

View File

@ -26,9 +26,9 @@ export function BannerUploader({ setBanner }: { setBanner: any }) {
className="inline-flex h-full w-full items-center justify-center bg-zinc-900/40" className="inline-flex h-full w-full items-center justify-center bg-zinc-900/40"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-8 w-8 animate-spin text-zinc-100" /> <LoaderIcon className="h-8 w-8 animate-spin text-white" />
) : ( ) : (
<PlusIcon className="h-8 w-8 text-zinc-100" /> <PlusIcon className="h-8 w-8 text-white" />
)} )}
</button> </button>
); );

View File

@ -20,15 +20,15 @@ export function Button({
break; break;
case 'publish': case 'publish':
preClass = preClass =
'w-min h-9 px-4 bg-fuchsia-500 rounded-md text-sm font-medium text-zinc-100 hover:bg-fuchsia-600'; 'w-min h-9 px-4 bg-fuchsia-500 rounded-md text-sm font-medium text-white hover:bg-fuchsia-600';
break; break;
case 'large': case 'large':
preClass = preClass =
'h-11 w-full bg-fuchsia-500 rounded-md font-medium text-zinc-100 hover:bg-fuchsia-600'; 'h-11 w-full bg-fuchsia-500 rounded-md font-medium text-white hover:bg-fuchsia-600';
break; break;
case 'large-alt': case 'large-alt':
preClass = preClass =
'h-11 w-full bg-zinc-800 rounded-md font-medium text-zinc-300 border-t border-zinc-700/50 hover:bg-zinc-900'; 'h-11 w-full bg-zinc-800 rounded-md font-medium text-white border-t border-zinc-700/50 hover:bg-zinc-900';
break; break;
default: default:
break; break;

View File

@ -17,12 +17,12 @@ export function MentionItem({ profile }: { profile: Profile }) {
/> />
</div> </div>
<div className="flex flex-col gap-px"> <div className="flex flex-col gap-px">
<h5 className="max-w-[15rem] text-sm font-medium leading-none text-zinc-100"> <h5 className="max-w-[15rem] text-sm font-medium leading-none text-white">
{profile.ident || ( {profile.ident || (
<div className="h-3 w-20 animate-pulse rounded-sm bg-zinc-700" /> <div className="h-3 w-20 animate-pulse rounded-sm bg-zinc-700" />
)} )}
</h5> </h5>
<span className="text-sm leading-none text-zinc-400"> <span className="text-sm leading-none text-white/50">
{displayNpub(profile.pubkey, 16)} {displayNpub(profile.pubkey, 16)}
</span> </span>
</div> </div>

View File

@ -178,7 +178,7 @@ export function EditProfileModal() {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Dialog.Title <Dialog.Title
as="h3" as="h3"
className="text-lg font-semibold leading-none text-zinc-100" className="text-lg font-semibold leading-none text-white"
> >
Edit profile Edit profile
</Dialog.Title> </Dialog.Title>
@ -197,13 +197,13 @@ export function EditProfileModal() {
type={'hidden'} type={'hidden'}
{...register('picture')} {...register('picture')}
value={picture} value={picture}
className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500" className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-white/50 dark:bg-zinc-800 dark:text-white dark:shadow-black/10 dark:placeholder:text-zinc-500"
/> />
<input <input
type={'hidden'} type={'hidden'}
{...register('banner')} {...register('banner')}
value={banner} value={banner}
className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500" className="shadow-input relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-black/5 !outline-none placeholder:text-white/50 dark:bg-zinc-800 dark:text-white dark:shadow-black/10 dark:placeholder:text-zinc-500"
/> />
<div className="relative"> <div className="relative">
<div className="relative h-44 w-full bg-zinc-800"> <div className="relative h-44 w-full bg-zinc-800">
@ -235,7 +235,7 @@ export function EditProfileModal() {
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="name" htmlFor="name"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Name Name
</label> </label>
@ -246,13 +246,13 @@ export function EditProfileModal() {
minLength: 4, minLength: 4,
})} })}
spellCheck={false} spellCheck={false}
className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="nip05" htmlFor="nip05"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Lume ID / NIP-05 Lume ID / NIP-05
</label> </label>
@ -263,7 +263,7 @@ export function EditProfileModal() {
minLength: 4, minLength: 4,
})} })}
spellCheck={false} spellCheck={false}
className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
<div className="absolute right-2 top-1/2 -translate-y-1/2 transform"> <div className="absolute right-2 top-1/2 -translate-y-1/2 transform">
{nip05.verified ? ( {nip05.verified ? (
@ -288,20 +288,20 @@ export function EditProfileModal() {
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="about" htmlFor="about"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Bio Bio
</label> </label>
<textarea <textarea
{...register('about')} {...register('about')}
spellCheck={false} spellCheck={false}
className="relative h-20 w-full resize-none rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-20 w-full resize-none rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="website" htmlFor="website"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Website Website
</label> </label>
@ -309,13 +309,13 @@ export function EditProfileModal() {
type={'text'} type={'text'}
{...register('website', { required: false })} {...register('website', { required: false })}
spellCheck={false} spellCheck={false}
className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label <label
htmlFor="website" htmlFor="website"
className="text-sm font-semibold uppercase tracking-wider text-zinc-400" className="text-sm font-semibold uppercase tracking-wider text-white/50"
> >
Lightning address Lightning address
</label> </label>
@ -323,17 +323,17 @@ export function EditProfileModal() {
type={'text'} type={'text'}
{...register('lud16', { required: false })} {...register('lud16', { required: false })}
spellCheck={false} spellCheck={false}
className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-zinc-100 !outline-none placeholder:text-zinc-500" className="relative h-10 w-full rounded-lg bg-zinc-800 px-3 py-2 text-white !outline-none placeholder:text-zinc-500"
/> />
</div> </div>
<div> <div>
<button <button
type="submit" type="submit"
disabled={!isValid} disabled={!isValid}
className="inline-flex h-11 w-full transform items-center justify-center gap-1 rounded-md bg-fuchsia-500 font-medium text-zinc-100 hover:bg-fuchsia-600 focus:outline-none active:translate-y-1 disabled:pointer-events-none disabled:opacity-50" className="inline-flex h-11 w-full transform items-center justify-center gap-1 rounded-md bg-fuchsia-500 font-medium text-white hover:bg-fuchsia-600 focus:outline-none active:translate-y-1 disabled:pointer-events-none disabled:opacity-50"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
'Update' 'Update'
)} )}

View File

@ -29,19 +29,19 @@ export function MediaUploader({ setState }: { setState: any }) {
className="group inline-flex h-6 w-6 items-center justify-center rounded bg-zinc-700 hover:bg-zinc-600" className="group inline-flex h-6 w-6 items-center justify-center rounded bg-zinc-700 hover:bg-zinc-600"
> >
{loading ? ( {loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
) : ( ) : (
<MediaIcon <MediaIcon
width={14} width={14}
height={14} height={14}
className="text-zinc-400 group-hover:text-zinc-200" className="text-white/50 group-hover:text-zinc-200"
/> />
)} )}
</button> </button>
</Tooltip.Trigger> </Tooltip.Trigger>
<Tooltip.Portal> <Tooltip.Portal>
<Tooltip.Content <Tooltip.Content
className="-left-10 select-none rounded-md bg-zinc-800/80 px-3.5 py-1.5 text-sm leading-none text-zinc-100 backdrop-blur-lg will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade" className="-left-10 select-none rounded-md bg-zinc-800/80 px-3.5 py-1.5 text-sm leading-none text-white backdrop-blur-lg will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade"
sideOffset={5} sideOffset={5}
> >
Upload media Upload media

View File

@ -43,10 +43,10 @@ export function NoteZap({ id }: { id: string }) {
<Dialog.Content className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border-t border-zinc-800/50 bg-zinc-900"> <Dialog.Content className="relative flex h-min w-full max-w-lg flex-col gap-2 rounded-lg border-t border-zinc-800/50 bg-zinc-900">
<div className="relative h-min w-full shrink-0 border-b border-zinc-800 px-5 py-3"> <div className="relative h-min w-full shrink-0 border-b border-zinc-800 px-5 py-3">
<div className="flex flex-col items-center gap-1.5"> <div className="flex flex-col items-center gap-1.5">
<Dialog.Title className="font-medium leading-none text-zinc-100"> <Dialog.Title className="font-medium leading-none text-white">
Zap (Beta) Zap (Beta)
</Dialog.Title> </Dialog.Title>
<Dialog.Description className="text-sm leading-none text-zinc-400"> <Dialog.Description className="text-sm leading-none text-white/50">
Send tip with Bitcoin via Lightning Send tip with Bitcoin via Lightning
</Dialog.Description> </Dialog.Description>
</div> </div>
@ -178,10 +178,10 @@ export function NoteZap({ id }: { id: string }) {
<QRCodeSVG value={invoice} size={256} /> <QRCodeSVG value={invoice} size={256} />
</div> </div>
<div className="flex flex-col items-center gap-1"> <div className="flex flex-col items-center gap-1">
<h3 className="text-lg font-medium leading-none text-zinc-100"> <h3 className="text-lg font-medium leading-none text-white">
Scan to pay Scan to pay
</h3> </h3>
<span className="text-center text-sm text-zinc-400"> <span className="text-center text-sm text-white/50">
You must use Bitcoin wallet which support Lightning You must use Bitcoin wallet which support Lightning
<br /> <br />
such as: Blue Wallet, Bitkit, Phoenix,... such as: Blue Wallet, Bitkit, Phoenix,...

View File

@ -26,7 +26,7 @@ export function Repost({ event }: { event: LumeEvent }) {
if (status === 'error') { if (status === 'error') {
return ( return (
<div className="flex items-center justify-center overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-3"> <div className="flex items-center justify-center overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-3">
<p className="text-zinc-400">Failed to fetch</p> <p className="text-white/50">Failed to fetch</p>
</div> </div>
); );
} }

View File

@ -17,7 +17,7 @@ export function SubNote({ id, root }: { id: string; root?: string }) {
if (status === 'error') { if (status === 'error') {
return ( return (
<div className="mb-5 flex overflow-hidden rounded-xl bg-zinc-800 px-3 py-3"> <div className="mb-5 flex overflow-hidden rounded-xl bg-zinc-800 px-3 py-3">
<p className="text-zinc-400">Failed to fetch</p> <p className="text-white/50">Failed to fetch</p>
</div> </div>
); );
} }

View File

@ -21,7 +21,7 @@ export function NoteKindUnsupport({ event }: { event: LumeEvent }) {
Lume isn&apos;t fully support this kind Lume isn&apos;t fully support this kind
</p> </p>
</div> </div>
<div className="select-text whitespace-pre-line break-all text-zinc-100"> <div className="select-text whitespace-pre-line break-all text-white">
<p>{event.content.toString()}</p> <p>{event.content.toString()}</p>
</div> </div>
</div> </div>

View File

@ -69,7 +69,7 @@ export function NoteMetadata({ id }: { id: string }) {
<div className="mb-3 flex items-center gap-3"> <div className="mb-3 flex items-center gap-3">
<div className="mt-2h-6 w-11 shrink-0"></div> <div className="mt-2h-6 w-11 shrink-0"></div>
<div className="mt-2 inline-flex h-6 items-center"> <div className="mt-2 inline-flex h-6 items-center">
<LoaderIcon className="h-4 w-4 animate-spin text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-white" />
</div> </div>
</div> </div>
); );

View File

@ -62,7 +62,7 @@ export function RepliesList({ id }: { id: string }) {
<div className="flex w-full items-center justify-center rounded-xl bg-white/10"> <div className="flex w-full items-center justify-center rounded-xl bg-white/10">
<div className="flex flex-col items-center justify-center gap-2 py-6"> <div className="flex flex-col items-center justify-center gap-2 py-6">
<h3 className="text-3xl">👋</h3> <h3 className="text-3xl">👋</h3>
<p className="leading-none text-zinc-400">Share your thought on it...</p> <p className="leading-none text-white/50">Share your thought on it...</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -54,7 +54,7 @@ export function NoteStats({ id }: { id: string }) {
if (status === 'loading') { if (status === 'loading') {
return ( return (
<div className="flex h-11 items-center"> <div className="flex h-11 items-center">
<LoaderIcon className="h-4 w-4 animate-spin text-zinc-100" /> <LoaderIcon className="h-4 w-4 animate-spin text-white" />
</div> </div>
); );
} }

View File

@ -21,13 +21,13 @@ export function RepostUser({ pubkey }: { pubkey: string }) {
className="relative z-20 inline-block h-6 w-6 rounded bg-white ring-1 ring-zinc-800" className="relative z-20 inline-block h-6 w-6 rounded bg-white ring-1 ring-zinc-800"
/> />
<div className="inline-flex items-baseline gap-1"> <div className="inline-flex items-baseline gap-1">
<h5 className="max-w-[18rem] truncate text-zinc-400"> <h5 className="max-w-[18rem] truncate text-white/50">
{user?.nip05?.toLowerCase() || {user?.nip05?.toLowerCase() ||
user?.name || user?.name ||
user?.display_name || user?.display_name ||
shortenKey(pubkey)} shortenKey(pubkey)}
</h5> </h5>
<span className="text-zinc-400">reposted</span> <span className="text-white/50">reposted</span>
</div> </div>
</div> </div>
); );

View File

@ -63,7 +63,7 @@ export function NotificationModal({ pubkey }: { pubkey: string }) {
<div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5"> <div className="h-min w-full shrink-0 border-b border-white/10 bg-white/5 px-5 py-5">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Dialog.Title className="text-lg font-semibold leading-none text-zinc-100"> <Dialog.Title className="text-lg font-semibold leading-none text-white">
Notification Notification
</Dialog.Title> </Dialog.Title>
<Dialog.Close asChild> <Dialog.Close asChild>
@ -75,7 +75,7 @@ export function NotificationModal({ pubkey }: { pubkey: string }) {
</button> </button>
</Dialog.Close> </Dialog.Close>
</div> </div>
<Dialog.Description className="text-sm leading-tight text-zinc-400"> <Dialog.Description className="text-sm leading-tight text-white/50">
All things happen when you rest in 24 hours ago All things happen when you rest in 24 hours ago
</Dialog.Description> </Dialog.Description>
</div> </div>
@ -83,7 +83,7 @@ export function NotificationModal({ pubkey }: { pubkey: string }) {
<div className="scrollbar-hide flex h-[500px] flex-col overflow-y-auto overflow-x-hidden pb-5"> <div className="scrollbar-hide flex h-[500px] flex-col overflow-y-auto overflow-x-hidden pb-5">
{status === 'loading' ? ( {status === 'loading' ? (
<div className="inline-flex items-center justify-center px-4 py-3"> <div className="inline-flex items-center justify-center px-4 py-3">
<LoaderIcon className="h-5 w-5 animate-spin text-black dark:text-zinc-100" /> <LoaderIcon className="h-5 w-5 animate-spin text-black dark:text-white" />
</div> </div>
) : data.length < 1 ? ( ) : data.length < 1 ? (
<div className="flex h-full w-full flex-col items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">

View File

@ -17,7 +17,7 @@ export function NotiMention({ event }: { event: NDKEvent }) {
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="flex items-start gap-1"> <div className="flex items-start gap-1">
<NotiUser pubkey={event.pubkey} /> <NotiUser pubkey={event.pubkey} />
<p className="leading-none text-zinc-400">reply your post</p> <p className="leading-none text-white/50">reply your post</p>
</div> </div>
<div> <div>
<span className="leading-none text-zinc-500">{createdAt}</span> <span className="leading-none text-zinc-500">{createdAt}</span>

View File

@ -14,7 +14,7 @@ export function NotiReaction({ event }: { event: NDKEvent }) {
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="flex items-start gap-1"> <div className="flex items-start gap-1">
<NotiUser pubkey={event.pubkey} /> <NotiUser pubkey={event.pubkey} />
<p className="leading-none text-zinc-400">reacted {event.content}</p> <p className="leading-none text-white/50">reacted {event.content}</p>
</div> </div>
<div> <div>
<span className="leading-none text-zinc-500">{createdAt}</span> <span className="leading-none text-zinc-500">{createdAt}</span>

View File

@ -14,7 +14,7 @@ export function NotiRepost({ event }: { event: NDKEvent }) {
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="flex items-start gap-1"> <div className="flex items-start gap-1">
<NotiUser pubkey={event.pubkey} /> <NotiUser pubkey={event.pubkey} />
<p className="leading-none text-zinc-400">repost your post</p> <p className="leading-none text-white/50">repost your post</p>
</div> </div>
<div> <div>
<span className="leading-none text-zinc-500">{createdAt}</span> <span className="leading-none text-zinc-500">{createdAt}</span>

View File

@ -14,7 +14,7 @@ export function Protected({ children }: { children: ReactNode }) {
if (status === 'loading') { if (status === 'loading') {
return ( return (
<div className="flex h-full w-full items-center justify-center bg-black/90"> <div className="flex h-full w-full items-center justify-center bg-black/90">
<LoaderIcon className="h-6 w-6 animate-spin text-zinc-100" /> <LoaderIcon className="h-6 w-6 animate-spin text-white" />
</div> </div>
); );
} }

View File

@ -75,10 +75,7 @@ export function User({
</button> </button>
</Popover.Trigger> </Popover.Trigger>
<div <div
className={twMerge( className={twMerge('flex flex-1 items-baseline gap-2', isRepost ? 'mt-4' : '')}
'flex flex-1 items-baseline justify-between',
isRepost ? 'mt-4' : ''
)}
> >
<h5 <h5
className={twMerge( className={twMerge(
@ -91,6 +88,7 @@ export function User({
user?.display_name || user?.display_name ||
shortenKey(pubkey)} shortenKey(pubkey)}
</h5> </h5>
<span className="leading-none text-white/50">·</span>
<span className="leading-none text-white/50">{createdAt}</span> <span className="leading-none text-white/50">{createdAt}</span>
</div> </div>
</div> </div>

View File

@ -2,7 +2,7 @@ import { NDKFilter } from '@nostr-dev-kit/ndk';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useNDK } from '@libs/ndk/provider'; import { useNDK } from '@libs/ndk/provider';
import { createMetadata, getUserMetadata } from '@libs/storage'; import { createMetadata } from '@libs/storage';
export function useProfile(pubkey: string, fallback?: string) { export function useProfile(pubkey: string, fallback?: string) {
const { ndk } = useNDK(); const { ndk } = useNDK();
@ -15,20 +15,14 @@ export function useProfile(pubkey: string, fallback?: string) {
['user', pubkey], ['user', pubkey],
async () => { async () => {
if (!fallback) { if (!fallback) {
const current = Math.floor(Date.now() / 1000); const filter: NDKFilter = { kinds: [0], authors: [pubkey] };
const cache = await getUserMetadata(pubkey); const events = await ndk.fetchEvents(filter);
if (cache && parseInt(cache.created_at) + 86400 >= current) { const latest = [...events].sort((a, b) => b.created_at - a.created_at).pop();
return JSON.parse(cache.content); if (latest) {
await createMetadata(latest.id, latest.pubkey, latest.content);
return JSON.parse(latest.content);
} else { } else {
const filter: NDKFilter = { kinds: [0], authors: [pubkey] }; throw new Error('User not found');
const events = await ndk.fetchEvents(filter);
const latest = [...events].sort((a, b) => b.created_at - a.created_at).pop();
if (latest) {
await createMetadata(latest.id, latest.pubkey, latest.content);
return JSON.parse(latest.content);
} else {
throw new Error('User not found');
}
} }
} else { } else {
const profile = JSON.parse(fallback); const profile = JSON.parse(fallback);