Compare commits
13 Commits
48
README.md
48
README.md
@@ -11,31 +11,15 @@ A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a
|
||||
|
||||
## Install
|
||||
|
||||
Click on the corresponding link below to download the installation package. Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
|
||||
请到发布页面下载对应的安装包:[Release page](https://github.com/clash-verge-rev/clash-verge-rev/releases)<br>
|
||||
Go to the [release page](https://github.com/clash-verge-rev/clash-verge-rev/releases) to download the corresponding installation package<br>
|
||||
Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
|
||||
|
||||
[[Windows x64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.5/Clash.Verge_1.5.5_x64-setup.exe)]
|
||||
[[Windows arm64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.5/Clash.Verge_1.5.5_arm64-setup.exe)]
|
||||
### 安装说明和常见问题,请到[文档页](https://clash-verge-rev.github.io/)查看:[Doc](https://clash-verge-rev.github.io/)
|
||||
|
||||
[[macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.5/Clash.Verge_1.5.5_x64.dmg)]
|
||||
[[macOS apple](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.5/Clash.Verge_1.5.5_aarch64.dmg)]
|
||||
---
|
||||
|
||||
[[Linux x64 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.5/clash-verge_1.5.5_amd64.AppImage)]
|
||||
[[Linux x64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.5/clash-verge_1.5.5_amd64.deb)]
|
||||
[[Linux arm64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.5/clash-verge_1.5.5_arm64.deb)]
|
||||
|
||||
Or you can build it yourself. Supports Windows, Linux and macOS 10.15+
|
||||
|
||||
Notes: If you could not start the app on Windows, please check that you have [Webview2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section) installed.
|
||||
|
||||
## Features
|
||||
|
||||
- Since the clash core has been removed. The project no longer maintains the clash core, but only the Clash Meta core.
|
||||
- Profiles management and enhancement (by yaml and Javascript). [Doc](https://clash-verge-rev.github.io)
|
||||
- Simple UI and supports custom theme color.
|
||||
- Built-in support [Clash.Meta(mihomo)](https://github.com/MetaCubeX/mihomo) core.
|
||||
- System proxy setting and guard.
|
||||
|
||||
#### TG Group: [@clash_verge_rev](https://t.me/clash_verge_rev)
|
||||
### TG Group: [@clash_verge_rev](https://t.me/clash_verge_rev)
|
||||
|
||||
## Promotion
|
||||
|
||||
@@ -51,15 +35,21 @@ Notes: If you could not start the app on Windows, please check that you have [We
|
||||
- 解锁流媒体及 ChatGPT
|
||||
- 官网:https://狗狗加速.com
|
||||
|
||||
## Features
|
||||
|
||||
- Since the clash core has been removed. The project no longer maintains the clash core, but only the Clash Meta core.
|
||||
- Profiles management and enhancement (by yaml and Javascript). [Doc](https://clash-verge-rev.github.io)
|
||||
- Improved UI and supports custom theme color.
|
||||
- Built-in support [Clash.Meta(mihomo)](https://github.com/MetaCubeX/mihomo) core.
|
||||
- System proxy setting and guard.
|
||||
|
||||
## Preview
|
||||
|
||||

|
||||
|
||||
### FAQ
|
||||
|
||||
#### 1. **macOS** "Clash Verge" is damaged and can't be opened
|
||||
|
||||
open the terminal and run `sudo xattr -r -d com.apple.quarantine /Applications/Clash\ Verge.app`
|
||||
Refer to [Doc FAQ Page](https://clash-verge-rev.github.io/faq.html)
|
||||
|
||||
## Development
|
||||
|
||||
@@ -73,14 +63,6 @@ pnpm run check
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Todos
|
||||
|
||||
> This keng is a little big...
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is a learning project for Rust practice.
|
||||
|
||||
## Contributions
|
||||
|
||||
Issue and PR welcome!
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
## v1.5.5
|
||||
## v1.5.6
|
||||
|
||||
### Features
|
||||
|
||||
- 全新 UI 界面 (by @Amnesiash)
|
||||
- 全新专属 Verge rev UI 界面 (by @Amnesiash) 及细节调整
|
||||
- 提供允许无效证书的开关
|
||||
- 删除不必要的快捷键
|
||||
- Provider 更新添加动画
|
||||
- Merge 支持 Provider
|
||||
- 更换订阅框的粘贴按钮,删除默认的"Remote File" Profile 名称
|
||||
- 链接菜单添加节点显示
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
|
||||
BIN
docs/preview.gif
BIN
docs/preview.gif
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 MiB After Width: | Height: | Size: 7.3 MiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "1.5.5",
|
||||
"version": "1.5.6",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "tauri dev",
|
||||
|
||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@@ -598,7 +598,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clash-verge"
|
||||
version = "1.5.5"
|
||||
version = "1.5.6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auto-launch",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "1.5.5"
|
||||
version = "1.5.6"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "Clash Verge",
|
||||
"version": "1.5.5"
|
||||
"version": "1.5.6"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="36" height="36" rx="18" fill="url(#paint0_linear_289_60)"/>
|
||||
<rect width="36" height="36" rx="18" fill="url(#paint1_linear_289_60)"/>
|
||||
<rect width="36" height="36" rx="18" fill="url(#paint0_linear_289_39)"/>
|
||||
<path d="M20.0083 9.91083C20.8155 10.1108 21.5881 10.431 22.3 10.8608C22.4427 10.947 22.5563 11.0739 22.6262 11.2253C22.696 11.3767 22.7188 11.5455 22.6916 11.71C22.5975 12.2842 22.74 12.7233 23.0083 12.9917C23.2766 13.26 23.7166 13.4025 24.29 13.3083C24.4545 13.2812 24.6233 13.304 24.7747 13.3738C24.9261 13.4437 25.053 13.5573 25.1391 13.7C25.569 14.4119 25.8893 15.1844 26.0891 15.9917C26.1294 16.1536 26.1201 16.3239 26.0624 16.4805C26.0048 16.6371 25.9015 16.7728 25.7658 16.87C25.2933 17.2092 25.0825 17.62 25.0825 18C25.0825 18.38 25.2933 18.7917 25.7658 19.1308C25.9013 19.228 26.0045 19.3635 26.0622 19.52C26.1198 19.6764 26.1292 19.8465 26.0891 20.0083C25.8892 20.8156 25.569 21.5881 25.1391 22.3C25.053 22.4427 24.9261 22.5564 24.7747 22.6262C24.6233 22.696 24.4545 22.7188 24.29 22.6917C23.7158 22.5975 23.2766 22.7408 23.0083 23.0083C22.74 23.2767 22.5975 23.7167 22.6916 24.29C22.719 24.4546 22.6962 24.6236 22.6264 24.7752C22.5566 24.9267 22.4429 25.0538 22.3 25.14C21.5881 25.5698 20.8155 25.8901 20.0083 26.09C19.8464 26.1302 19.6761 26.1209 19.5195 26.0633C19.3629 26.0056 19.2272 25.9023 19.13 25.7667C18.7908 25.2933 18.38 25.0833 18 25.0833C17.62 25.0833 17.2083 25.2933 16.8691 25.7667C16.772 25.9022 16.6365 26.0054 16.48 26.063C16.3236 26.1207 16.1535 26.1301 15.9916 26.09C15.1844 25.8901 14.4119 25.5698 13.7 25.14C13.5571 25.0538 13.4434 24.9267 13.3736 24.7752C13.3037 24.6236 13.281 24.4546 13.3083 24.29C13.4025 23.7167 13.2591 23.2775 12.9916 23.0092C12.7225 22.7408 12.2833 22.5975 11.71 22.6925C11.5454 22.7198 11.3763 22.6971 11.2248 22.6273C11.0733 22.5574 10.9462 22.4437 10.86 22.3008C10.43 21.5884 10.1098 20.8153 9.90998 20.0075C9.86992 19.8457 9.87931 19.6756 9.93695 19.5191C9.99459 19.3627 10.0978 19.2271 10.2333 19.13C10.7066 18.7917 10.9166 18.38 10.9166 18C10.9166 17.6208 10.7066 17.2083 10.2333 16.87C10.0978 16.7729 9.99459 16.6373 9.93695 16.4809C9.87931 16.3245 9.86992 16.1543 9.90998 15.9925C10.1098 15.185 10.4301 14.4122 10.86 13.7C10.9462 13.5571 11.0733 13.4434 11.2248 13.3736C11.3763 13.3037 11.5454 13.281 11.71 13.3083C12.2833 13.4025 12.7225 13.26 12.9908 12.9917C13.2591 12.7233 13.4025 12.2833 13.3075 11.71C13.2803 11.5455 13.3032 11.3767 13.373 11.2253C13.4428 11.0739 13.5564 10.947 13.6991 10.8608C14.4113 10.4309 15.1841 10.1107 15.9916 9.91083C16.1535 9.87077 16.3236 9.88017 16.48 9.93781C16.6365 9.99545 16.772 10.0987 16.8691 10.2342C17.2083 10.7067 17.62 10.9175 18 10.9175C18.3791 10.9175 18.7916 10.7067 19.13 10.2342C19.2271 10.0987 19.3627 9.99545 19.5191 9.93781C19.6755 9.88017 19.8465 9.87077 20.0083 9.91083ZM18 13.8333C16.8949 13.8333 15.8351 14.2723 15.0537 15.0537C14.2723 15.8351 13.8333 16.8949 13.8333 18C13.8333 19.1051 14.2723 20.1649 15.0537 20.9463C15.8351 21.7277 16.8949 22.1667 18 22.1667C19.105 22.1667 20.1649 21.7277 20.9463 20.9463C21.7277 20.1649 22.1666 19.1051 22.1666 18C22.1666 16.8949 21.7277 15.8351 20.9463 15.0537C20.1649 14.2723 19.105 13.8333 18 13.8333ZM18 15.5C18.663 15.5 19.2989 15.7634 19.7677 16.2322C20.2366 16.7011 20.5 17.337 20.5 18C20.5 18.663 20.2366 19.2989 19.7677 19.7678C19.2989 20.2366 18.663 20.5 18 20.5C17.3369 20.5 16.7011 20.2366 16.2322 19.7678C15.7634 19.2989 15.5 18.663 15.5 18C15.5 17.337 15.7634 16.7011 16.2322 16.2322C16.7011 15.7634 17.3369 15.5 18 15.5Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_289_60" x1="0" y1="0" x2="36" y2="36" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#E95E36"/>
|
||||
<stop offset="1" stop-color="#E0421D"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_289_60" x1="6" y1="6.5" x2="29.5" y2="30.5" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint0_linear_289_39" x1="6" y1="6.5" x2="29.5" y2="30.5" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#56718E"/>
|
||||
<stop offset="1" stop-color="#4B6683"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -5,7 +5,7 @@
|
||||
overflow: hidden;
|
||||
|
||||
&__left {
|
||||
flex: 1 0 228px;
|
||||
flex: 1 0 200px;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@@ -71,6 +71,7 @@
|
||||
flex: 1 1 80%;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 0px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.the-traffic {
|
||||
@@ -78,7 +79,7 @@
|
||||
|
||||
> div {
|
||||
margin: 0 auto;
|
||||
// padding: 0 20px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
.base-container {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
// border-radius: 10px;
|
||||
// border-top-left-radius: var(--border-radius);
|
||||
|
||||
> section {
|
||||
@@ -27,11 +28,11 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 16px 0;
|
||||
padding: 10px 0;
|
||||
box-sizing: border-box;
|
||||
scrollbar-gutter: stable;
|
||||
.base-content {
|
||||
width: calc(100% - 16px * 2);
|
||||
width: calc(100% - 10px * 2);
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { ReactNode, useState } from "react";
|
||||
import { ReactNode, useState, useEffect } from "react";
|
||||
import { Box, IconButton, Slide, Snackbar, Typography } from "@mui/material";
|
||||
import { Close, CheckCircleRounded, ErrorRounded } from "@mui/icons-material";
|
||||
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { appWindow } from "@tauri-apps/api/window";
|
||||
interface InnerProps {
|
||||
type: string;
|
||||
duration?: number;
|
||||
message: ReactNode;
|
||||
isDark?: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const NoticeInner = (props: InnerProps) => {
|
||||
const { type, message, duration = 1500, onClose } = props;
|
||||
const [visible, setVisible] = useState(true);
|
||||
|
||||
const [isDark, setIsDark] = useState(false);
|
||||
const { verge } = useVerge();
|
||||
const { theme_mode } = verge ?? {};
|
||||
const onBtnClose = () => {
|
||||
setVisible(false);
|
||||
onClose();
|
||||
@@ -22,6 +26,26 @@ const NoticeInner = (props: InnerProps) => {
|
||||
if (reason !== "clickaway") onBtnClose();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const themeMode = ["light", "dark", "system"].includes(theme_mode!)
|
||||
? theme_mode!
|
||||
: "light";
|
||||
|
||||
if (themeMode !== "system") {
|
||||
setIsDark(themeMode === "dark");
|
||||
return;
|
||||
}
|
||||
|
||||
appWindow.theme().then((m) => m && setIsDark(m === "dark"));
|
||||
const unlisten = appWindow.onThemeChanged((e) =>
|
||||
setIsDark(e.payload === "dark")
|
||||
);
|
||||
|
||||
return () => {
|
||||
unlisten.then((fn) => fn());
|
||||
};
|
||||
}, [theme_mode]);
|
||||
|
||||
const msgElement =
|
||||
type === "info" ? (
|
||||
message
|
||||
@@ -46,7 +70,13 @@ const NoticeInner = (props: InnerProps) => {
|
||||
autoHideDuration={duration}
|
||||
onClose={onAutoClose}
|
||||
message={msgElement}
|
||||
sx={{ maxWidth: 360 }}
|
||||
sx={{
|
||||
maxWidth: 360,
|
||||
".MuiSnackbarContent-root": {
|
||||
bgcolor: isDark ? "#50515C" : "#ffffff",
|
||||
color: isDark ? "#ffffff" : "#000000",
|
||||
},
|
||||
}}
|
||||
TransitionComponent={(p) => <Slide {...p} direction="left" />}
|
||||
transitionDuration={200}
|
||||
action={
|
||||
@@ -61,9 +91,9 @@ const NoticeInner = (props: InnerProps) => {
|
||||
interface NoticeInstance {
|
||||
(props: Omit<InnerProps, "onClose">): void;
|
||||
|
||||
info(message: ReactNode, duration?: number): void;
|
||||
error(message: ReactNode, duration?: number): void;
|
||||
success(message: ReactNode, duration?: number): void;
|
||||
info(message: ReactNode, duration?: number, isDark?: boolean): void;
|
||||
error(message: ReactNode, duration?: number, isDark?: boolean): void;
|
||||
success(message: ReactNode, duration?: number, isDark?: boolean): void;
|
||||
}
|
||||
|
||||
let parent: HTMLDivElement = null!;
|
||||
|
||||
@@ -58,7 +58,9 @@ export const ConnectionItem = (props: Props) => {
|
||||
|
||||
{!!metadata.process && <Tag>{metadata.process}</Tag>}
|
||||
|
||||
{chains?.length > 0 && <Tag>{chains[value.chains.length - 1]}</Tag>}
|
||||
{chains?.length > 0 && (
|
||||
<Tag>{[...chains].reverse().join(" / ")}</Tag>
|
||||
)}
|
||||
|
||||
<Tag>{dayjs(start).fromNow()}</Tag>
|
||||
|
||||
|
||||
@@ -3,19 +3,17 @@ import {
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemText,
|
||||
ListItemAvatar,
|
||||
Avatar,
|
||||
ListItemIcon,
|
||||
} from "@mui/material";
|
||||
import { useMatch, useResolvedPath, useNavigate } from "react-router-dom";
|
||||
import type { LinkProps } from "react-router-dom";
|
||||
|
||||
interface Props {
|
||||
to: string;
|
||||
children: string;
|
||||
img: string;
|
||||
icon: React.ReactNode;
|
||||
}
|
||||
export const LayoutItem = (props: Props) => {
|
||||
const { to, children, img } = props;
|
||||
const { to, children, icon } = props;
|
||||
|
||||
const resolved = useResolvedPath(to);
|
||||
const match = useMatch({ path: resolved.pathname, end: true });
|
||||
@@ -28,11 +26,10 @@ export const LayoutItem = (props: Props) => {
|
||||
sx={[
|
||||
{
|
||||
borderRadius: 2,
|
||||
marginLeft: 1.5,
|
||||
paddingLeft: 1,
|
||||
marginLeft: 1.25,
|
||||
paddingLeft: 1.5,
|
||||
paddingRight: 1,
|
||||
marginRight: 1.5,
|
||||
textAlign: "left",
|
||||
marginRight: 1.25,
|
||||
"& .MuiListItemText-primary": {
|
||||
color: "text.primary",
|
||||
fontWeight: "700",
|
||||
@@ -54,10 +51,11 @@ export const LayoutItem = (props: Props) => {
|
||||
]}
|
||||
onClick={() => navigate(to)}
|
||||
>
|
||||
<ListItemAvatar sx={{ marginRight: -0.5 }}>
|
||||
<Avatar src={img}></Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={children} />
|
||||
<ListItemIcon>{icon}</ListItemIcon>
|
||||
<ListItemText
|
||||
sx={{ textAlign: "center", marginLeft: "-35px" }}
|
||||
primary={children}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
);
|
||||
|
||||
@@ -75,7 +75,7 @@ export const LayoutTraffic = () => {
|
||||
};
|
||||
const valStyle: any = {
|
||||
component: "span",
|
||||
color: "primary",
|
||||
// color: "primary",
|
||||
textAlign: "center",
|
||||
sx: { flex: "1 1 56px", userSelect: "none" },
|
||||
};
|
||||
@@ -88,11 +88,7 @@ export const LayoutTraffic = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
width="188px"
|
||||
position="relative"
|
||||
onClick={trafficRef.current?.toggleStyle}
|
||||
>
|
||||
<Box position="relative" onClick={trafficRef.current?.toggleStyle}>
|
||||
{trafficGraph && pageVisible && (
|
||||
<div style={{ width: "100%", height: 60, marginBottom: 6 }}>
|
||||
<TrafficGraph ref={trafficRef} />
|
||||
@@ -103,9 +99,11 @@ export const LayoutTraffic = () => {
|
||||
<Box display="flex" alignItems="center" whiteSpace="nowrap">
|
||||
<ArrowUpward
|
||||
{...iconStyle}
|
||||
color={+up > 0 ? "primary" : "disabled"}
|
||||
color={+up > 0 ? "secondary" : "disabled"}
|
||||
/>
|
||||
<Typography {...valStyle}>{up}</Typography>
|
||||
<Typography {...valStyle} color="secondary">
|
||||
{up}
|
||||
</Typography>
|
||||
<Typography {...unitStyle}>{upUnit}/s</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -114,7 +112,9 @@ export const LayoutTraffic = () => {
|
||||
{...iconStyle}
|
||||
color={+down > 0 ? "primary" : "disabled"}
|
||||
/>
|
||||
<Typography {...valStyle}>{down}</Typography>
|
||||
<Typography {...valStyle} color="primary">
|
||||
{down}
|
||||
</Typography>
|
||||
<Typography {...unitStyle}>{downUnit}/s</Typography>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -21,23 +21,34 @@ export const ProfileBox = styled(Box)(
|
||||
"dark-false": text.primary,
|
||||
}[key]!;
|
||||
|
||||
const borderLeft = {
|
||||
"light-true": `3px solid ${primary.main}`,
|
||||
"light-false": "none",
|
||||
"dark-true": `3px solid ${primary.main}`,
|
||||
"dark-false": "none",
|
||||
const borderSelect = {
|
||||
"light-true": {
|
||||
borderLeft: `3px solid ${primary.main}`,
|
||||
width: `calc(100% + 3px)`,
|
||||
marginLeft: `-3px`,
|
||||
},
|
||||
"light-false": {
|
||||
width: "100%",
|
||||
},
|
||||
"dark-true": {
|
||||
borderLeft: `3px solid ${primary.main}`,
|
||||
width: `calc(100% + 3px)`,
|
||||
marginLeft: `-3px`,
|
||||
},
|
||||
"dark-false": {
|
||||
width: "100%",
|
||||
},
|
||||
}[key];
|
||||
|
||||
return {
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
display: "block",
|
||||
cursor: "pointer",
|
||||
textAlign: "left",
|
||||
padding: "8px 16px",
|
||||
boxSizing: "border-box",
|
||||
backgroundColor,
|
||||
borderLeft,
|
||||
...borderSelect,
|
||||
borderRadius: "8px",
|
||||
color,
|
||||
"& h2": { color: h2color },
|
||||
|
||||
@@ -66,19 +66,15 @@ export const ProxyItemMini = (props: Props) => {
|
||||
"&:hover .the-check": { display: !showDelay ? "block" : "none" },
|
||||
"&:hover .the-delay": { display: showDelay ? "block" : "none" },
|
||||
"&:hover .the-icon": { display: "none" },
|
||||
"&:hover ": {
|
||||
"&.Mui-selected": {
|
||||
width: `calc(100% + 3px)`,
|
||||
marginLeft: `-3px`,
|
||||
borderLeft: `3px solid ${selectColor}`,
|
||||
bgcolor:
|
||||
mode === "light"
|
||||
? alpha(primary.main, 0.15)
|
||||
: alpha(primary.main, 0.35),
|
||||
},
|
||||
"&.Mui-selected": {
|
||||
width: `calc(100% + 3px)`,
|
||||
marginLeft: `-3px`,
|
||||
borderLeft: `3px solid ${selectColor}`,
|
||||
bgcolor,
|
||||
},
|
||||
// "&.Mui-selected .MuiListItemText-secondary": { color },
|
||||
backgroundColor: bgcolor,
|
||||
};
|
||||
},
|
||||
@@ -95,8 +91,6 @@ export const ProxyItemMini = (props: Props) => {
|
||||
wordBreak: "break-all",
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
fontSize: "13px",
|
||||
fontWeight: "700",
|
||||
}}
|
||||
>
|
||||
{proxy.name}
|
||||
@@ -122,8 +116,6 @@ export const ProxyItemMini = (props: Props) => {
|
||||
wordBreak: "break-all",
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
fontSize: "11px",
|
||||
fontWeight: "700",
|
||||
marginRight: "8px",
|
||||
}}
|
||||
>
|
||||
@@ -219,12 +211,3 @@ const TypeBox = styled(Box)(({ theme: { palette, typography } }) => ({
|
||||
padding: "0 4px",
|
||||
lineHeight: 1.5,
|
||||
}));
|
||||
|
||||
const TypeTypo = styled(Box)(({ theme: { palette, typography } }) => ({
|
||||
display: "inline-block",
|
||||
fontSize: 10,
|
||||
fontFamily: typography.fontFamily,
|
||||
marginRight: "4px",
|
||||
padding: "0 2px",
|
||||
lineHeight: 1.25,
|
||||
}));
|
||||
|
||||
@@ -87,17 +87,13 @@ export const ProxyItem = (props: Props) => {
|
||||
"&:hover .the-check": { display: !showDelay ? "block" : "none" },
|
||||
"&:hover .the-delay": { display: showDelay ? "block" : "none" },
|
||||
"&:hover .the-icon": { display: "none" },
|
||||
"&:hover ": {
|
||||
"&.Mui-selected": {
|
||||
borderLeft: `3px solid ${selectColor}`,
|
||||
bgcolor:
|
||||
mode === "light"
|
||||
? alpha(primary.main, 0.15)
|
||||
: alpha(primary.main, 0.35),
|
||||
},
|
||||
"&.Mui-selected": {
|
||||
borderLeft: `3px solid ${selectColor}`,
|
||||
bgcolor,
|
||||
},
|
||||
// "&.Mui-selected .MuiListItemText-secondary": { bgcolor },
|
||||
backgroundColor: bgcolor,
|
||||
marginBottom: "8px",
|
||||
height: "40px",
|
||||
|
||||
@@ -47,7 +47,7 @@ export const ProxyRender = (props: RenderProps) => {
|
||||
style={{
|
||||
background: itembackgroundcolor,
|
||||
height: "64px",
|
||||
margin: "8px 16px",
|
||||
margin: "8px 8px",
|
||||
borderRadius: "8px",
|
||||
}}
|
||||
onClick={() => onHeadState(group.name, { open: !headState?.open })}
|
||||
@@ -113,7 +113,7 @@ export const ProxyRender = (props: RenderProps) => {
|
||||
if (type === 1 && !group.hidden) {
|
||||
return (
|
||||
<ProxyHead
|
||||
sx={{ pl: indent ? 4.5 : 2.5, pr: 3, mt: indent ? 1 : 0.5, mb: 1 }}
|
||||
sx={{ pl: 2, pr: 3, mt: indent ? 1 : 0.5, mb: 1 }}
|
||||
groupName={group.name}
|
||||
headState={headState!}
|
||||
onLocation={() => onLocation(group)}
|
||||
@@ -130,7 +130,7 @@ export const ProxyRender = (props: RenderProps) => {
|
||||
proxy={proxy!}
|
||||
selected={group.now === proxy?.name}
|
||||
showType={headState?.showType}
|
||||
sx={{ py: 0, pl: indent ? 4 : 2 }}
|
||||
sx={{ py: 0, pl: 1 }}
|
||||
onClick={() => onChangeProxy(group, proxy!)}
|
||||
/>
|
||||
);
|
||||
@@ -141,7 +141,7 @@ export const ProxyRender = (props: RenderProps) => {
|
||||
<Box
|
||||
sx={{
|
||||
py: 2,
|
||||
pl: indent ? 4.5 : 0,
|
||||
pl: 0,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
@@ -161,7 +161,7 @@ export const ProxyRender = (props: RenderProps) => {
|
||||
height: 56,
|
||||
display: "grid",
|
||||
gap: 1,
|
||||
pl: indent ? 4 : 2,
|
||||
pl: 2,
|
||||
pr: 2,
|
||||
pb: 1,
|
||||
gridTemplateColumns: `repeat(${item.col! || 2}, 1fr)`,
|
||||
|
||||
@@ -22,10 +22,13 @@ export const WebUIViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
const webUIList = verge?.web_ui_list || [];
|
||||
const webUIList = verge?.web_ui_list || [
|
||||
"https://d.metacubex.one/#?hostname=%host&port=%port&secret=%secret",
|
||||
"https://yacd.metacubex.one/?host=%host&port=%port&secret=%secret",
|
||||
];
|
||||
|
||||
const handleAdd = useLockFn(async (value: string) => {
|
||||
const newList = [value, ...webUIList];
|
||||
const newList = [...webUIList, value];
|
||||
mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old), false);
|
||||
await patchVerge({ web_ui_list: newList });
|
||||
});
|
||||
@@ -100,18 +103,6 @@ export const WebUIViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
onClose={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
>
|
||||
{editing && (
|
||||
<WebUIItem
|
||||
value=""
|
||||
onlyEdit
|
||||
onChange={(v) => {
|
||||
setEditing(false);
|
||||
handleAdd(v || "");
|
||||
}}
|
||||
onCancel={() => setEditing(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!editing && webUIList.length === 0 && (
|
||||
<BaseEmpty
|
||||
text="Empty List"
|
||||
@@ -132,6 +123,17 @@ export const WebUIViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
onOpenUrl={handleOpenUrl}
|
||||
/>
|
||||
))}
|
||||
{editing && (
|
||||
<WebUIItem
|
||||
value=""
|
||||
onlyEdit
|
||||
onChange={(v) => {
|
||||
setEditing(false);
|
||||
handleAdd(v || "");
|
||||
}}
|
||||
onCancel={() => setEditing(false)}
|
||||
/>
|
||||
)}
|
||||
</BaseDialog>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -167,6 +167,7 @@ const SettingVerge = ({ onError }: Props) => {
|
||||
<Input
|
||||
value={startup_script}
|
||||
disabled
|
||||
sx={{ width: 230 }}
|
||||
endAdornment={
|
||||
<>
|
||||
<Button
|
||||
|
||||
@@ -26,7 +26,7 @@ export const TestBox = styled(Box)(({ theme, "aria-selected": selected }) => {
|
||||
display: "block",
|
||||
cursor: "pointer",
|
||||
textAlign: "left",
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderRadius: 8,
|
||||
boxShadow: theme.shadows[2],
|
||||
padding: "8px 16px",
|
||||
boxSizing: "border-box",
|
||||
|
||||
@@ -104,10 +104,10 @@ export const TestItem = (props: Props) => {
|
||||
{icon && icon.trim() !== "" ? (
|
||||
<Box sx={{ display: "flex", justifyContent: "center" }}>
|
||||
{icon.trim().startsWith("http") && (
|
||||
<img src={icon} height="40px" style={{ marginRight: "8px" }} />
|
||||
<img src={icon} height="40px" />
|
||||
)}
|
||||
{icon.trim().startsWith("data") && (
|
||||
<img src={icon} height="40px" style={{ marginRight: "8px" }} />
|
||||
<img src={icon} height="40px" />
|
||||
)}
|
||||
{icon.trim().startsWith("<svg") && (
|
||||
<img
|
||||
|
||||
@@ -139,7 +139,7 @@ const Layout = () => {
|
||||
<LayoutItem
|
||||
key={router.label}
|
||||
to={router.link}
|
||||
img={router.img}
|
||||
icon={router.icon}
|
||||
>
|
||||
{t(router.label)}
|
||||
</LayoutItem>
|
||||
|
||||
@@ -6,47 +6,55 @@ import SettingsPage from "./settings";
|
||||
import ConnectionsPage from "./connections";
|
||||
import RulesPage from "./rules";
|
||||
|
||||
import ProxiesSvg from "@/assets/image/itemicon/proxies.svg?react";
|
||||
import ProfilesSvg from "@/assets/image/itemicon/profiles.svg?react";
|
||||
import ConnectionsSvg from "@/assets/image/itemicon/connections.svg?react";
|
||||
import RulesSvg from "@/assets/image/itemicon/rules.svg?react";
|
||||
import LogsSvg from "@/assets/image/itemicon/logs.svg?react";
|
||||
import TestSvg from "@/assets/image/itemicon/test.svg?react";
|
||||
import SettingsSvg from "@/assets/image/itemicon/settings.svg?react";
|
||||
|
||||
export const routers = [
|
||||
{
|
||||
label: "Label-Proxies",
|
||||
link: "/",
|
||||
img: "../../assets/image/itemicon/proxies.svg",
|
||||
icon: <ProxiesSvg />,
|
||||
ele: ProxiesPage,
|
||||
},
|
||||
{
|
||||
label: "Label-Profiles",
|
||||
link: "/profile",
|
||||
img: "../../assets/image/itemicon/profiles.svg",
|
||||
icon: <ProfilesSvg />,
|
||||
ele: ProfilesPage,
|
||||
},
|
||||
{
|
||||
label: "Label-Connections",
|
||||
link: "/connections",
|
||||
img: "../../assets/image/itemicon/connections.svg",
|
||||
icon: <ConnectionsSvg />,
|
||||
ele: ConnectionsPage,
|
||||
},
|
||||
{
|
||||
label: "Label-Rules",
|
||||
link: "/rules",
|
||||
img: "../../assets/image/itemicon/rules.svg",
|
||||
icon: <RulesSvg />,
|
||||
ele: RulesPage,
|
||||
},
|
||||
{
|
||||
label: "Label-Logs",
|
||||
link: "/logs",
|
||||
img: "../../assets/image/itemicon/logs.svg",
|
||||
icon: <LogsSvg />,
|
||||
ele: LogsPage,
|
||||
},
|
||||
{
|
||||
label: "Label-Test",
|
||||
link: "/test",
|
||||
img: "../../assets/image/itemicon/test.svg",
|
||||
icon: <TestSvg />,
|
||||
ele: TestPage,
|
||||
},
|
||||
{
|
||||
label: "Label-Settings",
|
||||
link: "/settings",
|
||||
img: "../../assets/image/itemicon/settings.svg",
|
||||
icon: <SettingsSvg />,
|
||||
ele: SettingsPage,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -125,7 +125,7 @@ const ConnectionsPage = () => {
|
||||
title={t("Connections")}
|
||||
contentStyle={{ height: "100%" }}
|
||||
header={
|
||||
<Box sx={{ mt: 1, display: "flex", alignItems: "center", gap: 2 }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
||||
<Box sx={{ mx: 1 }}>Download: {parseTraffic(download)}</Box>
|
||||
<Box sx={{ mx: 1 }}>Upload: {parseTraffic(upload)}</Box>
|
||||
<IconButton
|
||||
|
||||
@@ -42,7 +42,7 @@ const LogPage = () => {
|
||||
title={t("Logs")}
|
||||
contentStyle={{ height: "100%" }}
|
||||
header={
|
||||
<Box sx={{ mt: 1, display: "flex", alignItems: "center", gap: 2 }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
|
||||
@@ -240,7 +240,7 @@ const ProfilePage = () => {
|
||||
<BasePage
|
||||
title={t("Profiles")}
|
||||
header={
|
||||
<Box sx={{ mt: 1, display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
|
||||
@@ -113,7 +113,7 @@ const TestPage = () => {
|
||||
<BasePage
|
||||
title={t("Test")}
|
||||
header={
|
||||
<Box sx={{ mt: 1, display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
|
||||
Reference in New Issue
Block a user