12 changed files with 174 additions and 36 deletions
@ -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> |
||||||
|
) |
||||||
|
} |
||||||
@ -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> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
import OthersRelayList from '@/components/OthersRelayList' |
||||||
|
import { useFetchProfile } from '@/hooks' |
||||||
|
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' |
||||||
|
import { useTranslation } from 'react-i18next' |
||||||
|
|
||||||
|
export default function RelaySettingsPage({ id, index }: { id?: string; index?: number }) { |
||||||
|
const { t } = useTranslation() |
||||||
|
const { profile } = useFetchProfile(id) |
||||||
|
|
||||||
|
if (!id || !profile) { |
||||||
|
return null |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<SecondaryPageLayout |
||||||
|
index={index} |
||||||
|
title={t("username's used relays", { username: profile.username })} |
||||||
|
> |
||||||
|
<div className="px-4"> |
||||||
|
<OthersRelayList userId={id} /> |
||||||
|
</div> |
||||||
|
</SecondaryPageLayout> |
||||||
|
) |
||||||
|
} |
||||||
Loading…
Reference in new issue