mirror of
https://github.com/luminous-devs/lume.git
synced 2024-08-31 02:20:50 +00:00
polish
This commit is contained in:
parent
babcd8698e
commit
ae1e84655a
12
package.json
12
package.json
@ -18,14 +18,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@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",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
"@radix-ui/react-popover": "^1.0.6",
|
||||
"@radix-ui/react-tooltip": "^1.0.6",
|
||||
"@tanstack/react-query": "^4.32.0",
|
||||
"@tanstack/react-query-devtools": "^4.32.0",
|
||||
"@tanstack/react-query": "^4.32.1",
|
||||
"@tanstack/react-query-devtools": "^4.32.1",
|
||||
"@tanstack/react-virtual": "3.0.0-beta.54",
|
||||
"@tauri-apps/api": "2.0.0-alpha.5",
|
||||
"@tauri-apps/plugin-app": "github:tauri-apps/tauri-plugin-app#v2",
|
||||
@ -58,7 +58,7 @@
|
||||
"immer": "^10.0.2",
|
||||
"light-bolt11-decoder": "^3.0.0",
|
||||
"nostr-fetch": "^0.12.2",
|
||||
"nostr-tools": "^1.13.1",
|
||||
"nostr-tools": "^1.14.0",
|
||||
"qrcode.react": "^3.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@ -72,7 +72,7 @@
|
||||
"remark-gfm": "^3.0.1",
|
||||
"tauri-controls": "^0.0.5",
|
||||
"tippy.js": "^6.3.7",
|
||||
"zustand": "^4.3.9"
|
||||
"zustand": "^4.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
@ -105,7 +105,7 @@
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^4.9.5",
|
||||
"vite": "^4.4.7",
|
||||
"vite": "^4.4.8",
|
||||
"vite-plugin-top-level-await": "^1.3.1",
|
||||
"vite-tsconfig-paths": "^4.2.0"
|
||||
}
|
||||
|
188
pnpm-lock.yaml
188
pnpm-lock.yaml
@ -5,11 +5,11 @@ dependencies:
|
||||
specifier: ^1.7.16
|
||||
version: 1.7.16(react-dom@18.2.0)(react@18.2.0)
|
||||
'@nostr-dev-kit/ndk':
|
||||
specifier: ^0.7.7
|
||||
version: 0.7.7(typescript@4.9.5)
|
||||
specifier: ^0.8.0
|
||||
version: 0.8.0(typescript@4.9.5)
|
||||
'@nostr-fetch/adapter-ndk':
|
||||
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':
|
||||
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)
|
||||
@ -23,11 +23,11 @@ dependencies:
|
||||
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)
|
||||
'@tanstack/react-query':
|
||||
specifier: ^4.32.0
|
||||
version: 4.32.0(react-dom@18.2.0)(react@18.2.0)
|
||||
specifier: ^4.32.1
|
||||
version: 4.32.1(react-dom@18.2.0)(react@18.2.0)
|
||||
'@tanstack/react-query-devtools':
|
||||
specifier: ^4.32.0
|
||||
version: 4.32.0(@tanstack/react-query@4.32.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
specifier: ^4.32.1
|
||||
version: 4.32.1(@tanstack/react-query@4.32.1)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@tanstack/react-virtual':
|
||||
specifier: 3.0.0-beta.54
|
||||
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
|
||||
'@tauri-apps/plugin-dialog':
|
||||
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':
|
||||
specifier: github:tauri-apps/tauri-plugin-fs#v2
|
||||
version: github.com/tauri-apps/tauri-plugin-fs/60e8dec66d2582cc39ebdd7b7101e9c96c23e52a
|
||||
@ -54,10 +54,10 @@ dependencies:
|
||||
version: github.com/tauri-apps/tauri-plugin-http/b23c48592e1b6f1924feb273e1754944063e4ee8
|
||||
'@tauri-apps/plugin-notification':
|
||||
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':
|
||||
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':
|
||||
specifier: github:tauri-apps/tauri-plugin-process#v2
|
||||
version: github.com/tauri-apps/tauri-plugin-process/ed3f8f78ddecc72c926239f5a10ec6ce1b8c353e
|
||||
@ -125,8 +125,8 @@ dependencies:
|
||||
specifier: ^0.12.2
|
||||
version: 0.12.2
|
||||
nostr-tools:
|
||||
specifier: ^1.13.1
|
||||
version: 1.13.1
|
||||
specifier: ^1.14.0
|
||||
version: 1.14.0
|
||||
qrcode.react:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0(react@18.2.0)
|
||||
@ -167,8 +167,8 @@ dependencies:
|
||||
specifier: ^6.3.7
|
||||
version: 6.3.7
|
||||
zustand:
|
||||
specifier: ^4.3.9
|
||||
version: 4.3.9(immer@10.0.2)(react@18.2.0)
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0(@types/react@18.2.18)(immer@10.0.2)(react@18.2.0)
|
||||
|
||||
devDependencies:
|
||||
'@tailwindcss/typography':
|
||||
@ -203,7 +203,7 @@ devDependencies:
|
||||
version: 5.62.0(eslint@8.46.0)(typescript@4.9.5)
|
||||
'@vitejs/plugin-react-swc':
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2(vite@4.4.7)
|
||||
version: 3.3.2(vite@4.4.8)
|
||||
autoprefixer:
|
||||
specifier: ^10.4.14
|
||||
version: 10.4.14(postcss@8.4.27)
|
||||
@ -262,14 +262,14 @@ devDependencies:
|
||||
specifier: ^4.9.5
|
||||
version: 4.9.5
|
||||
vite:
|
||||
specifier: ^4.4.7
|
||||
version: 4.4.7(@types/node@18.17.1)
|
||||
specifier: ^4.4.8
|
||||
version: 4.4.8(@types/node@18.17.1)
|
||||
vite-plugin-top-level-await:
|
||||
specifier: ^1.3.1
|
||||
version: 1.3.1(vite@4.4.7)
|
||||
version: 1.3.1(vite@4.4.8)
|
||||
vite-tsconfig-paths:
|
||||
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:
|
||||
|
||||
@ -988,8 +988,8 @@ packages:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.15.0
|
||||
|
||||
/@nostr-dev-kit/ndk@0.7.7(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-IRTW16q40zzuSBkpYpDUcZJRrbw26JTeicfZN6O/2Gw7D2w6Pe42VqFwpbcP9xOnFPEGP2eNV6SwXQ3y0tjBtw==}
|
||||
/@nostr-dev-kit/ndk@0.8.0(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-SFrB7dW80kMZgquw33OUEjDpE5JJD11PsS/ET4Lxl5FtYMHP/unR61BmcIsCPhBXLm+0Pf2QqAq+N5/BYVZqEA==}
|
||||
dependencies:
|
||||
'@noble/hashes': 1.3.1
|
||||
'@noble/secp256k1': 2.0.0
|
||||
@ -1006,7 +1006,7 @@ packages:
|
||||
eventemitter3: 5.0.1
|
||||
light-bolt11-decoder: 3.0.0
|
||||
node-fetch: 3.3.2
|
||||
nostr-tools: 1.13.1
|
||||
nostr-tools: 1.14.0
|
||||
tsd: 0.28.1
|
||||
utf8-buffer: 1.0.0
|
||||
websocket-polyfill: 0.0.3
|
||||
@ -1017,13 +1017,13 @@ packages:
|
||||
- typescript
|
||||
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==}
|
||||
peerDependencies:
|
||||
'@nostr-dev-kit/ndk': ^0.5.0
|
||||
nostr-fetch: ^0.11.0
|
||||
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: 0.12.2
|
||||
dev: false
|
||||
@ -1618,8 +1618,8 @@ packages:
|
||||
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
|
||||
dev: false
|
||||
|
||||
/@swc/core-darwin-arm64@1.3.72:
|
||||
resolution: {integrity: sha512-oNSI5hVfZ+1xpj+dH1g4kQqA0VsGtqd8S9S+cDqkHZiOOVOevw9KN6dzVtmLOcPtlULVypVc0TVvsB55KdVZhQ==}
|
||||
/@swc/core-darwin-arm64@1.3.74:
|
||||
resolution: {integrity: sha512-2rMV4QxM583jXcREfo0MhV3Oj5pgRSfSh/kVrB1twL2rQxOrbzkAPT/8flmygdVoL4f2F7o1EY5lKlYxEBiIKQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
@ -1627,8 +1627,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-darwin-x64@1.3.72:
|
||||
resolution: {integrity: sha512-y5O/WQ1g0/VfTgeNahWIOutbdD5U2Gi703jaefdcoJo3FUx8WU108QQdbVGwGMgaqapo3iQB6Qs9paixYQAYsA==}
|
||||
/@swc/core-darwin-x64@1.3.74:
|
||||
resolution: {integrity: sha512-KKEGE1wXneYXe15fWDRM8/oekd/Q4yAuccA0vWY/7i6nOSPqWYcSDR0nRtR030ltDxWt0rk/eCTmNkrOWrKs3A==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
@ -1636,8 +1636,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm-gnueabihf@1.3.72:
|
||||
resolution: {integrity: sha512-05JdWcso0OomHF+7bk5MBDgI8MZ9skcQ/4nhSv5gboSgSiuBmKM15Bg3lZ5iAUwGByNj7pGkSmmd3YwTrXEB+g==}
|
||||
/@swc/core-linux-arm-gnueabihf@1.3.74:
|
||||
resolution: {integrity: sha512-HehH5DR6r/5fIVu7tu8ZqgrHkhSCQNewf1ztFQJgcmaQWn+H4AJERBjwkjosqh4TvUJucZv8vyRTvrFeBXaCSA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
@ -1645,8 +1645,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm64-gnu@1.3.72:
|
||||
resolution: {integrity: sha512-8qRELJaeYshhJgqvyOeXCKqBOpai+JYdWuouMbvvDUL85j3OcZhzR+bipexEbbJKcOCdRnoYB7Qg6mjqZ0t7VA==}
|
||||
/@swc/core-linux-arm64-gnu@1.3.74:
|
||||
resolution: {integrity: sha512-+xkbCRz/wczgdknoV4NwYxbRI2dD7x/qkIFcVM2buzLCq8oWLweuV8+aL4pRqu0qDh7ZSb1jcaVTUIsySCJznA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@ -1654,8 +1654,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm64-musl@1.3.72:
|
||||
resolution: {integrity: sha512-tOqAGZw+Pe7YrBHFrwFVyRiKqjgjzwYbJmY+UDxLrzWrZSVtC3eO2TPrp7kWmhirg40Og81BbdfRAl8ds48w0Q==}
|
||||
/@swc/core-linux-arm64-musl@1.3.74:
|
||||
resolution: {integrity: sha512-maKFZSCD3tQznzPV7T3V+TtiWZFEFM8YrnSS5fQNNb+K9J65sL+170uTb3M7H4cFkG+9Sm5k5yCrCIutlvV48g==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@ -1663,8 +1663,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-x64-gnu@1.3.72:
|
||||
resolution: {integrity: sha512-U2W2xWR3s9nplGVWz376GiBlcLTgxyYKlpZPBNZk0w3OvTcjKC62gW1Pe7PUkk4NgJUnaQDBa/mb4V4Zl+GZPA==}
|
||||
/@swc/core-linux-x64-gnu@1.3.74:
|
||||
resolution: {integrity: sha512-LEXpcShF6DLTWJSiBhMSYZkLQ27UvaQ24fCFhoIV/R3dhYaUpHmIyLPPBNC82T03lB3ONUFVwrRw6fxDJ/f00A==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@ -1672,8 +1672,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-x64-musl@1.3.72:
|
||||
resolution: {integrity: sha512-3+2dUiZBsifKgvnFEHWdysXjInK8K+BfPBw2tTZJmq1+fZLt0rvuErYDVMLfIJnVWLCcJMnDtTXrvkFV1y/6iA==}
|
||||
/@swc/core-linux-x64-musl@1.3.74:
|
||||
resolution: {integrity: sha512-sxsFctbFMZEFmDE7CmYljG0dMumH8XBTwwtGr8s6z0fYAzXBGNq2AFPcmEh2np9rPWkt7pE1m0ByESD+dMkbxQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@ -1681,8 +1681,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-arm64-msvc@1.3.72:
|
||||
resolution: {integrity: sha512-ndI8xZ2AId806D25xgqw2SFJ9gc/jhg21+5hA8XPq9ZL+oDiaYDztaP3ijVmZ1G5xXKD9DpgB7xmylv/f6o6GA==}
|
||||
/@swc/core-win32-arm64-msvc@1.3.74:
|
||||
resolution: {integrity: sha512-F7hY9/BjFCozA4YPFYFH5FGCyWwa44vIXHqG66F5cDwXDGFn8ZtBsYIsiPfUYcx0AeAo1ojnVWKPxokZhYNYqA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
@ -1690,8 +1690,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-ia32-msvc@1.3.72:
|
||||
resolution: {integrity: sha512-F3TK8JHP3SRFjLRlzcRVZPnvvGm2CQ5/cwbIkaEq0Dla3kyctU8SiRqvtYwWCW4JuY10cUygIg93Ec/C9Lkk4g==}
|
||||
/@swc/core-win32-ia32-msvc@1.3.74:
|
||||
resolution: {integrity: sha512-qBAsiD1AlIdqED6wy3UNRHyAys9pWMUidX0LJ6mj24r/vfrzzTBAUrLJe5m7bzE+F1Rgi001avYJeEW1DLEJ+Q==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
@ -1699,8 +1699,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-x64-msvc@1.3.72:
|
||||
resolution: {integrity: sha512-FXMnIUtLl0yEmGkw+xbUg/uUPExvUxUlLSHbX7CnbSuOIHqMHzvEd9skIueLAst4bvmJ8kT1hDyAIWQcTIAJYQ==}
|
||||
/@swc/core-win32-x64-msvc@1.3.74:
|
||||
resolution: {integrity: sha512-S3YAvvLprTnPRwQuy9Dkwubb5SRLpVK3JJsqYDbGfgj8PGQyKHZcVJ5X3nfFsoWLy3j9B/3Os2nawprRSzeC5A==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@ -1708,8 +1708,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core@1.3.72:
|
||||
resolution: {integrity: sha512-+AKjwLH3/STfPrd7CHzB9+NG1FVT0UKJMUChuWq9sQ8b9xlV8vUeRgZXgh/EHYvNQgl/OUTQKtL6xU2yOLuEuA==}
|
||||
/@swc/core@1.3.74:
|
||||
resolution: {integrity: sha512-P+MIExOTdWlfq8Heb1/NhBAke6UTckd4cRDuJoFcFMGBRvgoCMNWhnfP3FRRXPLI7GGg27dRZS+xHiqYyQmSrA==}
|
||||
engines: {node: '>=10'}
|
||||
requiresBuild: true
|
||||
peerDependencies:
|
||||
@ -1718,16 +1718,16 @@ packages:
|
||||
'@swc/helpers':
|
||||
optional: true
|
||||
optionalDependencies:
|
||||
'@swc/core-darwin-arm64': 1.3.72
|
||||
'@swc/core-darwin-x64': 1.3.72
|
||||
'@swc/core-linux-arm-gnueabihf': 1.3.72
|
||||
'@swc/core-linux-arm64-gnu': 1.3.72
|
||||
'@swc/core-linux-arm64-musl': 1.3.72
|
||||
'@swc/core-linux-x64-gnu': 1.3.72
|
||||
'@swc/core-linux-x64-musl': 1.3.72
|
||||
'@swc/core-win32-arm64-msvc': 1.3.72
|
||||
'@swc/core-win32-ia32-msvc': 1.3.72
|
||||
'@swc/core-win32-x64-msvc': 1.3.72
|
||||
'@swc/core-darwin-arm64': 1.3.74
|
||||
'@swc/core-darwin-x64': 1.3.74
|
||||
'@swc/core-linux-arm-gnueabihf': 1.3.74
|
||||
'@swc/core-linux-arm64-gnu': 1.3.74
|
||||
'@swc/core-linux-arm64-musl': 1.3.74
|
||||
'@swc/core-linux-x64-gnu': 1.3.74
|
||||
'@swc/core-linux-x64-musl': 1.3.74
|
||||
'@swc/core-win32-arm64-msvc': 1.3.74
|
||||
'@swc/core-win32-ia32-msvc': 1.3.74
|
||||
'@swc/core-win32-x64-msvc': 1.3.74
|
||||
dev: true
|
||||
|
||||
/@tailwindcss/typography@0.5.9(tailwindcss@3.3.3):
|
||||
@ -1749,27 +1749,27 @@ packages:
|
||||
remove-accents: 0.4.2
|
||||
dev: false
|
||||
|
||||
/@tanstack/query-core@4.32.0:
|
||||
resolution: {integrity: sha512-ei4IYwL2kmlKSlCw9WgvV7PpXi0MiswVwfQRxawhJA690zWO3dU49igaQ/UMTl+Jy9jj9dK5IKAYvbX7kUvviQ==}
|
||||
/@tanstack/query-core@4.32.1:
|
||||
resolution: {integrity: sha512-VEAGHboOFWN/bvf/7cCoeLQfld0AA8n0V/kfc77W+FvxnnSwJufEh6gfjqpX5bRE/DEYfYDYdNtuL3KM+lIs8Q==}
|
||||
dev: false
|
||||
|
||||
/@tanstack/react-query-devtools@4.32.0(@tanstack/react-query@4.32.0)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-rOmWqzKzRmQrQULV5Ova2FGEEPT76FZA3hz8T+LFkvp3ehw9ugSZ1BosgRJ7AFCeir+5pcNvFwILy4pDK8HpRw==}
|
||||
/@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-/ZgxCfGXLIXUvaIRzrNCP+C4iv1bIleNzXCjGKFZ4qKEifnv5A/SpWE2dG4SBjqXVlIkMAP82lesfoHcsOm+zg==}
|
||||
peerDependencies:
|
||||
'@tanstack/react-query': 4.32.0
|
||||
'@tanstack/react-query': 4.32.1
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
'@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-dom: 18.2.0(react@18.2.0)
|
||||
superjson: 1.13.1
|
||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@tanstack/react-query@4.32.0(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-B8WUMcByYAH9500ENejDCATOmEZhqjtS9wsfiQ3BNa+s+yAynY8SESI8WWHhSqUmjd0pmCSFRP6BOUGSda3QXA==}
|
||||
/@tanstack/react-query@4.32.1(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-lPTfOq6bR6DorPaS018gTMd3zs8r06tlERiVY6BRP9SnDkkl4ckqeANava/jPLWrSZP+EA15loQUTmvZs6k2GA==}
|
||||
peerDependencies:
|
||||
react: ^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:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@tanstack/query-core': 4.32.0
|
||||
'@tanstack/query-core': 4.32.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.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
|
||||
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==}
|
||||
peerDependencies:
|
||||
vite: ^4
|
||||
dependencies:
|
||||
'@swc/core': 1.3.72
|
||||
vite: 4.4.7(@types/node@18.17.1)
|
||||
'@swc/core': 1.3.74
|
||||
vite: 4.4.8(@types/node@18.17.1)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
dev: true
|
||||
@ -2758,7 +2758,7 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001518
|
||||
electron-to-chromium: 1.4.478
|
||||
electron-to-chromium: 1.4.482
|
||||
node-releases: 2.0.13
|
||||
update-browserslist-db: 1.0.11(browserslist@4.21.10)
|
||||
dev: true
|
||||
@ -3228,8 +3228,8 @@ packages:
|
||||
/eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
/electron-to-chromium@1.4.478:
|
||||
resolution: {integrity: sha512-qjTA8djMXd+ruoODDFGnRCRBpID+AAfYWCyGtYTNhsuwxI19s8q19gbjKTwRS5z/LyVf5wICaIiPQGLekmbJbA==}
|
||||
/electron-to-chromium@1.4.482:
|
||||
resolution: {integrity: sha512-h+UqpfmEr1Qkk0zp7ej/jid7CXoq4m4QzW6wNTb0ELJ/BZCpA4wgUylBIMGCe621tnr4l5VmoHjdoSx2lbnNJA==}
|
||||
dev: true
|
||||
|
||||
/emoji-regex@8.0.0:
|
||||
@ -5385,8 +5385,8 @@ packages:
|
||||
'@nostr-fetch/kernel': 0.12.2
|
||||
dev: false
|
||||
|
||||
/nostr-tools@1.13.1:
|
||||
resolution: {integrity: sha512-DTwpbxTH1/ar+afWd4gmVdpHH8CF290kdaxi00Llra88SHE6e38XuyzlRABVTcrBaceLMnoDdHmV3x16MoEFJg==}
|
||||
/nostr-tools@1.14.0:
|
||||
resolution: {integrity: sha512-hwq2i1z5/DneXRE5Zu/TzQuKzVLcB+gOdfT9CeoiScvNw/2dWRGJvyTXIdF92d7NQ7nMcEwqVJPDytLpEpiiKw==}
|
||||
dependencies:
|
||||
'@noble/curves': 1.1.0
|
||||
'@noble/hashes': 1.3.1
|
||||
@ -6124,7 +6124,7 @@ packages:
|
||||
remark-parse: 10.0.2
|
||||
remark-rehype: 10.1.0
|
||||
space-separated-tokens: 2.0.2
|
||||
style-to-object: 0.4.1
|
||||
style-to-object: 0.4.2
|
||||
unified: 10.1.2
|
||||
unist-util-visit: 4.1.2
|
||||
vfile: 5.3.7
|
||||
@ -6730,8 +6730,8 @@ packages:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
/style-to-object@0.4.1:
|
||||
resolution: {integrity: sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==}
|
||||
/style-to-object@0.4.2:
|
||||
resolution: {integrity: sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA==}
|
||||
dependencies:
|
||||
inline-style-parser: 0.1.1
|
||||
dev: false
|
||||
@ -6838,7 +6838,7 @@ packages:
|
||||
tailwind-merge: ^1.14.0
|
||||
dependencies:
|
||||
'@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
|
||||
clsx: 2.0.0
|
||||
react: 18.2.0
|
||||
@ -7257,21 +7257,21 @@ packages:
|
||||
vfile-message: 3.1.4
|
||||
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==}
|
||||
peerDependencies:
|
||||
vite: '>=2.8'
|
||||
dependencies:
|
||||
'@rollup/plugin-virtual': 3.0.1
|
||||
'@swc/core': 1.3.72
|
||||
'@swc/core': 1.3.74
|
||||
uuid: 9.0.0
|
||||
vite: 4.4.7(@types/node@18.17.1)
|
||||
vite: 4.4.8(@types/node@18.17.1)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
- rollup
|
||||
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==}
|
||||
peerDependencies:
|
||||
vite: '*'
|
||||
@ -7282,14 +7282,14 @@ packages:
|
||||
debug: 4.3.4
|
||||
globrex: 0.1.2
|
||||
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:
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/vite@4.4.7(@types/node@18.17.1):
|
||||
resolution: {integrity: sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==}
|
||||
/vite@4.4.8(@types/node@18.17.1):
|
||||
resolution: {integrity: sha512-LONawOUUjxQridNWGQlNizfKH89qPigK36XhMI7COMGztz8KNY0JHim7/xDd71CZwGT4HtSRgI7Hy+RlhG0Gvg==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@ -7446,18 +7446,22 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
/zustand@4.3.9(immer@10.0.2)(react@18.2.0):
|
||||
resolution: {integrity: sha512-Tat5r8jOMG1Vcsj8uldMyqYKC5IZvQif8zetmLHs9WoZlntTHmIoNM8TpLRY31ExncuUvUOXehd0kvahkuHjDw==}
|
||||
/zustand@4.4.0(@types/react@18.2.18)(immer@10.0.2)(react@18.2.0):
|
||||
resolution: {integrity: sha512-2dq6wq4dSxbiPTamGar0NlIG/av0wpyWZJGeQYtUOLegIUvhM2Bf86ekPlmgpUtS5uR7HyetSiktYrGsdsyZgQ==}
|
||||
engines: {node: '>=12.7.0'}
|
||||
peerDependencies:
|
||||
'@types/react': '>=16.8'
|
||||
immer: '>=9.0'
|
||||
react: '>=16.8'
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
immer:
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/react': 18.2.18
|
||||
immer: 10.0.2
|
||||
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
|
||||
dev: false
|
||||
|
||||
github.com/tauri-apps/tauri-plugin-dialog/80325934b699f02bea9abe4fe1311dfba793a2bb:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-dialog/tar.gz/80325934b699f02bea9abe4fe1311dfba793a2bb}
|
||||
github.com/tauri-apps/tauri-plugin-dialog/c84cc21fbcd1cd284a4832e8021e08460cd42963:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-dialog/tar.gz/c84cc21fbcd1cd284a4832e8021e08460cd42963}
|
||||
name: '@tauri-apps/plugin-dialog'
|
||||
version: 2.0.0-alpha.0
|
||||
dependencies:
|
||||
@ -7515,16 +7519,16 @@ packages:
|
||||
'@tauri-apps/api': 2.0.0-alpha.5
|
||||
dev: false
|
||||
|
||||
github.com/tauri-apps/tauri-plugin-notification/6d8c193765f7fcf97429c0106bc5699d41870cef:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-notification/tar.gz/6d8c193765f7fcf97429c0106bc5699d41870cef}
|
||||
github.com/tauri-apps/tauri-plugin-notification/9989c95217af5abcf847e790cb74dda485c0459a:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-notification/tar.gz/9989c95217af5abcf847e790cb74dda485c0459a}
|
||||
name: '@tauri-apps/plugin-notification'
|
||||
version: 2.0.0-alpha.0
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.0.0-alpha.5
|
||||
dev: false
|
||||
|
||||
github.com/tauri-apps/tauri-plugin-os/d235fbf70c53812c501f1d86a6b8c790bdf6bc8b:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-os/tar.gz/d235fbf70c53812c501f1d86a6b8c790bdf6bc8b}
|
||||
github.com/tauri-apps/tauri-plugin-os/a63d34fddb1bd97d6a634a1881e5cc26910e115f:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-os/tar.gz/a63d34fddb1bd97d6a634a1881e5cc26910e115f}
|
||||
name: '@tauri-apps/plugin-os'
|
||||
version: 2.0.0-alpha.0
|
||||
dependencies:
|
||||
|
139
src-tauri/Cargo.lock
generated
139
src-tauri/Cargo.lock
generated
@ -309,7 +309,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -326,7 +326,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -641,9 +641,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
@ -757,7 +760,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1065,7 +1068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1121,7 +1124,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1132,7 +1135,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1146,6 +1149,15 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
@ -1346,7 +1358,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1357,9 +1369,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
@ -1425,7 +1437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rustix 0.38.4",
|
||||
"rustix 0.38.6",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -1515,7 +1527,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1631,7 +1643,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2377,7 +2389,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix 0.38.4",
|
||||
"rustix 0.38.6",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -2579,9 +2591,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.3"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
|
||||
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@ -3282,7 +3294,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3844,22 +3856,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.4"
|
||||
version = "0.38.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5"
|
||||
checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.3",
|
||||
"linux-raw-sys 0.4.5",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.5"
|
||||
version = "0.21.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36"
|
||||
checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-webpki",
|
||||
@ -3989,22 +4001,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.178"
|
||||
version = "1.0.180"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348"
|
||||
checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.178"
|
||||
version = "1.0.180"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b"
|
||||
checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4026,7 +4038,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4075,7 +4087,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4669,9 +4681,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.27"
|
||||
version = "2.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0"
|
||||
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4774,9 +4786,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.10"
|
||||
version = "0.12.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e"
|
||||
checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
@ -4888,7 +4900,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-app"
|
||||
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 = [
|
||||
"tauri",
|
||||
]
|
||||
@ -4896,7 +4908,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-autostart"
|
||||
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 = [
|
||||
"auto-launch",
|
||||
"log",
|
||||
@ -4909,7 +4921,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-clipboard-manager"
|
||||
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 = [
|
||||
"arboard",
|
||||
"log",
|
||||
@ -4923,7 +4935,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
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 = [
|
||||
"glib",
|
||||
"log",
|
||||
@ -4940,7 +4952,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"glob",
|
||||
@ -4953,7 +4965,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-http"
|
||||
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 = [
|
||||
"bytes",
|
||||
"glob",
|
||||
@ -4971,7 +4983,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-notification"
|
||||
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 = [
|
||||
"log",
|
||||
"notify-rust",
|
||||
@ -4989,7 +5001,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-os"
|
||||
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 = [
|
||||
"gethostname 0.4.3",
|
||||
"log",
|
||||
@ -5005,7 +5017,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-process"
|
||||
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 = [
|
||||
"tauri",
|
||||
]
|
||||
@ -5013,7 +5025,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-single-instance"
|
||||
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 = [
|
||||
"log",
|
||||
"serde",
|
||||
@ -5027,7 +5039,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-sql"
|
||||
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 = [
|
||||
"futures-core",
|
||||
"log",
|
||||
@ -5043,7 +5055,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-store"
|
||||
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 = [
|
||||
"log",
|
||||
"serde",
|
||||
@ -5055,7 +5067,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-stronghold"
|
||||
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 = [
|
||||
"hex",
|
||||
"iota-crypto 0.23.0",
|
||||
@ -5071,7 +5083,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-updater"
|
||||
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 = [
|
||||
"base64 0.21.2",
|
||||
"dirs-next",
|
||||
@ -5098,7 +5110,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-upload"
|
||||
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 = [
|
||||
"futures-util",
|
||||
"log",
|
||||
@ -5115,7 +5127,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-window"
|
||||
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 = [
|
||||
"serde",
|
||||
"tauri",
|
||||
@ -5222,7 +5234,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand 2.0.0",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix 0.38.4",
|
||||
"rustix 0.38.6",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -5260,7 +5272,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5286,10 +5298,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.23"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446"
|
||||
checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa 1.0.9",
|
||||
"serde",
|
||||
"time-core",
|
||||
@ -5304,9 +5317,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4"
|
||||
checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
@ -5352,7 +5365,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5441,7 +5454,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5704,7 +5717,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -5738,7 +5751,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@ -6221,9 +6234,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.1"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11"
|
||||
checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@ -6442,7 +6455,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -31,10 +31,10 @@ export function User({ pubkey, fallback }: { pubkey: string; fallback?: string }
|
||||
/>
|
||||
</div>
|
||||
<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}
|
||||
</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)}
|
||||
</span>
|
||||
</div>
|
||||
|
@ -81,25 +81,25 @@ export function CreateStep1Screen() {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<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 className="flex flex-col gap-4">
|
||||
<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
|
||||
readOnly
|
||||
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 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">
|
||||
<input
|
||||
readOnly
|
||||
type={privkeyInput}
|
||||
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
|
||||
type="button"
|
||||
@ -110,13 +110,13 @@ export function CreateStep1Screen() {
|
||||
<EyeOffIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
) : (
|
||||
<EyeOnIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
@ -132,13 +132,13 @@ export function CreateStep1Screen() {
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button preset="large" onClick={() => submit()}>
|
||||
{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 →'
|
||||
)}
|
||||
</Button>
|
||||
{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()}>
|
||||
Download
|
||||
|
@ -74,7 +74,7 @@ export function CreateStep2Screen() {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<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
|
||||
</h1>
|
||||
</div>
|
||||
@ -85,7 +85,7 @@ export function CreateStep2Screen() {
|
||||
<input
|
||||
{...register('password', { required: true })}
|
||||
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
|
||||
type="button"
|
||||
@ -96,13 +96,13 @@ export function CreateStep2Screen() {
|
||||
<EyeOffIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
) : (
|
||||
<EyeOnIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
@ -122,10 +122,10 @@ export function CreateStep2Screen() {
|
||||
<button
|
||||
type="submit"
|
||||
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 ? (
|
||||
<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 →'
|
||||
)}
|
||||
|
@ -45,7 +45,7 @@ export function CreateStep3Screen() {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<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 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">
|
||||
@ -53,13 +53,13 @@ export function CreateStep3Screen() {
|
||||
type={'hidden'}
|
||||
{...register('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
|
||||
type={'hidden'}
|
||||
{...register('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 h-44 w-full bg-zinc-800">
|
||||
@ -91,7 +91,7 @@ export function CreateStep3Screen() {
|
||||
<div className="flex flex-col gap-1">
|
||||
<label
|
||||
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 *
|
||||
</label>
|
||||
@ -102,26 +102,26 @@ export function CreateStep3Screen() {
|
||||
minLength: 4,
|
||||
})}
|
||||
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 className="flex flex-col gap-1">
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
<textarea
|
||||
{...register('about')}
|
||||
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 className="flex flex-col gap-1">
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
@ -131,16 +131,16 @@ export function CreateStep3Screen() {
|
||||
required: 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>
|
||||
<button
|
||||
type="submit"
|
||||
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 ? (
|
||||
<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 →'
|
||||
)}
|
||||
|
@ -53,7 +53,7 @@ export function CreateStep4Screen() {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<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 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">
|
||||
@ -65,7 +65,7 @@ export function CreateStep4Screen() {
|
||||
autoCorrect="none"
|
||||
spellCheck="false"
|
||||
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>
|
||||
</div>
|
||||
@ -75,7 +75,7 @@ export function CreateStep4Screen() {
|
||||
disabled={username.length === 0}
|
||||
>
|
||||
{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 →'
|
||||
)}
|
||||
|
@ -168,13 +168,11 @@ export function CreateStep5Screen() {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<div className="mb-8 text-center">
|
||||
<h1 className="text-xl font-semibold text-zinc-100">
|
||||
Personalized your newsfeed
|
||||
</h1>
|
||||
<h1 className="text-xl font-semibold text-white">Personalized your newsfeed</h1>
|
||||
</div>
|
||||
<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="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
|
||||
<span className="font-semibold text-fuchsia-500">
|
||||
{follows.length}/10
|
||||
@ -183,7 +181,7 @@ export function CreateStep5Screen() {
|
||||
</div>
|
||||
{status === 'loading' ? (
|
||||
<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 className="scrollbar-hide flex h-96 flex-col overflow-y-auto py-2">
|
||||
@ -209,10 +207,10 @@ export function CreateStep5Screen() {
|
||||
<button
|
||||
type="button"
|
||||
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 ? (
|
||||
<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 →'
|
||||
)}
|
||||
|
@ -98,17 +98,17 @@ export function ImportStep1Screen() {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<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 className="flex flex-col gap-4">
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-3">
|
||||
<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
|
||||
{...register('privkey', { required: true, minLength: 32 })}
|
||||
type={'password'}
|
||||
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">
|
||||
{errors.privkey && <p>{errors.privkey.message}</p>}
|
||||
@ -118,10 +118,10 @@ export function ImportStep1Screen() {
|
||||
<button
|
||||
type="submit"
|
||||
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 ? (
|
||||
<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 →'
|
||||
)}
|
||||
|
@ -74,7 +74,7 @@ export function ImportStep2Screen() {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<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
|
||||
</h1>
|
||||
</div>
|
||||
@ -85,7 +85,7 @@ export function ImportStep2Screen() {
|
||||
<input
|
||||
{...register('password', { required: true })}
|
||||
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
|
||||
type="button"
|
||||
@ -96,13 +96,13 @@ export function ImportStep2Screen() {
|
||||
<EyeOffIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
) : (
|
||||
<EyeOnIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
@ -122,10 +122,10 @@ export function ImportStep2Screen() {
|
||||
<button
|
||||
type="submit"
|
||||
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 ? (
|
||||
<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 →'
|
||||
)}
|
||||
|
@ -75,7 +75,7 @@ export function ImportStep3Screen() {
|
||||
<User pubkey={account.pubkey} />
|
||||
<Button preset="large" onClick={() => submit()}>
|
||||
{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 →'
|
||||
)}
|
||||
|
@ -92,7 +92,7 @@ export function MigrateScreen() {
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<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
|
||||
</h1>
|
||||
</div>
|
||||
@ -100,15 +100,15 @@ export function MigrateScreen() {
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<div className="mt-1">
|
||||
<p className="text-sm text-zinc-400">
|
||||
<p className="text-sm text-white/50">
|
||||
You're using old Lume version which store your private key as
|
||||
plaintext in database, this is huge security risk.
|
||||
</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
|
||||
private key in secure storage.
|
||||
</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
|
||||
easy and fast!
|
||||
</p>
|
||||
@ -124,7 +124,7 @@ export function MigrateScreen() {
|
||||
{...register('password', { required: true })}
|
||||
type={passwordInput}
|
||||
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
|
||||
type="button"
|
||||
@ -135,13 +135,13 @@ export function MigrateScreen() {
|
||||
<EyeOffIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
) : (
|
||||
<EyeOnIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
@ -154,10 +154,10 @@ export function MigrateScreen() {
|
||||
<button
|
||||
type="submit"
|
||||
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 ? (
|
||||
<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 →'
|
||||
)}
|
||||
|
@ -38,7 +38,7 @@ export function OnboardingScreen() {
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<div className="mx-auto w-full max-w-md">
|
||||
<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
|
||||
</h1>
|
||||
<p className="text-sm text-zinc-300">
|
||||
@ -54,7 +54,7 @@ export function OnboardingScreen() {
|
||||
{status === 'success' && (
|
||||
<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>
|
||||
<a
|
||||
href="https://lume.nu"
|
||||
@ -71,12 +71,12 @@ export function OnboardingScreen() {
|
||||
<button
|
||||
type="button"
|
||||
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 ? (
|
||||
<>
|
||||
<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" />
|
||||
</>
|
||||
) : (
|
||||
|
@ -12,7 +12,7 @@ export function WelcomeScreen() {
|
||||
<div className="inline-flex w-full flex-col gap-3 px-10 pb-10">
|
||||
<Link
|
||||
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>Login with private key</span>
|
||||
|
@ -18,7 +18,7 @@ export function ChannelBlackList({ blacklist }: { blacklist: any }) {
|
||||
<MuteIcon
|
||||
width={16}
|
||||
height={16}
|
||||
className="text-zinc-400 group-hover:text-zinc-100"
|
||||
className="text-white/50 group-hover:text-white"
|
||||
/>
|
||||
</Popover.Button>
|
||||
<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">
|
||||
Your muted list
|
||||
</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,
|
||||
muted list will loaded again
|
||||
</p>
|
||||
|
@ -115,7 +115,7 @@ export function ChannelCreateModal() {
|
||||
<PlusIcon width={12} height={12} className="text-zinc-500" />
|
||||
</div>
|
||||
<div>
|
||||
<h5 className="font-medium text-zinc-400">Create channel</h5>
|
||||
<h5 className="font-medium text-white/50">Create channel</h5>
|
||||
</div>
|
||||
</button>
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
@ -147,7 +147,7 @@ export function ChannelCreateModal() {
|
||||
<div className="flex items-center justify-between">
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-semibold leading-none text-zinc-100"
|
||||
className="text-lg font-semibold leading-none text-white"
|
||||
>
|
||||
Create channel
|
||||
</Dialog.Title>
|
||||
@ -159,7 +159,7 @@ export function ChannelCreateModal() {
|
||||
<CancelIcon width={20} height={20} className="text-zinc-300" />
|
||||
</button>
|
||||
</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
|
||||
stop you or deceive what to speech
|
||||
</Dialog.Description>
|
||||
@ -174,10 +174,10 @@ export function ChannelCreateModal() {
|
||||
type={'hidden'}
|
||||
{...register('picture')}
|
||||
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">
|
||||
<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
|
||||
</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">
|
||||
@ -195,7 +195,7 @@ export function ChannelCreateModal() {
|
||||
<div className="flex flex-col gap-1">
|
||||
<label
|
||||
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 *
|
||||
</label>
|
||||
@ -206,28 +206,28 @@ export function ChannelCreateModal() {
|
||||
minLength: 4,
|
||||
})}
|
||||
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 className="flex flex-col gap-1">
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
<textarea
|
||||
{...register('about')}
|
||||
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 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">
|
||||
<span className="font-semibold leading-none text-zinc-100">
|
||||
<span className="font-semibold leading-none text-white">
|
||||
Encrypted
|
||||
</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
|
||||
send message
|
||||
</p>
|
||||
@ -248,10 +248,10 @@ export function ChannelCreateModal() {
|
||||
<button
|
||||
type="submit"
|
||||
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 ? (
|
||||
<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 →'
|
||||
)}
|
||||
|
@ -12,12 +12,12 @@ export function ChannelsListItem({ data }: { data: any }) {
|
||||
className={({ isActive }) =>
|
||||
twMerge(
|
||||
'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">
|
||||
<span className="text-xs text-zinc-100">#</span>
|
||||
<span className="text-xs text-white">#</span>
|
||||
</div>
|
||||
<div className="inline-flex w-full items-center justify-between">
|
||||
<h5 className="truncate font-medium text-zinc-200">{channel?.name}</h5>
|
||||
|
@ -74,7 +74,7 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
|
||||
<div className="flex w-full flex-col">
|
||||
<UserReply pubkey={replyTo.pubkey} />
|
||||
<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>
|
||||
<button
|
||||
@ -82,7 +82,7 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
|
||||
onClick={() => stopReply()}
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -99,7 +99,7 @@ export function MessageHideButton({ id }: { id: string }) {
|
||||
<CancelIcon width={20} height={20} className="text-zinc-300" />
|
||||
</button>
|
||||
</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.
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
@ -109,14 +109,14 @@ export function MessageHideButton({ id }: { id: string }) {
|
||||
<button
|
||||
type="button"
|
||||
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
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
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
|
||||
</button>
|
||||
|
@ -19,7 +19,7 @@ export function ChannelMessageItem({ data }: { data: LumeEvent }) {
|
||||
<div className="flex flex-col">
|
||||
<User pubkey={data.pubkey} time={data.created_at} isChat={true} />
|
||||
<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}
|
||||
</p>
|
||||
{Array.isArray(content.images) && content.images.length ? (
|
||||
|
@ -99,7 +99,7 @@ export function MessageMuteButton({ pubkey }: { pubkey: string }) {
|
||||
<CancelIcon width={20} height={20} className="text-zinc-300" />
|
||||
</button>
|
||||
</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.
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
@ -109,14 +109,14 @@ export function MessageMuteButton({ pubkey }: { pubkey: string }) {
|
||||
<button
|
||||
type="button"
|
||||
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
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
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
|
||||
</button>
|
||||
|
@ -32,10 +32,10 @@ export function ChannelMetadata({ id }: { id: string }) {
|
||||
<div className="inline-flex items-center gap-1">
|
||||
<h5 className="text-lg font-semibold leading-none">{metadata?.name}</h5>
|
||||
<button type="button" onClick={() => copyNoteID()}>
|
||||
<CopyIcon width={14} height={14} className="text-zinc-400" />
|
||||
<CopyIcon width={14} height={14} className="text-white/50" />
|
||||
</button>
|
||||
</div>
|
||||
<p className="leading-tight text-zinc-400">
|
||||
<p className="leading-tight text-white/50">
|
||||
{metadata?.about || (noteID && `${noteID.substring(0, 24)}...`)}
|
||||
</p>
|
||||
</div>
|
||||
|
@ -51,10 +51,10 @@ export function MutedItem({ data }: { data: any }) {
|
||||
/>
|
||||
</div>
|
||||
<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'}
|
||||
</span>
|
||||
<span className="text-base leading-none text-zinc-400">
|
||||
<span className="text-base leading-none text-white/50">
|
||||
{shortenKey(data.content)}
|
||||
</span>
|
||||
</div>
|
||||
@ -64,7 +64,7 @@ export function MutedItem({ data }: { data: any }) {
|
||||
<button
|
||||
type="button"
|
||||
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
|
||||
</button>
|
||||
@ -72,7 +72,7 @@ export function MutedItem({ data }: { data: any }) {
|
||||
<button
|
||||
type="button"
|
||||
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
|
||||
</button>
|
||||
|
@ -23,7 +23,7 @@ const Header = (
|
||||
<div className="w-full border-t border-zinc-800" />
|
||||
</div>
|
||||
<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', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
@ -40,7 +40,7 @@ const Empty = (
|
||||
<h3 className="text-base font-semibold leading-none text-white">
|
||||
Nothing to see here yet
|
||||
</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.
|
||||
</p>
|
||||
</div>
|
||||
@ -102,7 +102,7 @@ export function ChannelScreen() {
|
||||
data-tauri-drag-region
|
||||
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 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">
|
||||
|
@ -30,7 +30,7 @@ export function ChatMessageItem({
|
||||
<div className="flex flex-col">
|
||||
<User pubkey={data.sender_pubkey} time={data.created_at} isChat={true} />
|
||||
<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}
|
||||
</p>
|
||||
{content.images.length > 0 && <ImagePreview urls={content.images} />}
|
||||
|
@ -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="flex flex-col gap-1">
|
||||
<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
|
||||
</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-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
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
|
@ -26,7 +26,7 @@ export function ChatSidebar({ pubkey }: { pubkey: string }) {
|
||||
<h3 className="text-lg font-semibold leading-none">
|
||||
{user?.displayName || user?.name}
|
||||
</h3>
|
||||
<h5 className="leading-none text-zinc-400">
|
||||
<h5 className="leading-none text-white/50">
|
||||
{user?.nip05 || shortenKey(pubkey)}
|
||||
</h5>
|
||||
</div>
|
||||
@ -34,7 +34,7 @@ export function ChatSidebar({ pubkey }: { pubkey: string }) {
|
||||
<p className="leading-tight">{user?.bio || user?.about}</p>
|
||||
<Link
|
||||
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
|
||||
</Link>
|
||||
|
@ -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="flex flex-col gap-1">
|
||||
<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
|
||||
</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-none text-zinc-400">
|
||||
<Dialog.Description className="text-sm leading-none text-white/50">
|
||||
All messages from people you not follow
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { nip04 } from 'nostr-tools';
|
||||
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);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -106,7 +106,7 @@ export function ChatScreen() {
|
||||
data-tauri-drag-region
|
||||
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 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">
|
||||
@ -155,7 +155,7 @@ export function ChatScreen() {
|
||||
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">
|
||||
<h3 className="mb-2 text-4xl">🙌</h3>
|
||||
<p className="leading-none text-zinc-400">
|
||||
<p className="leading-none text-white/50">
|
||||
You two didn't talk yet, let's send first message
|
||||
</p>
|
||||
</div>
|
||||
|
@ -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(() => {
|
||||
async function prefetch() {
|
||||
const notes = await fetchNotes();
|
||||
@ -180,12 +140,12 @@ export function Root() {
|
||||
<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="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">
|
||||
<h3 className="text-lg font-semibold leading-tight text-zinc-100">
|
||||
<h3 className="text-lg font-semibold leading-tight text-white">
|
||||
Prefetching data...
|
||||
</h3>
|
||||
<p className="text-zinc-600">
|
||||
<p className="text-white/50">
|
||||
This may take a few seconds, please don't close app.
|
||||
</p>
|
||||
</div>
|
||||
|
@ -23,36 +23,36 @@ export function AccountSettingsScreen() {
|
||||
return (
|
||||
<div className="h-full w-full px-3 pt-12">
|
||||
<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="">
|
||||
{status === 'loading' ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<div className="flex flex-col gap-4">
|
||||
<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
|
||||
</label>
|
||||
<input
|
||||
readOnly
|
||||
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 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
|
||||
</label>
|
||||
<input
|
||||
readOnly
|
||||
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 className="flex flex-col gap-1">
|
||||
<label
|
||||
htmlFor="privkey"
|
||||
className="text-base font-semibold text-zinc-400"
|
||||
className="text-base font-semibold text-white/50"
|
||||
>
|
||||
Private Key
|
||||
</label>
|
||||
@ -61,7 +61,7 @@ export function AccountSettingsScreen() {
|
||||
readOnly
|
||||
type={type}
|
||||
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
|
||||
type="button"
|
||||
@ -72,13 +72,13 @@ export function AccountSettingsScreen() {
|
||||
<EyeOffIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
) : (
|
||||
<EyeOnIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className="text-zinc-500 group-hover:text-zinc-100"
|
||||
className="text-zinc-500 group-hover:text-white"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
|
@ -36,7 +36,7 @@ export function AutoStartSetting() {
|
||||
<div className="inline-flex items-center justify-between px-5 py-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<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>
|
||||
<Switch
|
||||
checked={enabled}
|
||||
|
@ -20,7 +20,7 @@ export function CacheTimeSetting() {
|
||||
<span className="font-medium leading-none text-zinc-200">
|
||||
Cache time (milliseconds)
|
||||
</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
|
||||
</span>
|
||||
</div>
|
||||
@ -37,7 +37,7 @@ export function CacheTimeSetting() {
|
||||
onClick={() => update()}
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@ export function VersionSetting() {
|
||||
<div className="inline-flex items-center justify-between px-5 py-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<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're using latest version
|
||||
</span>
|
||||
</div>
|
||||
@ -19,7 +19,7 @@ export function VersionSetting() {
|
||||
type="button"
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@ export function GeneralSettingsScreen() {
|
||||
return (
|
||||
<div className="h-full w-full px-3 pt-12">
|
||||
<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="flex h-full w-full flex-col divide-y divide-zinc-800">
|
||||
<AutoStartSetting />
|
||||
|
@ -4,7 +4,7 @@ export function ShortcutsSettingsScreen() {
|
||||
return (
|
||||
<div className="h-full w-full px-3 pt-12">
|
||||
<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="flex h-full w-full flex-col divide-y divide-zinc-800">
|
||||
<div className="inline-flex items-center justify-between px-5 py-4">
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
@ -121,15 +121,15 @@ export function FeedBlock({ params }: { params: Block }) {
|
||||
<div className="h-full">
|
||||
{status === 'loading' ? (
|
||||
<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 />
|
||||
</div>
|
||||
</div>
|
||||
) : itemsVirtualizer.length === 0 ? (
|
||||
<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">
|
||||
<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
|
||||
</p>
|
||||
</div>
|
||||
|
@ -133,15 +133,15 @@ export function FollowingBlock() {
|
||||
<div className="h-full">
|
||||
{status === 'loading' ? (
|
||||
<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 />
|
||||
</div>
|
||||
</div>
|
||||
) : itemsVirtualizer.length === 0 ? (
|
||||
<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">
|
||||
<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
|
||||
<br />
|
||||
Follow more people to have more fun.
|
||||
|
@ -39,15 +39,15 @@ export function HashtagBlock({ params }: { params: Block }) {
|
||||
<div className="h-full">
|
||||
{status === 'loading' ? (
|
||||
<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 />
|
||||
</div>
|
||||
</div>
|
||||
) : itemsVirtualizer.length === 0 ? (
|
||||
<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">
|
||||
<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
|
||||
</p>
|
||||
</div>
|
||||
|
212
src/app/space/components/modals/feed.tsx
Normal file
212
src/app/space/components/modals/feed.tsx
Normal 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>
|
||||
);
|
||||
}
|
132
src/app/space/components/modals/hashtag.tsx
Normal file
132
src/app/space/components/modals/hashtag.tsx
Normal 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>
|
||||
);
|
||||
}
|
184
src/app/space/components/modals/image.tsx
Normal file
184
src/app/space/components/modals/image.tsx
Normal 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>
|
||||
);
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { AddBlock } from '@app/space/components/add';
|
||||
import { FeedBlock } from '@app/space/components/blocks/feed';
|
||||
import { FollowingBlock } from '@app/space/components/blocks/following';
|
||||
import { HashtagBlock } from '@app/space/components/blocks/hashtag';
|
||||
import { ImageBlock } from '@app/space/components/blocks/image';
|
||||
import { ThreadBlock } from '@app/space/components/blocks/thread';
|
||||
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';
|
||||
|
||||
@ -76,13 +78,15 @@ export function SpaceScreen() {
|
||||
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">
|
||||
<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 className="flex w-[350px] shrink-0 flex-col">
|
||||
<div className="inline-flex h-full w-full items-center justify-center">
|
||||
<AddBlock />
|
||||
<div className="inline-flex h-full w-full flex-col items-center justify-center gap-1">
|
||||
<FeedModal />
|
||||
<ImageModal />
|
||||
<HashtagModal />
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-[250px] shrink-0" />
|
||||
|
@ -113,7 +113,7 @@ export function UserProfile({ pubkey }: { pubkey: string }) {
|
||||
</div>
|
||||
</div>
|
||||
<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}
|
||||
</p>
|
||||
<UserMetadata pubkey={pubkey} />
|
||||
|
@ -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"
|
||||
>
|
||||
{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>
|
||||
);
|
||||
|
@ -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"
|
||||
>
|
||||
{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>
|
||||
);
|
||||
|
@ -20,15 +20,15 @@ export function Button({
|
||||
break;
|
||||
case 'publish':
|
||||
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;
|
||||
case 'large':
|
||||
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;
|
||||
case 'large-alt':
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
|
@ -17,12 +17,12 @@ export function MentionItem({ profile }: { profile: Profile }) {
|
||||
/>
|
||||
</div>
|
||||
<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 || (
|
||||
<div className="h-3 w-20 animate-pulse rounded-sm bg-zinc-700" />
|
||||
)}
|
||||
</h5>
|
||||
<span className="text-sm leading-none text-zinc-400">
|
||||
<span className="text-sm leading-none text-white/50">
|
||||
{displayNpub(profile.pubkey, 16)}
|
||||
</span>
|
||||
</div>
|
||||
|
@ -178,7 +178,7 @@ export function EditProfileModal() {
|
||||
<div className="flex items-center justify-between">
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-semibold leading-none text-zinc-100"
|
||||
className="text-lg font-semibold leading-none text-white"
|
||||
>
|
||||
Edit profile
|
||||
</Dialog.Title>
|
||||
@ -197,13 +197,13 @@ export function EditProfileModal() {
|
||||
type={'hidden'}
|
||||
{...register('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
|
||||
type={'hidden'}
|
||||
{...register('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 h-44 w-full bg-zinc-800">
|
||||
@ -235,7 +235,7 @@ export function EditProfileModal() {
|
||||
<div className="flex flex-col gap-1">
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
@ -246,13 +246,13 @@ export function EditProfileModal() {
|
||||
minLength: 4,
|
||||
})}
|
||||
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 className="flex flex-col gap-1">
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
@ -263,7 +263,7 @@ export function EditProfileModal() {
|
||||
minLength: 4,
|
||||
})}
|
||||
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">
|
||||
{nip05.verified ? (
|
||||
@ -288,20 +288,20 @@ export function EditProfileModal() {
|
||||
<div className="flex flex-col gap-1">
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
<textarea
|
||||
{...register('about')}
|
||||
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 className="flex flex-col gap-1">
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
@ -309,13 +309,13 @@ export function EditProfileModal() {
|
||||
type={'text'}
|
||||
{...register('website', { required: 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 className="flex flex-col gap-1">
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
@ -323,17 +323,17 @@ export function EditProfileModal() {
|
||||
type={'text'}
|
||||
{...register('lud16', { required: 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
|
||||
type="submit"
|
||||
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 ? (
|
||||
<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'
|
||||
)}
|
||||
|
@ -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"
|
||||
>
|
||||
{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
|
||||
width={14}
|
||||
height={14}
|
||||
className="text-zinc-400 group-hover:text-zinc-200"
|
||||
className="text-white/50 group-hover:text-zinc-200"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<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}
|
||||
>
|
||||
Upload media
|
||||
|
@ -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">
|
||||
<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">
|
||||
<Dialog.Title className="font-medium leading-none text-zinc-100">
|
||||
<Dialog.Title className="font-medium leading-none text-white">
|
||||
Zap (Beta)
|
||||
</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
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
@ -178,10 +178,10 @@ export function NoteZap({ id }: { id: string }) {
|
||||
<QRCodeSVG value={invoice} size={256} />
|
||||
</div>
|
||||
<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
|
||||
</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
|
||||
<br />
|
||||
such as: Blue Wallet, Bitkit, Phoenix,...
|
||||
|
@ -26,7 +26,7 @@ export function Repost({ event }: { event: LumeEvent }) {
|
||||
if (status === 'error') {
|
||||
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">
|
||||
<p className="text-zinc-400">Failed to fetch</p>
|
||||
<p className="text-white/50">Failed to fetch</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export function SubNote({ id, root }: { id: string; root?: string }) {
|
||||
if (status === 'error') {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ export function NoteKindUnsupport({ event }: { event: LumeEvent }) {
|
||||
Lume isn't fully support this kind
|
||||
</p>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -69,7 +69,7 @@ export function NoteMetadata({ id }: { id: string }) {
|
||||
<div className="mb-3 flex items-center gap-3">
|
||||
<div className="mt-2h-6 w-11 shrink-0"></div>
|
||||
<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>
|
||||
);
|
||||
|
@ -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 flex-col items-center justify-center gap-2 py-6">
|
||||
<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>
|
||||
|
@ -54,7 +54,7 @@ export function NoteStats({ id }: { id: string }) {
|
||||
if (status === 'loading') {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
@ -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"
|
||||
/>
|
||||
<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?.name ||
|
||||
user?.display_name ||
|
||||
shortenKey(pubkey)}
|
||||
</h5>
|
||||
<span className="text-zinc-400">reposted</span>
|
||||
<span className="text-white/50">reposted</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -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="flex flex-col gap-1">
|
||||
<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
|
||||
</Dialog.Title>
|
||||
<Dialog.Close asChild>
|
||||
@ -75,7 +75,7 @@ export function NotificationModal({ pubkey }: { pubkey: string }) {
|
||||
</button>
|
||||
</Dialog.Close>
|
||||
</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
|
||||
</Dialog.Description>
|
||||
</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">
|
||||
{status === 'loading' ? (
|
||||
<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>
|
||||
) : data.length < 1 ? (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
||||
|
@ -17,7 +17,7 @@ export function NotiMention({ event }: { event: NDKEvent }) {
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start gap-1">
|
||||
<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>
|
||||
<span className="leading-none text-zinc-500">{createdAt}</span>
|
||||
|
@ -14,7 +14,7 @@ export function NotiReaction({ event }: { event: NDKEvent }) {
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start gap-1">
|
||||
<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>
|
||||
<span className="leading-none text-zinc-500">{createdAt}</span>
|
||||
|
@ -14,7 +14,7 @@ export function NotiRepost({ event }: { event: NDKEvent }) {
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start gap-1">
|
||||
<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>
|
||||
<span className="leading-none text-zinc-500">{createdAt}</span>
|
||||
|
@ -14,7 +14,7 @@ export function Protected({ children }: { children: ReactNode }) {
|
||||
if (status === 'loading') {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
@ -75,10 +75,7 @@ export function User({
|
||||
</button>
|
||||
</Popover.Trigger>
|
||||
<div
|
||||
className={twMerge(
|
||||
'flex flex-1 items-baseline justify-between',
|
||||
isRepost ? 'mt-4' : ''
|
||||
)}
|
||||
className={twMerge('flex flex-1 items-baseline gap-2', isRepost ? 'mt-4' : '')}
|
||||
>
|
||||
<h5
|
||||
className={twMerge(
|
||||
@ -91,6 +88,7 @@ export function User({
|
||||
user?.display_name ||
|
||||
shortenKey(pubkey)}
|
||||
</h5>
|
||||
<span className="leading-none text-white/50">·</span>
|
||||
<span className="leading-none text-white/50">{createdAt}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@ import { NDKFilter } from '@nostr-dev-kit/ndk';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { useNDK } from '@libs/ndk/provider';
|
||||
import { createMetadata, getUserMetadata } from '@libs/storage';
|
||||
import { createMetadata } from '@libs/storage';
|
||||
|
||||
export function useProfile(pubkey: string, fallback?: string) {
|
||||
const { ndk } = useNDK();
|
||||
@ -15,20 +15,14 @@ export function useProfile(pubkey: string, fallback?: string) {
|
||||
['user', pubkey],
|
||||
async () => {
|
||||
if (!fallback) {
|
||||
const current = Math.floor(Date.now() / 1000);
|
||||
const cache = await getUserMetadata(pubkey);
|
||||
if (cache && parseInt(cache.created_at) + 86400 >= current) {
|
||||
return JSON.parse(cache.content);
|
||||
const filter: NDKFilter = { kinds: [0], authors: [pubkey] };
|
||||
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 {
|
||||
const filter: NDKFilter = { kinds: [0], authors: [pubkey] };
|
||||
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');
|
||||
}
|
||||
throw new Error('User not found');
|
||||
}
|
||||
} else {
|
||||
const profile = JSON.parse(fallback);
|
||||
|
Loading…
Reference in New Issue
Block a user