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

View File

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

View File

@ -4,7 +4,7 @@ import { DEFAULT_AVATAR } from "@stores/constants";
import { useProfile } from "@utils/hooks/useProfile"; 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); const { user, isError, isLoading } = useProfile(pubkey);
return ( return (

View File

@ -1,44 +1,13 @@
import MiniMember from "@app/channel/components/miniMember"; import { Member } from "@app/channel/components/member";
import { useChannelMessages } from "@stores/channels";
import { channelMembersAtom } from "@stores/channel"; import { useEffect } from "react";
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;
export function ChannelMembers() {
return ( return (
<div> <div className="flex flex-wrap gap-1">
<div className="group flex -space-x-2 overflow-hidden hover:-space-x-1"> {[].map((member) => (
{miniMembersList.map((member, index) => ( <Member key={member} pubkey={member} />
<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> </div>
); );
} }

View File

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

View File

@ -3,13 +3,11 @@ import CancelIcon from "@icons/cancel";
import { ImagePicker } from "@shared/form/imagePicker"; import { ImagePicker } from "@shared/form/imagePicker";
import { RelayContext } from "@shared/relayProvider"; import { RelayContext } from "@shared/relayProvider";
import { useActiveAccount } from "@stores/accounts"; import { useActiveAccount } from "@stores/accounts";
import { channelContentAtom, channelReplyAtom } from "@stores/channel"; import { useChannelMessages } from "@stores/channels";
import { WRITEONLY_RELAYS } from "@stores/constants"; import { WRITEONLY_RELAYS } from "@stores/constants";
import { dateToUnix } from "@utils/date"; import { dateToUnix } from "@utils/date";
import { useAtom, useAtomValue } from "jotai";
import { useResetAtom } from "jotai/utils";
import { getEventHash, getSignature } from "nostr-tools"; import { getEventHash, getSignature } from "nostr-tools";
import { useContext } from "react"; import { useContext, useState } from "react";
export default function ChannelMessageForm({ export default function ChannelMessageForm({
channelID, channelID,
@ -17,20 +15,20 @@ export default function ChannelMessageForm({
const pool: any = useContext(RelayContext); const pool: any = useContext(RelayContext);
const account = useActiveAccount((state: any) => state.account); const account = useActiveAccount((state: any) => state.account);
const [value, setValue] = useAtom(channelContentAtom); const [value, setValue] = useState("");
const resetValue = useResetAtom(channelContentAtom); const [replyTo, closeReply] = useChannelMessages((state: any) => [
state.replyTo,
const channelReply = useAtomValue(channelReplyAtom); state.closeReply,
const resetChannelReply = useResetAtom(channelReplyAtom); ]);
const submitEvent = () => { const submitEvent = () => {
let tags: any[][]; let tags: any[][];
if (channelReply.id !== null) { if (replyTo.id !== null) {
tags = [ tags = [
["e", channelID, "", "root"], ["e", channelID, "", "root"],
["e", channelReply.id, "", "reply"], ["e", replyTo.id, "", "reply"],
["p", channelReply.pubkey, ""], ["p", replyTo.pubkey, ""],
]; ];
} else { } else {
tags = [["e", channelID, "", "root"]]; tags = [["e", channelID, "", "root"]];
@ -50,11 +48,6 @@ export default function ChannelMessageForm({
// publish note // publish note
pool.publish(event, WRITEONLY_RELAYS); pool.publish(event, WRITEONLY_RELAYS);
// reset state
resetValue();
// reset channel reply
resetChannelReply();
} else { } else {
console.log("error"); console.log("error");
} }
@ -68,24 +61,22 @@ export default function ChannelMessageForm({
}; };
const stopReply = () => { const stopReply = () => {
resetChannelReply(); closeReply();
}; };
return ( return (
<div <div
className={`relative ${ 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`} } 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="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 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"> <div className="flex w-full flex-col">
<UserReply pubkey={channelReply.pubkey} /> <UserReply pubkey={replyTo.pubkey} />
<div className="-mt-3.5 pl-[32px]"> <div className="-mt-3.5 pl-[32px]">
<div className="text-base text-white"> <div className="text-base text-white">{replyTo.content}</div>
{channelReply.content}
</div>
</div> </div>
</div> </div>
<button <button
@ -105,13 +96,12 @@ export default function ChannelMessageForm({
spellCheck={false} spellCheck={false}
placeholder="Message" placeholder="Message"
className={`relative ${ 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`} } 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="absolute bottom-2 w-full px-2">
<div className="flex w-full items-center justify-between bg-zinc-800"> <div className="flex w-full items-center justify-between bg-zinc-800">
<div className="flex items-center gap-2 divide-x divide-zinc-700"> <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 className="flex items-center gap-2 pl-2" />
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">

View File

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

View File

@ -1,25 +1,61 @@
import MessageHideButton from "@app/channel/components/messages/hideButton"; import { MessageHideButton } from "@app/channel/components/messages/hideButton";
import MessageMuteButton from "@app/channel/components/messages/muteButton"; import { MessageMuteButton } from "@app/channel/components/messages/muteButton";
import MessageReplyButton from "@app/channel/components/messages/replyButton"; import { MessageReplyButton } from "@app/channel/components/messages/replyButton";
import { ChannelMessageUser } from "@app/channel/components/messages/user"; 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 { noteParser } from "@utils/parser";
import { useMemo } from "react"; import { useMemo, useState } from "react";
export function ChannelMessageItem({ data }: { data: any }) { export function ChannelMessageItem({ data }: { data: any }) {
const content = useMemo(() => noteParser(data), [data]); const content = useMemo(() => noteParser(data), [data]);
const [hide, setHide] = useState(data.hide);
const toggleHide = () => {
setHide((prev) => !prev);
};
if (data.mute) return null;
return ( 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="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"> <div className="flex flex-col">
<ChannelMessageUser pubkey={data.pubkey} time={data.created_at} /> <ChannelMessageUser pubkey={data.pubkey} time={data.created_at} />
<div className="-mt-[20px] pl-[49px]"> <div className="-mt-[20px] pl-[49px]">
<div className="whitespace-pre-line break-words text-base leading-tight"> {hide ? (
{data.hide ? ( <>
<span className="italic text-zinc-400">[hided message]</span> <p className="leading-tight italic text-zinc-400">
) : ( [hided message]
content.parsed </p>
)} <button type="button" onClick={() => toggleHide()}>
</div> 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> </div>
<div className="absolute -top-4 right-4 z-10 hidden group-hover:inline-flex"> <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 { RelayContext } from "@shared/relayProvider";
import { Tooltip } from "@shared/tooltip"; import { Tooltip } from "@shared/tooltip";
import { useActiveAccount } from "@stores/accounts"; import { useActiveAccount } from "@stores/accounts";
import { channelMessagesAtom } from "@stores/channel"; import { useChannelMessages } from "@stores/channels";
import { WRITEONLY_RELAYS } from "@stores/constants"; import { WRITEONLY_RELAYS } from "@stores/constants";
import { dateToUnix } from "@utils/date"; import { dateToUnix } from "@utils/date";
import { useAtom } from "jotai";
import { getEventHash, getSignature } from "nostr-tools"; import { getEventHash, getSignature } from "nostr-tools";
import { Fragment, useContext, useState } from "react"; 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 pool: any = useContext(RelayContext);
const account = useActiveAccount((state: any) => state.account); 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 [isOpen, setIsOpen] = useState(false);
const closeModal = () => { const closeModal = () => {
@ -27,31 +26,25 @@ export default function MessageMuteButton({ pubkey }: { pubkey: string }) {
}; };
const muteUser = () => { const muteUser = () => {
if (account) { const event: any = {
const event: any = { content: "",
content: "", created_at: dateToUnix(),
created_at: dateToUnix(), kind: 44,
kind: 44, pubkey: account.pubkey,
pubkey: account.pubkey, tags: [["p", pubkey]],
tags: [["p", pubkey]], };
};
event.id = getEventHash(event);
event.sig = getSignature(event, account.privkey);
// publish note event.id = getEventHash(event);
pool.publish(event, WRITEONLY_RELAYS); event.sig = getSignature(event, account.privkey);
// update local state // publish note
const cloneMessages = [...messages]; pool.publish(event, WRITEONLY_RELAYS);
const finalMessages = cloneMessages.filter(
(message) => message.pubkey !== pubkey, // update state
); mute(pubkey);
setMessages(finalMessages);
// close modal // close modal
closeModal(); closeModal();
} else {
console.log("error");
}
}; };
return ( return (

View File

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

View File

@ -10,11 +10,14 @@ dayjs.extend(relativeTime);
export function ChannelMessageUser({ export function ChannelMessageUser({
pubkey, pubkey,
time, time,
}: { pubkey: string; time: number }) { }: {
pubkey: string;
time: number;
}) {
const { user, isError, isLoading } = useProfile(pubkey); const { user, isError, isLoading } = useProfile(pubkey);
return ( return (
<div className="group flex items-start gap-3"> <div className="flex items-start gap-3">
{isError || isLoading ? ( {isError || isLoading ? (
<> <>
<div className="relative h-11 w-11 shrink animate-pulse rounded-md bg-zinc-800" /> <div className="relative h-11 w-11 shrink animate-pulse rounded-md bg-zinc-800" />
@ -35,7 +38,7 @@ export function ChannelMessageUser({
</div> </div>
<div className="flex w-full flex-1 items-start justify-between"> <div className="flex w-full flex-1 items-start justify-between">
<div className="flex items-baseline gap-2 text-base"> <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)} {user?.nip05 || user?.name || shortenKey(pubkey)}
</span> </span>
<span className="leading-none text-zinc-500">·</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"; import { nip19 } from "nostr-tools";
export default function ChannelMetadata({ export function ChannelMetadata({
id, id,
pubkey, pubkey,
}: { id: string; pubkey: string }) { }: { id: string; pubkey: string }) {
@ -23,24 +23,24 @@ export default function ChannelMetadata({
}; };
return ( return (
<div className="inline-flex items-center gap-2"> <div className="flex flex-col gap-2">
<div className="relative shrink-0 rounded-md"> <div className="relative shrink-0 rounded-md h-11 w-11">
<Image <Image
src={metadata?.picture || DEFAULT_AVATAR} src={metadata?.picture || DEFAULT_AVATAR}
alt={id} 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>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-2">
<div className="flex items-center gap-1"> <div className="inline-flex items-center gap-1">
<h5 className="truncate text-base font-medium leading-none text-white"> <h5 className="leading-none text-lg font-semibold">
{metadata?.name} {metadata?.name}
</h5> </h5>
<button type="button" onClick={() => copyNoteID()}> <button type="button" onClick={() => copyNoteID()}>
<CopyIcon width={14} height={14} className="text-zinc-400" /> <CopyIcon width={14} height={14} className="text-zinc-400" />
</button> </button>
</div> </div>
<p className="text-base leading-none text-zinc-400"> <p className="leading-tight text-zinc-400">
{metadata?.about || (noteID && `${noteID.substring(0, 24)}...`)} {metadata?.about || (noteID && `${noteID.substring(0, 24)}...`)}
</p> </p>
</div> </div>

View File

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

View File

@ -1,5 +1,6 @@
import { ChatMessageUser } from "@app/chat/components/messages/user"; import { ChatMessageUser } from "@app/chat/components/messages/user";
import { useDecryptMessage } from "@app/chat/hooks/useDecryptMessage"; import { useDecryptMessage } from "@app/chat/hooks/useDecryptMessage";
import { MentionNote } from "@app/note/components/mentions/note";
import ImagePreview from "@app/note/components/preview/image"; import ImagePreview from "@app/note/components/preview/image";
import VideoPreview from "@app/note/components/preview/video"; import VideoPreview from "@app/note/components/preview/video";
import { noteParser } from "@utils/parser"; 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> </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 { getChannels } from "@utils/storage";
import { create } from "zustand"; import { create } from "zustand";
import { immer } from "zustand/middleware/immer";
export const useChannels = create((set) => ({ export const useChannels = create((set) => ({
channels: [], channels: [],
@ -9,10 +10,31 @@ export const useChannels = create((set) => ({
}, },
})); }));
export const useChannelMessages = create((set) => ({ export const useChannelMessages = create(
messages: [], immer((set) => ({
replyTo: null, messages: [],
add: (message: any) => { members: new Set(),
set((state: any) => ({ messages: [...state.messages, message] })); 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, sender_pubkey: string,
) { ) {
const db = await connect(); const db = await connect();
let receiver = [];
const sender: any = await db.select( const sender: any = await db.select(
`SELECT * FROM chats WHERE sender_pubkey = "${sender_pubkey}" AND receiver_pubkey = "${receiver_pubkey}";`, `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( const result = [...sender, ...receiver].sort(
(x: { created_at: number }, y: { created_at: number }) => (x: { created_at: number }, y: { created_at: number }) =>