diff --git a/package.json b/package.json
index 1a934a48d553c0a315205dea0bb4a51c86a3fdd2..adf63a95d8a5da184ffe22b54a39d67204b2f9a0 100644
--- a/package.json
+++ b/package.json
@@ -15,11 +15,13 @@
     "@mui/material": "^5.2.3",
     "@tauri-apps/api": "^1.0.0-beta.8",
     "axios": "^0.24.0",
+    "dayjs": "^1.10.7",
     "react": "^17.0.0",
     "react-dom": "^17.0.0",
     "react-router-dom": "^6.0.2",
     "react-virtuoso": "^2.3.1",
-    "recoil": "^0.5.2"
+    "recoil": "^0.5.2",
+    "swr": "^1.1.2-beta.0"
   },
   "devDependencies": {
     "@tauri-apps/cli": "^1.0.0-beta.10",
diff --git a/src/components/profile-item.tsx b/src/components/profile-item.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..a6c19975349a4600cb2c8b320099d26c6ae528d4
--- /dev/null
+++ b/src/components/profile-item.tsx
@@ -0,0 +1,131 @@
+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;
+}
+
+const ProfileItemComp: React.FC<Props> = (props) => {
+  const { selected, itemData, onClick } = 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();
+          }}
+        >
+          <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;
diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx
index e081c98037453277415f86bdab5189f343de45d9..143871e1c7ced12e835c6146eab0b32118d9cc2f 100644
--- a/src/pages/_layout.tsx
+++ b/src/pages/_layout.tsx
@@ -1,4 +1,5 @@
 import { useMemo } from "react";
+import { SWRConfig } from "swr";
 import { Route, Routes } from "react-router-dom";
 import { useRecoilValue } from "recoil";
 import { createTheme, List, Paper, ThemeProvider } from "@mui/material";
