mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 04:43:44 +08:00
feat: add proxy item check loading
This commit is contained in:
parent
59c856fc0e
commit
005c6bb9f1
50
src/components/base/base-loading.tsx
Normal file
50
src/components/base/base-loading.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { styled } from "@mui/material";
|
||||||
|
|
||||||
|
const Loading = styled("div")`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 18px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
margin: 2px;
|
||||||
|
border-radius: 100%;
|
||||||
|
animation: loading 0.7s -0.15s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div:nth-child(2n-1) {
|
||||||
|
animation-delay: -0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading {
|
||||||
|
50% {
|
||||||
|
opacity: 0.2;
|
||||||
|
transform: scale(0.75);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LoadingItem = styled("div")(({ theme }) => ({
|
||||||
|
background: theme.palette.text.secondary,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const BaseLoading = () => {
|
||||||
|
return (
|
||||||
|
<Loading>
|
||||||
|
<LoadingItem />
|
||||||
|
<LoadingItem />
|
||||||
|
<LoadingItem />
|
||||||
|
</Loading>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BaseLoading;
|
@ -13,6 +13,7 @@ import {
|
|||||||
Theme,
|
Theme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import delayManager from "@/services/delay";
|
import delayManager from "@/services/delay";
|
||||||
|
import BaseLoading from "../base/base-loading";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
groupName: string;
|
groupName: string;
|
||||||
@ -43,6 +44,9 @@ const TypeBox = styled(Box)(({ theme }) => ({
|
|||||||
|
|
||||||
const ProxyItem = (props: Props) => {
|
const ProxyItem = (props: Props) => {
|
||||||
const { groupName, proxy, selected, showType = true, sx, onClick } = props;
|
const { groupName, proxy, selected, showType = true, sx, onClick } = props;
|
||||||
|
|
||||||
|
// -1/<=0 为 不显示
|
||||||
|
// -2 为 loading
|
||||||
const [delay, setDelay] = useState(-1);
|
const [delay, setDelay] = useState(-1);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -61,6 +65,7 @@ const ProxyItem = (props: Props) => {
|
|||||||
}, [proxy]);
|
}, [proxy]);
|
||||||
|
|
||||||
const onDelay = useLockFn(async () => {
|
const onDelay = useLockFn(async () => {
|
||||||
|
setDelay(-2);
|
||||||
return delayManager
|
return delayManager
|
||||||
.checkDelay(proxy.name, groupName)
|
.checkDelay(proxy.name, groupName)
|
||||||
.then((result) => setDelay(result))
|
.then((result) => setDelay(result))
|
||||||
@ -81,14 +86,9 @@ const ProxyItem = (props: Props) => {
|
|||||||
? alpha(primary.main, 0.15)
|
? alpha(primary.main, 0.15)
|
||||||
: alpha(primary.main, 0.35);
|
: alpha(primary.main, 0.35);
|
||||||
const color = mode === "light" ? primary.main : primary.light;
|
const color = mode === "light" ? primary.main : primary.light;
|
||||||
|
|
||||||
const showDelay = delay > 0;
|
const showDelay = delay > 0;
|
||||||
const showIcon = !showDelay && selected;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
".the-check": { display: "none" },
|
|
||||||
".the-delay": { display: showDelay ? "block" : "none" },
|
|
||||||
".the-icon": { display: showIcon ? "block" : "none" },
|
|
||||||
"&:hover .the-check": { display: !showDelay ? "block" : "none" },
|
"&:hover .the-check": { display: !showDelay ? "block" : "none" },
|
||||||
"&:hover .the-delay": { display: showDelay ? "block" : "none" },
|
"&:hover .the-delay": { display: showDelay ? "block" : "none" },
|
||||||
"&:hover .the-icon": { display: "none" },
|
"&:hover .the-icon": { display: "none" },
|
||||||
@ -116,7 +116,14 @@ const ProxyItem = (props: Props) => {
|
|||||||
<ListItemIcon
|
<ListItemIcon
|
||||||
sx={{ justifyContent: "flex-end", color: "primary.main" }}
|
sx={{ justifyContent: "flex-end", color: "primary.main" }}
|
||||||
>
|
>
|
||||||
{!proxy.provider && (
|
{delay === -2 && (
|
||||||
|
<Widget>
|
||||||
|
<BaseLoading />
|
||||||
|
</Widget>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!proxy.provider && delay !== -2 && (
|
||||||
|
// provider的节点不支持检测
|
||||||
<Widget
|
<Widget
|
||||||
className="the-check"
|
className="the-check"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@ -124,43 +131,49 @@ const ProxyItem = (props: Props) => {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onDelay();
|
onDelay();
|
||||||
}}
|
}}
|
||||||
sx={(theme) => ({
|
sx={({ palette }) => ({
|
||||||
":hover": { bgcolor: alpha(theme.palette.primary.main, 0.15) },
|
display: "none", // hover才显示
|
||||||
|
":hover": { bgcolor: alpha(palette.primary.main, 0.15) },
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
Check
|
Check
|
||||||
</Widget>
|
</Widget>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Widget
|
{delay > 0 && (
|
||||||
className="the-delay"
|
// 显示延迟
|
||||||
onClick={(e) => {
|
<Widget
|
||||||
if (proxy.provider) return;
|
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}ms`}
|
||||||
|
</Widget>
|
||||||
|
)}
|
||||||
|
|
||||||
e.preventDefault();
|
{delay !== -2 && delay <= 0 && selected && (
|
||||||
e.stopPropagation();
|
// 展示已选择的icon
|
||||||
onDelay();
|
<CheckCircleOutlineRounded
|
||||||
}}
|
className="the-icon"
|
||||||
color={
|
sx={{ fontSize: 16 }}
|
||||||
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}ms`}
|
|
||||||
</Widget>
|
|
||||||
|
|
||||||
<CheckCircleOutlineRounded
|
|
||||||
className="the-icon"
|
|
||||||
sx={{ fontSize: 16 }}
|
|
||||||
/>
|
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user