feat: others relays

This commit is contained in:
codytseng
2025-01-17 12:07:22 +08:00
parent 6543f29529
commit 64a5573969
12 changed files with 174 additions and 36 deletions

View File

@@ -1,4 +1,3 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import {
Select,
SelectContent,
@@ -7,9 +6,9 @@ import {
SelectValue
} from '@/components/ui/select'
import { TMailboxRelay, TMailboxRelayScope } from '@/types'
import { CircleX, Server } from 'lucide-react'
import { useMemo } from 'react'
import { CircleX } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import RelayIcon from '../RelayIcon'
export default function MailboxRelay({
mailboxRelay,
@@ -21,20 +20,11 @@ export default function MailboxRelay({
removeMailboxRelay: (url: string) => void
}) {
const { t } = useTranslation()
const relayIcon = useMemo(() => {
const url = new URL(mailboxRelay.url)
return `${url.protocol === 'wss:' ? 'https:' : 'http:'}//${url.host}/favicon.ico`
}, [mailboxRelay.url])
return (
<div className="flex items-center justify-between">
<div className="flex items-center gap-2 flex-1 w-0">
<Avatar className="w-6 h-6">
<AvatarImage src={relayIcon} />
<AvatarFallback>
<Server size={14} />
</AvatarFallback>
</Avatar>
<RelayIcon url={mailboxRelay.url} />
<div className="truncate">{mailboxRelay.url}</div>
</div>
<div className="flex items-center gap-4">

View File

@@ -1,4 +1,5 @@
import { Button } from '@/components/ui/button'
import { relayListToMailboxRelay } from '@/lib/relay'
import { normalizeUrl } from '@/lib/url'
import { useNostr } from '@/providers/NostrProvider'
import { TMailboxRelay, TMailboxRelayScope } from '@/types'
@@ -17,16 +18,7 @@ export default function MailboxSetting() {
useEffect(() => {
if (!relayList) return
const mailboxRelays: TMailboxRelay[] = relayList.read.map((url) => ({ url, scope: 'read' }))
relayList.write.forEach((url) => {
const item = mailboxRelays.find((r) => r.url === url)
if (item) {
item.scope = 'both'
} else {
mailboxRelays.push({ url, scope: 'write' })
}
})
setRelays(mailboxRelays)
setRelays(relayListToMailboxRelay(relayList))
}, [relayList])
if (!pubkey) {

View File

@@ -0,0 +1,66 @@
import { useSecondaryPage } from '@/PageManager'
import { Button } from '@/components/ui/button'
import { useFetchRelayList } from '@/hooks/useFetchRelayList'
import { toNoteList } from '@/lib/link'
import { userIdToPubkey } from '@/lib/pubkey'
import { relayListToMailboxRelay } from '@/lib/relay'
import { simplifyUrl } from '@/lib/url'
import { TMailboxRelay } from '@/types'
import { ListPlus, Telescope } from 'lucide-react'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import RelayIcon from '../RelayIcon'
import SaveRelayDropdownMenu from '../SaveRelayDropdownMenu'
import { Badge } from '../ui/badge'
export default function OthersRelayList({ userId }: { userId: string }) {
const { t } = useTranslation()
const pubkey = useMemo(() => userIdToPubkey(userId), [userId])
const { relayList, isFetching } = useFetchRelayList(pubkey)
const mailboxRelays = useMemo(() => relayListToMailboxRelay(relayList), [relayList])
if (isFetching) {
return <div className="text-center text-sm text-muted-foreground">{t('loading...')}</div>
}
return (
<div className="space-y-2">
{mailboxRelays.map((relay, index) => (
<RelayItem key={`read-${relay.url}-${index}`} relay={relay} />
))}
</div>
)
}
function RelayItem({ relay }: { relay: TMailboxRelay }) {
const { t } = useTranslation()
const { push } = useSecondaryPage()
const { url, scope } = relay
return (
<div className="flex items-center gap-2 justify-between">
<div
className="flex items-center gap-2 cursor-pointer flex-1 w-0"
onClick={() => push(toNoteList({ relay: url }))}
>
<RelayIcon url={url} />
<div className="truncate">{simplifyUrl(url)}</div>
</div>
<div className="flex items-center gap-1 shrink-0">
{scope === 'read' ? (
<Badge className="bg-blue-400 hover:bg-blue-400/80">{t('Read')}</Badge>
) : scope === 'write' ? (
<Badge className="bg-green-400 hover:bg-green-400/80">{t('Write')}</Badge>
) : null}
<Button variant="ghost" size="icon" onClick={() => push(toNoteList({ relay: url }))}>
<Telescope />
</Button>
<SaveRelayDropdownMenu urls={[url]}>
<Button variant="ghost" size="icon">
<ListPlus />
</Button>
</SaveRelayDropdownMenu>
</div>
</div>
)
}

View File

@@ -0,0 +1,27 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Server } from 'lucide-react'
import { useMemo } from 'react'
export default function RelayIcon({
url,
className = 'w-6 h-6',
iconSize = 14
}: {
url: string
className?: string
iconSize?: number
}) {
const icon = useMemo(() => {
const u = new URL(url)
return `${u.protocol === 'wss:' ? 'https:' : 'http:'}//${u.host}/favicon.ico`
}, [url])
return (
<Avatar className={className}>
<AvatarImage src={icon} />
<AvatarFallback>
<Server size={iconSize} />
</AvatarFallback>
</Avatar>
)
}