You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
3.8 KiB
97 lines
3.8 KiB
import { useSecondaryPage } from '@/PageManager' |
|
import { Button } from '@/components/ui/button' |
|
import { |
|
DropdownMenu, |
|
DropdownMenuContent, |
|
DropdownMenuItem, |
|
DropdownMenuLabel, |
|
DropdownMenuSeparator, |
|
DropdownMenuTrigger |
|
} from '@/components/ui/dropdown-menu' |
|
import { useRelayConnectionRows } from '@/hooks/useRelayConnectionRows' |
|
import { toRelay } from '@/lib/link' |
|
import { simplifyUrl } from '@/lib/url' |
|
import { cn } from '@/lib/utils' |
|
import { useTranslation } from 'react-i18next' |
|
import RelayIcon from '../RelayIcon' |
|
|
|
const MAX_ICONS = 14 |
|
|
|
function rowMenuClass(connected: boolean) { |
|
return cn(!connected && 'opacity-50 text-muted-foreground') |
|
} |
|
|
|
/** |
|
* Desktop sidebar: relay avatars for favorites + defaults + inbox; muted when the pool socket is down. |
|
*/ |
|
export function ConnectedRelaysSidebarStrip({ className }: { className?: string }) { |
|
const { t } = useTranslation() |
|
const { push } = useSecondaryPage() |
|
const { rows } = useRelayConnectionRows() |
|
const shown = rows.slice(0, MAX_ICONS) |
|
const overflowRows = rows.slice(MAX_ICONS) |
|
const overflow = overflowRows.length |
|
|
|
if (rows.length === 0) { |
|
return ( |
|
<div className={cn('px-1 py-1.5 xl:px-0', className)} title={t('Active relays')}> |
|
<p className="text-center text-[0.6rem] font-medium text-muted-foreground xl:text-left">{t('Active relays')}</p> |
|
<p className="mt-0.5 text-center text-[0.55rem] text-muted-foreground/80 xl:text-left">—</p> |
|
</div> |
|
) |
|
} |
|
|
|
return ( |
|
<div className={cn('px-1 py-2 xl:px-0', className)} title={t('Active relays')}> |
|
<p className="mb-1.5 text-center text-[0.65rem] font-medium leading-snug text-foreground xl:text-left"> |
|
{t('Active relays')} |
|
</p> |
|
<div className="flex flex-wrap justify-center gap-1 xl:justify-start"> |
|
{shown.map(({ url, connected }) => ( |
|
<span |
|
key={url} |
|
title={ |
|
connected ? simplifyUrl(url) : `${simplifyUrl(url)} — ${t('Not connected')}` |
|
} |
|
className={cn('inline-flex', !connected && 'opacity-40 grayscale')} |
|
> |
|
<RelayIcon url={url} className="h-5 w-5" iconSize={11} /> |
|
</span> |
|
))} |
|
{overflow > 0 ? ( |
|
<DropdownMenu> |
|
<DropdownMenuTrigger asChild> |
|
<Button |
|
type="button" |
|
variant="ghost" |
|
size="sm" |
|
className="h-5 min-h-5 min-w-5 shrink-0 rounded-full bg-muted px-1 py-0 text-[0.6rem] font-medium tabular-nums text-muted-foreground hover:bg-muted/80 hover:text-foreground" |
|
title={t('More relays', { count: overflow })} |
|
aria-label={t('More relays', { count: overflow })} |
|
> |
|
+{overflow} |
|
</Button> |
|
</DropdownMenuTrigger> |
|
<DropdownMenuContent align="start" side="right" className="max-h-[min(70vh,24rem)] w-72 overflow-y-auto"> |
|
<DropdownMenuLabel className="text-xs font-normal text-muted-foreground"> |
|
{t('More relays', { count: overflow })} |
|
</DropdownMenuLabel> |
|
<DropdownMenuSeparator /> |
|
{overflowRows.map(({ url, connected }) => ( |
|
<DropdownMenuItem |
|
key={url} |
|
className={cn('min-w-0 gap-2', rowMenuClass(connected))} |
|
title={connected ? simplifyUrl(url) : `${simplifyUrl(url)} — ${t('Not connected')}`} |
|
onClick={() => push(toRelay(url))} |
|
> |
|
<RelayIcon url={url} className="h-5 w-5 shrink-0" iconSize={11} /> |
|
<span className="truncate">{simplifyUrl(url)}</span> |
|
</DropdownMenuItem> |
|
))} |
|
</DropdownMenuContent> |
|
</DropdownMenu> |
|
) : null} |
|
</div> |
|
</div> |
|
) |
|
}
|
|
|