mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-15 19:22:26 +08:00
Style: UI improvement & 1.4.6 ready
This commit is contained in:
parent
e743478a4d
commit
7a030b9224
20
README.md
20
README.md
|
@ -41,18 +41,18 @@ A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a
|
|||
|
||||
Download from [release](https://github.com/clash-verge-rev/clash-verge-rev/releases). 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.4.5/Clash.Verge_1.4.5_x64-setup.exe)
|
||||
- [Windows x86](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/Clash.Verge_1.4.5_x86-setup.exe)
|
||||
- [Windows arm64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/Clash.Verge_1.4.5_arm64-setup.exe)
|
||||
- [Windows x64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/Clash.Verge_1.4.6_x64-setup.exe)
|
||||
- [Windows x86](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/Clash.Verge_1.4.6_x86-setup.exe)
|
||||
- [Windows arm64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/Clash.Verge_1.4.6_arm64-setup.exe)
|
||||
|
||||
- [macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/Clash.Verge_1.4.5_x64.dmg)
|
||||
- [macOS apple](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/Clash.Verge_1.4.5_aarch64.dmg)
|
||||
- [macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/Clash.Verge_1.4.6_x64.dmg)
|
||||
- [macOS apple](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/Clash.Verge_1.4.6_aarch64.dmg)
|
||||
|
||||
- [Linux x64 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/clash-verge_1.4.5_amd64.AppImage)
|
||||
- [Linux x64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/clash-verge_1.4.5_amd64.deb)
|
||||
- [Linux x86 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/clash-verge_1.4.5_i386.AppImage)
|
||||
- [Linux x86 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/clash-verge_1.4.5_i386.deb)
|
||||
- [Linux arm64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.5/clash-verge_1.4.5_arm64.deb)
|
||||
- [Linux x64 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/clash-verge_1.4.6_amd64.AppImage)
|
||||
- [Linux x64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/clash-verge_1.4.6_amd64.deb)
|
||||
- [Linux x86 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/clash-verge_1.4.6_i386.AppImage)
|
||||
- [Linux x86 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/clash-verge_1.4.6_i386.deb)
|
||||
- [Linux arm64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.6/clash-verge_1.4.6_arm64.deb)
|
||||
|
||||
Or you can build it yourself. Supports Windows, Linux and macOS 10.15+
|
||||
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
## v1.4.6
|
||||
|
||||
### Features
|
||||
|
||||
- 更新 Clash Meta(mihomo) Core to v1.18.0
|
||||
- UI 优化调整
|
||||
|
||||
---
|
||||
|
||||
## v1.4.5
|
||||
|
||||
### Features
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "clash-verge",
|
||||
"version": "1.4.5",
|
||||
"version": "1.4.6",
|
||||
"license": "GPL-3.0",
|
||||
"scripts": {
|
||||
"dev": "tauri dev",
|
||||
|
|
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
|
@ -559,7 +559,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clash-verge"
|
||||
version = "1.4.5"
|
||||
version = "1.4.6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auto-launch",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clash-verge"
|
||||
version = "1.4.5"
|
||||
version = "1.4.6"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"package": {
|
||||
"productName": "Clash Verge",
|
||||
"version": "1.4.5"
|
||||
"version": "1.4.6"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
|
|
|
@ -27,15 +27,25 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 5px 5px;
|
||||
padding: 10px 0;
|
||||
box-sizing: border-box;
|
||||
scrollbar-gutter: stable;
|
||||
|
||||
.base-content {
|
||||
width: 100%;
|
||||
// max-width: 850px;
|
||||
width: calc(100% - 10px * 2);
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.no-padding {
|
||||
> section {
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
|
||||
.base-content {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,11 @@ interface Props {
|
|||
header?: React.ReactNode; // something behind title
|
||||
contentStyle?: React.CSSProperties;
|
||||
children?: ReactNode;
|
||||
full?: boolean;
|
||||
}
|
||||
|
||||
export const BasePage: React.FC<Props> = (props) => {
|
||||
const { title, header, contentStyle, children } = props;
|
||||
const { title, header, contentStyle, full, children } = props;
|
||||
const { theme } = useCustomTheme();
|
||||
|
||||
const isDark = theme.palette.mode === "dark";
|
||||
|
@ -28,7 +29,7 @@ export const BasePage: React.FC<Props> = (props) => {
|
|||
</header>
|
||||
|
||||
<div
|
||||
className="base-container"
|
||||
className={full ? "base-container no-padding" : "base-container"}
|
||||
style={{ backgroundColor: isDark ? "#090909" : "#ffffff" }}
|
||||
>
|
||||
<section
|
||||
|
|
|
@ -114,6 +114,7 @@ const ConnectionsPage = () => {
|
|||
|
||||
return (
|
||||
<BasePage
|
||||
full
|
||||
title={t("Connections")}
|
||||
contentStyle={{ height: "100%" }}
|
||||
header={
|
||||
|
@ -142,75 +143,72 @@ const ConnectionsPage = () => {
|
|||
</Box>
|
||||
}
|
||||
>
|
||||
<Box sx={{ boxShadow: 0, height: "100%" }}>
|
||||
<Box
|
||||
sx={{
|
||||
pt: 1,
|
||||
mb: 0.5,
|
||||
mx: "12px",
|
||||
height: "36px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
userSelect: "text",
|
||||
}}
|
||||
>
|
||||
{!isTableLayout && (
|
||||
<Select
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
value={curOrderOpt}
|
||||
onChange={(e) => setOrderOpt(e.target.value)}
|
||||
sx={{
|
||||
mr: 1,
|
||||
width: i18n.language === "en" ? 190 : 120,
|
||||
'[role="button"]': { py: 0.65 },
|
||||
}}
|
||||
>
|
||||
{Object.keys(orderOpts).map((opt) => (
|
||||
<MenuItem key={opt} value={opt}>
|
||||
<span style={{ fontSize: 14 }}>{t(opt)}</span>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
hiddenLabel
|
||||
fullWidth
|
||||
<Box
|
||||
sx={{
|
||||
pt: 1,
|
||||
mb: 0.5,
|
||||
mx: "10px",
|
||||
height: "36px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
userSelect: "text",
|
||||
}}
|
||||
>
|
||||
{!isTableLayout && (
|
||||
<Select
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
spellCheck="false"
|
||||
variant="outlined"
|
||||
placeholder={t("Filter conditions")}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||
/>
|
||||
</Box>
|
||||
value={curOrderOpt}
|
||||
onChange={(e) => setOrderOpt(e.target.value)}
|
||||
sx={{
|
||||
mr: 1,
|
||||
width: i18n.language === "en" ? 190 : 120,
|
||||
'[role="button"]': { py: 0.65 },
|
||||
}}
|
||||
>
|
||||
{Object.keys(orderOpts).map((opt) => (
|
||||
<MenuItem key={opt} value={opt}>
|
||||
<span style={{ fontSize: 14 }}>{t(opt)}</span>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
|
||||
<Box height="calc(100% - 50px)" sx={{ userSelect: "text" }}>
|
||||
{filterConn.length === 0 ? (
|
||||
<BaseEmpty text="No Connections" />
|
||||
) : isTableLayout ? (
|
||||
<ConnectionTable
|
||||
connections={filterConn}
|
||||
onShowDetail={(detail) => detailRef.current?.open(detail)}
|
||||
/>
|
||||
) : (
|
||||
<Virtuoso
|
||||
data={filterConn}
|
||||
itemContent={(index, item) => (
|
||||
<ConnectionItem
|
||||
value={item}
|
||||
onShowDetail={() => detailRef.current?.open(item)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<ConnectionDetail ref={detailRef} />
|
||||
<TextField
|
||||
hiddenLabel
|
||||
fullWidth
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
spellCheck="false"
|
||||
variant="outlined"
|
||||
placeholder={t("Filter conditions")}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box height="calc(100% - 50px)" sx={{ userSelect: "text" }}>
|
||||
{filterConn.length === 0 ? (
|
||||
<BaseEmpty text="No Connections" />
|
||||
) : isTableLayout ? (
|
||||
<ConnectionTable
|
||||
connections={filterConn}
|
||||
onShowDetail={(detail) => detailRef.current?.open(detail)}
|
||||
/>
|
||||
) : (
|
||||
<Virtuoso
|
||||
data={filterConn}
|
||||
itemContent={(index, item) => (
|
||||
<ConnectionItem
|
||||
value={item}
|
||||
onShowDetail={() => detailRef.current?.open(item)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<ConnectionDetail ref={detailRef} />
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -38,6 +38,7 @@ const LogPage = () => {
|
|||
|
||||
return (
|
||||
<BasePage
|
||||
full
|
||||
title={t("Logs")}
|
||||
contentStyle={{ height: "100%" }}
|
||||
header={
|
||||
|
@ -66,61 +67,52 @@ const LogPage = () => {
|
|||
>
|
||||
<Box
|
||||
sx={{
|
||||
boxSizing: "border-box",
|
||||
boxShadow: 0,
|
||||
height: "100%",
|
||||
userSelect: "text",
|
||||
pt: 1,
|
||||
mb: 0.5,
|
||||
mx: "10px",
|
||||
height: "36px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
pt: 1,
|
||||
mb: 0.5,
|
||||
mx: "12px",
|
||||
height: "36px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
<Select
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
value={logState}
|
||||
onChange={(e) => setLogState(e.target.value)}
|
||||
sx={{ width: 120, mr: 1, '[role="button"]': { py: 0.65 } }}
|
||||
>
|
||||
<Select
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
value={logState}
|
||||
onChange={(e) => setLogState(e.target.value)}
|
||||
sx={{ width: 120, mr: 1, '[role="button"]': { py: 0.65 } }}
|
||||
>
|
||||
<MenuItem value="all">ALL</MenuItem>
|
||||
<MenuItem value="inf">INFO</MenuItem>
|
||||
<MenuItem value="warn">WARN</MenuItem>
|
||||
<MenuItem value="err">ERROR</MenuItem>
|
||||
</Select>
|
||||
<MenuItem value="all">ALL</MenuItem>
|
||||
<MenuItem value="inf">INFO</MenuItem>
|
||||
<MenuItem value="warn">WARN</MenuItem>
|
||||
<MenuItem value="err">ERROR</MenuItem>
|
||||
</Select>
|
||||
|
||||
<TextField
|
||||
hiddenLabel
|
||||
fullWidth
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
spellCheck="false"
|
||||
variant="outlined"
|
||||
placeholder={t("Filter conditions")}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||
<TextField
|
||||
hiddenLabel
|
||||
fullWidth
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
spellCheck="false"
|
||||
variant="outlined"
|
||||
placeholder={t("Filter conditions")}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box height="calc(100% - 50px)">
|
||||
{filterLogs.length > 0 ? (
|
||||
<Virtuoso
|
||||
initialTopMostItemIndex={999}
|
||||
data={filterLogs}
|
||||
itemContent={(index, item) => <LogItem value={item} />}
|
||||
followOutput={"smooth"}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box height="calc(100% - 50px)">
|
||||
{filterLogs.length > 0 ? (
|
||||
<Virtuoso
|
||||
initialTopMostItemIndex={999}
|
||||
data={filterLogs}
|
||||
itemContent={(index, item) => <LogItem value={item} />}
|
||||
followOutput={"smooth"}
|
||||
/>
|
||||
) : (
|
||||
<BaseEmpty text="No Logs" />
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
<BaseEmpty text="No Logs" />
|
||||
)}
|
||||
</Box>
|
||||
</BasePage>
|
||||
);
|
||||
|
|
|
@ -51,6 +51,7 @@ const ProxyPage = () => {
|
|||
|
||||
return (
|
||||
<BasePage
|
||||
full
|
||||
contentStyle={{ height: "100%" }}
|
||||
title={t("Proxy Groups")}
|
||||
header={
|
||||
|
@ -72,16 +73,7 @@ const ProxyPage = () => {
|
|||
</Box>
|
||||
}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
borderRadius: 1,
|
||||
boxShadow: 0,
|
||||
height: "100%",
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
>
|
||||
<ProxyGroups mode={curMode!} />
|
||||
</Box>
|
||||
<ProxyGroups mode={curMode!} />
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -18,45 +18,43 @@ const RulesPage = () => {
|
|||
}, [data, filterText]);
|
||||
|
||||
return (
|
||||
<BasePage title={t("Rules")} contentStyle={{ height: "100%" }}>
|
||||
<Box sx={{ boxSizing: "border-box", boxShadow: 0, height: "100%" }}>
|
||||
<Box
|
||||
sx={{
|
||||
pt: 1,
|
||||
mb: 0.5,
|
||||
mx: "12px",
|
||||
height: "36px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
hiddenLabel
|
||||
fullWidth
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
variant="outlined"
|
||||
spellCheck="false"
|
||||
placeholder={t("Filter conditions")}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||
/>
|
||||
</Box>
|
||||
<BasePage full title={t("Rules")} contentStyle={{ height: "100%" }}>
|
||||
<Box
|
||||
sx={{
|
||||
pt: 1,
|
||||
mb: 0.5,
|
||||
mx: "10px",
|
||||
height: "36px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
hiddenLabel
|
||||
fullWidth
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
variant="outlined"
|
||||
spellCheck="false"
|
||||
placeholder={t("Filter conditions")}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box height="calc(100% - 50px)">
|
||||
{rules.length > 0 ? (
|
||||
<Virtuoso
|
||||
data={rules}
|
||||
itemContent={(index, item) => (
|
||||
<RuleItem index={index + 1} value={item} />
|
||||
)}
|
||||
followOutput={"smooth"}
|
||||
/>
|
||||
) : (
|
||||
<BaseEmpty text="No Rules" />
|
||||
)}
|
||||
</Box>
|
||||
<Box height="calc(100% - 50px)">
|
||||
{rules.length > 0 ? (
|
||||
<Virtuoso
|
||||
data={rules}
|
||||
itemContent={(index, item) => (
|
||||
<RuleItem index={index + 1} value={item} />
|
||||
)}
|
||||
followOutput={"smooth"}
|
||||
/>
|
||||
) : (
|
||||
<BaseEmpty text="No Rules" />
|
||||
)}
|
||||
</Box>
|
||||
</BasePage>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue
Block a user