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.
106 lines
3.8 KiB
106 lines
3.8 KiB
import { useSmartRelayNavigation } from '@/PageManager' |
|
import { Button } from '@/components/ui/button' |
|
import { |
|
DropdownMenu, |
|
DropdownMenuContent, |
|
DropdownMenuLabel, |
|
DropdownMenuSeparator, |
|
DropdownMenuTrigger |
|
} from '@/components/ui/dropdown-menu' |
|
import { useRelayConnectionRows } from '@/hooks/useRelayConnectionRows' |
|
import { toRelay } from '@/lib/link' |
|
import { cn } from '@/lib/utils' |
|
import { useTranslation } from 'react-i18next' |
|
import RelayIcon from '../RelayIcon' |
|
import { |
|
ACTIVE_RELAYS_MAX_ICONS, |
|
activeRelayRowMuted, |
|
activeRelayRowTitle |
|
} from './active-relays-display' |
|
|
|
/** |
|
* Compact relay status: icon buttons only (no hostname labels). |
|
*/ |
|
export function ActiveRelaysIconGrid({ className }: { className?: string }) { |
|
const { t } = useTranslation() |
|
const { navigateToRelay } = useSmartRelayNavigation() |
|
const { rows } = useRelayConnectionRows() |
|
const shown = rows.slice(0, ACTIVE_RELAYS_MAX_ICONS) |
|
const overflowRows = rows.slice(ACTIVE_RELAYS_MAX_ICONS) |
|
const overflow = overflowRows.length |
|
|
|
if (rows.length === 0) { |
|
return ( |
|
<p className={cn('text-xs text-muted-foreground', className)} title={t('Active relays')}> |
|
— |
|
</p> |
|
) |
|
} |
|
|
|
return ( |
|
<div className={cn('flex flex-wrap gap-1', className)} title={t('Active relays')}> |
|
{shown.map(({ url, connected }) => ( |
|
<Button |
|
key={url} |
|
type="button" |
|
variant="ghost" |
|
size="sm" |
|
className={cn( |
|
'h-7 w-7 min-h-7 min-w-7 shrink-0 rounded-full p-0 hover:bg-muted/80', |
|
activeRelayRowMuted(connected) && 'opacity-40 grayscale' |
|
)} |
|
title={activeRelayRowTitle(url, connected, t)} |
|
aria-label={activeRelayRowTitle(url, connected, t)} |
|
onClick={() => navigateToRelay(toRelay(url))} |
|
> |
|
<RelayIcon url={url} className="h-6 w-6" iconSize={12} /> |
|
</Button> |
|
))} |
|
{overflow > 0 ? ( |
|
<DropdownMenu> |
|
<DropdownMenuTrigger asChild> |
|
<Button |
|
type="button" |
|
variant="ghost" |
|
size="sm" |
|
className="h-7 min-h-7 min-w-7 shrink-0 rounded-full bg-muted px-1.5 py-0 text-[0.65rem] 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="w-auto max-w-[min(18rem,calc(100vw-1.5rem))] p-2" |
|
> |
|
<DropdownMenuLabel className="text-xs font-normal text-muted-foreground py-1"> |
|
{t('More relays', { count: overflow })} |
|
</DropdownMenuLabel> |
|
<DropdownMenuSeparator /> |
|
<div className="flex flex-wrap gap-1 max-w-[16rem]"> |
|
{overflowRows.map(({ url, connected }) => ( |
|
<Button |
|
key={url} |
|
type="button" |
|
variant="ghost" |
|
size="sm" |
|
className={cn( |
|
'h-7 w-7 min-h-7 min-w-7 shrink-0 rounded-full p-0 hover:bg-muted/80', |
|
activeRelayRowMuted(connected) && 'opacity-40 grayscale' |
|
)} |
|
title={activeRelayRowTitle(url, connected, t)} |
|
aria-label={activeRelayRowTitle(url, connected, t)} |
|
onClick={() => navigateToRelay(toRelay(url))} |
|
> |
|
<RelayIcon url={url} className="h-6 w-6" iconSize={12} /> |
|
</Button> |
|
))} |
|
</div> |
|
</DropdownMenuContent> |
|
</DropdownMenu> |
|
) : null} |
|
</div> |
|
) |
|
}
|
|
|