clash-verge/src/components/profile-item.tsx

134 lines
3.2 KiB
TypeScript

import React from "react";
import dayjs from "dayjs";
import {
alpha,
Box,
ButtonBase,
styled,
Typography,
LinearProgress,
IconButton,
} from "@mui/material";
import { MenuRounded } from "@mui/icons-material";
import { ProfileItem } from "../services/command";
import parseTraffic from "../utils/parse-traffic";
const Wrapper = styled(Box)(({ theme }) => ({
width: "100%",
display: "block",
cursor: "pointer",
textAlign: "left",
borderRadius: theme.shape.borderRadius,
boxShadow: theme.shadows[2],
padding: "8px 16px",
boxSizing: "border-box",
}));
interface Props {
selected: boolean;
itemData: ProfileItem;
onClick: () => void;
onUpdate: () => void;
}
const ProfileItemComp: React.FC<Props> = (props) => {
const { selected, itemData, onClick, onUpdate } = props;
const { name = "Profile", extra } = itemData;
const { upload = 0, download = 0, total = 0 } = extra ?? {};
const from = parseUrl(itemData.url);
const expire = parseExpire(extra?.expire);
const progress = Math.round(((download + upload) * 100) / (total + 0.1));
return (
<Wrapper
sx={({ palette }) => {
const { mode, primary, text, grey } = palette;
const isDark = mode === "dark";
if (selected) {
const bgcolor = isDark
? alpha(primary.main, 0.35)
: alpha(primary.main, 0.15);
return {
bgcolor,
color: isDark ? alpha(text.secondary, 0.6) : text.secondary,
"& h2": {
color: isDark ? primary.light : primary.main,
},
};
}
const bgcolor = isDark
? alpha(grey[700], 0.35)
: palette.background.paper;
return {
bgcolor,
color: isDark ? alpha(text.secondary, 0.6) : text.secondary,
"& h2": {
color: isDark ? text.primary : text.primary,
},
};
}}
onClick={onClick}
>
<Box display="flex" justifyContent="space-between">
<Typography
width="calc(100% - 40px)"
variant="h6"
component="h2"
noWrap
title={name}
>
{name}
</Typography>
<IconButton
sx={{ width: 30, height: 30 }}
color="inherit"
onClick={(e) => {
e.stopPropagation();
onUpdate();
}}
>
<MenuRounded />
</IconButton>
</Box>
<Typography noWrap title={from}>
{from}
</Typography>
<Box
sx={{
my: 0.5,
fontSize: 14,
display: "flex",
justifyContent: "space-between",
}}
>
<span>
{parseTraffic(upload + download)} / {parseTraffic(total)}
</span>
<span>{expire}</span>
</Box>
<LinearProgress variant="determinate" value={progress} color="inherit" />
</Wrapper>
);
};
function parseUrl(url?: string) {
if (!url) return "";
const regex = /https?:\/\/(.+?)\//;
const result = url.match(regex);
return result ? result[1] : "local file";
}
function parseExpire(expire?: number) {
if (!expire) return "-";
return dayjs(expire * 1000).format("YYYY-MM-DD");
}
export default ProfileItemComp;