mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
feat: support to change proxy layout column
This commit is contained in:
182
src/components/proxy/proxy-item-mini.tsx
Normal file
182
src/components/proxy/proxy-item-mini.tsx
Normal file
@@ -0,0 +1,182 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { CheckCircleOutlineRounded } from "@mui/icons-material";
|
||||
import {
|
||||
alpha,
|
||||
Box,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
styled,
|
||||
} from "@mui/material";
|
||||
import { BaseLoading } from "@/components/base";
|
||||
import delayManager from "@/services/delay";
|
||||
|
||||
interface Props {
|
||||
groupName: string;
|
||||
proxy: IProxyItem;
|
||||
selected: boolean;
|
||||
showType?: boolean;
|
||||
onClick?: (name: string) => void;
|
||||
}
|
||||
|
||||
// 多列布局
|
||||
export const ProxyItemMini = (props: Props) => {
|
||||
const { groupName, proxy, selected, showType = true, onClick } = props;
|
||||
|
||||
// -1/<=0 为 不显示
|
||||
// -2 为 loading
|
||||
const [delay, setDelay] = useState(-1);
|
||||
|
||||
useEffect(() => {
|
||||
delayManager.setListener(proxy.name, groupName, setDelay);
|
||||
|
||||
return () => {
|
||||
delayManager.removeListener(proxy.name, groupName);
|
||||
};
|
||||
}, [proxy.name, groupName]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!proxy) return;
|
||||
setDelay(delayManager.getDelayFix(proxy, groupName));
|
||||
}, [proxy]);
|
||||
|
||||
const onDelay = useLockFn(async () => {
|
||||
setDelay(-2);
|
||||
setDelay(await delayManager.checkDelay(proxy.name, groupName));
|
||||
});
|
||||
|
||||
return (
|
||||
<ListItemButton
|
||||
dense
|
||||
selected={selected}
|
||||
onClick={() => onClick?.(proxy.name)}
|
||||
sx={[
|
||||
{ borderRadius: 1, pl: 1.5, pr: 1 },
|
||||
({ palette: { mode, primary } }) => {
|
||||
const bgcolor =
|
||||
mode === "light"
|
||||
? alpha(primary.main, 0.15)
|
||||
: alpha(primary.main, 0.35);
|
||||
const color = mode === "light" ? primary.main : primary.light;
|
||||
const showDelay = delay > 0;
|
||||
|
||||
return {
|
||||
"&:hover .the-check": { display: !showDelay ? "block" : "none" },
|
||||
"&:hover .the-delay": { display: showDelay ? "block" : "none" },
|
||||
"&:hover .the-icon": { display: "none" },
|
||||
"&.Mui-selected": { bgcolor },
|
||||
"&.Mui-selected .MuiListItemText-secondary": { color },
|
||||
};
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ListItemText
|
||||
title={proxy.name}
|
||||
secondary={
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
textOverflow: "ellipsis",
|
||||
wordBreak: "break-all",
|
||||
overflow: "hidden",
|
||||
whiteSpace: showType ? "nowrap" : "inherit",
|
||||
}}
|
||||
>
|
||||
{proxy.name}
|
||||
</div>
|
||||
|
||||
{showType && (
|
||||
<>
|
||||
{!!proxy.provider && (
|
||||
<TypeBox component="span">{proxy.provider}</TypeBox>
|
||||
)}
|
||||
<TypeBox component="span">{proxy.type}</TypeBox>
|
||||
{proxy.udp && <TypeBox component="span">UDP</TypeBox>}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<ListItemIcon sx={{ justifyContent: "flex-end", color: "primary.main" }}>
|
||||
{delay === -2 && (
|
||||
<Widget>
|
||||
<BaseLoading />
|
||||
</Widget>
|
||||
)}
|
||||
|
||||
{!proxy.provider && delay !== -2 && (
|
||||
// provider的节点不支持检测
|
||||
<Widget
|
||||
className="the-check"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onDelay();
|
||||
}}
|
||||
sx={({ palette }) => ({
|
||||
display: "none", // hover才显示
|
||||
":hover": { bgcolor: alpha(palette.primary.main, 0.15) },
|
||||
})}
|
||||
>
|
||||
Check
|
||||
</Widget>
|
||||
)}
|
||||
|
||||
{delay > 0 && (
|
||||
// 显示延迟
|
||||
<Widget
|
||||
className="the-delay"
|
||||
onClick={(e) => {
|
||||
if (proxy.provider) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onDelay();
|
||||
}}
|
||||
color={
|
||||
delay > 500
|
||||
? "error.main"
|
||||
: delay < 100
|
||||
? "success.main"
|
||||
: "text.secondary"
|
||||
}
|
||||
sx={({ palette }) =>
|
||||
!proxy.provider
|
||||
? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{delay > 1e5 ? "Error" : delay > 3000 ? "Timeout" : `${delay}`}
|
||||
</Widget>
|
||||
)}
|
||||
|
||||
{delay !== -2 && delay <= 0 && selected && (
|
||||
// 展示已选择的icon
|
||||
<CheckCircleOutlineRounded
|
||||
className="the-icon"
|
||||
sx={{ fontSize: 16 }}
|
||||
/>
|
||||
)}
|
||||
</ListItemIcon>
|
||||
</ListItemButton>
|
||||
);
|
||||
};
|
||||
|
||||
const Widget = styled(Box)(() => ({
|
||||
padding: "3px 6px",
|
||||
fontSize: 14,
|
||||
borderRadius: "4px",
|
||||
}));
|
||||
|
||||
const TypeBox = styled(Box)(({ theme }) => ({
|
||||
display: "inline-block",
|
||||
border: "1px solid #ccc",
|
||||
borderColor: alpha(theme.palette.text.secondary, 0.36),
|
||||
color: alpha(theme.palette.text.secondary, 0.42),
|
||||
borderRadius: 4,
|
||||
fontSize: 10,
|
||||
marginRight: "4px",
|
||||
padding: "0 2px",
|
||||
lineHeight: 1.25,
|
||||
}));
|
||||
Reference in New Issue
Block a user