update channel

This commit is contained in:
Ren Amamiya 2023-05-29 22:04:50 +07:00
parent 0492729e7e
commit c8f643198e
18 changed files with 340 additions and 467 deletions

View File

@ -15,19 +15,19 @@
"dependencies": {
"@floating-ui/react": "^0.23.1",
"@headlessui/react": "^1.7.14",
"@tanstack/react-query": "^4.29.7",
"@tanstack/react-query": "^4.29.11",
"@tanstack/react-virtual": "3.0.0-beta.54",
"@tauri-apps/api": "^1.3.0",
"@vidstack/react": "^0.4.5",
"dayjs": "^1.11.7",
"destr": "^1.2.2",
"jotai": "^2.1.0",
"immer": "^10.0.2",
"light-bolt11-decoder": "^3.0.0",
"nostr-relaypool": "^0.6.27",
"nostr-relaypool": "^0.6.28",
"nostr-tools": "^1.11.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.43.9",
"react-hook-form": "^7.44.2",
"react-markdown": "^8.0.7",
"react-virtuoso": "^4.3.8",
"remark-gfm": "^3.0.1",
@ -43,8 +43,8 @@
"devDependencies": {
"@tailwindcss/typography": "^0.5.9",
"@tauri-apps/cli": "^1.3.1",
"@types/node": "^18.16.14",
"@types/react": "^18.2.6",
"@types/node": "^18.16.16",
"@types/react": "^18.2.7",
"@types/react-dom": "^18.2.4",
"@types/youtube-player": "^5.5.7",
"@vitejs/plugin-react-swc": "^3.3.1",
@ -54,13 +54,13 @@
"encoding": "^0.1.13",
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"postcss": "^8.4.23",
"postcss": "^8.4.24",
"prop-types": "^15.8.1",
"rome": "12.1.0",
"tailwindcss": "^3.3.2",
"typescript": "^4.9.5",
"vite": "^4.3.8",
"vite-plugin-ssr": "^0.4.126",
"vite": "^4.3.9",
"vite-plugin-ssr": "^0.4.130",
"vite-plugin-top-level-await": "^1.3.1",
"vite-tsconfig-paths": "^4.2.0",
"ws": "^8.13.0"

View File

@ -8,8 +8,8 @@ dependencies:
specifier: ^1.7.14
version: 1.7.14(react-dom@18.2.0)(react@18.2.0)
'@tanstack/react-query':
specifier: ^4.29.7
version: 4.29.7(react-dom@18.2.0)(react@18.2.0)
specifier: ^4.29.11
version: 4.29.11(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)
@ -18,22 +18,22 @@ dependencies:
version: 1.3.0
'@vidstack/react':
specifier: ^0.4.5
version: 0.4.5(@types/react@18.2.6)(maverick.js@0.33.1)(media-icons@0.4.2)(react@18.2.0)(vidstack@0.4.5)
version: 0.4.5(@types/react@18.2.7)(maverick.js@0.33.1)(media-icons@0.4.2)(react@18.2.0)(vidstack@0.4.5)
dayjs:
specifier: ^1.11.7
version: 1.11.7
destr:
specifier: ^1.2.2
version: 1.2.2
jotai:
specifier: ^2.1.0
version: 2.1.0(react@18.2.0)
immer:
specifier: ^10.0.2
version: 10.0.2
light-bolt11-decoder:
specifier: ^3.0.0
version: 3.0.0
nostr-relaypool:
specifier: ^0.6.27
version: 0.6.27(ws@8.13.0)
specifier: ^0.6.28
version: 0.6.28(ws@8.13.0)
nostr-tools:
specifier: ^1.11.1
version: 1.11.1
@ -44,11 +44,11 @@ dependencies:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
react-hook-form:
specifier: ^7.43.9
version: 7.43.9(react@18.2.0)
specifier: ^7.44.2
version: 7.44.2(react@18.2.0)
react-markdown:
specifier: ^8.0.7
version: 8.0.7(@types/react@18.2.6)(react@18.2.0)
version: 8.0.7(@types/react@18.2.7)(react@18.2.0)
react-virtuoso:
specifier: ^4.3.8
version: 4.3.8(react-dom@18.2.0)(react@18.2.0)
@ -78,7 +78,7 @@ dependencies:
version: 0.4.5
zustand:
specifier: ^4.3.8
version: 4.3.8(react@18.2.0)
version: 4.3.8(immer@10.0.2)(react@18.2.0)
devDependencies:
'@tailwindcss/typography':
@ -88,11 +88,11 @@ devDependencies:
specifier: ^1.3.1
version: 1.3.1
'@types/node':
specifier: ^18.16.14
version: 18.16.14
specifier: ^18.16.16
version: 18.16.16
'@types/react':
specifier: ^18.2.6
version: 18.2.6
specifier: ^18.2.7
version: 18.2.7
'@types/react-dom':
specifier: ^18.2.4
version: 18.2.4
@ -101,10 +101,10 @@ devDependencies:
version: 5.5.7
'@vitejs/plugin-react-swc':
specifier: ^3.3.1
version: 3.3.1(vite@4.3.8)
version: 3.3.1(vite@4.3.9)
autoprefixer:
specifier: ^10.4.14
version: 10.4.14(postcss@8.4.23)
version: 10.4.14(postcss@8.4.24)
cross-env:
specifier: ^7.0.3
version: 7.0.3
@ -121,8 +121,8 @@ devDependencies:
specifier: ^13.2.2
version: 13.2.2
postcss:
specifier: ^8.4.23
version: 8.4.23
specifier: ^8.4.24
version: 8.4.24
prop-types:
specifier: ^15.8.1
version: 15.8.1
@ -136,17 +136,17 @@ devDependencies:
specifier: ^4.9.5
version: 4.9.5
vite:
specifier: ^4.3.8
version: 4.3.8(@types/node@18.16.14)
specifier: ^4.3.9
version: 4.3.9(@types/node@18.16.16)
vite-plugin-ssr:
specifier: ^0.4.126
version: 0.4.126(vite@4.3.8)
specifier: ^0.4.130
version: 0.4.130(vite@4.3.9)
vite-plugin-top-level-await:
specifier: ^1.3.1
version: 1.3.1(vite@4.3.8)
version: 1.3.1(vite@4.3.9)
vite-tsconfig-paths:
specifier: ^4.2.0
version: 4.2.0(typescript@4.9.5)(vite@4.3.8)
version: 4.2.0(typescript@4.9.5)(vite@4.3.9)
ws:
specifier: ^8.13.0
version: 8.13.0
@ -378,8 +378,8 @@ packages:
resolution: {integrity: sha512-EvYTiXet5XqweYGClEmpu3BoxmsQ4hkj3QaYA6qEnigCWffTP3vNRwBReTdrwDwo7OoJ3wM8Uoe9Uk4n+d4hfg==}
dev: false
/@floating-ui/dom@1.2.8:
resolution: {integrity: sha512-XLwhYV90MxiHDq6S0rzFZj00fnDM+A1R9jhSioZoMsa7G0Q0i+Q4x40ajR8FHSdYDE1bgjG45mIWe6jtv9UPmg==}
/@floating-ui/dom@1.2.9:
resolution: {integrity: sha512-sosQxsqgxMNkV3C+3UqTS6LxP7isRLwX8WMepp843Rb3/b0Wz8+MdUkxJksByip3C2WwLugLHN1b4ibn//zKwQ==}
dependencies:
'@floating-ui/core': 1.2.6
dev: false
@ -390,7 +390,7 @@ packages:
react: '>=16.8.0'
react-dom: '>=16.8.0'
dependencies:
'@floating-ui/dom': 1.2.8
'@floating-ui/dom': 1.2.9
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
@ -580,8 +580,8 @@ packages:
'@scure/base': 1.1.1
dev: false
/@swc/core-darwin-arm64@1.3.59:
resolution: {integrity: sha512-AnqWFBgEKHP0jb4iZqx7eVQT9/rX45+DE4Ox7GpwCahUKxxrsDLyXzKhwLwQuAjUvtu5JcSB77szKpPGDM49fQ==}
/@swc/core-darwin-arm64@1.3.60:
resolution: {integrity: sha512-oCDKWGdSO1WyErduGfiITRDoq7ZBt9PXETlhi8BGKH/wCc/3mfSNI9wXAg3Stn8mrT0lUJtdsnwMI/eZp6dK+A==}
engines: {node: '>=10'}
cpu: [arm64]
os: [darwin]
@ -589,8 +589,8 @@ packages:
dev: true
optional: true
/@swc/core-darwin-x64@1.3.59:
resolution: {integrity: sha512-iqDs+yii9mOsmpJez82SEi4d4prWDRlapHxKnDVJ0x1AqRo41vIq8t3fujrvCHYU5VQgOYGh4ooXQpaP2H3B2A==}
/@swc/core-darwin-x64@1.3.60:
resolution: {integrity: sha512-pcE/1oUlmN/BkKndOPtViqTkaM5pomagXATo+Muqn4QNMnkSOEVcmF9T3Lr3nB1A7O/fwCew3/aHwZ5B2TZ1tA==}
engines: {node: '>=10'}
cpu: [x64]
os: [darwin]
@ -598,8 +598,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-arm-gnueabihf@1.3.59:
resolution: {integrity: sha512-PB0PP+SgkCSd/kYmltnPiGv42cOSaih1OjXCEjxvNwUFEmWqluW6uGdWaNiR1LoYMxhcHZTc336jL2+O3l6p0Q==}
/@swc/core-linux-arm-gnueabihf@1.3.60:
resolution: {integrity: sha512-Moc+86SWcbPr06PaQYUb0Iwli425F7QgjwTCNEPYA6OYUsjaJhXMaHViW2WdGIXue2+eaQbg31BHQd14jXcoBg==}
engines: {node: '>=10'}
cpu: [arm]
os: [linux]
@ -607,8 +607,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-arm64-gnu@1.3.59:
resolution: {integrity: sha512-Ol/JPszWZ+OZ44FOdJe35TfJ1ckG4pYaisZJ4E7PzfwfVe2ygX85C5WWR4e5L0Y1zFvzpcI7gdyC2wzcXk4Cig==}
/@swc/core-linux-arm64-gnu@1.3.60:
resolution: {integrity: sha512-pPGZrTgSXBvp6IrXPXz8UJr82AElf8hMuK4rNHmLGDCqrWnRIFLUpiAsc2WCFIgdwqitZNQoM+F2vbceA/bkKg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
@ -616,8 +616,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-arm64-musl@1.3.59:
resolution: {integrity: sha512-PtTTtGbj9GiY5gJdoSFL2A0vL6BRaS1haAhp6g3hZvLDkTTg+rJURmzwBMMjaQlnGC62x/lLf6MoszHG/05//Q==}
/@swc/core-linux-arm64-musl@1.3.60:
resolution: {integrity: sha512-HSFQaVUkjWYNsQeymAQ3IPX3csRQvHe6MFyqPfvCCQ4dFlxPvlS7VvNaLnGG+ZW1ek7Lc+hEX+4NGzZKsxDIHA==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
@ -625,8 +625,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-x64-gnu@1.3.59:
resolution: {integrity: sha512-XBW9AGi0YsIN76IfesnDSBn/5sjR69J75KUNte8sH6seYlHJ0/kblqUMbUcfr0CiGoJadbzAZeKZZmfN7EsHpg==}
/@swc/core-linux-x64-gnu@1.3.60:
resolution: {integrity: sha512-WJt/X6HHM3/TszckRA7UKMXec3FHYsB9xswQbIYxN4bfTQodu3Rc8bmpHYtFO7ScMLrhY+RljHLK6wclPvaEXw==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
@ -634,8 +634,8 @@ packages:
dev: true
optional: true
/@swc/core-linux-x64-musl@1.3.59:
resolution: {integrity: sha512-Cy5E939SdWPQ34cg6UABNO0RyEe0FuWqzZ/GLKtK11Ir4fjttVlucZiY59uQNyUVUc8T2qE0VBFCyD/zYGuHtg==}
/@swc/core-linux-x64-musl@1.3.60:
resolution: {integrity: sha512-DGGBqAPUXy/aPMBKokL3osZC9kM97HchiDPuprzwgTMP40YQ3hGCzNJ5jK7sOk9Tc4PEdZ2Igfr9sBHmCrxxQw==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
@ -643,8 +643,8 @@ packages:
dev: true
optional: true
/@swc/core-win32-arm64-msvc@1.3.59:
resolution: {integrity: sha512-z5ZJxizRvRoSAaevRIi3YjQh74OFWEIhonSDWNdqDL7RbjEivcatYcG7OikH6s+rtPhOcwNm3PbGV2Prcgh/gg==}
/@swc/core-win32-arm64-msvc@1.3.60:
resolution: {integrity: sha512-wQg/BZPJvp5WpUbsBp7VHjhUh0DfYOPhP6dH67WO9QQ07+DvOk2DR2Bfh0z0ts1k7H/FsAqExWtTDCWMCRJiRQ==}
engines: {node: '>=10'}
cpu: [arm64]
os: [win32]
@ -652,8 +652,8 @@ packages:
dev: true
optional: true
/@swc/core-win32-ia32-msvc@1.3.59:
resolution: {integrity: sha512-vxpsn+hrKAhi5YusQfB/JXUJJVX40rIRE/L49ilBEqdbH8Khkoego6AD+2vWqTdJcUHo1WiAIAEZ0rTsjyorLQ==}
/@swc/core-win32-ia32-msvc@1.3.60:
resolution: {integrity: sha512-nqkd0XIVyGbnBwAxP4GIfx6n45/hAPETpmQYpDSGnucOKFJfvGdFGL81GDG1acPCq/oFtR3tIyTbPpKmJ0N6xQ==}
engines: {node: '>=10'}
cpu: [ia32]
os: [win32]
@ -661,8 +661,8 @@ packages:
dev: true
optional: true
/@swc/core-win32-x64-msvc@1.3.59:
resolution: {integrity: sha512-Ris/cJbURylcLwqz4RZUUBCEGsuaIHOJsvf69W5pGKHKBryVoOTNhBKpo3Km2hoAi5qFQ/ou0trAT4hBsVPZvQ==}
/@swc/core-win32-x64-msvc@1.3.60:
resolution: {integrity: sha512-ouw+s22i9PYQpSE7Xc+ZittEyA87jElXABesviSpP+jgHt10sM5KFUpVAeV8DRlxJCXMJJ5AhOdCf4TAtFr+6A==}
engines: {node: '>=10'}
cpu: [x64]
os: [win32]
@ -670,8 +670,8 @@ packages:
dev: true
optional: true
/@swc/core@1.3.59:
resolution: {integrity: sha512-ZBw31zd2E5SXiodwGvjQdx5ZC90b2uyX/i2LeMMs8LKfXD86pfOfQac+JVrnyEKDhASXj9icgsF9NXBhaMr3Kw==}
/@swc/core@1.3.60:
resolution: {integrity: sha512-dWfic7sVjnrStzGcMWakHd2XPau8UXGPmFUTkx6xGX+DOVtfAQVzG6ZW7ohw/yNcTqI05w6Ser26XMTMGBgXdA==}
engines: {node: '>=10'}
requiresBuild: true
peerDependencies:
@ -680,16 +680,16 @@ packages:
'@swc/helpers':
optional: true
optionalDependencies:
'@swc/core-darwin-arm64': 1.3.59
'@swc/core-darwin-x64': 1.3.59
'@swc/core-linux-arm-gnueabihf': 1.3.59
'@swc/core-linux-arm64-gnu': 1.3.59
'@swc/core-linux-arm64-musl': 1.3.59
'@swc/core-linux-x64-gnu': 1.3.59
'@swc/core-linux-x64-musl': 1.3.59
'@swc/core-win32-arm64-msvc': 1.3.59
'@swc/core-win32-ia32-msvc': 1.3.59
'@swc/core-win32-x64-msvc': 1.3.59
'@swc/core-darwin-arm64': 1.3.60
'@swc/core-darwin-x64': 1.3.60
'@swc/core-linux-arm-gnueabihf': 1.3.60
'@swc/core-linux-arm64-gnu': 1.3.60
'@swc/core-linux-arm64-musl': 1.3.60
'@swc/core-linux-x64-gnu': 1.3.60
'@swc/core-linux-x64-musl': 1.3.60
'@swc/core-win32-arm64-msvc': 1.3.60
'@swc/core-win32-ia32-msvc': 1.3.60
'@swc/core-win32-x64-msvc': 1.3.60
dev: true
/@tailwindcss/typography@0.5.9(tailwindcss@3.3.2):
@ -704,12 +704,12 @@ packages:
tailwindcss: 3.3.2
dev: true
/@tanstack/query-core@4.29.7:
resolution: {integrity: sha512-GXG4b5hV2Loir+h2G+RXhJdoZhJLnrBWsuLB2r0qBRyhWuXq9w/dWxzvpP89H0UARlH6Mr9DiVj4SMtpkF/aUA==}
/@tanstack/query-core@4.29.11:
resolution: {integrity: sha512-8C+hF6SFAb/TlFZyS9FItgNwrw4PMa7YeX+KQYe2ZAiEz6uzg6yIr+QBzPkUwZ/L0bXvGd1sufTm3wotoz+GwQ==}
dev: false
/@tanstack/react-query@4.29.7(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-ijBWEzAIo09fB1yd22slRZzprrZ5zMdWYzBnCg5qiXuFbH78uGN1qtGz8+Ed4MuhaPaYSD+hykn+QEKtQviEtg==}
/@tanstack/react-query@4.29.11(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-aLaOAhBnCr12YKPjDsZOc0fAtkyaW7f9KfVfw49oYpfe0H9EPXBUgDBIKJ8qdHF3uGzTVSMcmpiw1Za41BLZlw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
@ -720,7 +720,7 @@ packages:
react-native:
optional: true
dependencies:
'@tanstack/query-core': 4.29.7
'@tanstack/query-core': 4.29.11
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
use-sync-external-store: 1.2.0(react@18.2.0)
@ -857,8 +857,8 @@ packages:
resolution: {integrity: sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==}
dev: false
/@types/lodash@4.14.194:
resolution: {integrity: sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==}
/@types/lodash@4.14.195:
resolution: {integrity: sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==}
dev: false
/@types/mdast@3.0.11:
@ -871,8 +871,8 @@ packages:
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
dev: false
/@types/node@18.16.14:
resolution: {integrity: sha512-+ImzUB3mw2c5ISJUq0punjDilUQ5GnUim0ZRvchHIWJmOC0G+p0kzhXBqj6cDjK0QdPFwzrHWgrJp3RPvCG5qg==}
/@types/node@18.16.16:
resolution: {integrity: sha512-NpaM49IGQQAUlBhHMF82QH80J08os4ZmyF9MkpCzWAGuOHqE4gTEbhzd7L3l5LmWuZ6E0OiC1FweQ4tsiW35+g==}
dev: true
/@types/prop-types@15.7.5:
@ -881,11 +881,11 @@ packages:
/@types/react-dom@18.2.4:
resolution: {integrity: sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==}
dependencies:
'@types/react': 18.2.6
'@types/react': 18.2.7
dev: true
/@types/react@18.2.6:
resolution: {integrity: sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==}
/@types/react@18.2.7:
resolution: {integrity: sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw==}
dependencies:
'@types/prop-types': 15.7.5
'@types/scheduler': 0.16.3
@ -902,7 +902,7 @@ packages:
resolution: {integrity: sha512-W8F4eoTIvzXeNrT3JroQPimZLXnlJA8smYygHZUKFPVoYwgs/OhJkA1VBhL3iSs57OQkuINqHlY4SmMT5wtnJg==}
dev: true
/@vidstack/react@0.4.5(@types/react@18.2.6)(maverick.js@0.33.1)(media-icons@0.4.2)(react@18.2.0)(vidstack@0.4.5):
/@vidstack/react@0.4.5(@types/react@18.2.7)(maverick.js@0.33.1)(media-icons@0.4.2)(react@18.2.0)(vidstack@0.4.5):
resolution: {integrity: sha512-spcim3+p1fMzkhHRKn5PS54YQjfThW5M3F2+R8tCT+wpsxbbCDa/TGdLBoIy2oC0LNziPkn0vlBWIZko9F5iig==}
engines: {node: '>=16'}
peerDependencies:
@ -912,20 +912,20 @@ packages:
react: ^18.0.0
vidstack: 0.4.5
dependencies:
'@types/react': 18.2.6
'@types/react': 18.2.7
maverick.js: 0.33.1
media-icons: 0.4.2
react: 18.2.0
vidstack: 0.4.5
dev: false
/@vitejs/plugin-react-swc@3.3.1(vite@4.3.8):
/@vitejs/plugin-react-swc@3.3.1(vite@4.3.9):
resolution: {integrity: sha512-ZoYjGxMniXP7X+5ry/W1tpY7w0OeLUEsBF5RHFPmAhpgwwNWie8OF4056MRXRi9QgvYYoZPDzdOXGK3wlCoTfQ==}
peerDependencies:
vite: ^4
dependencies:
'@swc/core': 1.3.59
vite: 4.3.8(@types/node@18.16.14)
'@swc/core': 1.3.60
vite: 4.3.9(@types/node@18.16.16)
transitivePeerDependencies:
- '@swc/helpers'
dev: true
@ -1001,19 +1001,19 @@ packages:
engines: {node: '>=8'}
dev: true
/autoprefixer@10.4.14(postcss@8.4.23):
/autoprefixer@10.4.14(postcss@8.4.24):
resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
dependencies:
browserslist: 4.21.5
browserslist: 4.21.6
caniuse-lite: 1.0.30001489
fraction.js: 4.2.0
normalize-range: 0.1.2
picocolors: 1.0.0
postcss: 8.4.23
postcss: 8.4.24
postcss-value-parser: 4.2.0
dev: true
@ -1044,15 +1044,15 @@ packages:
fill-range: 7.0.1
dev: true
/browserslist@4.21.5:
resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==}
/browserslist@4.21.6:
resolution: {integrity: sha512-PF07dKGXKR+/bljJzCB6rAYtHEu21TthLxmJagtQizx+rwiqdRDBO5971Xu1N7MgcMLi4+mr4Cnl76x7O3DHtA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001489
electron-to-chromium: 1.4.405
electron-to-chromium: 1.4.411
node-releases: 2.0.12
update-browserslist-db: 1.0.11(browserslist@4.21.5)
update-browserslist-db: 1.0.11(browserslist@4.21.6)
dev: true
/cac@6.7.14:
@ -1249,8 +1249,8 @@ packages:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: true
/electron-to-chromium@1.4.405:
resolution: {integrity: sha512-JdDgnwU69FMZURoesf9gNOej2Cms1XJFfLk24y1IBtnAdhTcJY/mXnokmpmxHN59PcykBP4bgUU98vLY44Lhuw==}
/electron-to-chromium@1.4.411:
resolution: {integrity: sha512-5VXLW4Qw89vM2WTICHua/y8v7fKGDRVa2VPOtBB9IpLvW316B+xd8yD1wTmLPY2ot/00P/qt87xdolj4aG/Lzg==}
dev: true
/emoji-regex@8.0.0:
@ -1441,6 +1441,10 @@ packages:
safer-buffer: 2.1.2
dev: true
/immer@10.0.2:
resolution: {integrity: sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==}
dev: false
/immer@9.0.21:
resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
dev: false
@ -1546,18 +1550,6 @@ packages:
hasBin: true
dev: true
/jotai@2.1.0(react@18.2.0):
resolution: {integrity: sha512-fR82PtHAmEQrc/daMEYGc4EteW96/b6wodtDSCzLvoJA/6y4YG70er4hh2f8CYwYjqwQ0eZUModGfG4DmwkTyQ==}
engines: {node: '>=12.20.0'}
peerDependencies:
react: '>=17.0.0'
peerDependenciesMeta:
react:
optional: true
dependencies:
react: 18.2.0
dev: false
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@ -1598,7 +1590,7 @@ packages:
object-inspect: 1.12.3
pidtree: 0.6.0
string-argv: 0.3.2
yaml: 2.3.0
yaml: 2.3.1
transitivePeerDependencies:
- enquirer
- supports-color
@ -2134,8 +2126,8 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/nostr-relaypool@0.6.27(ws@8.13.0):
resolution: {integrity: sha512-YtQxb8z9VHsPEQfC4rkxztqyGvWM1kcwiLhp/N8PpZX1+9mJhoIFctgpGxWB1LXhZgRiyJfY5Ml4EklvtWELuw==}
/nostr-relaypool@0.6.28(ws@8.13.0):
resolution: {integrity: sha512-kyLChBunf6IB2O3MSPHBe9iSokBGyqZHvAJXZ5+eh9C4znAu7iY8L/yh0V4Ta/P9TtzDna3QTEgFWVan4m0vBA==}
dependencies:
'@jest/source-map': 29.4.3
isomorphic-ws: 5.0.0(ws@8.13.0)
@ -2246,29 +2238,29 @@ packages:
engines: {node: '>= 6'}
dev: true
/postcss-import@15.1.0(postcss@8.4.23):
/postcss-import@15.1.0(postcss@8.4.24):
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
engines: {node: '>=14.0.0'}
peerDependencies:
postcss: ^8.0.0
dependencies:
postcss: 8.4.23
postcss: 8.4.24
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.2
dev: true
/postcss-js@4.0.1(postcss@8.4.23):
/postcss-js@4.0.1(postcss@8.4.24):
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
engines: {node: ^12 || ^14 || >= 16}
peerDependencies:
postcss: ^8.4.21
dependencies:
camelcase-css: 2.0.1
postcss: 8.4.23
postcss: 8.4.24
dev: true
/postcss-load-config@4.0.1(postcss@8.4.23):
/postcss-load-config@4.0.1(postcss@8.4.24):
resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
engines: {node: '>= 14'}
peerDependencies:
@ -2281,17 +2273,17 @@ packages:
optional: true
dependencies:
lilconfig: 2.1.0
postcss: 8.4.23
yaml: 2.3.0
postcss: 8.4.24
yaml: 2.3.1
dev: true
/postcss-nested@6.0.1(postcss@8.4.23):
/postcss-nested@6.0.1(postcss@8.4.24):
resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
engines: {node: '>=12.0'}
peerDependencies:
postcss: ^8.2.14
dependencies:
postcss: 8.4.23
postcss: 8.4.24
postcss-selector-parser: 6.0.13
dev: true
@ -2315,8 +2307,8 @@ packages:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
dev: true
/postcss@8.4.23:
resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==}
/postcss@8.4.24:
resolution: {integrity: sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.6
@ -2349,8 +2341,8 @@ packages:
scheduler: 0.23.0
dev: false
/react-hook-form@7.43.9(react@18.2.0):
resolution: {integrity: sha512-AUDN3Pz2NSeoxQ7Hs6OhQhDr6gtF9YRuutGDwPQqhSUAHJSgGl2VeY3qN19MG0SucpjgDiuMJ4iC5T5uB+eaNQ==}
/react-hook-form@7.44.2(react@18.2.0):
resolution: {integrity: sha512-IyihmIbCwzDI/iqlecTRa7+4BCnzNx40upSlGvIU7qwENhTf6APatm4bmL9ANtWKPYlD67SIlxfls7GwCUe+Lg==}
engines: {node: '>=12.22.0'}
peerDependencies:
react: ^16.8.0 || ^17 || ^18
@ -2365,7 +2357,7 @@ packages:
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
dev: false
/react-markdown@8.0.7(@types/react@18.2.6)(react@18.2.0):
/react-markdown@8.0.7(@types/react@18.2.7)(react@18.2.0):
resolution: {integrity: sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==}
peerDependencies:
'@types/react': '>=16'
@ -2373,7 +2365,7 @@ packages:
dependencies:
'@types/hast': 2.3.4
'@types/prop-types': 15.7.5
'@types/react': 18.2.6
'@types/react': 18.2.7
'@types/unist': 2.0.6
comma-separated-tokens: 2.0.3
hast-util-whitespace: 2.0.1
@ -2584,7 +2576,7 @@ packages:
dependencies:
'@juggle/resize-observer': 3.4.0
'@types/is-hotkey': 0.1.7
'@types/lodash': 4.14.194
'@types/lodash': 4.14.195
direction: 1.0.4
is-hotkey: 0.1.8
is-plain-object: 5.0.0
@ -2659,7 +2651,7 @@ packages:
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.0.1
strip-ansi: 7.1.0
dev: true
/strip-ansi@6.0.1:
@ -2669,8 +2661,8 @@ packages:
ansi-regex: 5.0.1
dev: true
/strip-ansi@7.0.1:
resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==}
/strip-ansi@7.1.0:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
dependencies:
ansi-regex: 6.0.1
@ -2742,11 +2734,11 @@ packages:
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.0.0
postcss: 8.4.23
postcss-import: 15.1.0(postcss@8.4.23)
postcss-js: 4.0.1(postcss@8.4.23)
postcss-load-config: 4.0.1(postcss@8.4.23)
postcss-nested: 6.0.1(postcss@8.4.23)
postcss: 8.4.24
postcss-import: 15.1.0(postcss@8.4.24)
postcss-js: 4.0.1(postcss@8.4.24)
postcss-load-config: 4.0.1(postcss@8.4.24)
postcss-nested: 6.0.1(postcss@8.4.24)
postcss-selector-parser: 6.0.13
postcss-value-parser: 4.2.0
resolve: 1.22.2
@ -2885,13 +2877,13 @@ packages:
unist-util-visit-parents: 5.1.3
dev: false
/update-browserslist-db@1.0.11(browserslist@4.21.5):
/update-browserslist-db@1.0.11(browserslist@4.21.6):
resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
dependencies:
browserslist: 4.21.5
browserslist: 4.21.6
escalade: 3.1.1
picocolors: 1.0.0
dev: true
@ -2950,8 +2942,8 @@ packages:
type-fest: 3.11.0
dev: false
/vite-plugin-ssr@0.4.126(vite@4.3.8):
resolution: {integrity: sha512-mQr9vFiiIh49KST8iCodwr8x6c9+ldu+LFAVJQJiQdW7Z7WgjyiF7833pVSsDFfw0bIFHoxtN2eoY75bxUQHHA==}
/vite-plugin-ssr@0.4.130(vite@4.3.9):
resolution: {integrity: sha512-EYyTeOviS6P7bFod1FxV+mglRckEh+jWdFYMMnoT7zz2MQyCSQQs/mZ/EXPyeqPY4PwvwAY3MzPbb0bPdUA+PA==}
engines: {node: '>=12.19.0'}
hasBin: true
peerDependencies:
@ -2971,24 +2963,24 @@ packages:
esbuild: 0.17.19
fast-glob: 3.2.12
sirv: 2.0.3
vite: 4.3.8(@types/node@18.16.14)
vite: 4.3.9(@types/node@18.16.16)
dev: true
/vite-plugin-top-level-await@1.3.1(vite@4.3.8):
/vite-plugin-top-level-await@1.3.1(vite@4.3.9):
resolution: {integrity: sha512-55M1h4NAwkrpxPNOJIBzKZFihqLUzIgnElLSmPNPMR2Fn9+JHKaNg3sVX1Fq+VgvuBksQYxiD3OnwQAUu7kaPQ==}
peerDependencies:
vite: '>=2.8'
dependencies:
'@rollup/plugin-virtual': 3.0.1
'@swc/core': 1.3.59
'@swc/core': 1.3.60
uuid: 9.0.0
vite: 4.3.8(@types/node@18.16.14)
vite: 4.3.9(@types/node@18.16.16)
transitivePeerDependencies:
- '@swc/helpers'
- rollup
dev: true
/vite-tsconfig-paths@4.2.0(typescript@4.9.5)(vite@4.3.8):
/vite-tsconfig-paths@4.2.0(typescript@4.9.5)(vite@4.3.9):
resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==}
peerDependencies:
vite: '*'
@ -2999,14 +2991,14 @@ packages:
debug: 4.3.4
globrex: 0.1.2
tsconfck: 2.1.1(typescript@4.9.5)
vite: 4.3.8(@types/node@18.16.14)
vite: 4.3.9(@types/node@18.16.16)
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/vite@4.3.8(@types/node@18.16.14):
resolution: {integrity: sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==}
/vite@4.3.9(@types/node@18.16.16):
resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
@ -3030,9 +3022,9 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 18.16.14
'@types/node': 18.16.16
esbuild: 0.17.19
postcss: 8.4.23
postcss: 8.4.24
rollup: 3.23.0
optionalDependencies:
fsevents: 2.3.2
@ -3080,12 +3072,12 @@ packages:
utf-8-validate:
optional: true
/yaml@2.3.0:
resolution: {integrity: sha512-8/1wgzdKc7bc9E6my5wZjmdavHLvO/QOmLG1FBugblEvY4IXrLjlViIOmL24HthU042lWTDRO90Fz1Yp66UnMw==}
engines: {node: '>= 14', npm: '>= 7'}
/yaml@2.3.1:
resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
engines: {node: '>= 14'}
dev: true
/zustand@4.3.8(react@18.2.0):
/zustand@4.3.8(immer@10.0.2)(react@18.2.0):
resolution: {integrity: sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==}
engines: {node: '>=12.7.0'}
peerDependencies:
@ -3097,6 +3089,7 @@ packages:
react:
optional: true
dependencies:
immer: 10.0.2
react: 18.2.0
use-sync-external-store: 1.2.0(react@18.2.0)
dev: false

View File

@ -4,7 +4,7 @@ import { DEFAULT_AVATAR } from "@stores/constants";
import { useProfile } from "@utils/hooks/useProfile";
export default function MiniMember({ pubkey }: { pubkey: string }) {
export function Member({ pubkey }: { pubkey: string }) {
const { user, isError, isLoading } = useProfile(pubkey);
return (

View File

@ -1,44 +1,13 @@
import MiniMember from "@app/channel/components/miniMember";
import { channelMembersAtom } from "@stores/channel";
import { useAtomValue } from "jotai";
export default function ChannelMembers() {
const membersAsSet = useAtomValue(channelMembersAtom);
const membersAsArray = [...membersAsSet];
const miniMembersList = membersAsArray.slice(0, 4);
const totalMembers =
membersAsArray.length > 0
? `+${Intl.NumberFormat("en-US", {
notation: "compact",
maximumFractionDigits: 1,
}).format(membersAsArray.length)}`
: 0;
import { Member } from "@app/channel/components/member";
import { useChannelMessages } from "@stores/channels";
import { useEffect } from "react";
export function ChannelMembers() {
return (
<div>
<div className="group flex -space-x-2 overflow-hidden hover:-space-x-1">
{miniMembersList.map((member, index) => (
<MiniMember key={`item-${index}`} pubkey={member} />
))}
{totalMembers ? (
<div className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-zinc-900 ring-2 ring-zinc-950 transition-all duration-150 ease-in-out group-hover:bg-zinc-800">
<span className="text-base font-medium text-zinc-400 group-hover:text-white">
{totalMembers}
</span>
</div>
) : (
<div>
<button
type="button"
className="inline-flex h-8 items-center justify-center rounded-md bg-fuchsia-500 px-4 text-base text-white shadow-button"
>
Invite
</button>
</div>
)}
</div>
<div className="flex flex-wrap gap-1">
{[].map((member) => (
<Member key={member} pubkey={member} />
))}
</div>
);
}

View File

@ -9,6 +9,7 @@ export function ChannelMessageList() {
const virtuosoRef = useRef(null);
const messages = useChannelMessages((state: any) => state.messages);
const sorted = messages;
const itemContent: any = useCallback(
(index: string | number) => {
@ -33,10 +34,7 @@ export function ChannelMessageList() {
components={{
Header: () => (
<div className="relative py-4">
<div
className="absolute inset-0 flex items-center"
aria-hidden="true"
>
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-zinc-800" />
</div>
<div className="relative flex justify-center">

View File

@ -3,13 +3,11 @@ import CancelIcon from "@icons/cancel";
import { ImagePicker } from "@shared/form/imagePicker";
import { RelayContext } from "@shared/relayProvider";
import { useActiveAccount } from "@stores/accounts";
import { channelContentAtom, channelReplyAtom } from "@stores/channel";
import { useChannelMessages } from "@stores/channels";
import { WRITEONLY_RELAYS } from "@stores/constants";
import { dateToUnix } from "@utils/date";
import { useAtom, useAtomValue } from "jotai";
import { useResetAtom } from "jotai/utils";
import { getEventHash, getSignature } from "nostr-tools";
import { useContext } from "react";
import { useContext, useState } from "react";
export default function ChannelMessageForm({
channelID,
@ -17,20 +15,20 @@ export default function ChannelMessageForm({
const pool: any = useContext(RelayContext);
const account = useActiveAccount((state: any) => state.account);
const [value, setValue] = useAtom(channelContentAtom);
const resetValue = useResetAtom(channelContentAtom);
const channelReply = useAtomValue(channelReplyAtom);
const resetChannelReply = useResetAtom(channelReplyAtom);
const [value, setValue] = useState("");
const [replyTo, closeReply] = useChannelMessages((state: any) => [
state.replyTo,
state.closeReply,
]);
const submitEvent = () => {
let tags: any[][];
if (channelReply.id !== null) {
if (replyTo.id !== null) {
tags = [
["e", channelID, "", "root"],
["e", channelReply.id, "", "reply"],
["p", channelReply.pubkey, ""],
["e", replyTo.id, "", "reply"],
["p", replyTo.pubkey, ""],
];
} else {
tags = [["e", channelID, "", "root"]];
@ -50,11 +48,6 @@ export default function ChannelMessageForm({
// publish note
pool.publish(event, WRITEONLY_RELAYS);
// reset state
resetValue();
// reset channel reply
resetChannelReply();
} else {
console.log("error");
}
@ -68,24 +61,22 @@ export default function ChannelMessageForm({
};
const stopReply = () => {
resetChannelReply();
closeReply();
};
return (
<div
className={`relative ${
channelReply.id ? "h-36" : "h-24"
replyTo.id ? "h-36" : "h-24"
} w-full overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[11px] 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-[7px] after:shadow-highlight 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`}
>
{channelReply.id && (
{replyTo.id && (
<div className="absolute left-0 top-0 z-10 h-14 w-full p-[2px]">
<div className="flex h-full w-full items-center justify-between rounded-t-md border-b border-zinc-700/70 bg-zinc-900 px-3">
<div className="flex w-full flex-col">
<UserReply pubkey={channelReply.pubkey} />
<UserReply pubkey={replyTo.pubkey} />
<div className="-mt-3.5 pl-[32px]">
<div className="text-base text-white">
{channelReply.content}
</div>
<div className="text-base text-white">{replyTo.content}</div>
</div>
</div>
<button
@ -105,13 +96,12 @@ export default function ChannelMessageForm({
spellCheck={false}
placeholder="Message"
className={`relative ${
channelReply.id ? "h-36 pt-16" : "h-24 pt-3"
replyTo.id ? "h-36 pt-16" : "h-24 pt-3"
} w-full resize-none rounded-lg border border-black/5 px-3.5 pb-3 text-base shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-white dark:shadow-black/10 dark:placeholder:text-zinc-500`}
/>
<div className="absolute bottom-2 w-full px-2">
<div className="flex w-full items-center justify-between bg-zinc-800">
<div className="flex items-center gap-2 divide-x divide-zinc-700">
<ImagePicker type="channel" />
<div className="flex items-center gap-2 pl-2" />
</div>
<div className="flex items-center gap-2">

View File

@ -4,19 +4,18 @@ import HideIcon from "@icons/hide";
import { RelayContext } from "@shared/relayProvider";
import { Tooltip } from "@shared/tooltip";
import { useActiveAccount } from "@stores/accounts";
import { channelMessagesAtom } from "@stores/channel";
import { useChannelMessages } from "@stores/channels";
import { WRITEONLY_RELAYS } from "@stores/constants";
import { dateToUnix } from "@utils/date";
import { useAtom } from "jotai";
import { getEventHash, getSignature } from "nostr-tools";
import { Fragment, useContext, useState } from "react";
export default function MessageHideButton({ id }: { id: string }) {
export function MessageHideButton({ id }: { id: string }) {
const pool: any = useContext(RelayContext);
const account = useActiveAccount((state: any) => state.account);
const hide = useChannelMessages((state: any) => state.hideMessage);
const [isOpen, setIsOpen] = useState(false);
const [messages, setMessages] = useAtom(channelMessagesAtom);
const closeModal = () => {
setIsOpen(false);
@ -27,34 +26,25 @@ export default function MessageHideButton({ id }: { id: string }) {
};
const hideMessage = () => {
if (account) {
const event: any = {
content: "",
created_at: dateToUnix(),
kind: 43,
pubkey: account.pubkey,
tags: [["e", id]],
};
event.id = getEventHash(event);
event.sig = getSignature(event, account.privkey);
const event: any = {
content: "",
created_at: dateToUnix(),
kind: 43,
pubkey: account.pubkey,
tags: [["e", id]],
};
// publish note
pool.publish(event, WRITEONLY_RELAYS);
event.id = getEventHash(event);
event.sig = getSignature(event, account.privkey);
// update local state
const cloneMessages = [...messages];
const targetMessage = cloneMessages.findIndex(
(message) => message.id === id,
);
// publish note
pool.publish(event, WRITEONLY_RELAYS);
cloneMessages[targetMessage]["hide"] = true;
setMessages(cloneMessages);
// update state
hide(id);
// close modal
closeModal();
} else {
console.log("error");
}
// close modal
closeModal();
};
return (

View File

@ -1,25 +1,61 @@
import MessageHideButton from "@app/channel/components/messages/hideButton";
import MessageMuteButton from "@app/channel/components/messages/muteButton";
import MessageReplyButton from "@app/channel/components/messages/replyButton";
import { MessageHideButton } from "@app/channel/components/messages/hideButton";
import { MessageMuteButton } from "@app/channel/components/messages/muteButton";
import { MessageReplyButton } from "@app/channel/components/messages/replyButton";
import { ChannelMessageUser } from "@app/channel/components/messages/user";
import { MentionNote } from "@app/note/components/mentions/note";
import ImagePreview from "@app/note/components/preview/image";
import VideoPreview from "@app/note/components/preview/video";
import { noteParser } from "@utils/parser";
import { useMemo } from "react";
import { useMemo, useState } from "react";
export function ChannelMessageItem({ data }: { data: any }) {
const content = useMemo(() => noteParser(data), [data]);
const [hide, setHide] = useState(data.hide);
const toggleHide = () => {
setHide((prev) => !prev);
};
if (data.mute) return null;
return (
<div className="group relative flex h-min min-h-min w-full select-text flex-col px-5 py-3 hover:bg-black/20">
<div className="flex flex-col">
<ChannelMessageUser pubkey={data.pubkey} time={data.created_at} />
<div className="-mt-[20px] pl-[49px]">
<div className="whitespace-pre-line break-words text-base leading-tight">
{data.hide ? (
<span className="italic text-zinc-400">[hided message]</span>
) : (
content.parsed
)}
</div>
{hide ? (
<>
<p className="leading-tight italic text-zinc-400">
[hided message]
</p>
<button type="button" onClick={() => toggleHide()}>
show
</button>
</>
) : (
<>
<p className="whitespace-pre-line break-words text-base leading-tight">
{content.parsed}
</p>
{Array.isArray(content.images) && content.images.length ? (
<ImagePreview urls={content.images} />
) : (
<></>
)}
{Array.isArray(content.videos) && content.videos.length ? (
<VideoPreview urls={content.videos} />
) : (
<></>
)}
{Array.isArray(content.notes) && content.notes.length ? (
content.notes.map((note: string) => (
<MentionNote key={note} id={note} />
))
) : (
<></>
)}
</>
)}
</div>
</div>
<div className="absolute -top-4 right-4 z-10 hidden group-hover:inline-flex">

View File

@ -4,18 +4,17 @@ import MuteIcon from "@icons/mute";
import { RelayContext } from "@shared/relayProvider";
import { Tooltip } from "@shared/tooltip";
import { useActiveAccount } from "@stores/accounts";
import { channelMessagesAtom } from "@stores/channel";
import { useChannelMessages } from "@stores/channels";
import { WRITEONLY_RELAYS } from "@stores/constants";
import { dateToUnix } from "@utils/date";
import { useAtom } from "jotai";
import { getEventHash, getSignature } from "nostr-tools";
import { Fragment, useContext, useState } from "react";
export default function MessageMuteButton({ pubkey }: { pubkey: string }) {
export function MessageMuteButton({ pubkey }: { pubkey: string }) {
const pool: any = useContext(RelayContext);
const account = useActiveAccount((state: any) => state.account);
const mute = useChannelMessages((state: any) => state.muteUser);
const [messages, setMessages] = useAtom(channelMessagesAtom);
const [isOpen, setIsOpen] = useState(false);
const closeModal = () => {
@ -27,31 +26,25 @@ export default function MessageMuteButton({ pubkey }: { pubkey: string }) {
};
const muteUser = () => {
if (account) {
const event: any = {
content: "",
created_at: dateToUnix(),
kind: 44,
pubkey: account.pubkey,
tags: [["p", pubkey]],
};
event.id = getEventHash(event);
event.sig = getSignature(event, account.privkey);
const event: any = {
content: "",
created_at: dateToUnix(),
kind: 44,
pubkey: account.pubkey,
tags: [["p", pubkey]],
};
// publish note
pool.publish(event, WRITEONLY_RELAYS);
event.id = getEventHash(event);
event.sig = getSignature(event, account.privkey);
// update local state
const cloneMessages = [...messages];
const finalMessages = cloneMessages.filter(
(message) => message.pubkey !== pubkey,
);
setMessages(finalMessages);
// close modal
closeModal();
} else {
console.log("error");
}
// publish note
pool.publish(event, WRITEONLY_RELAYS);
// update state
mute(pubkey);
// close modal
closeModal();
};
return (

View File

@ -1,20 +1,16 @@
import { Tooltip } from "@shared/tooltip";
import ReplyMessageIcon from "@icons/replyMessage";
import { Tooltip } from "@shared/tooltip";
import { useChannelMessages } from "@stores/channels";
import { channelReplyAtom } from "@stores/channel";
import { useSetAtom } from "jotai";
export default function MessageReplyButton({
export function MessageReplyButton({
id,
pubkey,
content,
}: { id: string; pubkey: string; content: string }) {
const setChannelReplyAtom = useSetAtom(channelReplyAtom);
const openReply = useChannelMessages((state: any) => state.openReply);
const createReply = () => {
setChannelReplyAtom({ id: id, pubkey: pubkey, content: content });
openReply(id, pubkey, content);
};
return (

View File

@ -10,11 +10,14 @@ dayjs.extend(relativeTime);
export function ChannelMessageUser({
pubkey,
time,
}: { pubkey: string; time: number }) {
}: {
pubkey: string;
time: number;
}) {
const { user, isError, isLoading } = useProfile(pubkey);
return (
<div className="group flex items-start gap-3">
<div className="flex items-start gap-3">
{isError || isLoading ? (
<>
<div className="relative h-11 w-11 shrink animate-pulse rounded-md bg-zinc-800" />
@ -35,7 +38,7 @@ export function ChannelMessageUser({
</div>
<div className="flex w-full flex-1 items-start justify-between">
<div className="flex items-baseline gap-2 text-base">
<span className="font-semibold leading-none text-white group-hover:underline">
<span className="font-semibold leading-none text-white">
{user?.nip05 || user?.name || shortenKey(pubkey)}
</span>
<span className="leading-none text-zinc-500">·</span>

View File

@ -8,7 +8,7 @@ import { DEFAULT_AVATAR } from "@stores/constants";
import { nip19 } from "nostr-tools";
export default function ChannelMetadata({
export function ChannelMetadata({
id,
pubkey,
}: { id: string; pubkey: string }) {
@ -23,24 +23,24 @@ export default function ChannelMetadata({
};
return (
<div className="inline-flex items-center gap-2">
<div className="relative shrink-0 rounded-md">
<div className="flex flex-col gap-2">
<div className="relative shrink-0 rounded-md h-11 w-11">
<Image
src={metadata?.picture || DEFAULT_AVATAR}
alt={id}
className="h-8 w-8 rounded bg-zinc-900 object-contain ring-2 ring-zinc-950"
className="h-11 w-11 rounded-md object-contain bg-zinc-900"
/>
</div>
<div className="flex flex-col gap-1">
<div className="flex items-center gap-1">
<h5 className="truncate text-base font-medium leading-none text-white">
<div className="flex flex-col gap-2">
<div className="inline-flex items-center gap-1">
<h5 className="leading-none text-lg font-semibold">
{metadata?.name}
</h5>
<button type="button" onClick={() => copyNoteID()}>
<CopyIcon width={14} height={14} className="text-zinc-400" />
</button>
</div>
<p className="text-base leading-none text-zinc-400">
<p className="leading-tight text-zinc-400">
{metadata?.about || (noteID && `${noteID.substring(0, 24)}...`)}
</p>
</div>

View File

@ -1,8 +1,8 @@
import ChannelBlackList from "@app/channel/components/blacklist";
import ChannelMembers from "@app/channel/components/members";
import { ChannelMembers } from "@app/channel/components/members";
import { ChannelMessageList } from "@app/channel/components/messageList";
import ChannelMessageForm from "@app/channel/components/messages/form";
import ChannelMetadata from "@app/channel/components/metadata";
import { ChannelMetadata } from "@app/channel/components/metadata";
import ChannelUpdateModal from "@app/channel/components/updateModal";
import { RelayContext } from "@shared/relayProvider";
import { useActiveAccount } from "@stores/accounts";
@ -66,14 +66,23 @@ export function Page() {
READONLY_RELAYS,
(event: { id: string; pubkey: string }) => {
const message: any = event;
// handle hide message
if (hided.includes(event.id)) {
message["hide"] = true;
} else {
message["hide"] = false;
}
if (!muted.array.includes(event.pubkey)) {
addMessage(message);
// handle mute user
if (muted.array.includes(event.pubkey)) {
message["mute"] = true;
} else {
message["mute"] = false;
}
// add to store
addMessage(message);
},
);
@ -101,23 +110,17 @@ export function Page() {
</div>
</div>
</div>
<div className="col-span-1">
<div className="col-span-1 flex flex-col">
<div
data-tauri-drag-region
className="h-11 w-full shrink-0 inline-flex items-center justify-center border-b border-zinc-900"
/>
<div>
<div className="p-3 flex flex-col gap-3">
<ChannelMetadata id={channelID} pubkey={channelPubkey} />
</div>
<div className="flex items-center gap-2">
<ChannelMembers />
{!muted ? <></> : <ChannelBlackList blacklist={muted.original} />}
{account ? (
account.pubkey === channelPubkey && (
<ChannelUpdateModal id={channelID} />
)
) : (
<></>
{muted && <ChannelBlackList blacklist={muted.original} />}
{account && account.pubkey === channelPubkey && (
<ChannelUpdateModal id={channelID} />
)}
</div>
</div>

View File

@ -1,5 +1,6 @@
import { ChatMessageUser } from "@app/chat/components/messages/user";
import { useDecryptMessage } from "@app/chat/hooks/useDecryptMessage";
import { MentionNote } from "@app/note/components/mentions/note";
import ImagePreview from "@app/note/components/preview/image";
import VideoPreview from "@app/note/components/preview/video";
import { noteParser } from "@utils/parser";
@ -40,6 +41,13 @@ export const ChatMessageItem = memo(function ChatMessageItem({
) : (
<></>
)}
{Array.isArray(content.notes) && content.notes.length ? (
content.notes.map((note: string) => (
<MentionNote key={note} id={note} />
))
) : (
<></>
)}
</div>
</div>
</div>

View File

@ -1,102 +0,0 @@
import PlusIcon from "@icons/plus";
import { channelContentAtom } from "@stores/channel";
import { createBlobFromFile } from "@utils/createBlobFromFile";
import { open } from "@tauri-apps/api/dialog";
import { Body, fetch } from "@tauri-apps/api/http";
import { useSetAtom } from "jotai";
import { useState } from "react";
export function ImagePicker({ type }: { type: string }) {
let atom;
switch (type) {
case "channel":
atom = channelContentAtom;
break;
default:
throw new Error("Invalid type");
}
const [loading, setLoading] = useState(false);
const setValue = useSetAtom(atom);
const openFileDialog = async () => {
const selected: any = await open({
multiple: false,
filters: [
{
name: "Image",
extensions: ["png", "jpeg", "jpg", "gif"],
},
],
});
if (Array.isArray(selected)) {
// user selected multiple files
} else if (selected === null) {
// user cancelled the selection
} else {
setLoading(true);
const filename = selected.split("/").pop();
const file = await createBlobFromFile(selected);
const buf = await file.arrayBuffer();
const res: { data: { file: { id: string } } } = await fetch(
"https://void.cat/upload?cli=false",
{
method: "POST",
timeout: 5,
headers: {
accept: "*/*",
"Content-Type": "application/octet-stream",
"V-Filename": filename,
"V-Description": "Upload from https://lume.nu",
"V-Strip-Metadata": "true",
},
body: Body.bytes(buf),
},
);
const webpImage = `https://void.cat/d/${res.data.file.id}.webp`;
setValue((content: string) => `${content} ${webpImage}`);
setLoading(false);
}
};
return (
<button
type="button"
onClick={() => openFileDialog()}
className="inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-zinc-700"
>
{loading ? (
<svg
className="h-4 w-4 animate-spin text-black dark:text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<title id="loading">Loading</title>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
) : (
<PlusIcon width={16} height={16} className="text-zinc-400" />
)}
</button>
);
}

View File

@ -1,31 +0,0 @@
import { atom } from "jotai";
import { atomWithReset } from "jotai/utils";
// channel reply id
export const channelReplyAtom = atomWithReset({
id: null,
pubkey: null,
content: null,
});
// channel messages
export const channelMessagesAtom = atomWithReset([]);
export const sortedChannelMessagesAtom = atom((get) => {
const messages = get(channelMessagesAtom);
return messages.sort(
(x: { created_at: number }, y: { created_at: number }) =>
x.created_at - y.created_at,
);
});
// channel user list
export const channelMembersAtom = atom((get) => {
const messages = get(channelMessagesAtom);
const uniqueMembers = new Set(
messages.map((m: { pubkey: string }) => m.pubkey),
);
return uniqueMembers;
});
// channel message content
export const channelContentAtom = atomWithReset("");

View File

@ -1,5 +1,6 @@
import { getChannels } from "@utils/storage";
import { create } from "zustand";
import { immer } from "zustand/middleware/immer";
export const useChannels = create((set) => ({
channels: [],
@ -9,10 +10,31 @@ export const useChannels = create((set) => ({
},
}));
export const useChannelMessages = create((set) => ({
messages: [],
replyTo: null,
add: (message: any) => {
set((state: any) => ({ messages: [...state.messages, message] }));
},
}));
export const useChannelMessages = create(
immer((set) => ({
messages: [],
members: new Set(),
replyTo: { id: null, pubkey: null, content: null },
add: (message: any) => {
set((state: any) => ({ messages: [...state.messages, message] }));
},
openReply: (id: string, pubkey: string, content: string) => {
set(() => ({ replyTo: { id, pubkey, content } }));
},
closeReply: () => {
set(() => ({ replyTo: { id: null, pubkey: null, content: null } }));
},
hideMessage: (id: string) => {
set((state) => {
const target = state.messages.findIndex((m) => m.id === id);
state.messages[target]["hide"] = true;
});
},
muteUser: (pubkey: string) => {
set((state) => {
const target = state.messages.findIndex((m) => m.pubkey === pubkey);
state.messages[target]["mute"] = true;
});
},
})),
);

View File

@ -286,12 +286,17 @@ export async function getChatMessages(
sender_pubkey: string,
) {
const db = await connect();
let receiver = [];
const sender: any = await db.select(
`SELECT * FROM chats WHERE sender_pubkey = "${sender_pubkey}" AND receiver_pubkey = "${receiver_pubkey}";`,
);
const receiver: any = await db.select(
`SELECT * FROM chats WHERE sender_pubkey = "${receiver_pubkey}" AND receiver_pubkey = "${sender_pubkey}";`,
);
if (receiver_pubkey !== sender_pubkey) {
receiver = await db.select(
`SELECT * FROM chats WHERE sender_pubkey = "${receiver_pubkey}" AND receiver_pubkey = "${sender_pubkey}";`,
);
}
const result = [...sender, ...receiver].sort(
(x: { created_at: number }, y: { created_at: number }) =>