diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss
index c751c11c4f4d04f138a58ec257dbe52ba59f626d..3d5ba1142b651027dbe0995b4e7490a3b999d7c2 100644
--- a/src/assets/styles/index.scss
+++ b/src/assets/styles/index.scss
@@ -1,5 +1,5 @@
 html {
-  background-color: #fff;
+  background-color: #fefefe;
 }
 
 body {
@@ -15,53 +15,4 @@ code {
     monospace;
 }
 
-.layout {
-  width: 100%;
-  height: 100%;
-  display: flex;
-
-  &__sidebar {
-    height: 100vh;
-    flex: 1 1 25%;
-    border-right: 1px solid #ccc;
-
-    > h1 {
-      text-align: center;
-      color: #303133;
-    }
-
-    > h3 {
-      text-align: center;
-      color: #909399;
-    }
-  }
-
-  &__links {
-    $link-height: 60px;
-
-    border-top: 1px solid #ccc;
-
-    > a {
-      display: block;
-      width: 100%;
-      height: $link-height;
-      line-height: $link-height;
-      text-align: center;
-      user-select: none;
-      font-size: 24px;
-      color: #606266;
-      border-bottom: 1px solid #ccc;
-      text-decoration: none;
-
-      &.active {
-        background-color: #eee;
-      }
-    }
-  }
-
-  &__content {
-    flex: 1 1 75%;
-    padding: 20px 30px;
-    box-sizing: border-box;
-  }
-}
+@import "./layout.scss";
diff --git a/src/assets/styles/layout.scss b/src/assets/styles/layout.scss
new file mode 100644
index 0000000000000000000000000000000000000000..5f52266af3a5ad783b56213683c9fbb14e1372f4
--- /dev/null
+++ b/src/assets/styles/layout.scss
@@ -0,0 +1,28 @@
+.layout {
+  width: 100%;
+  height: 100%;
+  display: flex;
+
+  &__sidebar {
+    position: relative;
+    height: 100vh;
+    flex: 1 1 25%;
+  }
+
+  &__traffic {
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: 18px;
+
+    > div {
+      margin: 0 auto;
+    }
+  }
+
+  &__content {
+    flex: 1 1 75%;
+    padding: 20px 30px;
+    box-sizing: border-box;
+  }
+}
diff --git a/src/components/list-item-link.tsx b/src/components/list-item-link.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..95fc5272a5e1bbd037fa86508c2a6f0411652803
--- /dev/null
+++ b/src/components/list-item-link.tsx
@@ -0,0 +1,31 @@
+import { ListItem, ListItemButton, ListItemText } from "@mui/material";
+import { useMatch, useResolvedPath, useNavigate } from "react-router-dom";
+import type { LinkProps } from "react-router-dom";
+
+const ListItemLink = (props: LinkProps) => {
+  const { to, children } = props;
+
+  const resolved = useResolvedPath(to);
+  const match = useMatch({ path: resolved.pathname, end: true });
+  const navigate = useNavigate();
+
+  return (
+    <ListItem sx={{ py: 0.5, maxWidth: 250, mx: "auto" }}>
+      <ListItemButton
+        sx={{
+          borderRadius: 2,
+          textAlign: "center",
+          bgcolor: match ? "rgba(91,92,157,0.15)" : "transparent",
+        }}
+        onClick={() => navigate(to)}
+      >
+        <ListItemText
+          primary={children}
+          sx={{ color: match ? "primary.main" : "text.primary" }}
+        />
+      </ListItemButton>
+    </ListItem>
+  );
+};
+
+export default ListItemLink;
diff --git a/src/components/traffic.tsx b/src/components/traffic.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..26b8f55cb41c574abe35f805f806f51d3fcb39fe
--- /dev/null
+++ b/src/components/traffic.tsx
@@ -0,0 +1,69 @@
+import axios from "axios";
+import { useEffect, useState } from "react";
+import { ArrowDownward, ArrowUpward } from "@mui/icons-material";
+import parseTraffic from "../utils/parse-traffic";
+import { Typography } from "@mui/material";
+import { Box } from "@mui/system";
+
+const Traffic = () => {
+  const [traffic, setTraffic] = useState({ up: 0, down: 0 });
+
+  useEffect(() => {
+    const onTraffic = () => {
+      axios({
+        url: `http://127.0.0.1:9090/traffic`,
+        method: "GET",
+        onDownloadProgress: (progressEvent) => {
+          const data = progressEvent.currentTarget.response || "";
+          const lastData = data.slice(data.trim().lastIndexOf("\n") + 1);
+          try {
+            if (lastData) setTraffic(JSON.parse(lastData));
+          } catch {}
+        },
+      }).catch(() => setTimeout(onTraffic, 500));
+    };
+
+    onTraffic();
+  }, []);
+
+  const [up, upUnit] = parseTraffic(traffic.up);
+  const [down, downUnit] = parseTraffic(traffic.down);
+
+  const valStyle: any = {
+    component: "span",
+    color: "primary",
+    textAlign: "center",
+    sx: { flex: "1 1 54px" },
+  };
+  const unitStyle: any = {
+    component: "span",
+    color: "grey.500",
+    fontSize: "12px",
+    textAlign: "right",
+    sx: { flex: "0 1 28px", userSelect: "none" },
+  };
+
+  return (
+    <Box width="110px">
+      <Box mb={2} display="flex" alignItems="center" whiteSpace="nowrap">
+        <ArrowUpward
+          fontSize="small"
+          color={+up > 0 ? "primary" : "disabled"}
+        />
+        <Typography {...valStyle}>{up}</Typography>
+        <Typography {...unitStyle}>{upUnit}</Typography>
+      </Box>
+
+      <Box display="flex" alignItems="center" whiteSpace="nowrap">
+        <ArrowDownward
+          fontSize="small"
+          color={+down > 0 ? "primary" : "disabled"}
+        />
+        <Typography {...valStyle}>{down}</Typography>
+        <Typography {...unitStyle}>{downUnit}</Typography>
+      </Box>
+    </Box>
+  );
+};
+
+export default Traffic;
diff --git a/src/main.tsx b/src/main.tsx
index 40dca8cee76a81ec120030ec1145d752f910de8c..a9fa3296aa510328ce68606cd85f4f1dfef0ba6b 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -2,39 +2,32 @@ import "./assets/styles/index.scss";
 
 import React from "react";
 import ReactDOM from "react-dom";
-import { BrowserRouter, NavLink, Route, Routes } from "react-router-dom";
-import HomePage from "./pages/home";
-import ProfilesPage from "./pages/profiles";
-import { version } from "../package.json";
+import { BrowserRouter } from "react-router-dom";
+import { createTheme, ThemeProvider } from "@mui/material";
+import Layout from "./pages/_layout";
 
-function Layout() {
-  return (
-    <div className="layout">
-      <div className="layout__sidebar">
-        <h1>Clash Verge</h1>
-        <h3>{version}</h3>
+const theme = createTheme({
+  palette: {
+    mode: "light",
+    primary: {
+      main: "#5b5c9d",
+    },
+    text: {
+      primary: "#637381",
+      secondary: "#909399",
+    },
+  },
+});
 
-        <div className="layout__links">
-          <NavLink to="/">Home</NavLink>
-          <NavLink to="/profiles">Profiles</NavLink>
-        </div>
-      </div>
-
-      <div className="layout__content">
-        <Routes>
-          <Route path="/" element={<HomePage />} />
-          <Route path="/profiles" element={<ProfilesPage />} />
-        </Routes>
-      </div>
-    </div>
-  );
-}
+// console.log(theme);
 
 ReactDOM.render(
   <React.StrictMode>
-    <BrowserRouter>
-      <Layout />
-    </BrowserRouter>
+    <ThemeProvider theme={theme}>
+      <BrowserRouter>
+        <Layout />
+      </BrowserRouter>
+    </ThemeProvider>
   </React.StrictMode>,
   document.getElementById("root")
 );
diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..ee0907730916da494fc562d8892d13e98f6f5011
--- /dev/null
+++ b/src/pages/_layout.tsx
@@ -0,0 +1,74 @@
+import { Route, Routes } from "react-router-dom";
+import { List, Paper, Typography } from "@mui/material";
+import LogPage from "../pages/log";
+import HomePage from "../pages/home";
+import ProxyPage from "../pages/proxy";
+import SettingPage from "../pages/setting";
+import ProfilesPage from "../pages/profiles";
+import ConnectionsPage from "../pages/connections";
+import ListItemLink from "../components/list-item-link";
+import Traffic from "../components/traffic";
+
+const Layout = () => {
+  const routers = [
+    {
+      label: "代理",
+      link: "/proxy",
+    },
+    {
+      label: "规则",
+      link: "/profiles",
+    },
+    {
+      label: "连接",
+      link: "/connections",
+    },
+    {
+      label: "日志",
+      link: "/log",
+    },
+    {
+      label: "设置",
+      link: "/setting",
+    },
+  ];
+
+  return (
+    <Paper square elevation={0} className="layout">
+      <div className="layout__sidebar">
+        <Typography
+          variant="h3"
+          component="h1"
+          sx={{ my: 2, px: 2, textAlign: "center", userSelect: "none" }}
+        >
+          Clash Verge
+        </Typography>
+
+        <List sx={{ userSelect: "none" }}>
+          {routers.map((router) => (
+            <ListItemLink key={router.label} to={router.link}>
+              {router.label}
+            </ListItemLink>
+          ))}
+        </List>
+
+        <div className="layout__traffic">
+          <Traffic />
+        </div>
+      </div>
+
+      <div className="layout__content">
+        <Routes>
+          <Route path="/" element={<HomePage />} />
+          <Route path="/proxy" element={<ProxyPage />} />
+          <Route path="/profiles" element={<ProfilesPage />} />
+          <Route path="/log" element={<LogPage />} />
+          <Route path="/connections" element={<ConnectionsPage />} />
+          <Route path="/setting" element={<SettingPage />} />
+        </Routes>
+      </div>
+    </Paper>
+  );
+};
+
+export default Layout;
diff --git a/src/pages/connections.tsx b/src/pages/connections.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..cb267e047115325bb380d71ec8ad56b13c23b35d
--- /dev/null
+++ b/src/pages/connections.tsx
@@ -0,0 +1,5 @@
+const ConnectionsPage = () => {
+  return <h1>Connection</h1>;
+};
+
+export default ConnectionsPage;
diff --git a/src/pages/home.tsx b/src/pages/home.tsx
index f7ff78f4483d3a37753f9d77447da518fd0ed564..5bda849e5bd4d575c422cfef3860afd70b294f6f 100644
--- a/src/pages/home.tsx
+++ b/src/pages/home.tsx
@@ -1,18 +1,10 @@
-import { useState } from "react";
-import { TextField } from "@material-ui/core";
+import { Typography } from "@mui/material";
 
 const HomePage = () => {
-  const [port, setPort] = useState("7890");
-
   return (
-    <div>
-      <TextField
-        label="Port"
-        fullWidth
-        value={port}
-        onChange={(e) => setPort(e.target.value)}
-      />
-    </div>
+    <Typography variant="h1" textAlign="center" mt={10}>
+      Hello Clash!
+    </Typography>
   );
 };
 
diff --git a/src/pages/log.tsx b/src/pages/log.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..6b5c9e689969119de793fb1f69de28467bb8b131
--- /dev/null
+++ b/src/pages/log.tsx
@@ -0,0 +1,5 @@
+const LogPage = () => {
+  return <h1>Log</h1>;
+};
+
+export default LogPage;
diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx
index 4ed657ba482ad0b386caaa107d7762219c99eb40..067833eb60ccb905efee0be57b4f0ce1b32ab64f 100644
--- a/src/pages/profiles.tsx
+++ b/src/pages/profiles.tsx
@@ -1,6 +1,6 @@
 import { useState } from "react";
 import { invoke } from "@tauri-apps/api";
-import { Button, Grid, TextField } from "@material-ui/core";
+import { Button, Grid, TextField } from "@mui/material";
 
 const ProfilesPage = () => {
   const [url, setUrl] = useState("");
diff --git a/src/pages/proxy.tsx b/src/pages/proxy.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..2808614d425710f089180c4022f4c5d9f5585628
--- /dev/null
+++ b/src/pages/proxy.tsx
@@ -0,0 +1,5 @@
+const ProxyPage = () => {
+  return <h1>Proxy</h1>;
+};
+
+export default ProxyPage;
diff --git a/src/pages/setting.tsx b/src/pages/setting.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..be8d857e4a0eae51063dc0eb235a6dbc16c13950
--- /dev/null
+++ b/src/pages/setting.tsx
@@ -0,0 +1,5 @@
+const SettingPage = () => {
+  return <h1>Setting</h1>;
+};
+
+export default SettingPage;
diff --git a/src/utils/parse-traffic.ts b/src/utils/parse-traffic.ts
new file mode 100644
index 0000000000000000000000000000000000000000..529cc3d09bd09c86486d9279763fb7ef5cac0613
--- /dev/null
+++ b/src/utils/parse-traffic.ts
@@ -0,0 +1,23 @@
+const parseTraffic = (num: number) => {
+  const gb = 1024 ** 3;
+  const mb = 1024 ** 2;
+  const kb = 1024;
+  let t = num;
+  let u = "B";
+
+  if (num < 1000) return [`${Math.round(t)}`, "B/s"];
+  if (num <= mb) {
+    t = num / kb;
+    u = "KB";
+  } else if (num <= gb) {
+    t = num / mb;
+    u = "MB";
+  } else {
+    t = num / gb;
+    u = "GB";
+  }
+  if (t >= 100) return [`${Math.round(t)}`, `${u}/s`];
+  return [`${Math.round(t * 10) / 10}`, `${u}/s`];
+};
+
+export default parseTraffic;