feat: favorite relays (#250)

This commit is contained in:
Cody Tseng
2025-04-05 15:31:34 +08:00
committed by GitHub
parent fab9ff88b5
commit c739d9d28c
63 changed files with 1081 additions and 982 deletions

View File

@@ -1,33 +1,31 @@
import client from '@/services/client.service'
import { TRelaySet } from '@/types'
import { ChevronDown, Circle, CircleCheck } from 'lucide-react'
import { useEffect, useState } from 'react'
import { ChevronDown, FolderClosed } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import RelayIcon from '../RelayIcon'
export default function RelaySetCard({
relaySet,
select,
onSelectChange,
showConnectionStatus = false
onSelectChange
}: {
relaySet: TRelaySet
select: boolean
onSelectChange: (select: boolean) => void
showConnectionStatus?: boolean
}) {
const { t } = useTranslation()
const [expand, setExpand] = useState(false)
return (
<div
className={`w-full border rounded-lg p-4 ${select ? 'border-highlight bg-highlight/5' : ''}`}
className={`w-full border rounded-lg p-4 ${select ? 'border-highlight bg-highlight/5' : 'clickable'}`}
onClick={() => onSelectChange(!select)}
>
<div className="flex justify-between items-center">
<div
className="flex space-x-2 items-center cursor-pointer"
onClick={() => onSelectChange(!select)}
>
<RelaySetActiveToggle select={select} />
<div className="flex space-x-2 items-center cursor-pointer">
<div className="flex justify-center items-center w-6 h-6 shrink-0">
<FolderClosed className="size-4" />
</div>
<div className="h-8 font-semibold flex items-center select-none">{relaySet.name}</div>
</div>
<div className="flex gap-1">
@@ -36,21 +34,11 @@ export default function RelaySetCard({
</RelayUrlsExpandToggle>
</div>
</div>
{expand && (
<RelayUrls urls={relaySet.relayUrls} showConnectionStatus={showConnectionStatus} />
)}
{expand && <RelayUrls urls={relaySet.relayUrls} />}
</div>
)
}
function RelaySetActiveToggle({ select }: { select: boolean }) {
return select ? (
<CircleCheck size={18} className="text-highlight shrink-0" />
) : (
<Circle size={18} className="shrink-0" />
)
}
function RelayUrlsExpandToggle({
children,
expand,
@@ -63,7 +51,10 @@ function RelayUrlsExpandToggle({
return (
<div
className="text-sm text-muted-foreground flex items-center gap-1 cursor-pointer hover:text-foreground"
onClick={() => onExpandChange(!expand)}
onClick={(e) => {
e.stopPropagation()
onExpandChange(!expand)
}}
>
<div className="select-none">{children}</div>
<ChevronDown
@@ -74,49 +65,15 @@ function RelayUrlsExpandToggle({
)
}
function RelayUrls({
showConnectionStatus = false,
urls
}: {
showConnectionStatus?: boolean
urls: string[]
}) {
const [relays, setRelays] = useState<
{
url: string
isConnected: boolean
}[]
>(urls.map((url) => ({ url, isConnected: false })) ?? [])
useEffect(() => {
if (!showConnectionStatus || urls.length === 0) return
const interval = setInterval(() => {
const connectionStatusMap = client.listConnectionStatus()
setRelays((pre) => {
return pre.map((relay) => {
const isConnected = connectionStatusMap.get(relay.url) || false
return { ...relay, isConnected }
})
})
}, 1000)
return () => clearInterval(interval)
}, [showConnectionStatus, urls])
function RelayUrls({ urls }: { urls: string[] }) {
if (!urls) return null
return (
<div>
{relays.map(({ url, isConnected: isConnected }, index) => (
<div key={index} className="flex items-center gap-2">
{showConnectionStatus &&
(isConnected ? (
<div className="text-green-500 text-xs"></div>
) : (
<div className="text-red-500 text-xs"></div>
))}
<div className="text-muted-foreground text-sm">{url}</div>
<div className="pl-8 space-y-1">
{urls.map((url) => (
<div key={url} className="flex items-center gap-2">
<RelayIcon url={url} className="w-4 h-4" iconSize={10} />
<div className="text-muted-foreground text-sm truncate">{url}</div>
</div>
))}
</div>