@@ -55,6 +56,15 @@ const Layout = () => {
     }
 
     return createTheme({
+      breakpoints: {
+        values: {
+          xs: 0,
+          sm: 650,
+          md: 900,
+          lg: 1200,
+          xl: 1536,
+        },
+      },
       palette: {
         mode: paletteMode,
         primary: {
@@ -69,38 +79,40 @@ const Layout = () => {
   }, [paletteMode]);
 
   return (
-    <ThemeProvider theme={theme}>
-      <Paper square elevation={0} className="layout">
-        <div className="layout__sidebar">
-          <div className="layout__logo">
-            <img src={LogoSvg} width="100%" alt="" />
-          </div>
+    <SWRConfig value={{}}>
+      <ThemeProvider theme={theme}>
+        <Paper square elevation={0} className="layout">
+          <div className="layout__sidebar">
+            <div className="layout__logo">
+              <img src={LogoSvg} width="100%" alt="" />
+            </div>
 
-          <List sx={{ userSelect: "none" }}>
-            {routers.map((router) => (
-              <ListItemLink key={router.label} to={router.link}>
-                {router.label}
-              </ListItemLink>
-            ))}
-          </List>
+            <List sx={{ userSelect: "none" }}>
+              {routers.map((router) => (
+                <ListItemLink key={router.label} to={router.link}>
+                  {router.label}
+                </ListItemLink>
+              ))}
+            </List>
 
-          <div className="layout__traffic">
-            <Traffic />
+            <div className="layout__traffic">
+              <Traffic />
+            </div>
           </div>
-        </div>
 
-        <div className="layout__content">
-          <Routes>
-            <Route path="/" element={<HomePage />} />
-            <Route path="/proxy" element={<ProxyPage />} />
-            <Route path="/rules" element={<RulesPage />} />
-            <Route path="/log" element={<LogPage />} />
-            <Route path="/connections" element={<ConnectionsPage />} />
-            <Route path="/setting" element={<SettingPage />} />
-          </Routes>
-        </div>
-      </Paper>
-    </ThemeProvider>
+          <div className="layout__content">
+            <Routes>
+              <Route path="/" element={<HomePage />} />
+              <Route path="/proxy" element={<ProxyPage />} />
+              <Route path="/rules" element={<RulesPage />} />
+              <Route path="/log" element={<LogPage />} />
+              <Route path="/connections" element={<ConnectionsPage />} />
+              <Route path="/setting" element={<SettingPage />} />
+            </Routes>
+          </div>
+        </Paper>
+      </ThemeProvider>
+    </SWRConfig>
   );
 };
 
diff --git a/src/pages/rules.tsx b/src/pages/rules.tsx
index 72f54fbfb544dacafd898647fc9592e4a8f5f1a7..030a0b8772f06cf800117d086d8c0daa132dd38c 100644
--- a/src/pages/rules.tsx
+++ b/src/pages/rules.tsx
@@ -1,14 +1,18 @@
 import { useState } from "react";
-import { Box, Button, TextField, Typography } from "@mui/material";
-import { importProfile } from "../services/command";
+import useSWR, { useSWRConfig } from "swr";
+import { Box, Button, Grid, TextField, Typography } from "@mui/material";
+import { getProfiles, importProfile, putProfiles } from "../services/command";
+import ProfileItemComp from "../components/profile-item";
 import useNotice from "../utils/use-notice";
 
 const RulesPage = () => {
   const [url, setUrl] = useState("");
   const [disabled, setDisabled] = useState(false);
-
   const [notice, noticeElement] = useNotice();
 
+  const { mutate } = useSWRConfig();
+  const { data: profiles = {} } = useSWR("getProfiles", getProfiles);
+
   const onClick = () => {
     if (!url) return;
     setUrl("");
@@ -19,14 +23,26 @@ const RulesPage = () => {
       .finally(() => setDisabled(false));
   };
 
+  const onProfileChange = (index: number) => {
+    putProfiles(index)
+      .then(() => {
+        mutate("getProfiles", { ...profiles, current: index }, true);
+      })
+      .catch((err) => {
+        console.error(err);
+      });
+  };
+
   return (
     <Box sx={{ width: 0.9, maxWidth: "850px", mx: "auto", mb: 2 }}>
       <Typography variant="h4" component="h1" sx={{ py: 2, mb: 1 }}>
         Rules
       </Typography>
 
-      <Box sx={{ display: "flex" }}>
+      <Box sx={{ display: "flex", mb: 3 }}>
         <TextField
+          id="profile_url"
+          name="profile_url"
           label="Profile URL"
           size="small"
           fullWidth
@@ -34,11 +50,27 @@ const RulesPage = () => {
           onChange={(e) => setUrl(e.target.value)}
           sx={{ mr: 4 }}
         />
-        <Button disabled={disabled} variant="contained" onClick={onClick}>
+        <Button
+          disabled={!url || disabled}
+          variant="contained"
+          onClick={onClick}
+        >
           Import
         </Button>
       </Box>
 
+      <Grid container spacing={3}>
+        {profiles?.items?.map((item, idx) => (
+          <Grid item xs={12} sm={6} key={item.file}>
+            <ProfileItemComp
+              selected={profiles.current === idx}
+              itemData={item}
+              onClick={() => onProfileChange(idx)}
+            />
+          </Grid>
+        ))}
+      </Grid>
+
       {noticeElement}
     </Box>
   );
diff --git a/src/services/command.ts b/src/services/command.ts
index ccc44e217d13a4c1a20e77d4492f6b7326861d41..57bd471d1f8b2bc822724012cb0b8fc5dcd65c46 100644
--- a/src/services/command.ts
+++ b/src/services/command.ts
@@ -38,9 +38,13 @@ export interface ProfilesConfig {
 }
 
 export async function getProfiles() {
-  return (await invoke<ProfilesConfig[] | null>("get_profiles")) ?? [];
+  return invoke<ProfilesConfig | null>("get_profiles");
 }
 
 export async function setProfiles(current: number, profile: ProfileItem) {
   return invoke<void>("set_profiles", { current, profile });
 }
+
+export async function putProfiles(current: number) {
+  return invoke<void>("put_profiles", { current });
+}