mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 13:10:30 +08:00
fix: profiles cannot click
This commit is contained in:
parent
9acab62d1f
commit
a69d24b29c
@ -80,11 +80,13 @@ const App: React.FC = () => {
|
|||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const page = useRoutes(routes)
|
const page = useRoutes(routes)
|
||||||
const setTitlebar = (): void => {
|
const setTitlebar = (): void => {
|
||||||
if (!useWindowFrame && platform !== 'darwin') {
|
if (!useWindowFrame) {
|
||||||
const options = { height: 48 } as TitleBarOverlayOptions
|
const options = { height: 48 } as TitleBarOverlayOptions
|
||||||
try {
|
try {
|
||||||
options.color = window.getComputedStyle(document.documentElement).backgroundColor
|
if (platform !== 'darwin') {
|
||||||
options.symbolColor = window.getComputedStyle(document.documentElement).color
|
options.color = window.getComputedStyle(document.documentElement).backgroundColor
|
||||||
|
options.symbolColor = window.getComputedStyle(document.documentElement).color
|
||||||
|
}
|
||||||
setTitleBarOverlay(options)
|
setTitleBarOverlay(options)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
|||||||
@ -30,7 +30,7 @@ interface Props {
|
|||||||
updateProfileItem: (item: IProfileItem) => Promise<void>
|
updateProfileItem: (item: IProfileItem) => Promise<void>
|
||||||
removeProfileItem: (id: string) => Promise<void>
|
removeProfileItem: (id: string) => Promise<void>
|
||||||
mutateProfileConfig: () => void
|
mutateProfileConfig: () => void
|
||||||
onClick: () => Promise<void>
|
onPress: () => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MenuItem {
|
interface MenuItem {
|
||||||
@ -48,7 +48,7 @@ const ProfileItem: React.FC<Props> = (props) => {
|
|||||||
removeProfileItem,
|
removeProfileItem,
|
||||||
mutateProfileConfig,
|
mutateProfileConfig,
|
||||||
updateProfileItem,
|
updateProfileItem,
|
||||||
onClick,
|
onPress,
|
||||||
isCurrent
|
isCurrent
|
||||||
} = props
|
} = props
|
||||||
const extra = info?.extra
|
const extra = info?.extra
|
||||||
@ -175,145 +175,142 @@ const ProfileItem: React.FC<Props> = (props) => {
|
|||||||
)}
|
)}
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
|
isPressable
|
||||||
|
onPress={() => {
|
||||||
|
if (disableSelect) return
|
||||||
|
setSelecting(true)
|
||||||
|
onPress().finally(() => {
|
||||||
|
setSelecting(false)
|
||||||
|
})
|
||||||
|
}}
|
||||||
className={`${isCurrent ? 'bg-primary' : ''} ${selecting ? 'blur-sm' : ''}`}
|
className={`${isCurrent ? 'bg-primary' : ''} ${selecting ? 'blur-sm' : ''}`}
|
||||||
>
|
>
|
||||||
<div
|
<div ref={setNodeRef} {...attributes} {...listeners} className="w-full h-full">
|
||||||
className="w-full h-full cursor-pointer"
|
<CardBody className="pb-1">
|
||||||
onClick={() => {
|
<div className="flex justify-between h-[32px]">
|
||||||
if (disableSelect) return
|
<h3
|
||||||
setSelecting(true)
|
title={info?.name}
|
||||||
onClick().finally(() => {
|
className={`text-ellipsis whitespace-nowrap overflow-hidden text-md font-bold leading-[32px] ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||||
setSelecting(false)
|
>
|
||||||
})
|
{info?.name}
|
||||||
}}
|
</h3>
|
||||||
>
|
<div className="flex">
|
||||||
<div ref={setNodeRef} {...attributes} {...listeners} className="w-full h-full">
|
{info.type === 'remote' && (
|
||||||
<CardBody className="pb-1">
|
<Tooltip placement="left" content={dayjs(info.updated).fromNow()}>
|
||||||
<div className="flex justify-between h-[32px]">
|
<Button
|
||||||
<h3
|
isIconOnly
|
||||||
title={info?.name}
|
size="sm"
|
||||||
className={`text-ellipsis whitespace-nowrap overflow-hidden text-md font-bold leading-[32px] ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
variant="light"
|
||||||
>
|
color="default"
|
||||||
{info?.name}
|
disabled={updating}
|
||||||
</h3>
|
onPress={async () => {
|
||||||
<div className="flex">
|
setUpdating(true)
|
||||||
{info.type === 'remote' && (
|
await addProfileItem(info)
|
||||||
<Tooltip placement="left" content={dayjs(info.updated).fromNow()}>
|
setUpdating(false)
|
||||||
<Button
|
}}
|
||||||
isIconOnly
|
>
|
||||||
size="sm"
|
<IoMdRefresh
|
||||||
variant="light"
|
|
||||||
color="default"
|
color="default"
|
||||||
disabled={updating}
|
className={`${isCurrent ? 'text-primary-foreground' : 'text-foreground'} text-[24px] ${updating ? 'animate-spin' : ''}`}
|
||||||
onPress={async () => {
|
/>
|
||||||
setUpdating(true)
|
</Button>
|
||||||
await addProfileItem(info)
|
</Tooltip>
|
||||||
setUpdating(false)
|
)}
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IoMdRefresh
|
|
||||||
color="default"
|
|
||||||
className={`${isCurrent ? 'text-primary-foreground' : 'text-foreground'} text-[24px] ${updating ? 'animate-spin' : ''}`}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Dropdown>
|
<Dropdown>
|
||||||
<DropdownTrigger>
|
<DropdownTrigger>
|
||||||
<Button isIconOnly size="sm" variant="light" color="default">
|
<Button isIconOnly size="sm" variant="light" color="default">
|
||||||
<IoMdMore
|
<IoMdMore
|
||||||
color="default"
|
color="default"
|
||||||
className={`text-[24px] ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
className={`text-[24px] ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownTrigger>
|
</DropdownTrigger>
|
||||||
<DropdownMenu onAction={onMenuAction}>
|
<DropdownMenu onAction={onMenuAction}>
|
||||||
{menuItems.map((item) => (
|
{menuItems.map((item) => (
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
showDivider={item.showDivider}
|
showDivider={item.showDivider}
|
||||||
key={item.key}
|
key={item.key}
|
||||||
color={item.color}
|
color={item.color}
|
||||||
className={item.className}
|
className={item.className}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
))}
|
))}
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{info.type === 'remote' && extra && (
|
</div>
|
||||||
<div
|
{info.type === 'remote' && extra && (
|
||||||
className={`mt-2 flex justify-between ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
<div
|
||||||
>
|
className={`mt-2 flex justify-between ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||||
<small>{`${calcTraffic(usage)}/${calcTraffic(total)}`}</small>
|
>
|
||||||
{profileDisplayDate === 'expire' ? (
|
<small>{`${calcTraffic(usage)}/${calcTraffic(total)}`}</small>
|
||||||
<Button
|
{profileDisplayDate === 'expire' ? (
|
||||||
size="sm"
|
<Button
|
||||||
variant="light"
|
|
||||||
className={`h-[20px] p-1 m-0 ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
|
||||||
onPress={async () => {
|
|
||||||
await patchAppConfig({ profileDisplayDate: 'update' })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{extra.expire ? dayjs.unix(extra.expire).format('YYYY-MM-DD') : '长期有效'}
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="light"
|
|
||||||
className={`h-[20px] p-1 m-0 ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
|
||||||
onPress={async () => {
|
|
||||||
await patchAppConfig({ profileDisplayDate: 'expire' })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{dayjs(info.updated).fromNow()}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardBody>
|
|
||||||
<CardFooter className="pt-0">
|
|
||||||
{info.type === 'remote' && !extra && (
|
|
||||||
<div
|
|
||||||
className={`w-full mt-2 flex justify-between ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
|
||||||
>
|
|
||||||
<Chip
|
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="bordered"
|
variant="light"
|
||||||
className={`${isCurrent ? 'text-primary-foreground border-primary-foreground' : 'border-primary text-primary'}`}
|
className={`h-[20px] p-1 m-0 ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||||
|
onPress={async () => {
|
||||||
|
await patchAppConfig({ profileDisplayDate: 'update' })
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
|
{extra.expire ? dayjs.unix(extra.expire).format('YYYY-MM-DD') : '长期有效'}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="light"
|
||||||
|
className={`h-[20px] p-1 m-0 ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||||
|
onPress={async () => {
|
||||||
|
await patchAppConfig({ profileDisplayDate: 'expire' })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dayjs(info.updated).fromNow()}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardBody>
|
||||||
|
<CardFooter className="pt-0">
|
||||||
|
{info.type === 'remote' && !extra && (
|
||||||
|
<div
|
||||||
|
className={`w-full mt-2 flex justify-between ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||||
|
>
|
||||||
|
<Chip
|
||||||
|
size="sm"
|
||||||
|
variant="bordered"
|
||||||
|
className={`${isCurrent ? 'text-primary-foreground border-primary-foreground' : 'border-primary text-primary'}`}
|
||||||
|
>
|
||||||
{t('profiles.remote')}
|
{t('profiles.remote')}
|
||||||
</Chip>
|
</Chip>
|
||||||
<small>{dayjs(info.updated).fromNow()}</small>
|
<small>{dayjs(info.updated).fromNow()}</small>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{info.type === 'local' && (
|
{info.type === 'local' && (
|
||||||
<div
|
<div
|
||||||
className={`mt-2 flex justify-between ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
className={`mt-2 flex justify-between ${isCurrent ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||||
|
>
|
||||||
|
<Chip
|
||||||
|
size="sm"
|
||||||
|
variant="bordered"
|
||||||
|
className={`${isCurrent ? 'text-primary-foreground border-primary-foreground' : 'border-primary text-primary'}`}
|
||||||
>
|
>
|
||||||
<Chip
|
|
||||||
size="sm"
|
|
||||||
variant="bordered"
|
|
||||||
className={`${isCurrent ? 'text-primary-foreground border-primary-foreground' : 'border-primary text-primary'}`}
|
|
||||||
>
|
|
||||||
{t('profiles.local')}
|
{t('profiles.local')}
|
||||||
</Chip>
|
</Chip>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{extra && (
|
{extra && (
|
||||||
<Progress
|
<Progress
|
||||||
className="w-full"
|
className="w-full"
|
||||||
aria-label={t('profiles.trafficUsage')}
|
aria-label={t('profiles.trafficUsage')}
|
||||||
classNames={{
|
classNames={{
|
||||||
indicator: isCurrent ? 'bg-primary-foreground' : 'bg-foreground'
|
indicator: isCurrent ? 'bg-primary-foreground' : 'bg-foreground'
|
||||||
}}
|
}}
|
||||||
value={calcPercent(extra?.upload, extra?.download, extra?.total)}
|
value={calcPercent(extra?.upload, extra?.download, extra?.total)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -51,6 +51,8 @@ const ProxyItem: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
onPress={() => onSelect(group.name, proxy.name)}
|
||||||
|
isPressable
|
||||||
fullWidth
|
fullWidth
|
||||||
shadow="sm"
|
shadow="sm"
|
||||||
className={`${
|
className={`${
|
||||||
@ -62,98 +64,93 @@ const ProxyItem: React.FC<Props> = (props) => {
|
|||||||
}`}
|
}`}
|
||||||
radius="sm"
|
radius="sm"
|
||||||
>
|
>
|
||||||
<div
|
<CardBody className="p-1">
|
||||||
onClick={() => onSelect(group.name, proxy.name)}
|
{proxyDisplayMode === 'full' ? (
|
||||||
className="cursor-pointer"
|
<div className="flex flex-col gap-1">
|
||||||
>
|
<div className="flex justify-between items-center pl-1">
|
||||||
<CardBody className="p-1">
|
<div className="text-ellipsis overflow-hidden whitespace-nowrap" title={proxy.name}>
|
||||||
{proxyDisplayMode === 'full' ? (
|
{proxy.name}
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<div className="flex justify-between items-center pl-1">
|
|
||||||
<div className="text-ellipsis overflow-hidden whitespace-nowrap" title={proxy.name}>
|
|
||||||
{proxy.name}
|
|
||||||
</div>
|
|
||||||
{fixed && (
|
|
||||||
<Button
|
|
||||||
isIconOnly
|
|
||||||
title={t('proxies.unpin')}
|
|
||||||
color="danger"
|
|
||||||
onPress={async () => {
|
|
||||||
await mihomoUnfixedProxy(group.name)
|
|
||||||
mutateProxies()
|
|
||||||
}}
|
|
||||||
variant="light"
|
|
||||||
className="h-[20px] p-0 text-sm"
|
|
||||||
>
|
|
||||||
<FaMapPin className="text-md le" />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center pl-1">
|
{fixed && (
|
||||||
<div className="flex gap-1 items-center">
|
|
||||||
<div className="text-foreground-400 text-xs bg-default-100 px-1 rounded-md">
|
|
||||||
{proxy.type}
|
|
||||||
</div>
|
|
||||||
{['tfo', 'udp', 'xudp', 'mptcp', 'smux'].map(protocol =>
|
|
||||||
proxy[protocol as keyof IMihomoProxy] && (
|
|
||||||
<div key={protocol} className="text-foreground-400 text-xs bg-default-100 px-1 rounded-md">
|
|
||||||
{protocol}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
title={proxy.type}
|
|
||||||
isLoading={loading}
|
|
||||||
color={delayColor(delay)}
|
|
||||||
onPress={onDelay}
|
|
||||||
variant="light"
|
|
||||||
className="h-full text-sm ml-auto -mt-0.5"
|
|
||||||
>
|
|
||||||
{delayText(delay)}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex justify-between items-center pl-1 p-1">
|
|
||||||
<div className="text-ellipsis overflow-hidden whitespace-nowrap">
|
|
||||||
<div className="flag-emoji inline" title={proxy.name}>
|
|
||||||
{proxy.name}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-end">
|
|
||||||
{fixed && (
|
|
||||||
<Button
|
|
||||||
isIconOnly
|
|
||||||
title={t('proxies.unpin')}
|
title={t('proxies.unpin')}
|
||||||
color="danger"
|
color="danger"
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
await mihomoUnfixedProxy(group.name)
|
await mihomoUnfixedProxy(group.name)
|
||||||
mutateProxies()
|
mutateProxies()
|
||||||
}}
|
}}
|
||||||
variant="light"
|
|
||||||
className="h-[20px] p-0 text-sm"
|
|
||||||
>
|
|
||||||
<FaMapPin className="text-md le" />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<Button
|
|
||||||
isIconOnly
|
|
||||||
title={proxy.type}
|
|
||||||
isLoading={loading}
|
|
||||||
color={delayColor(delay)}
|
|
||||||
onPress={onDelay}
|
|
||||||
variant="light"
|
variant="light"
|
||||||
className="h-full p-0 text-sm"
|
className="h-[20px] p-0 text-sm"
|
||||||
>
|
>
|
||||||
{delayText(delay)}
|
<FaMapPin className="text-md le" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className="flex justify-between items-center pl-1">
|
||||||
</CardBody>
|
<div className="flex gap-1 items-center">
|
||||||
</div>
|
<div className="text-foreground-400 text-xs bg-default-100 px-1 rounded-md">
|
||||||
|
{proxy.type}
|
||||||
|
</div>
|
||||||
|
{['tfo', 'udp', 'xudp', 'mptcp', 'smux'].map(protocol =>
|
||||||
|
proxy[protocol as keyof IMihomoProxy] && (
|
||||||
|
<div key={protocol} className="text-foreground-400 text-xs bg-default-100 px-1 rounded-md">
|
||||||
|
{protocol}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
title={proxy.type}
|
||||||
|
isLoading={loading}
|
||||||
|
color={delayColor(delay)}
|
||||||
|
onPress={onDelay}
|
||||||
|
variant="light"
|
||||||
|
className="h-full text-sm ml-auto -mt-0.5"
|
||||||
|
>
|
||||||
|
{delayText(delay)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex justify-between items-center pl-1 p-1">
|
||||||
|
<div className="text-ellipsis overflow-hidden whitespace-nowrap">
|
||||||
|
<div className="flag-emoji inline" title={proxy.name}>
|
||||||
|
{proxy.name}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end">
|
||||||
|
{fixed && (
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
title={t('proxies.unpin')}
|
||||||
|
color="danger"
|
||||||
|
onPress={async () => {
|
||||||
|
await mihomoUnfixedProxy(group.name)
|
||||||
|
mutateProxies()
|
||||||
|
}}
|
||||||
|
variant="light"
|
||||||
|
className="h-[20px] p-0 text-sm"
|
||||||
|
>
|
||||||
|
<FaMapPin className="text-md le" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
title={proxy.type}
|
||||||
|
isLoading={loading}
|
||||||
|
color={delayColor(delay)}
|
||||||
|
onPress={onDelay}
|
||||||
|
variant="light"
|
||||||
|
className="h-full p-0 text-sm"
|
||||||
|
>
|
||||||
|
{delayText(delay)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -395,7 +395,7 @@ const Profiles: React.FC = () => {
|
|||||||
mutateProfileConfig={mutateProfileConfig}
|
mutateProfileConfig={mutateProfileConfig}
|
||||||
updateProfileItem={updateProfileItem}
|
updateProfileItem={updateProfileItem}
|
||||||
info={item}
|
info={item}
|
||||||
onClick={async () => {
|
onPress={async () => {
|
||||||
await changeCurrentProfile(item.id)
|
await changeCurrentProfile(item.id)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -329,121 +329,118 @@ const Proxies: React.FC = () => {
|
|||||||
className={`w-full pt-2 ${index === groupCounts.length - 1 && !isOpen[index] ? 'pb-2' : ''} px-2`}
|
className={`w-full pt-2 ${index === groupCounts.length - 1 && !isOpen[index] ? 'pb-2' : ''} px-2`}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
|
isPressable
|
||||||
fullWidth
|
fullWidth
|
||||||
|
onPress={() => {
|
||||||
|
setIsOpen((prev) => {
|
||||||
|
const newOpen = [...prev]
|
||||||
|
newOpen[index] = !prev[index]
|
||||||
|
return newOpen
|
||||||
|
})
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<CardBody className="w-full">
|
||||||
onClick={(): void => {
|
<div className="flex justify-between">
|
||||||
setIsOpen((prev) => {
|
<div className="flex text-ellipsis overflow-hidden whitespace-nowrap">
|
||||||
const newOpen = [...prev]
|
{groups[index].icon ? (
|
||||||
newOpen[index] = !prev[index]
|
<Avatar
|
||||||
return newOpen
|
className="bg-transparent mr-2"
|
||||||
})
|
size="sm"
|
||||||
}}
|
radius="sm"
|
||||||
className="cursor-pointer"
|
src={
|
||||||
>
|
groups[index].icon.startsWith('<svg')
|
||||||
<CardBody className="w-full">
|
? `data:image/svg+xml;utf8,${groups[index].icon}`
|
||||||
<div className="flex justify-between">
|
: localStorage.getItem(groups[index].icon) || groups[index].icon
|
||||||
<div className="flex text-ellipsis overflow-hidden whitespace-nowrap">
|
}
|
||||||
{groups[index].icon ? (
|
/>
|
||||||
<Avatar
|
) : null}
|
||||||
className="bg-transparent mr-2"
|
<div className="text-ellipsis overflow-hidden whitespace-nowrap">
|
||||||
size="sm"
|
<div
|
||||||
radius="sm"
|
title={groups[index].name}
|
||||||
src={
|
className="inline flag-emoji h-[32px] text-md leading-[32px]"
|
||||||
groups[index].icon.startsWith('<svg')
|
>
|
||||||
? `data:image/svg+xml;utf8,${groups[index].icon}`
|
{groups[index].name}
|
||||||
: localStorage.getItem(groups[index].icon) || groups[index].icon
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<div className="text-ellipsis overflow-hidden whitespace-nowrap">
|
|
||||||
<div
|
|
||||||
title={groups[index].name}
|
|
||||||
className="inline flag-emoji h-[32px] text-md leading-[32px]"
|
|
||||||
>
|
|
||||||
{groups[index].name}
|
|
||||||
</div>
|
|
||||||
{proxyDisplayMode === 'full' && (
|
|
||||||
<div
|
|
||||||
title={groups[index].type}
|
|
||||||
className="inline ml-2 text-sm text-foreground-500"
|
|
||||||
>
|
|
||||||
{groups[index].type}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{proxyDisplayMode === 'full' && (
|
|
||||||
<div className="inline flag-emoji ml-2 text-sm text-foreground-500">
|
|
||||||
{groups[index].now}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
{proxyDisplayMode === 'full' && (
|
{proxyDisplayMode === 'full' && (
|
||||||
<Chip size="sm" className="my-1 mr-2">
|
<div
|
||||||
{groups[index].all.length}
|
title={groups[index].type}
|
||||||
</Chip>
|
className="inline ml-2 text-sm text-foreground-500"
|
||||||
|
>
|
||||||
|
{groups[index].type}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{proxyDisplayMode === 'full' && (
|
||||||
|
<div className="inline flag-emoji ml-2 text-sm text-foreground-500">
|
||||||
|
{groups[index].now}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<CollapseInput
|
|
||||||
title={t('proxies.search.placeholder')}
|
|
||||||
value={searchValue[index]}
|
|
||||||
onValueChange={(v) => {
|
|
||||||
setSearchValue((prev) => {
|
|
||||||
const newSearchValue = [...prev]
|
|
||||||
newSearchValue[index] = v
|
|
||||||
return newSearchValue
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
title={t('proxies.locate')}
|
|
||||||
variant="light"
|
|
||||||
size="sm"
|
|
||||||
isIconOnly
|
|
||||||
onPress={() => {
|
|
||||||
if (!isOpen[index]) {
|
|
||||||
setIsOpen((prev) => {
|
|
||||||
const newOpen = [...prev]
|
|
||||||
newOpen[index] = true
|
|
||||||
return newOpen
|
|
||||||
})
|
|
||||||
}
|
|
||||||
let i = 0
|
|
||||||
for (let j = 0; j < index; j++) {
|
|
||||||
i += groupCounts[j]
|
|
||||||
}
|
|
||||||
i += Math.floor(
|
|
||||||
allProxies[index].findIndex(
|
|
||||||
(proxy) => proxy.name === groups[index].now
|
|
||||||
) / cols
|
|
||||||
)
|
|
||||||
virtuosoRef.current?.scrollToIndex({
|
|
||||||
index: Math.floor(i),
|
|
||||||
align: 'start'
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FaLocationCrosshairs className="text-lg text-foreground-500" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
title={t('proxies.delay.test')}
|
|
||||||
variant="light"
|
|
||||||
isLoading={delaying[index]}
|
|
||||||
size="sm"
|
|
||||||
isIconOnly
|
|
||||||
onPress={() => {
|
|
||||||
onGroupDelay(index)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MdOutlineSpeed className="text-lg text-foreground-500" />
|
|
||||||
</Button>
|
|
||||||
<IoIosArrowBack
|
|
||||||
className={`transition duration-200 ml-2 h-[32px] text-lg text-foreground-500 ${isOpen[index] ? '-rotate-90' : ''}`}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardBody>
|
<div className="flex">
|
||||||
</div>
|
{proxyDisplayMode === 'full' && (
|
||||||
|
<Chip size="sm" className="my-1 mr-2">
|
||||||
|
{groups[index].all.length}
|
||||||
|
</Chip>
|
||||||
|
)}
|
||||||
|
<CollapseInput
|
||||||
|
title={t('proxies.search.placeholder')}
|
||||||
|
value={searchValue[index]}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setSearchValue((prev) => {
|
||||||
|
const newSearchValue = [...prev]
|
||||||
|
newSearchValue[index] = v
|
||||||
|
return newSearchValue
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title={t('proxies.locate')}
|
||||||
|
variant="light"
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
onPress={() => {
|
||||||
|
if (!isOpen[index]) {
|
||||||
|
setIsOpen((prev) => {
|
||||||
|
const newOpen = [...prev]
|
||||||
|
newOpen[index] = true
|
||||||
|
return newOpen
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let i = 0
|
||||||
|
for (let j = 0; j < index; j++) {
|
||||||
|
i += groupCounts[j]
|
||||||
|
}
|
||||||
|
i += Math.floor(
|
||||||
|
allProxies[index].findIndex(
|
||||||
|
(proxy) => proxy.name === groups[index].now
|
||||||
|
) / cols
|
||||||
|
)
|
||||||
|
virtuosoRef.current?.scrollToIndex({
|
||||||
|
index: Math.floor(i),
|
||||||
|
align: 'start'
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FaLocationCrosshairs className="text-lg text-foreground-500" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
title={t('proxies.delay.test')}
|
||||||
|
variant="light"
|
||||||
|
isLoading={delaying[index]}
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
onPress={() => {
|
||||||
|
onGroupDelay(index)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdOutlineSpeed className="text-lg text-foreground-500" />
|
||||||
|
</Button>
|
||||||
|
<IoIosArrowBack
|
||||||
|
className={`transition duration-200 ml-2 h-[32px] text-lg text-foreground-500 ${isOpen[index] ? '-rotate-90' : ''}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user