feat: refactor and adjust ui
This commit is contained in:
parent
59c09f90f9
commit
d6c3bc57c0
@ -28,3 +28,4 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@import "./layout.scss";
|
@import "./layout.scss";
|
||||||
|
@import "./page.scss";
|
||||||
|
@ -27,6 +27,10 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.the-newbtn {
|
.the-newbtn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
@ -54,27 +58,24 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
flex: 1 1 75%;
|
flex: 1 1 75%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 2px 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.the-bar {
|
.the-bar {
|
||||||
flex: 0 0 30px;
|
position: absolute;
|
||||||
width: 100%;
|
top: 2px;
|
||||||
height: 30px;
|
right: 8px;
|
||||||
padding: 0 16px;
|
height: 36px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.the-content {
|
.the-content {
|
||||||
flex: 1 1 100%;
|
position: absolute;
|
||||||
overflow: auto;
|
left: 0;
|
||||||
box-sizing: border-box;
|
right: 0;
|
||||||
scrollbar-gutter: stable;
|
top: 30px;
|
||||||
|
bottom: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
src/assets/styles/page.scss
Normal file
33
src/assets/styles/page.scss
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
.base-page {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> header {
|
||||||
|
flex: 0 0 58px;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 850px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
> section {
|
||||||
|
position: relative;
|
||||||
|
flex: 1 1 100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 8px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
|
||||||
|
.base-content {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 850px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
src/components/base-page.tsx
Normal file
32
src/components/base-page.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Typography } from "@mui/material";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title?: React.ReactNode; // the page title
|
||||||
|
header?: React.ReactNode; // something behind title
|
||||||
|
contentStyle?: React.CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BasePage: React.FC<Props> = (props) => {
|
||||||
|
const { title, header, contentStyle, children } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="base-page" data-windrag>
|
||||||
|
<header data-windrag>
|
||||||
|
<Typography variant="h4" component="h1">
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{header}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section data-windrag>
|
||||||
|
<div className="base-content" style={contentStyle} data-windrag>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BasePage;
|
40
src/components/update-button.tsx
Normal file
40
src/components/update-button.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import useSWR from "swr";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Button } from "@mui/material";
|
||||||
|
import { checkUpdate } from "@tauri-apps/api/updater";
|
||||||
|
import UpdateDialog from "./update-dialog";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateButton = (props: Props) => {
|
||||||
|
const { className } = props;
|
||||||
|
|
||||||
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
|
||||||
|
errorRetryCount: 2,
|
||||||
|
revalidateIfStale: false,
|
||||||
|
focusThrottleInterval: 36e5, // 1 hour
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!updateInfo?.shouldUpdate) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
color="error"
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
className={className}
|
||||||
|
onClick={() => setDialogOpen(true)}
|
||||||
|
>
|
||||||
|
New
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<UpdateDialog open={dialogOpen} onClose={() => setDialogOpen(false)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UpdateButton;
|
39
src/components/window-control.tsx
Normal file
39
src/components/window-control.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { Button } from "@mui/material";
|
||||||
|
import { appWindow } from "@tauri-apps/api/window";
|
||||||
|
import {
|
||||||
|
CloseRounded,
|
||||||
|
CropLandscapeOutlined,
|
||||||
|
HorizontalRuleRounded,
|
||||||
|
} from "@mui/icons-material";
|
||||||
|
|
||||||
|
const WindowControl = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
sx={{ minWidth: 48 }}
|
||||||
|
onClick={() => appWindow.minimize()}
|
||||||
|
>
|
||||||
|
<HorizontalRuleRounded />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
sx={{ minWidth: 48 }}
|
||||||
|
onClick={() => appWindow.toggleMaximize()}
|
||||||
|
>
|
||||||
|
<CropLandscapeOutlined />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
sx={{ minWidth: 48 }}
|
||||||
|
onClick={() => appWindow.hide()}
|
||||||
|
>
|
||||||
|
<CloseRounded />
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WindowControl;
|
@ -1,72 +1,26 @@
|
|||||||
import { useEffect, useMemo, useState } from "react";
|
|
||||||
import useSWR, { SWRConfig } from "swr";
|
import useSWR, { SWRConfig } from "swr";
|
||||||
|
import { useEffect, useMemo } from "react";
|
||||||
import { Route, Routes } from "react-router-dom";
|
import { Route, Routes } from "react-router-dom";
|
||||||
import { useRecoilState } from "recoil";
|
import { useRecoilState } from "recoil";
|
||||||
import {
|
import { alpha, createTheme, List, Paper, ThemeProvider } from "@mui/material";
|
||||||
alpha,
|
import { appWindow } from "@tauri-apps/api/window";
|
||||||
Button,
|
|
||||||
createTheme,
|
|
||||||
IconButton,
|
|
||||||
List,
|
|
||||||
Paper,
|
|
||||||
ThemeProvider,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { HorizontalRuleRounded, CloseRounded } from "@mui/icons-material";
|
|
||||||
import { checkUpdate } from "@tauri-apps/api/updater";
|
|
||||||
import { atomPaletteMode, atomThemeBlur } from "../states/setting";
|
import { atomPaletteMode, atomThemeBlur } from "../states/setting";
|
||||||
import { getVergeConfig, windowDrag, windowHide } from "../services/cmds";
|
import { getVergeConfig } from "../services/cmds";
|
||||||
|
import { routers } from "./_routers";
|
||||||
import LogoSvg from "../assets/image/logo.svg";
|
import LogoSvg from "../assets/image/logo.svg";
|
||||||
import LogPage from "./log";
|
|
||||||
import ProfilePage from "./profile";
|
|
||||||
import ProxyPage from "./proxy";
|
|
||||||
import SettingPage from "./setting";
|
|
||||||
import ConnectionsPage from "./connections";
|
|
||||||
import LayoutItem from "../components/layout-item";
|
|
||||||
import Traffic from "../components/traffic";
|
import Traffic from "../components/traffic";
|
||||||
import UpdateDialog from "../components/update-dialog";
|
import LayoutItem from "../components/layout-item";
|
||||||
|
import UpdateButton from "../components/update-button";
|
||||||
const routers = [
|
import WindowControl from "../components/window-control";
|
||||||
{
|
|
||||||
label: "Proxy",
|
|
||||||
link: "/",
|
|
||||||
ele: ProxyPage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Profile",
|
|
||||||
link: "/profile",
|
|
||||||
ele: ProfilePage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Connections",
|
|
||||||
link: "/connections",
|
|
||||||
ele: ConnectionsPage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Log",
|
|
||||||
link: "/log",
|
|
||||||
ele: LogPage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Setting",
|
|
||||||
link: "/setting",
|
|
||||||
ele: SettingPage,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const Layout = () => {
|
const Layout = () => {
|
||||||
const [mode, setMode] = useRecoilState(atomPaletteMode);
|
const [mode, setMode] = useRecoilState(atomPaletteMode);
|
||||||
const [blur, setBlur] = useRecoilState(atomThemeBlur);
|
const [blur, setBlur] = useRecoilState(atomThemeBlur);
|
||||||
const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig);
|
const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig);
|
||||||
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
|
|
||||||
errorRetryCount: 2,
|
|
||||||
revalidateIfStale: false,
|
|
||||||
focusThrottleInterval: 36e5, // 1 hour
|
|
||||||
});
|
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.addEventListener("keydown", (e) => {
|
window.addEventListener("keydown", (e) => {
|
||||||
if (e.key === "Escape") windowHide();
|
if (e.key === "Escape") appWindow.hide();
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -96,6 +50,12 @@ const Layout = () => {
|
|||||||
});
|
});
|
||||||
}, [mode]);
|
}, [mode]);
|
||||||
|
|
||||||
|
const onDragging = (e: any) => {
|
||||||
|
if (e?.target?.dataset?.windrag) {
|
||||||
|
appWindow.startDragging();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SWRConfig value={{}}>
|
<SWRConfig value={{}}>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
@ -103,38 +63,21 @@ const Layout = () => {
|
|||||||
square
|
square
|
||||||
elevation={0}
|
elevation={0}
|
||||||
className="layout"
|
className="layout"
|
||||||
|
onPointerDown={onDragging}
|
||||||
sx={[
|
sx={[
|
||||||
(theme) => ({
|
(theme) => ({
|
||||||
bgcolor: alpha(theme.palette.background.paper, blur ? 0.85 : 1),
|
bgcolor: alpha(theme.palette.background.paper, blur ? 0.85 : 1),
|
||||||
}),
|
}),
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<div className="layout__left">
|
<div className="layout__left" data-windrag>
|
||||||
<div className="the-logo">
|
<div className="the-logo" data-windrag>
|
||||||
<img
|
<img src={LogoSvg} alt="" data-windrag />
|
||||||
src={LogoSvg}
|
|
||||||
width="100%"
|
|
||||||
alt=""
|
|
||||||
onPointerDown={(e) => {
|
|
||||||
windowDrag();
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{updateInfo?.shouldUpdate && (
|
<UpdateButton className="the-newbtn" />
|
||||||
<Button
|
|
||||||
color="error"
|
|
||||||
variant="contained"
|
|
||||||
size="small"
|
|
||||||
className="the-newbtn"
|
|
||||||
onClick={() => setDialogOpen(true)}
|
|
||||||
>
|
|
||||||
New
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<List className="the-menu">
|
<List className="the-menu" data-windrag>
|
||||||
{routers.map((router) => (
|
{routers.map((router) => (
|
||||||
<LayoutItem key={router.label} to={router.link}>
|
<LayoutItem key={router.label} to={router.link}>
|
||||||
{router.label}
|
{router.label}
|
||||||
@ -142,29 +85,17 @@ const Layout = () => {
|
|||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<div className="the-traffic">
|
<div className="the-traffic" data-windrag>
|
||||||
<Traffic />
|
<Traffic />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="layout__right">
|
<div className="layout__right" data-windrag>
|
||||||
<div
|
<div className="the-bar">
|
||||||
className="the-bar"
|
<WindowControl />
|
||||||
onPointerDown={(e) =>
|
|
||||||
e.target === e.currentTarget && windowDrag()
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{/* todo: onClick = windowMini */}
|
|
||||||
<IconButton size="small" sx={{ mx: 1 }} onClick={windowHide}>
|
|
||||||
<HorizontalRuleRounded fontSize="inherit" />
|
|
||||||
</IconButton>
|
|
||||||
|
|
||||||
<IconButton size="small" onClick={windowHide}>
|
|
||||||
<CloseRounded fontSize="inherit" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="the-content">
|
<div className="the-content" data-windrag>
|
||||||
<Routes>
|
<Routes>
|
||||||
{routers.map(({ label, link, ele: Ele }) => (
|
{routers.map(({ label, link, ele: Ele }) => (
|
||||||
<Route key={label} path={link} element={<Ele />} />
|
<Route key={label} path={link} element={<Ele />} />
|
||||||
@ -173,7 +104,6 @@ const Layout = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
<UpdateDialog open={dialogOpen} onClose={() => setDialogOpen(false)} />
|
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</SWRConfig>
|
</SWRConfig>
|
||||||
);
|
);
|
||||||
|
33
src/pages/_routers.tsx
Normal file
33
src/pages/_routers.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import LogPage from "./log";
|
||||||
|
import ProxyPage from "./proxy";
|
||||||
|
import ProfilePage from "./profile";
|
||||||
|
import SettingPage from "./setting";
|
||||||
|
import ConnectionsPage from "./connections";
|
||||||
|
|
||||||
|
export const routers = [
|
||||||
|
{
|
||||||
|
label: "Proxy",
|
||||||
|
link: "/",
|
||||||
|
ele: ProxyPage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Profile",
|
||||||
|
link: "/profile",
|
||||||
|
ele: ProfilePage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Connections",
|
||||||
|
link: "/connections",
|
||||||
|
ele: ConnectionsPage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Log",
|
||||||
|
link: "/log",
|
||||||
|
ele: LogPage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Setting",
|
||||||
|
link: "/setting",
|
||||||
|
ele: SettingPage,
|
||||||
|
},
|
||||||
|
];
|
@ -1,8 +1,9 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Box, Paper, Typography } from "@mui/material";
|
import { Paper } from "@mui/material";
|
||||||
import { Virtuoso } from "react-virtuoso";
|
import { Virtuoso } from "react-virtuoso";
|
||||||
import { getInfomation } from "../services/api";
|
|
||||||
import { ApiType } from "../services/types";
|
import { ApiType } from "../services/types";
|
||||||
|
import { getInfomation } from "../services/api";
|
||||||
|
import BasePage from "../components/base-page";
|
||||||
import ConnectionItem from "../components/connection-item";
|
import ConnectionItem from "../components/connection-item";
|
||||||
|
|
||||||
const ConnectionsPage = () => {
|
const ConnectionsPage = () => {
|
||||||
@ -26,25 +27,14 @@ const ConnectionsPage = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<BasePage title="Connections" contentStyle={{ height: "100%" }}>
|
||||||
sx={{
|
<Paper sx={{ boxShadow: 2, height: "100%" }}>
|
||||||
width: 0.9,
|
|
||||||
maxWidth: "850px",
|
|
||||||
height: "100%",
|
|
||||||
mx: "auto",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="h4" component="h1" sx={{ py: 2 }}>
|
|
||||||
Connections
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Paper sx={{ boxShadow: 2, height: "calc(100% - 100px)" }}>
|
|
||||||
<Virtuoso
|
<Virtuoso
|
||||||
data={conn.connections}
|
data={conn.connections}
|
||||||
itemContent={(index, item) => <ConnectionItem value={item} />}
|
itemContent={(index, item) => <ConnectionItem value={item} />}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</BasePage>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Box, Button, Paper, Typography } from "@mui/material";
|
import { Button, Paper } from "@mui/material";
|
||||||
import { Virtuoso } from "react-virtuoso";
|
import { Virtuoso } from "react-virtuoso";
|
||||||
import { ApiType } from "../services/types";
|
import { ApiType } from "../services/types";
|
||||||
import { getInfomation } from "../services/api";
|
import { getInfomation } from "../services/api";
|
||||||
|
import BasePage from "../components/base-page";
|
||||||
import LogItem from "../components/log-item";
|
import LogItem from "../components/log-item";
|
||||||
|
|
||||||
let logCache: ApiType.LogItem[] = [];
|
let logCache: ApiType.LogItem[] = [];
|
||||||
@ -28,33 +29,27 @@ const LogPage = () => {
|
|||||||
return () => ws?.close();
|
return () => ws?.close();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
const onClear = () => {
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: "relative",
|
|
||||||
width: 0.9,
|
|
||||||
maxWidth: "850px",
|
|
||||||
height: "100%",
|
|
||||||
mx: "auto",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="h4" component="h1" sx={{ py: 2 }}>
|
|
||||||
Logs
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="contained"
|
|
||||||
sx={{ position: "absolute", top: 22, right: 0 }}
|
|
||||||
onClick={() => {
|
|
||||||
setLogData([]);
|
setLogData([]);
|
||||||
logCache = [];
|
logCache = [];
|
||||||
}}
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BasePage
|
||||||
|
title="Logs"
|
||||||
|
contentStyle={{ height: "100%" }}
|
||||||
|
header={
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
sx={{ mt: 1 }}
|
||||||
|
variant="contained"
|
||||||
|
onClick={onClear}
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
</Button>
|
</Button>
|
||||||
|
}
|
||||||
<Paper sx={{ boxShadow: 2, height: "calc(100% - 100px)" }}>
|
>
|
||||||
|
<Paper sx={{ boxShadow: 2, height: "100%" }}>
|
||||||
<Virtuoso
|
<Virtuoso
|
||||||
initialTopMostItemIndex={999}
|
initialTopMostItemIndex={999}
|
||||||
data={logData}
|
data={logData}
|
||||||
@ -62,7 +57,7 @@ const LogPage = () => {
|
|||||||
followOutput={"smooth"}
|
followOutput={"smooth"}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</BasePage>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
import useSWR, { useSWRConfig } from "swr";
|
import useSWR, { useSWRConfig } from "swr";
|
||||||
import { Box, Button, Grid, TextField, Typography } from "@mui/material";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { Box, Button, Grid, TextField } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
getProfiles,
|
getProfiles,
|
||||||
selectProfile,
|
selectProfile,
|
||||||
@ -8,9 +8,10 @@ import {
|
|||||||
importProfile,
|
importProfile,
|
||||||
} from "../services/cmds";
|
} from "../services/cmds";
|
||||||
import { getProxies, updateProxy } from "../services/api";
|
import { getProxies, updateProxy } from "../services/api";
|
||||||
import ProfileItemComp from "../components/profile-item";
|
|
||||||
import useNotice from "../utils/use-notice";
|
|
||||||
import noop from "../utils/noop";
|
import noop from "../utils/noop";
|
||||||
|
import useNotice from "../utils/use-notice";
|
||||||
|
import BasePage from "../components/base-page";
|
||||||
|
import ProfileItemComp from "../components/profile-item";
|
||||||
|
|
||||||
const ProfilePage = () => {
|
const ProfilePage = () => {
|
||||||
const [url, setUrl] = useState("");
|
const [url, setUrl] = useState("");
|
||||||
@ -97,11 +98,7 @@ const ProfilePage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ width: 0.9, maxWidth: "850px", mx: "auto", mb: 2 }}>
|
<BasePage title="Profiles">
|
||||||
<Typography variant="h4" component="h1" sx={{ py: 2, mb: 1 }}>
|
|
||||||
Profiles
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Box sx={{ display: "flex", mb: 3 }}>
|
<Box sx={{ display: "flex", mb: 3 }}>
|
||||||
<TextField
|
<TextField
|
||||||
id="profile_url"
|
id="profile_url"
|
||||||
@ -136,7 +133,7 @@ const ProfilePage = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{noticeElement}
|
{noticeElement}
|
||||||
</Box>
|
</BasePage>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import useSWR, { useSWRConfig } from "swr";
|
import useSWR, { useSWRConfig } from "swr";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Box, List, Paper, Typography } from "@mui/material";
|
import { List, Paper } from "@mui/material";
|
||||||
import { getProxies } from "../services/api";
|
import { getProxies } from "../services/api";
|
||||||
import ProxyGroup from "../components/proxy-group";
|
import BasePage from "../components/base-page";
|
||||||
import ProxyItem from "../components/proxy-item";
|
import ProxyItem from "../components/proxy-item";
|
||||||
|
import ProxyGroup from "../components/proxy-group";
|
||||||
|
|
||||||
const ProxyPage = () => {
|
const ProxyPage = () => {
|
||||||
const { mutate } = useSWRConfig();
|
const { mutate } = useSWRConfig();
|
||||||
@ -19,12 +20,8 @@ const ProxyPage = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ width: 0.9, maxWidth: "850px", mx: "auto", mb: 2 }}>
|
<BasePage title={groups.length ? "Proxy Groups" : "Proxies"}>
|
||||||
<Typography variant="h4" component="h1" sx={{ py: 2 }}>
|
<Paper sx={{ borderRadius: 1, boxShadow: 2, mb: 1 }}>
|
||||||
{groups.length ? "Proxy Groups" : "Proxies"}
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Paper sx={{ borderRadius: 1, boxShadow: 2 }}>
|
|
||||||
{groups.length > 0 && (
|
{groups.length > 0 && (
|
||||||
<List>
|
<List>
|
||||||
{groups.map((group) => (
|
{groups.map((group) => (
|
||||||
@ -46,7 +43,7 @@ const ProxyPage = () => {
|
|||||||
</List>
|
</List>
|
||||||
)}
|
)}
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</BasePage>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import { Box, Paper, Typography } from "@mui/material";
|
import { Paper } from "@mui/material";
|
||||||
|
import BasePage from "../components/base-page";
|
||||||
import SettingVerge from "../components/setting-verge";
|
import SettingVerge from "../components/setting-verge";
|
||||||
import SettingClash from "../components/setting-clash";
|
import SettingClash from "../components/setting-clash";
|
||||||
|
|
||||||
const SettingPage = () => {
|
const SettingPage = () => {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ width: 0.9, maxWidth: 850, mx: "auto", mb: 2 }}>
|
<BasePage title="Settings">
|
||||||
<Typography variant="h4" component="h1" sx={{ py: 2 }}>
|
|
||||||
Setting
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Paper sx={{ borderRadius: 1, boxShadow: 2 }}>
|
<Paper sx={{ borderRadius: 1, boxShadow: 2 }}>
|
||||||
<SettingVerge />
|
<SettingVerge />
|
||||||
</Paper>
|
</Paper>
|
||||||
@ -16,7 +13,7 @@ const SettingPage = () => {
|
|||||||
<Paper sx={{ borderRadius: 1, boxShadow: 2, mt: 3 }}>
|
<Paper sx={{ borderRadius: 1, boxShadow: 2, mt: 3 }}>
|
||||||
<SettingClash />
|
<SettingClash />
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</BasePage>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,18 +36,6 @@ export async function restartSidecar() {
|
|||||||
return invoke<void>("restart_sidecar");
|
return invoke<void>("restart_sidecar");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function windowDrag() {
|
|
||||||
return invoke<void>("win_drag");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function windowHide() {
|
|
||||||
return invoke<void>("win_hide");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function windowMini() {
|
|
||||||
return invoke<void>("win_mini");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getClashInfo() {
|
export async function getClashInfo() {
|
||||||
return invoke<CmdType.ClashInfo | null>("get_clash_info");
|
return invoke<CmdType.ClashInfo | null>("get_clash_info");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user