Compare commits

...
57 Commits
Author SHA1 Message Date
MystiPanda 84027cbae1 Release 1.6.6 2024-06-12 10:33:20 +08:00
MystiPanda 5343040ef3 fix: start param error 2024-06-12 10:19:23 +08:00
MystiPanda 75cd7dd4b9 chore: update & fmt & clippy 2024-06-12 10:00:22 +08:00
dongchengjie fb6ffd8e09 chore: missing locale 2024-06-11 16:19:25 +08:00
dongchengjie aca9e61f39 chore: locale "Invalid Bypass Format" 2024-06-09 20:02:20 +08:00
MystiPanda 56078098a4 fix: start param error 2024-06-09 20:00:17 +08:00
MystiPanda 1f197965e0 feat: check bypass format 2024-06-09 13:37:47 +08:00
MystiPanda 183f0f6c42 feat: keep default bypass 2024-06-09 12:45:57 +08:00
dongchengjie 76624c7d83 chore: missing locale 2024-06-09 11:16:13 +08:00
dongchengjie ab47c56ec5 chore: locale reorganization 2024-06-09 09:12:14 +08:00
Eric Huang ad35ed96c8 feat(settings page): add loading state (#1157)
* feat(settings page): add loading state

* fix: type
2024-06-09 06:26:07 +08:00
wonfen 97bd51cf5f chore: update ci with apple notarization 2024-06-09 02:01:33 +08:00
MystiPanda f4a110cfd7 ci: fix error 2024-06-08 20:58:57 +08:00
MystiPanda e9ed06adfd ci: update 2024-06-08 20:45:28 +08:00
MystiPanda bc5eaf34fe feat: add download button on updater dialog
#1129
2024-06-08 20:35:23 +08:00
MystiPanda 3e8b891dd0 fix: run app as normal user 2024-06-08 20:20:47 +08:00
MystiPanda 3f2ea4bc64 build: update depends 2024-06-08 20:02:25 +08:00
MystiPanda ae81b37c1d build: remove appimage 2024-06-08 19:36:58 +08:00
MystiPanda b4349afb1b ci: codesign 2024-06-08 18:52:34 +08:00
dongchengjie 0cffe8e3f7 chore: disbale Meta+Q on macOS 2024-06-08 13:12:24 +08:00
Sukka 7a1f4f9abe refactor: simplify useConnectionSetting (#1141) 2024-06-07 17:23:53 +08:00
wonfen 5768b01786 fix: apple sign error again 2024-06-07 17:19:44 +08:00
MystiPanda 7e9079467f fix: sign error 2024-06-07 16:39:06 +08:00
MystiPanda 615e96922e fix: sign error 2024-06-07 16:37:58 +08:00
Eric Huang 8b94c452fb feat: make SettingItem clickable (#1138)
* feat: make `SettingItem` clickable

* clean up
2024-06-07 15:51:51 +08:00
Sukka 66dd510acc refactor: replace recoil (#1137) 2024-06-07 12:27:37 +08:00
wonfen 96e044566c Style: modify proxy pages 2024-06-07 10:32:27 +08:00
MystiPanda 726ad84d7f fix: sign error 2024-06-06 16:06:58 +08:00
wonfen 4fc422f880 chore: apple developer sign test 2024-06-06 15:21:53 +08:00
dongchengjie 1938024ab3 chore: test_delay trace 2024-06-05 19:17:43 +08:00
dongchengjie 05b1de6fd5 chore: theme colors to uppercase 2024-06-05 14:20:24 +08:00
dongchengjie 0bf8807b50 build: no legacy chunks 2024-06-05 09:04:08 +08:00
Sukka 23668ee74e fix(#1126): add Object.hasOwn polyfill (#1127) 2024-06-05 00:12:06 +08:00
dongchengjie 6bc5c5a808 fix: csp missing asset: 2024-06-04 15:26:39 +08:00
MystiPanda 330004dc72 build: update depends 2024-06-04 12:16:42 +08:00
MystiPanda a900d6d742 Release 1.6.5 2024-06-04 12:11:38 +08:00
MystiPanda bfea70eec9 fix: package error 2024-06-04 10:47:17 +08:00
MystiPanda 13babbf330 feat: support rpm package 2024-06-04 10:16:25 +08:00
MystiPanda 0a6fe382ac build: use latest tauri 2024-06-04 10:09:04 +08:00
Zhenfu Shi dd6dea9dfc chore: Enable Ad Hoc signing on macOS (#1117)
Closes #1116
2024-06-03 09:01:33 +08:00
wonfen 11434fba68 Revert "chore: change default test url"
This reverts commit 69b65d06a4.
2024-06-03 08:25:06 +08:00
dongchengjie 10bf90c92a chore: use icons files instead of hard coding 2024-06-03 07:21:40 +08:00
dongchengjie 5193fe4bab fix: group selected be overwritten when saving test 2024-06-03 06:38:20 +08:00
dongchengjie 4df4995623 chore: improve UI in connections page 2024-06-02 21:52:31 +08:00
aixiao0621 f5f4ecf46a fix: a display error on the connections page 2024-06-02 17:26:23 +08:00
MystiPanda 69b65d06a4 chore: change default test url 2024-06-01 23:14:47 +08:00
MystiPanda e6bf4e836d build: update depends 2024-06-01 23:01:27 +08:00
dongchengjie 01d67eb239 refactor: polyfills review 2024-05-30 20:27:12 +08:00
dongchengjie 3514cfbd44 fix: research when search box mode changes 2024-05-30 10:45:24 +08:00
dongchengjie cade35fe10 chore: Content-Security-Policy 2024-05-29 10:20:56 +08:00
dongchengjie 2c6df77f5a ci: fix heap oom 2024-05-29 09:49:11 +08:00
dongchengjie 0276ae91b5 build: polyfills 2024-05-29 09:39:26 +08:00
dongchengjie 60fee2accb build: import babel 2024-05-28 09:59:41 +08:00
dongchengjie 03e2632294 fix: try to fix #1084 2024-05-27 23:19:44 +08:00
dongchengjie 194fe59458 typo: inconsistent style in layout-viewer 2024-05-27 16:37:48 +08:00
MystiPanda e400111f8a Release 1.6.4 2024-05-26 22:07:53 +08:00
MystiPanda 8bc7607783 Revert "refactor: use axios tauri adapter"
This reverts commit 7e361cb3f1.
2024-05-26 21:18:02 +08:00
80 changed files with 4372 additions and 2525 deletions
+2 -5
View File
@@ -1,8 +1,5 @@
pnpm install
pnpm check $INPUT_TARGET
sed -i "s/#openssl/openssl={version=\"0.10\",features=[\"vendored\"]}/g" src-tauri/Cargo.toml
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ]; then
pnpm build --target $INPUT_TARGET
else
pnpm build --target $INPUT_TARGET -b deb
fi
cargo tauri build --target $INPUT_TARGET
+2
View File
@@ -5,6 +5,8 @@ tar -Jxvf ./node-v20.10.0-linux-x64.tar.xz
export PATH=$(pwd)/node-v20.10.0-linux-x64/bin:$PATH
npm install pnpm -g
cargo install --git https://github.com/tauri-apps/tauri --branch 1.x tauri-cli
rustup target add "$INPUT_TARGET"
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ]; then
+27 -23
View File
@@ -43,15 +43,17 @@ jobs:
with:
workspaces: src-tauri
- name: Install Tauri CLI
run: cargo install --git https://github.com/tauri-apps/tauri --branch 1.x tauri-cli
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "20"
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9
run_install: false
- name: Pnpm install and check
@@ -62,16 +64,23 @@ jobs:
- name: Tauri build
uses: tauri-apps/tauri-action@v0
env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with:
tagName: alpha
releaseName: "Clash Verge Rev Alpha"
releaseBody: "More new features are now supported."
releaseDraft: false
prerelease: true
tauriScript: pnpm
tauriScript: cargo tauri
args: --target ${{ matrix.target }}
- name: Portable Bundle
@@ -101,6 +110,7 @@ jobs:
- name: Build for Linux
uses: ./.github/build-for-linux
env:
NODE_OPTIONS: "--max_old_space_size=4096"
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
@@ -114,7 +124,6 @@ jobs:
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
- name: Upload Release
if: startsWith(matrix.target, 'x86_64')
uses: softprops/action-gh-release@v2
with:
tag_name: alpha
@@ -122,17 +131,9 @@ jobs:
body: "More new features are now supported."
prerelease: true
token: ${{ secrets.GITHUB_TOKEN }}
files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
- name: Upload Release
uses: softprops/action-gh-release@v2
with:
tag_name: alpha
name: "Clash Verge Rev Alpha"
body: "More new features are now supported."
prerelease: true
token: ${{ secrets.GITHUB_TOKEN }}
files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
files: |
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
alpha-for-fixed-webview2:
strategy:
@@ -161,15 +162,17 @@ jobs:
with:
workspaces: src-tauri
- name: Install Tauri CLI
run: cargo install --git https://github.com/tauri-apps/tauri --branch 1.x tauri-cli
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "20"
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9
run_install: false
- name: Pnpm install and check
@@ -188,11 +191,12 @@ jobs:
id: build
uses: tauri-apps/tauri-action@v0
env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
tauriScript: pnpm
tauriScript: cargo tauri
args: --target ${{ matrix.target }}
- name: Rename
@@ -245,12 +249,12 @@ jobs:
- MacOS apple M芯片: aarch64.dmg
### Linux
- Linux 64位: amd64.AppImage/amd64.deb
- Linux 32位: i386.deb
- Linux arm64架构: arm64.deb
- Linux armv7架构: armhf.deb
- Linux 64位: amd64.deb/amd64.rpm
- Linux 32位: i386.deb/i386.rpm
- Linux arm64架构: arm64.deb/aarch64.rpm
- Linux armv7架构: armhf.deb/armhfp.rpm
### Windows (Win7 用户请查看下面FAQ手动替换内核使用)
### Windows (Win7 用户请查看下面FAQ中的解决方案)
#### 正常版本(推荐)
- 64位: x64-setup.exe
- 32位: x86-setup.exe
+16 -19
View File
@@ -45,10 +45,9 @@ jobs:
with:
node-version: "20"
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9
run_install: false
- name: Pnpm install and check
@@ -59,9 +58,16 @@ jobs:
- name: Tauri build
uses: tauri-apps/tauri-action@v0
env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with:
tagName: v__VERSION__
releaseName: "Clash Verge Rev v__VERSION__"
@@ -96,6 +102,7 @@ jobs:
- name: Build for Linux
uses: ./.github/build-for-linux
env:
NODE_OPTIONS: "--max_old_space_size=4096"
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
@@ -108,23 +115,15 @@ jobs:
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
- name: Upload Release
if: startsWith(matrix.target, 'x86_64')
uses: softprops/action-gh-release@v2
with:
tag_name: v${{env.VERSION}}
name: "Clash Verge Rev v${{env.VERSION}}"
body: "More new features are now supported."
token: ${{ secrets.GITHUB_TOKEN }}
files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
- name: Upload Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{env.VERSION}}
name: "Clash Verge Rev v${{env.VERSION}}"
body: "More new features are now supported."
token: ${{ secrets.GITHUB_TOKEN }}
files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
files: |
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
release-for-fixed-webview2:
strategy:
@@ -158,10 +157,9 @@ jobs:
with:
node-version: "20"
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9
run_install: false
- name: Pnpm install and check
@@ -180,6 +178,7 @@ jobs:
id: build
uses: tauri-apps/tauri-action@v0
env:
NODE_OPTIONS: "--max_old_space_size=4096"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
@@ -219,10 +218,9 @@ jobs:
with:
node-version: "20"
- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9
run_install: false
- name: Pnpm install
@@ -245,10 +243,9 @@ jobs:
with:
node-version: "20"
- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9
run_install: false
- name: Pnpm install
+3 -5
View File
@@ -7,17 +7,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "20"
- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9
run_install: false
- name: Pnpm install
@@ -39,10 +38,9 @@ jobs:
with:
node-version: "20"
- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 9
run_install: false
- name: Pnpm install
+32 -1
View File
@@ -1,4 +1,35 @@
## v1.6.3
## v1.6.6
### Features
- MacOS 应用签名
- 删除 AppImage
- 应用更新对话框添加下载按钮
- 设置系统代理绕过时保留默认值
- 系统代理绕过设置输入格式检查
### Bugs Fixes
- MacOS 代理组图标无法显示
- RPM 包依赖缺失
---
## v1.6.5
### Features
- 添加 RPM 包支持
- 优化细节
### Bugs Fixes
- MacOS 10.15 编辑器空白的问题
- MacOS 低版本启动白屏的问题
---
## v1.6.4
### Features
+27 -25
View File
@@ -1,6 +1,6 @@
{
"name": "clash-verge",
"version": "1.6.3",
"version": "1.6.6",
"license": "GPL-3.0-only",
"scripts": {
"dev": "tauri dev",
@@ -24,47 +24,47 @@
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@juggle/resize-observer": "^3.4.0",
"@mui/icons-material": "^5.15.16",
"@mui/icons-material": "^5.15.19",
"@mui/lab": "5.0.0-alpha.149",
"@mui/material": "^5.15.16",
"@mui/x-data-grid": "^6.19.11",
"@tauri-apps/api": "^1.5.4",
"@mui/material": "^5.15.19",
"@mui/x-data-grid": "^6.20.1",
"@tauri-apps/api": "^1.5.6",
"@types/json-schema": "^7.0.15",
"ahooks": "^3.7.11",
"axios": "^1.6.8",
"axios-tauri-api-adapter": "^0.2.1",
"ahooks": "^3.8.0",
"axios": "^1.7.2",
"dayjs": "1.11.5",
"i18next": "^23.11.3",
"foxact": "^0.2.35",
"i18next": "^23.11.5",
"lodash-es": "^4.17.21",
"meta-json-schema": "1.18.5-alpha",
"monaco-editor": "^0.48.0",
"monaco-yaml": "^5.1.1",
"types-pac": "^1.0.2",
"meta-json-schema": "1.18.5-alpha4",
"monaco-editor": "^0.49.0",
"monaco-yaml": "^5.2.0",
"nanoid": "^5.0.7",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^3.1.4",
"react-hook-form": "^7.51.4",
"react-hook-form": "^7.51.5",
"react-i18next": "^13.5.0",
"react-markdown": "^9.0.1",
"react-router-dom": "^6.23.0",
"react-router-dom": "^6.23.1",
"react-transition-group": "^4.4.5",
"react-virtuoso": "^4.7.10",
"recoil": "^0.7.7",
"react-virtuoso": "^4.7.11",
"swr": "^1.3.0",
"tar": "^6.2.1"
"tar": "^6.2.1",
"types-pac": "^1.0.2"
},
"devDependencies": {
"@actions/github": "^5.1.1",
"@tauri-apps/cli": "^1.5.13",
"@tauri-apps/cli": "^1.5.14",
"@types/fs-extra": "^9.0.13",
"@types/js-cookie": "^3.0.6",
"@types/lodash-es": "^4.17.12",
"@types/react": "^18.3.1",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-transition-group": "^4.4.10",
"@vitejs/plugin-react": "^4.2.1",
"adm-zip": "^0.5.12",
"@vitejs/plugin-legacy": "^5.4.1",
"@vitejs/plugin-react": "^4.3.1",
"adm-zip": "^0.5.14",
"cross-env": "^7.0.3",
"fs-extra": "^11.2.0",
"https-proxy-agent": "^5.0.1",
@@ -72,9 +72,10 @@
"node-fetch": "^3.3.2",
"prettier": "^2.8.8",
"pretty-quick": "^3.3.1",
"sass": "^1.77.0",
"sass": "^1.77.5",
"terser": "^5.31.1",
"typescript": "^5.4.5",
"vite": "^5.2.11",
"vite": "^5.2.13",
"vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-svgr": "^4.2.0"
},
@@ -83,5 +84,6 @@
"semi": true,
"singleQuote": false,
"endOfLine": "lf"
}
},
"packageManager": "pnpm@9.1.4"
}
+2370 -718
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -41,6 +41,7 @@ async function resolveUpdater() {
"windows-x86_64": { signature: "", url: "" },
"windows-aarch64": { signature: "", url: "" },
"windows-x86": { signature: "", url: "" },
"windows-i686": { signature: "", url: "" },
},
};
@@ -60,11 +61,13 @@ async function resolveUpdater() {
// win32 url
if (name.endsWith("x86_fixed_webview2-setup.nsis.zip")) {
updateData.platforms["windows-x86"].url = browser_download_url;
updateData.platforms["windows-i686"].url = browser_download_url;
}
// win32 signature
if (name.endsWith("x86_fixed_webview2-setup.nsis.zip.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-x86"].signature = sig;
updateData.platforms["windows-i686"].signature = sig;
}
// win arm url
+12 -15
View File
@@ -46,11 +46,13 @@ async function resolveUpdater() {
"darwin-x86_64": { signature: "", url: "" },
"linux-x86_64": { signature: "", url: "" },
"linux-x86": { signature: "", url: "" },
"linux-i686": { signature: "", url: "" },
"linux-aarch64": { signature: "", url: "" },
"linux-armv7": { signature: "", url: "" },
"windows-x86_64": { signature: "", url: "" },
"windows-aarch64": { signature: "", url: "" },
"windows-x86": { signature: "", url: "" },
"windows-i686": { signature: "", url: "" },
},
};
@@ -72,11 +74,13 @@ async function resolveUpdater() {
// win32 url
if (name.endsWith("x64-setup.nsis.zip")) {
updateData.platforms["windows-x86"].url = browser_download_url;
updateData.platforms["windows-i686"].url = browser_download_url;
}
// win32 signature
if (name.endsWith("x64-setup.nsis.zip.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-x86"].signature = sig;
updateData.platforms["windows-i686"].signature = sig;
}
// win arm url
@@ -106,29 +110,22 @@ async function resolveUpdater() {
// darwin url (aarch)
if (name.endsWith("aarch64.app.tar.gz")) {
updateData.platforms["darwin-aarch64"].url = browser_download_url;
// 使linux可以检查更新
updateData.platforms.linux.url = browser_download_url;
updateData.platforms["linux-x86_64"].url = browser_download_url;
updateData.platforms["linux-x86"].url = browser_download_url;
updateData.platforms["linux-i686"].url = browser_download_url;
updateData.platforms["linux-aarch64"].url = browser_download_url;
updateData.platforms["linux-armv7"].url = browser_download_url;
}
// darwin signature (aarch)
if (name.endsWith("aarch64.app.tar.gz.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["darwin-aarch64"].signature = sig;
}
// linux x64 url
if (name.endsWith("amd64.AppImage.tar.gz")) {
updateData.platforms.linux.url = browser_download_url;
updateData.platforms["linux-x86_64"].url = browser_download_url;
updateData.platforms["linux-x86"].url = browser_download_url;
// 暂时使用x64版本的url和sig,使得可以检查更新,但aarch64版本还不支持构建appimage
updateData.platforms["linux-aarch64"].url = browser_download_url;
updateData.platforms["linux-armv7"].url = browser_download_url;
}
// linux x64 signature
if (name.endsWith("amd64.AppImage.tar.gz.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.linux.signature = sig;
updateData.platforms["linux-x86_64"].signature = sig;
updateData.platforms["linux-x86"].url = browser_download_url;
// 暂时使用x64版本的url和sig,使得可以检查更新,但aarch64版本还不支持构建appimage
updateData.platforms["linux-i686"].url = browser_download_url;
updateData.platforms["linux-aarch64"].signature = sig;
updateData.platforms["linux-armv7"].signature = sig;
}
+507 -486
View File
File diff suppressed because it is too large Load Diff
+6 -7
View File
@@ -1,6 +1,6 @@
[package]
name = "clash-verge"
version = "1.6.3"
version = "1.6.6"
description = "clash verge"
authors = ["zzzgydi", "wonfen", "MystiPanda"]
license = "GPL-3.0-only"
@@ -10,13 +10,13 @@ edition = "2021"
build = "build.rs"
[build-dependencies]
tauri-build = { version = "1", features = [] }
tauri-build = { git="https://github.com/tauri-apps/tauri",branch = "1.x", features = [] }
[dependencies]
warp = "0.3"
anyhow = "1.0"
dirs = "5.0"
open = "5.0"
open = "5.1"
log = "0.4"
dunce = "1.0"
log4rs = "1"
@@ -26,9 +26,9 @@ sysinfo = "0.30"
boa_engine = "0.18"
serde_json = "1.0"
serde_yaml = "0.9"
once_cell = "1.18"
once_cell = "1.19"
port_scanner = "0.1.5"
delay_timer = "0.11.5"
delay_timer = "0.11"
parking_lot = "0.12"
percent-encoding = "2.3.1"
window-shadows = { version = "0.2" }
@@ -37,8 +37,7 @@ serde = { version = "1.0", features = ["derive"] }
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" }
tauri = { version = "1.6", features = [ "http-all", "fs-read-file", "fs-exists", "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "icon-ico", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "devtools"] }
tauri = { git="https://github.com/tauri-apps/tauri",branch = "1.x", features = [ "fs-read-file", "fs-exists", "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "icon-ico", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "devtools"] }
[target.'cfg(windows)'.dependencies]
runas = "=1.2.0"
deelevate = "0.2.0"
+1 -1
View File
@@ -327,7 +327,7 @@ pub fn copy_icon_file(path: String, name: String) -> CmdResult<String> {
Err(err) => Err(err.to_string()),
}
} else {
return Err("file not found".to_string());
Err("file not found".to_string())
}
}
+1
View File
@@ -1,4 +1,5 @@
mod clash;
#[allow(clippy::module_inception)]
mod config;
mod draft;
mod prfitem;
+6 -3
View File
@@ -103,7 +103,9 @@ impl PrfOption {
a.user_agent = b.user_agent.or(a.user_agent);
a.with_proxy = b.with_proxy.or(a.with_proxy);
a.self_proxy = b.self_proxy.or(a.self_proxy);
a.danger_accept_invalid_certs = b.danger_accept_invalid_certs.or(a.danger_accept_invalid_certs);
a.danger_accept_invalid_certs = b
.danger_accept_invalid_certs
.or(a.danger_accept_invalid_certs);
a.update_interval = b.update_interval.or(a.update_interval);
Some(a)
}
@@ -182,7 +184,8 @@ impl PrfItem {
let opt_ref = option.as_ref();
let with_proxy = opt_ref.map_or(false, |o| o.with_proxy.unwrap_or(false));
let self_proxy = opt_ref.map_or(false, |o| o.self_proxy.unwrap_or(false));
let accept_invalid_certs = opt_ref.map_or(false, |o| o.danger_accept_invalid_certs.unwrap_or(false));
let accept_invalid_certs =
opt_ref.map_or(false, |o| o.danger_accept_invalid_certs.unwrap_or(false));
let user_agent = opt_ref.and_then(|o| o.user_agent.clone());
let update_interval = opt_ref.and_then(|o| o.update_interval);
@@ -300,7 +303,7 @@ impl PrfItem {
Some(value) => {
let str_value = value.to_str().unwrap_or("");
Some(str_value.to_string())
},
}
None => None,
};
+4 -4
View File
@@ -116,12 +116,12 @@ impl CoreManager {
// 服务模式启动失败就直接运行sidecar
log::debug!(target: "app", "try to run core in service mode");
match (|| async {
let res = async {
service::check_service().await?;
service::run_core_by_service(&config_path).await
})()
.await
{
}
.await;
match res {
Ok(_) => return Ok(()),
Err(err) => {
// 修改这个值,免得stop出错
+2 -2
View File
@@ -43,7 +43,7 @@ impl Hotkey {
}
}
}
*self.current.lock() = hotkeys.clone();
self.current.lock().clone_from(hotkeys);
}
Ok(())
@@ -142,7 +142,7 @@ impl Hotkey {
});
new_map.iter().for_each(|(&key, &func)| {
if old_map.get(key).is_none() {
if !old_map.contains_key(key) {
add_list.push((key, func));
}
});
+2 -1
View File
@@ -22,7 +22,8 @@ pub fn grant_permission(core: String) -> anyhow::Result<()> {
#[cfg(target_os = "linux")]
let output = {
let path = path.replace(' ', "\\ "); // 避免路径中有空格
let shell = format!("setcap cap_net_bind_service,cap_net_admin,cap_dac_override=+ep {path}");
let shell =
format!("setcap cap_net_bind_service,cap_net_admin,cap_dac_override=+ep {path}");
let sudo = match Command::new("which").arg("pkexec").output() {
Ok(output) => {
+2 -1
View File
@@ -1,13 +1,14 @@
pub mod clash_api;
#[allow(clippy::module_inception)]
mod core;
pub mod handle;
pub mod hotkey;
pub mod logger;
pub mod manager;
pub mod service;
pub mod sysopt;
pub mod timer;
pub mod tray;
pub mod service;
pub mod win_uwp;
pub use self::core::*;
+45 -48
View File
@@ -41,6 +41,34 @@ static DEFAULT_BYPASS: &str = "localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172
static DEFAULT_BYPASS: &str =
"127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,localhost,*.local,*.crashlytics.com,<local>";
fn get_bypass() -> String {
let bypass = DEFAULT_BYPASS.to_string();
let res = {
let verge = Config::verge();
let verge = verge.latest();
verge.system_proxy_bypass.clone()
};
let custom_bypass = match res {
Some(bypass) => bypass,
None => "".to_string(),
};
#[cfg(target_os = "windows")]
let bypass = if custom_bypass.is_empty() {
bypass
} else {
format!("{};{}", bypass, custom_bypass)
};
#[cfg(not(target_os = "windows"))]
let bypass = if custom_bypass.is_empty() {
bypass
} else {
format!("{},{}", bypass, custom_bypass)
};
bypass
}
impl Sysopt {
pub fn global() -> &'static Sysopt {
static SYSOPT: OnceCell<Sysopt> = OnceCell::new();
@@ -63,12 +91,11 @@ impl Sysopt {
.unwrap_or(Config::clash().data().get_mixed_port());
let pac_port = IVerge::get_singleton_port();
let (enable, bypass, pac) = {
let (enable, pac) = {
let verge = Config::verge();
let verge = verge.latest();
(
verge.enable_system_proxy.unwrap_or(false),
verge.system_proxy_bypass.clone(),
verge.proxy_auto_config.unwrap_or(false),
)
};
@@ -76,16 +103,7 @@ impl Sysopt {
enable,
host: String::from("127.0.0.1"),
port,
bypass: match bypass {
Some(bypass) => {
if bypass.is_empty() {
DEFAULT_BYPASS.into()
} else {
bypass
}
}
None => DEFAULT_BYPASS.into(),
},
bypass: get_bypass(),
};
let mut auto = Autoproxy {
enable,
@@ -127,28 +145,26 @@ impl Sysopt {
let mut cur_autoproxy = self.cur_autoproxy.lock();
let old_autoproxy = self.old_autoproxy.lock();
let (enable, bypass, pac) = {
let (enable, pac) = {
let verge = Config::verge();
let verge = verge.latest();
(
verge.enable_system_proxy.unwrap_or(false),
verge.system_proxy_bypass.clone(),
verge.proxy_auto_config.unwrap_or(false),
)
};
if pac {
if cur_autoproxy.is_none() || old_autoproxy.is_none() {
drop(cur_autoproxy);
drop(old_autoproxy);
return self.init_sysproxy();
}
} else {
if cur_sysproxy.is_none() || old_sysproxy.is_none() {
drop(cur_sysproxy);
drop(old_sysproxy);
return self.init_sysproxy();
}
if pac && (cur_autoproxy.is_none() || old_autoproxy.is_none()) {
drop(cur_autoproxy);
drop(old_autoproxy);
return self.init_sysproxy();
}
if !pac && (cur_sysproxy.is_none() || old_sysproxy.is_none()) {
drop(cur_sysproxy);
drop(old_sysproxy);
return self.init_sysproxy();
}
let port = Config::verge()
.latest()
.verge_mixed_port
@@ -156,16 +172,7 @@ impl Sysopt {
let pac_port = IVerge::get_singleton_port();
let mut sysproxy = cur_sysproxy.take().unwrap();
sysproxy.bypass = match bypass {
Some(bypass) => {
if bypass.is_empty() {
DEFAULT_BYPASS.into()
} else {
bypass
}
}
None => DEFAULT_BYPASS.into(),
};
sysproxy.bypass = get_bypass();
sysproxy.port = port;
let mut autoproxy = cur_autoproxy.take().unwrap();
@@ -349,14 +356,13 @@ impl Sysopt {
loop {
sleep(Duration::from_secs(wait_secs)).await;
let (enable, guard, guard_duration, bypass, pac) = {
let (enable, guard, guard_duration, pac) = {
let verge = Config::verge();
let verge = verge.latest();
(
verge.enable_system_proxy.unwrap_or(false),
verge.enable_proxy_guard.unwrap_or(false),
verge.proxy_guard_duration.unwrap_or(10),
verge.system_proxy_bypass.clone(),
verge.proxy_auto_config.unwrap_or(false),
)
};
@@ -389,16 +395,7 @@ impl Sysopt {
enable: true,
host: "127.0.0.1".into(),
port,
bypass: match bypass {
Some(bypass) => {
if bypass.is_empty() {
DEFAULT_BYPASS.into()
} else {
bypass
}
}
None => DEFAULT_BYPASS.into(),
},
bypass: get_bypass(),
};
log_err!(sysproxy.set_system_proxy());
+1 -1
View File
@@ -88,7 +88,7 @@ impl Tray {
),
))
.add_native_item(SystemTrayMenuItem::Separator)
.add_item(CustomMenuItem::new("quit", t!("Quit", "退出")).accelerator("CmdOrControl+Q"))
.add_item(CustomMenuItem::new("quit", t!("Quit", "退出")))
}
pub fn update_systray(app_handle: &AppHandle) -> Result<()> {
+7 -7
View File
@@ -88,13 +88,13 @@ impl ChainItem {
impl ChainSupport {
pub fn is_support(&self, core: Option<&String>) -> bool {
match core {
Some(core) => match (self, core.as_str()) {
(ChainSupport::All, _) => true,
(ChainSupport::Clash, "clash") => true,
(ChainSupport::ClashMeta, "clash-meta") => true,
(ChainSupport::ClashMetaAlpha, "clash-meta-alpha") => true,
_ => false,
},
Some(core) => matches!(
(self, core.as_str()),
(ChainSupport::All, _)
| (ChainSupport::Clash, "clash")
| (ChainSupport::ClashMeta, "clash-meta")
| (ChainSupport::ClashMetaAlpha, "clash-meta-alpha")
),
None => true,
}
}
+1 -5
View File
@@ -60,11 +60,7 @@ pub fn use_sort(config: Mapping) -> Mapping {
let supported_keys: HashSet<&str> = HANDLE_FIELDS.into_iter().chain(DEFAULT_FIELDS).collect();
let config_keys: HashSet<&str> = config
.keys()
.filter_map(|e| e.as_str())
.into_iter()
.collect();
let config_keys: HashSet<&str> = config.keys().filter_map(|e| e.as_str()).collect();
config_keys.difference(&supported_keys).for_each(|&key| {
let key = Value::from(key);
+1 -1
View File
@@ -12,7 +12,7 @@ const MERGE_FIELDS: [&str; 6] = [
fn deep_merge(a: &mut Value, b: &Value) {
match (a, b) {
(&mut Value::Mapping(ref mut a), &Value::Mapping(ref b)) => {
(&mut Value::Mapping(ref mut a), Value::Mapping(b)) => {
for (k, v) in b {
deep_merge(a.entry(k.clone()).or_insert(Value::Null), v);
}
+4 -6
View File
@@ -136,17 +136,15 @@ pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
.map(|(_, c)| c)
.for_each(|item| {
log::debug!(target: "app", "run builtin script {}", item.uid);
match item.data {
ChainType::Script(script) => match use_script(script, config.to_owned()) {
if let ChainType::Script(script) = item.data {
match use_script(script, config.to_owned()) {
Ok((res_config, _)) => {
config = res_config;
}
Err(err) => {
log::error!(target: "app", "builtin script error `{err}`");
}
},
_ => {}
}
}
});
}
@@ -155,7 +153,7 @@ pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
config = use_sort(config);
let mut exists_set = HashSet::new();
exists_set.extend(exists_keys.into_iter());
exists_set.extend(exists_keys);
exists_keys = exists_set.into_iter().collect();
(config, exists_keys, result_map)
+1 -1
View File
@@ -16,7 +16,7 @@ pub fn use_script(script: String, config: Mapping) -> Result<(Mapping, Vec<(Stri
2,
NativeFunction::from_closure(
move |_: &JsValue, args: &[JsValue], context: &mut Context| {
let level = args.get(0).unwrap().to_string(context)?;
let level = args.first().unwrap().to_string(context)?;
let level = level.to_std_string().unwrap();
let data = args.get(1).unwrap().to_string(context)?;
let data = data.to_std_string().unwrap();
+20 -10
View File
@@ -106,7 +106,7 @@ pub fn toggle_tun_mode() {
pub async fn patch_clash(patch: Mapping) -> Result<()> {
Config::clash().draft().patch_config(patch.clone());
match {
let res = {
let redir_port = patch.get("redir-port");
let tproxy_port = patch.get("tproxy-port");
let mixed_port = patch.get("mixed-port");
@@ -156,7 +156,8 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
Config::runtime().latest().patch_config(patch);
<Result<()>>::Ok(())
} {
};
match res {
Ok(()) => {
Config::clash().apply();
Config::clash().data().save_config()?;
@@ -193,7 +194,7 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
let tproxy_enabled = patch.verge_tproxy_enabled;
let socks_enabled = patch.verge_socks_enabled;
let http_enabled = patch.verge_http_enabled;
match {
let res = {
let service_mode = patch.enable_service_mode;
if service_mode.is_some() {
@@ -255,7 +256,8 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
}
<Result<()>>::Ok(())
} {
};
match res {
Ok(()) => {
Config::verge().apply();
Config::verge().data().save_file()?;
@@ -385,11 +387,19 @@ pub async fn test_delay(url: String) -> Result<u32> {
.get(url).header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0");
let start = Instant::now();
let response = request.send().await?;
if response.status().is_success() {
let delay = start.elapsed().as_millis() as u32;
Ok(delay)
} else {
Ok(10000u32)
let response = request.send().await;
match response {
Ok(response) => {
log::trace!(target: "app", "test_delay response: {:#?}", response);
if response.status().is_success() {
Ok(start.elapsed().as_millis() as u32)
} else {
Ok(10000u32)
}
}
Err(err) => {
log::trace!(target: "app", "test_delay error: {:#?}", err);
Err(err.into())
}
}
}
+3 -3
View File
@@ -137,7 +137,7 @@ pub fn delete_log() -> Result<()> {
}
let service_log_dir = log_dir.join("service");
for file in fs::read_dir(&service_log_dir)?.flatten() {
for file in fs::read_dir(service_log_dir)?.flatten() {
let _ = process_file(file);
}
@@ -318,11 +318,11 @@ pub fn startup_script() -> Result<()> {
Some(dir) => {
let _ = Command::new(shell)
.current_dir(dir.to_path_buf())
.args(&[path])
.args([path])
.output()?;
}
None => {
let _ = Command::new(shell).args(&[path]).output()?;
let _ = Command::new(shell).args([path]).output()?;
}
}
}
+6 -4
View File
@@ -99,9 +99,12 @@ pub fn resolve_setup(app: &mut App) {
let argvs: Vec<String> = std::env::args().collect();
if argvs.len() > 1 {
tauri::async_runtime::block_on(async {
resolve_scheme(argvs[1].to_owned()).await;
});
let param = argvs[1].as_str();
if param.starts_with("clash:") {
tauri::async_runtime::block_on(async {
resolve_scheme(argvs[1].to_owned()).await;
});
}
}
}
@@ -205,7 +208,6 @@ pub fn create_window(app_handle: &AppHandle) {
}
Err(_) => {
log::error!("failed to create window");
return;
}
}
}
+8 -6
View File
@@ -28,12 +28,14 @@ pub fn check_singleton() -> Result<()> {
let argvs: Vec<String> = std::env::args().collect();
if argvs.len() > 1 {
let param = argvs[1].as_str();
reqwest::get(format!(
"http://127.0.0.1:{port}/commands/scheme?param={param}"
))
.await?
.text()
.await?;
if param.starts_with("clash:") {
reqwest::get(format!(
"http://127.0.0.1:{port}/commands/scheme?param={param}"
))
.await?
.text()
.await?;
}
} else {
reqwest::get(format!("http://127.0.0.1:{port}/commands/visible"))
.await?
+2 -6
View File
@@ -2,7 +2,7 @@
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"package": {
"productName": "Clash Verge",
"version": "1.6.3"
"version": "1.6.6"
},
"build": {
"distDir": "../dist",
@@ -38,10 +38,6 @@
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
},
"allowlist": {
"http": {
"all": true,
"scope": ["http://**", "http://**"]
},
"shell": {
"all": true
},
@@ -79,7 +75,7 @@
},
"windows": [],
"security": {
"csp": "script-src 'unsafe-eval' 'self'; default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; img-src asset: http: https: data: 'self';"
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: asset: 'unsafe-eval' 'unsafe-inline' 'self';"
}
}
}
+12 -2
View File
@@ -6,10 +6,20 @@
},
"bundle": {
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
"targets": ["deb", "appimage", "updater"],
"targets": ["deb", "rpm"],
"deb": {
"depends": ["openssl"],
"desktopTemplate": "./template/clash-verge.desktop"
"desktopTemplate": "./template/clash-verge.desktop",
"provides": ["clash-verge", "clash-meta"],
"conflicts": ["clash-verge", "clash-meta"],
"replaces": ["clash-verge", "clash-meta"]
},
"rpm": {
"depends": ["openssl"],
"desktopTemplate": "./template/clash-verge.desktop",
"provides": ["clash-verge", "clash-meta"],
"conflicts": ["clash-verge", "clash-meta"],
"obsoletes": ["clash-verge", "clash-meta"]
}
}
}
+7 -2
View File
@@ -323,10 +323,15 @@ Var AppStartMenuFolder
!define MUI_FINISHPAGE_SHOWREADME_TEXT "$(createDesktop)"
!define MUI_FINISHPAGE_SHOWREADME_FUNCTION CreateDesktopShortcut
; Show run app after installation.
!define MUI_FINISHPAGE_RUN "$INSTDIR\${MAINBINARYNAME}.exe"
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION RunMainBinary
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive
!insertmacro MUI_PAGE_FINISH
Function RunMainBinary
nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" ""
FunctionEnd
; Uninstaller Pages
; 1. Confirm uninstall page
Var DeleteAppDataCheckbox
@@ -729,7 +734,7 @@ Function .onInstSuccess
${GetOptions} $CMDLINE "/R" $R0
IfErrors run_done 0
${GetOptions} $CMDLINE "/ARGS" $R0
Exec '"$INSTDIR\${MAINBINARYNAME}.exe" $R0'
nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" "$R0"
run_done:
FunctionEnd
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="48" height="48"><path d="M16.125 1c-1.153.067-2.477.71-3.264 1.527-.71.744-1.272 1.85-1.043 2.918 1.253.033 2.511-.626 3.264-1.459.703-.779 1.236-1.866 1.043-2.986zm.068 4.443c-1.809 0-2.565 1.112-3.818 1.112-1.289 0-2.467-1.041-4.027-1.041C6.226 5.514 3 7.48 3 12.11 3 16.324 6.818 21 8.973 21c1.309.013 1.626-.823 3.402-.832 1.778-.013 2.162.843 3.473.832 1.476-.011 2.628-1.633 3.47-2.918.604-.92.853-1.39 1.32-2.43-3.472-.88-4.163-6.48 0-7.638-.785-1.341-3.08-2.57-4.445-2.57z"/></svg>

After

Width:  |  Height:  |  Size: 556 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" width="48" height="48"><path d="M15 3C8.373 3 3 8.373 3 15c0 5.623 3.872 10.328 9.092 11.63a1.751 1.751 0 0 1-.092-.583v-2.051h-1.508c-.821 0-1.551-.353-1.905-1.009-.393-.729-.461-1.844-1.435-2.526-.289-.227-.069-.486.264-.451.615.174 1.125.596 1.605 1.222.478.627.703.769 1.596.769.433 0 1.081-.025 1.691-.121.328-.833.895-1.6 1.588-1.962-3.996-.411-5.903-2.399-5.903-5.098 0-1.162.495-2.286 1.336-3.233-.276-.94-.623-2.857.106-3.587 1.798 0 2.885 1.166 3.146 1.481A8.993 8.993 0 0 1 15.495 9c1.036 0 2.024.174 2.922.483C18.675 9.17 19.763 8 21.565 8c.732.731.381 2.656.102 3.594.836.945 1.328 2.066 1.328 3.226 0 2.697-1.904 4.684-5.894 5.097C18.199 20.49 19 22.1 19 23.313v2.734c0 .104-.023.179-.035.268C23.641 24.676 27 20.236 27 15c0-6.627-5.373-12-12-12z"/></svg>

After

Width:  |  Height:  |  Size: 829 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"><path fill="#FFC107" d="M43.611 20.083H42V20H24v8h11.303c-1.649 4.657-6.08 8-11.303 8-6.627 0-12-5.373-12-12s5.373-12 12-12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4 12.955 4 4 12.955 4 24s8.955 20 20 20 20-8.955 20-20c0-1.341-.138-2.65-.389-3.917z"/><path fill="#FF3D00" d="M6.306 14.691l6.571 4.819C14.655 15.108 18.961 12 24 12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4 16.318 4 9.656 8.337 6.306 14.691z"/><path fill="#4CAF50" d="M24 44c5.166 0 9.86-1.977 13.409-5.192l-6.19-5.238A11.91 11.91 0 0 1 24 36c-5.202 0-9.619-3.317-11.283-7.946l-6.522 5.025C9.505 39.556 16.227 44 24 44z"/><path fill="#1976D2" d="M43.611 20.083H42V20H24v8h11.303a12.04 12.04 0 0 1-4.087 5.571l.003-.002 6.19 5.238C36.971 39.205 44 34 44 24c0-1.341-.138-2.65-.389-3.917z"/></svg>

After

Width:  |  Height:  |  Size: 901 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"><path fill="#FF3D00" d="M43.2 33.9c-.4 2.1-2.1 3.7-4.2 4-3.3.5-8.8 1.1-15 1.1-6.1 0-11.6-.6-15-1.1-2.1-.3-3.8-1.9-4.2-4-.4-2.3-.8-5.7-.8-9.9s.4-7.6.8-9.9c.4-2.1 2.1-3.7 4.2-4C12.3 9.6 17.8 9 24 9c6.2 0 11.6.6 15 1.1 2.1.3 3.8 1.9 4.2 4 .4 2.3.9 5.7.9 9.9-.1 4.2-.5 7.6-.9 9.9z"/><path fill="#FFF" d="M20 31V17l12 7z"/></svg>

After

Width:  |  Height:  |  Size: 407 B

+38
View File
@@ -0,0 +1,38 @@
import React from "react";
import { Box, styled } from "@mui/material";
type Props = {
label: string;
fontSize?: string;
width?: string;
padding?: string;
children?: React.ReactNode;
};
export const BaseFieldset: React.FC<Props> = (props: Props) => {
const Fieldset = styled(Box)(() => ({
position: "relative",
border: "1px solid #bbb",
borderRadius: "5px",
width: props.width ?? "auto",
padding: props.padding ?? "15px",
}));
const Label = styled("legend")(({ theme }) => ({
position: "absolute",
top: "-10px",
left: props.padding ?? "15px",
backgroundColor: theme.palette.background.paper,
backgroundImage:
"linear-gradient(rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0.16))",
color: theme.palette.text.primary,
fontSize: props.fontSize ?? "1em",
}));
return (
<Fieldset component="fieldset">
<Label>{props.label}</Label>
{props.children}
</Fieldset>
);
};
+12 -2
View File
@@ -1,6 +1,6 @@
import { Box, SvgIcon, TextField, Theme, styled } from "@mui/material";
import { Box, SvgIcon, TextField, styled } from "@mui/material";
import Tooltip from "@mui/material/Tooltip";
import { ChangeEvent, useState } from "react";
import { ChangeEvent, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import matchCaseIcon from "@/assets/image/component/match_case.svg?react";
@@ -22,6 +22,7 @@ type SearchProps = {
export const BaseSearchBox = styled((props: SearchProps) => {
const { t } = useTranslation();
const inputRef = useRef<HTMLInputElement>(null);
const [matchCase, setMatchCase] = useState(true);
const [matchWholeWord, setMatchWholeWord] = useState(false);
const [useRegularExpression, setUseRegularExpression] = useState(false);
@@ -36,6 +37,14 @@ export const BaseSearchBox = styled((props: SearchProps) => {
inheritViewBox: true,
};
useEffect(() => {
if (!inputRef.current) return;
onChange({
target: inputRef.current,
} as ChangeEvent<HTMLInputElement>);
}, [matchCase, matchWholeWord, useRegularExpression]);
const onChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
props.onSearch(
(content) => doSearch([content], e.target?.value ?? "").length > 0,
@@ -80,6 +89,7 @@ export const BaseSearchBox = styled((props: SearchProps) => {
return (
<Tooltip title={errorMessage} placement="bottom-start">
<TextField
inputRef={inputRef}
hiddenLabel
fullWidth
size="small"
@@ -19,6 +19,7 @@ const Tag = styled("span")(({ theme }) => ({
border: "1px solid",
borderRadius: 4,
borderColor: alpha(theme.palette.text.secondary, 0.35),
marginTop: "4px",
marginRight: "4px",
}));
+1
View File
@@ -36,6 +36,7 @@ export const LayoutControl = () => {
<ButtonGroup
variant="text"
sx={{
zIndex: 1000,
height: "100%",
".MuiButtonGroup-grouped": {
borderRadius: "0px",
+3 -3
View File
@@ -1,8 +1,7 @@
import { useEffect, useMemo } from "react";
import { useRecoilState } from "recoil";
import { alpha, createTheme, Shadows, Theme } from "@mui/material";
import { appWindow } from "@tauri-apps/api/window";
import { atomThemeMode } from "@/services/states";
import { useSetThemeMode, useThemeMode } from "@/services/states";
import { defaultTheme, defaultDarkTheme } from "@/pages/_theme";
import { useVerge } from "@/hooks/use-verge";
@@ -12,7 +11,8 @@ import { useVerge } from "@/hooks/use-verge";
export const useCustomTheme = () => {
const { verge } = useVerge();
const { theme_mode, theme_setting } = verge ?? {};
const [mode, setMode] = useRecoilState(atomThemeMode);
const mode = useThemeMode();
const setMode = useSetThemeMode();
useEffect(() => {
const themeMode = ["light", "dark", "system"].includes(theme_mode!)
+3 -4
View File
@@ -1,9 +1,8 @@
import dayjs from "dayjs";
import { useEffect } from "react";
import { useRecoilValue, useSetRecoilState } from "recoil";
import { getClashLogs } from "@/services/cmds";
import { useClashInfo } from "@/hooks/use-clash";
import { atomEnableLog, atomLogData } from "@/services/states";
import { useEnableLog, useSetLogData } from "@/services/states";
import { useWebsocket } from "@/hooks/use-websocket";
const MAX_LOG_NUM = 1000;
@@ -12,8 +11,8 @@ const MAX_LOG_NUM = 1000;
export const useLogSetup = () => {
const { clashInfo } = useClashInfo();
const enableLog = useRecoilValue(atomEnableLog);
const setLogData = useSetRecoilState(atomLogData);
const [enableLog] = useEnableLog();
const setLogData = useSetLogData();
const { connect, disconnect } = useWebsocket((event) => {
const data = JSON.parse(event.data) as ILogItem;
+3 -4
View File
@@ -1,6 +1,5 @@
import { ReactNode, useEffect, useRef } from "react";
import { useLockFn } from "ahooks";
import { useRecoilValue } from "recoil";
import { useTranslation } from "react-i18next";
import {
Button,
@@ -9,7 +8,7 @@ import {
DialogContent,
DialogTitle,
} from "@mui/material";
import { atomThemeMode } from "@/services/states";
import { useThemeMode } from "@/services/states";
import { readProfileFile, saveProfileFile } from "@/services/cmds";
import { Notice } from "@/components/base";
import { nanoid } from "nanoid";
@@ -90,7 +89,7 @@ export const EditorViewer = (props: Props) => {
const { t } = useTranslation();
const editorRef = useRef<any>();
const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
const themeMode = useRecoilValue(atomThemeMode);
const themeMode = useThemeMode();
useEffect(() => {
if (!open) return;
@@ -131,7 +130,7 @@ export const EditorViewer = (props: Props) => {
padding: {
top: 33, // 顶部padding防止遮挡snippets
},
fontFamily: `Fira Code, Roboto Mono, Roboto, Source Code Pro, Menlo, Monaco, Consolas, Courier New, monospace, "Apple Color Emoji"${
fontFamily: `Fira Code, JetBrains Mono, Roboto Mono, "Source Code Pro", Consolas, Menlo, Monaco, monospace, "Courier New", "Apple Color Emoji"${
getSystem() === "windows" ? ", twemoji mozilla" : ""
}`,
fontLigatures: true, // 连字符
+4 -3
View File
@@ -2,7 +2,6 @@ import dayjs from "dayjs";
import { mutate } from "swr";
import { useEffect, useState } from "react";
import { useLockFn } from "ahooks";
import { useRecoilState } from "recoil";
import { useTranslation } from "react-i18next";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
@@ -17,7 +16,7 @@ import {
CircularProgress,
} from "@mui/material";
import { RefreshRounded, DragIndicator } from "@mui/icons-material";
import { atomLoadingCache } from "@/services/states";
import { useLoadingCache, useSetLoadingCache } from "@/services/states";
import { updateProfile, deleteProfile, viewProfile } from "@/services/cmds";
import { Notice } from "@/components/base";
import { EditorViewer } from "@/components/profile/editor-viewer";
@@ -47,7 +46,8 @@ export const ProfileItem = (props: Props) => {
const { t } = useTranslation();
const [anchorEl, setAnchorEl] = useState<any>(null);
const [position, setPosition] = useState({ left: 0, top: 0 });
const [loadingCache, setLoadingCache] = useRecoilState(atomLoadingCache);
const loadingCache = useLoadingCache();
const setLoadingCache = useSetLoadingCache();
const { uid, name = "Profile", extra, updated = 0 } = itemData;
@@ -278,6 +278,7 @@ export const ProfileItem = (props: Props) => {
{/* only if has url can it be updated */}
{hasUrl && (
<IconButton
title={t("Refresh")}
sx={{
position: "absolute",
p: "3px",
+2 -2
View File
@@ -69,7 +69,7 @@ export const ProviderButton = () => {
sx={{ textTransform: "capitalize" }}
onClick={() => setOpen(true)}
>
{t("Provider")}
{t("Proxy Provider")}
</Button>
<BaseDialog
@@ -171,7 +171,7 @@ export const ProviderButton = () => {
<IconButton
size="small"
color="inherit"
title="Update Provider"
title={`${t("Update")}${t("Proxy Provider")}`}
onClick={() => handleUpdate(key, index)}
sx={{
animation: updating[index]
+2 -3
View File
@@ -17,8 +17,7 @@ import { ProxyItem } from "./proxy-item";
import { ProxyItemMini } from "./proxy-item-mini";
import type { IRenderItem } from "./use-render-list";
import { useVerge } from "@/hooks/use-verge";
import { useRecoilState } from "recoil";
import { atomThemeMode } from "@/services/states";
import { useThemeMode } from "@/services/states";
import { useEffect, useMemo, useState } from "react";
import { convertFileSrc } from "@tauri-apps/api/tauri";
import { downloadIconCache } from "@/services/cmds";
@@ -38,7 +37,7 @@ export const ProxyRender = (props: RenderProps) => {
const { type, group, headState, proxy, proxyCol } = item;
const { verge } = useVerge();
const enable_group_icon = verge?.enable_group_icon ?? true;
const [mode] = useRecoilState(atomThemeMode);
const mode = useThemeMode();
const isDark = mode === "light" ? false : true;
const itembackgroundcolor = isDark ? "#282A36" : "#ffffff";
const [iconCachePath, setIconCachePath] = useState("");
+2 -2
View File
@@ -67,7 +67,7 @@ export const ProviderButton = () => {
sx={{ textTransform: "capitalize" }}
onClick={() => setOpen(true)}
>
{t("Provider")}
{t("Rule Provider")}
</Button>
<BaseDialog
@@ -145,7 +145,7 @@ export const ProviderButton = () => {
<IconButton
size="small"
color="inherit"
title="Update Provider"
title={`${t("Update")}${t("Rule Provider")}`}
onClick={() => handleUpdate(key, index)}
sx={{
animation: updating[index]
+38 -18
View File
@@ -1,9 +1,16 @@
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { useTranslation } from "react-i18next";
import { List, Button, Select, MenuItem } from "@mui/material";
import {
List,
Button,
Select,
MenuItem,
styled,
ListItem,
ListItemText,
} from "@mui/material";
import { useVerge } from "@/hooks/use-verge";
import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base";
import { SettingItem } from "./setting-comp";
import { GuardState } from "./guard-state";
import { open as openDialog } from "@tauri-apps/api/dialog";
import { convertFileSrc } from "@tauri-apps/api/tauri";
@@ -77,7 +84,8 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
onCancel={() => setOpen(false)}
>
<List>
<SettingItem label={t("Traffic Graph")}>
<Item>
<ListItemText primary={t("Traffic Graph")} />
<GuardState
value={verge?.traffic_graph ?? true}
valueProps="checked"
@@ -88,9 +96,10 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
>
<Switch edge="end" />
</GuardState>
</SettingItem>
</Item>
<SettingItem label={t("Memory Usage")}>
<Item>
<ListItemText primary={t("Memory Usage")} />
<GuardState
value={verge?.enable_memory_usage ?? true}
valueProps="checked"
@@ -101,9 +110,10 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
>
<Switch edge="end" />
</GuardState>
</SettingItem>
</Item>
<SettingItem label={t("Proxy Group Icon")}>
<Item>
<ListItemText primary={t("Proxy Group Icon")} />
<GuardState
value={verge?.enable_group_icon ?? true}
valueProps="checked"
@@ -114,9 +124,10 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
>
<Switch edge="end" />
</GuardState>
</SettingItem>
</Item>
<SettingItem label={t("Menu Icon")}>
<Item>
<ListItemText primary={t("Menu Icon")} />
<GuardState
value={verge?.menu_icon ?? "monochrome"}
onCatch={onError}
@@ -130,9 +141,11 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
<MenuItem value="disable">{t("Disable")}</MenuItem>
</Select>
</GuardState>
</SettingItem>
</Item>
{OS === "macos" && (
<SettingItem label={t("Tray Icon")}>
<Item>
<ListItemText primary={t("Tray Icon")} />
<GuardState
value={verge?.tray_icon ?? "monochrome"}
onCatch={onError}
@@ -148,10 +161,11 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
<MenuItem value="colorful">{t("Colorful")}</MenuItem>
</Select>
</GuardState>
</SettingItem>
</Item>
)}
<SettingItem label={t("Common Tray Icon")}>
<Item>
<ListItemText primary={t("Common Tray Icon")} />
<GuardState
value={verge?.common_tray_icon}
onCatch={onError}
@@ -194,9 +208,10 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
{verge?.common_tray_icon ? t("Clear") : t("Browse")}
</Button>
</GuardState>
</SettingItem>
</Item>
<SettingItem label={t("System Proxy Tray Icon")}>
<Item>
<ListItemText primary={t("System Proxy Tray Icon")} />
<GuardState
value={verge?.sysproxy_tray_icon}
onCatch={onError}
@@ -239,9 +254,10 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
{verge?.sysproxy_tray_icon ? t("Clear") : t("Browse")}
</Button>
</GuardState>
</SettingItem>
</Item>
<SettingItem label={t("Tun Tray Icon")}>
<Item>
<ListItemText primary={t("Tun Tray Icon")} />
<GuardState
value={verge?.tun_tray_icon}
onCatch={onError}
@@ -282,8 +298,12 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
{verge?.tun_tray_icon ? t("Clear") : t("Browse")}
</Button>
</GuardState>
</SettingItem>
</Item>
</List>
</BaseDialog>
);
});
const Item = styled(ListItem)(() => ({
padding: "5px 2px",
}));
+34 -9
View File
@@ -1,34 +1,59 @@
import React, { ReactNode } from "react";
import React, { ReactNode, useState } from "react";
import {
Box,
List,
ListItem,
ListItemButton,
ListItemText,
ListSubheader,
} from "@mui/material";
import { ChevronRightRounded } from "@mui/icons-material";
import CircularProgress from "@mui/material/CircularProgress";
import isAsyncFunction from "@/utils/is-async-function";
interface ItemProps {
label: ReactNode;
extra?: ReactNode;
children?: ReactNode;
secondary?: ReactNode;
onClick?: () => void | Promise<any>;
}
export const SettingItem: React.FC<ItemProps> = (props) => {
const { label, extra, children, secondary } = props;
const { label, extra, children, secondary, onClick } = props;
const clickable = !!onClick;
const primary = !extra ? (
const primary = (
<Box sx={{ display: "flex", alignItems: "center", fontSize: "14px" }}>
<span>{label}</span>
</Box>
) : (
<Box sx={{ display: "flex", alignItems: "center", fontSize: "14px" }}>
<span>{label}</span>
{extra}
{extra ? extra : null}
</Box>
);
return (
const [isLoading, setIsLoading] = useState(false);
const handleClick = () => {
if (onClick) {
if (isAsyncFunction(onClick)) {
setIsLoading(true);
onClick()!.finally(() => setIsLoading(false));
} else {
onClick();
}
}
};
return clickable ? (
<ListItem disablePadding>
<ListItemButton onClick={handleClick} disabled={isLoading}>
<ListItemText primary={primary} secondary={secondary} />
{isLoading ? (
<CircularProgress color="inherit" size={20} />
) : (
<ChevronRightRounded />
)}
</ListItemButton>
</ListItem>
) : (
<ListItem sx={{ pt: "5px", pb: "5px" }}>
<ListItemText primary={primary} secondary={secondary} />
{children}
+76 -64
View File
@@ -1,8 +1,9 @@
import { forwardRef, useImperativeHandle, useState } from "react";
import { useLockFn } from "ahooks";
import { useTranslation } from "react-i18next";
import { Box, IconButton, Tooltip } from "@mui/material";
import { InfoRounded } from "@mui/icons-material";
import {
Box,
InputAdornment,
List,
ListItem,
@@ -17,12 +18,22 @@ import { getSystemProxy, getAutotemProxy } from "@/services/cmds";
import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base";
import { Edit } from "@mui/icons-material";
import { EditorViewer } from "@/components/profile/editor-viewer";
import { BaseFieldset } from "@/components/base/base-fieldset";
import getSystem from "@/utils/get-system";
const DEFAULT_PAC = `function FindProxyForURL(url, host) {
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
}`;
export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
const { t } = useTranslation();
let validReg;
if (getSystem() === "windows") {
validReg =
/^(\*?\w+(\.\w+)*|\d{1,3}(\.\d{1,3}){0,2}\.\*|\d{1,3}(\.\d{1,3}){3})(;(\*?\w+(\.\w+)*|\d{1,3}(\.\d{1,3}){0,2}\.\*|\d{1,3}(\.\d{1,3}){3}))*$/;
} else {
validReg =
/^((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+(\/\d{1,3})?)(,((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+(\/\d{1,3})?))*$/;
}
const [open, setOpen] = useState(false);
const [editorOpen, setEditorOpen] = useState(false);
@@ -90,7 +101,10 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
if (value.pac_content !== pac_file_content) {
patch.pac_file_content = value.pac_content;
}
if (value.bypass && !validReg.test(value.bypass)) {
Notice.error(t("Invalid Bypass Format"));
return;
}
try {
await patchVerge(patch);
setOpen(false);
@@ -103,7 +117,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
<BaseDialog
open={open}
title={t("System Proxy Setting")}
contentSx={{ width: 450, maxHeight: 300 }}
contentSx={{ width: 450, maxHeight: 565 }}
okBtn={t("Save")}
cancelBtn={t("Cancel")}
onClose={() => setOpen(false)}
@@ -111,6 +125,36 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
onOk={onSave}
>
<List>
<BaseFieldset label={t("Current System Proxy")} padding="15px 10px">
<FlexBox>
<Typography className="label">{t("Enable status")}</Typography>
<Typography className="value">
{value.pac
? autoproxy?.enable
? t("Enabled")
: t("Disabled")
: sysproxy?.enable
? t("Enabled")
: t("Disabled")}
</Typography>
</FlexBox>
{!value.pac && (
<>
<FlexBox>
<Typography className="label">{t("Server Addr")}</Typography>
<Typography className="value">
{sysproxy?.server ? sysproxy.server : t("Not available")}
</Typography>
</FlexBox>
</>
)}
{value.pac && (
<FlexBox>
<Typography className="label">{t("PAC URL")}</Typography>
<Typography className="value">{autoproxy?.url || "-"}</Typography>
</FlexBox>
)}
</BaseFieldset>
<ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary={t("Use PAC Mode")} />
<Switch
@@ -120,8 +164,17 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
onChange={(_, e) => setValue((v) => ({ ...v, pac: e }))}
/>
</ListItem>
<ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary={t("Proxy Guard")} />
<Tooltip title={t("Proxy Guard Info")}>
<IconButton color="inherit" size="small">
<InfoRounded
fontSize="inherit"
style={{ cursor: "pointer", opacity: 0.75 }}
/>
</IconButton>
</Tooltip>
<Switch
edge="end"
disabled={!enabled}
@@ -150,27 +203,32 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
</ListItem>
{!value.pac && (
<>
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
<ListItemText
primary={t("Proxy Bypass")}
sx={{ padding: "3px 0" }}
/>
</ListItem>
<ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary={t("Proxy Bypass")} />
<TextField
error={value.bypass ? !validReg.test(value.bypass) : false}
disabled={!enabled}
size="small"
autoComplete="off"
multiline
rows={4}
sx={{ width: "100%" }}
value={value.bypass}
onChange={(e) => {
setValue((v) => ({ ...v, bypass: e.target.value }));
}}
/>
<ListItemText primary={t("Bypass")} />
<FlexBox>
<TextField
disabled={!enabled}
disabled={true}
size="small"
autoComplete="off"
multiline
rows={4}
sx={{ width: "100%" }}
value={value.bypass}
placeholder={sysproxy?.bypass || `-`}
onChange={(e) =>
setValue((v) => ({ ...v, bypass: e.target.value }))
}
value={sysproxy?.bypass || "-"}
/>
</ListItem>
</FlexBox>
</>
)}
{value.pac && (
@@ -210,52 +268,6 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
</>
)}
</List>
<Box sx={{ mt: 2.5 }}>
<Typography variant="body1" sx={{ fontSize: "18px", mb: 1 }}>
{t("Current System Proxy")}
</Typography>
<FlexBox>
<Typography className="label">{t("Enable status")}</Typography>
<Typography className="value">
{value.pac
? (!!autoproxy?.enable).toString()
: (!!sysproxy?.enable).toString()}
</Typography>
</FlexBox>
{!value.pac && (
<>
<FlexBox>
<Typography className="label">{t("Server Addr")}</Typography>
<Typography className="value">
{sysproxy?.server || "-"}
</Typography>
</FlexBox>
<FlexBox>
<Typography className="label">{t("Bypass")}</Typography>
</FlexBox>
<FlexBox>
<TextField
disabled={true}
size="small"
autoComplete="off"
multiline
rows={4}
sx={{ width: "100%" }}
value={sysproxy?.bypass || "-"}
/>
</FlexBox>
</>
)}
{value.pac && (
<FlexBox>
<Typography className="label">{t("PAC URL")}</Typography>
<Typography className="value">{autoproxy?.url || "-"}</Typography>
</FlexBox>
)}
</Box>
</BaseDialog>
);
});
@@ -266,6 +278,6 @@ const FlexBox = styled("div")`
.label {
flex: none;
width: 85px;
//width: 85px;
}
`;
+1 -1
View File
@@ -81,7 +81,7 @@ export const ThemeViewer = forwardRef<DialogRef>((props, ref) => {
title={t("Theme Setting")}
okBtn={t("Save")}
cancelBtn={t("Cancel")}
contentSx={{ width: 400, maxHeight: 300, overflow: "auto", pb: 0 }}
contentSx={{ width: 400, maxHeight: 505, overflow: "auto", pb: 0 }}
onClose={() => setOpen(false)}
onCancel={() => setOpen(false)}
onOk={onSave}
+24 -5
View File
@@ -1,15 +1,15 @@
import useSWR from "swr";
import { forwardRef, useImperativeHandle, useState, useMemo } from "react";
import { useLockFn } from "ahooks";
import { Box, LinearProgress } from "@mui/material";
import { useRecoilState } from "recoil";
import { Box, LinearProgress, Button } from "@mui/material";
import { useTranslation } from "react-i18next";
import { relaunch } from "@tauri-apps/api/process";
import { checkUpdate, installUpdate } from "@tauri-apps/api/updater";
import { BaseDialog, DialogRef, Notice } from "@/components/base";
import { atomUpdateState } from "@/services/states";
import { useUpdateState, useSetUpdateState } from "@/services/states";
import { listen, Event, UnlistenFn } from "@tauri-apps/api/event";
import { portableFlag } from "@/pages/_layout";
import { open as openUrl } from "@tauri-apps/api/shell";
import ReactMarkdown from "react-markdown";
let eventListener: UnlistenFn | null = null;
@@ -18,7 +18,9 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const [updateState, setUpdateState] = useRecoilState(atomUpdateState);
const updateState = useUpdateState();
const setUpdateState = useSetUpdateState();
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
errorRetryCount: 2,
@@ -75,7 +77,24 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
return (
<BaseDialog
open={open}
title={`New Version v${updateInfo?.manifest?.version}`}
title={
<Box display="flex" justifyContent="space-between">
{`New Version v${updateInfo?.manifest?.version}`}
<Box>
<Button
variant="contained"
size="small"
onClick={() => {
openUrl(
`https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/v${updateInfo?.manifest?.version}`
);
}}
>
{t("Go to Release Page")}
</Button>
</Box>
</Box>
}
contentSx={{ minWidth: 360, maxWidth: 400, height: "50vh" }}
okBtn={t("Update")}
cancelBtn={t("Cancel")}
+8 -6
View File
@@ -13,6 +13,7 @@ import {
EditRounded,
OpenInNewRounded,
} from "@mui/icons-material";
import { useTranslation } from "react-i18next";
interface Props {
value?: string;
@@ -35,6 +36,7 @@ export const WebUIItem = (props: Props) => {
const [editing, setEditing] = useState(false);
const [editValue, setEditValue] = useState(value);
const { t } = useTranslation();
if (editing || onlyEdit) {
return (
@@ -45,12 +47,12 @@ export const WebUIItem = (props: Props) => {
size="small"
value={editValue}
onChange={(e) => setEditValue(e.target.value)}
placeholder={`Support %host %port %secret`}
placeholder={t("Support %host, %port, %secret")}
autoComplete="off"
/>
<IconButton
size="small"
title="Save"
title={t("Save")}
color="inherit"
onClick={() => {
onChange(editValue);
@@ -61,7 +63,7 @@ export const WebUIItem = (props: Props) => {
</IconButton>
<IconButton
size="small"
title="Cancel"
title={t("Cancel")}
color="inherit"
onClick={() => {
onCancel?.();
@@ -100,7 +102,7 @@ export const WebUIItem = (props: Props) => {
/>
<IconButton
size="small"
title="Open URL"
title={t("Open URL")}
color="inherit"
onClick={() => onOpenUrl?.(value)}
>
@@ -108,7 +110,7 @@ export const WebUIItem = (props: Props) => {
</IconButton>
<IconButton
size="small"
title="Edit"
title={t("Edit")}
color="inherit"
onClick={() => {
setEditing(true);
@@ -119,7 +121,7 @@ export const WebUIItem = (props: Props) => {
</IconButton>
<IconButton
size="small"
title="Delete"
title={t("Delete")}
color="inherit"
onClick={onDelete}
>
@@ -105,10 +105,10 @@ export const WebUIViewer = forwardRef<DialogRef>((props, ref) => {
>
{!editing && webUIList.length === 0 && (
<BaseEmpty
text="Empty List"
text="Empty"
extra={
<Typography mt={2} sx={{ fontSize: "12px" }}>
Replace host, port, secret with "%host" "%port" "%secret"
{t("Replace host, port, secret with %host, %port, %secret")}
</Typography>
}
/>
+14 -44
View File
@@ -9,7 +9,7 @@ import {
IconButton,
Tooltip,
} from "@mui/material";
import { ArrowForward, Settings, Shuffle } from "@mui/icons-material";
import { Settings, Shuffle } from "@mui/icons-material";
import { DialogRef, Notice, Switch } from "@/components/base";
import { useClash } from "@/hooks/use-clash";
import { GuardState } from "./mods/guard-state";
@@ -51,14 +51,14 @@ const SettingClash = ({ onError }: Props) => {
const onChangeVerge = (patch: Partial<IVergeConfig>) => {
mutateVerge({ ...verge, ...patch }, false);
};
const onUpdateGeo = useLockFn(async () => {
const onUpdateGeo = async () => {
try {
await updateGeoData();
Notice.success(t("GeoData Updated"));
} catch (err: any) {
Notice.error(err?.response.data.message || err.toString());
}
});
};
return (
<SettingList title={t("Clash Setting")}>
@@ -120,7 +120,10 @@ const SettingClash = ({ onError }: Props) => {
color={enable_random_port ? "primary" : "inherit"}
size="small"
onClick={() => {
Notice.success(t("Restart Application to Apply Modifications"), 1000);
Notice.success(
t("Restart Application to Apply Modifications"),
1000
);
onChangeVerge({ enable_random_port: !enable_random_port });
patchVerge({ enable_random_port: !enable_random_port });
}}
@@ -146,27 +149,12 @@ const SettingClash = ({ onError }: Props) => {
/>
</SettingItem>
<SettingItem label={t("External")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => ctrlRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem
onClick={() => ctrlRef.current?.open()}
label={t("External")}
/>
<SettingItem label={t("Web UI")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => webRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem onClick={() => webRef.current?.open()} label={t("Web UI")} />
<SettingItem
label={t("Clash Core")}
@@ -187,28 +175,10 @@ const SettingClash = ({ onError }: Props) => {
</SettingItem>
{isWIN && (
<SettingItem label={t("Open UWP tool")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={invoke_uwp_tool}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem onClick={invoke_uwp_tool} label={t("Open UWP tool")} />
)}
<SettingItem label={t("Update GeoData")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={onUpdateGeo}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem onClick={onUpdateGeo} label={t("Update GeoData")} />
</SettingList>
);
};
+20 -10
View File
@@ -123,16 +123,26 @@ const SettingSystem = ({ onError }: Props) => {
<SettingItem
label={t("System Proxy")}
extra={
<IconButton
color="inherit"
size="small"
onClick={() => sysproxyRef.current?.open()}
>
<Settings
fontSize="inherit"
style={{ cursor: "pointer", opacity: 0.75 }}
/>
</IconButton>
<>
<Tooltip title={t("System Proxy Info")} placement="top">
<IconButton color="inherit" size="small">
<InfoRounded
fontSize="inherit"
style={{ cursor: "pointer", opacity: 0.75 }}
/>
</IconButton>
</Tooltip>
<IconButton
color="inherit"
size="small"
onClick={() => sysproxyRef.current?.open()}
>
<Settings
fontSize="inherit"
style={{ cursor: "pointer", opacity: 0.75 }}
/>
</IconButton>
</>
}
>
<GuardState
+35 -123
View File
@@ -2,14 +2,7 @@ import { useRef } from "react";
import { useLockFn } from "ahooks";
import { useTranslation } from "react-i18next";
import { open } from "@tauri-apps/api/dialog";
import {
Button,
IconButton,
MenuItem,
Select,
Input,
Typography,
} from "@mui/material";
import { Button, MenuItem, Select, Input, Typography } from "@mui/material";
import {
exitApp,
openAppDir,
@@ -17,7 +10,6 @@ import {
openLogsDir,
openDevTools,
} from "@/services/cmds";
import { ArrowForward } from "@mui/icons-material";
import { checkUpdate } from "@tauri-apps/api/updater";
import { useVerge } from "@/hooks/use-verge";
import { version } from "@root/package.json";
@@ -63,7 +55,7 @@ const SettingVerge = ({ onError }: Props) => {
mutateVerge({ ...verge, ...patch }, false);
};
const onCheckUpdate = useLockFn(async () => {
const onCheckUpdate = async () => {
try {
const info = await checkUpdate();
if (!info?.shouldUpdate) {
@@ -74,7 +66,7 @@ const SettingVerge = ({ onError }: Props) => {
} catch (err: any) {
Notice.error(err.message || err.toString());
}
});
};
return (
<SettingList title={t("Verge Setting")}>
@@ -213,128 +205,48 @@ const SettingVerge = ({ onError }: Props) => {
></Input>
</GuardState>
</SettingItem>
<SettingItem label={t("Theme Setting")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => themeRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem label={t("Layout Setting")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => layoutRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem
onClick={() => themeRef.current?.open()}
label={t("Theme Setting")}
/>
<SettingItem label={t("Miscellaneous")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => miscRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem
onClick={() => layoutRef.current?.open()}
label={t("Layout Setting")}
/>
<SettingItem label={t("Hotkey Setting")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => hotkeyRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem
onClick={() => miscRef.current?.open()}
label={t("Miscellaneous")}
/>
<SettingItem label={t("Runtime Config")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => configRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem
onClick={() => hotkeyRef.current?.open()}
label={t("Hotkey Setting")}
/>
<SettingItem label={t("Open App Dir")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={openAppDir}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem
onClick={() => configRef.current?.open()}
label={t("Runtime Config")}
/>
<SettingItem label={t("Open Core Dir")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={openCoreDir}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem onClick={openAppDir} label={t("Open App Dir")} />
<SettingItem label={t("Open Logs Dir")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={openLogsDir}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem onClick={openCoreDir} label={t("Open Core Dir")} />
<SettingItem label={t("Check for Updates")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={onCheckUpdate}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem onClick={openLogsDir} label={t("Open Logs Dir")} />
<SettingItem label={t("Open Dev Tools")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={openDevTools}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem onClick={onCheckUpdate} label={t("Check for Updates")} />
<SettingItem label={t("Exit")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => {
exitApp();
}}
>
<ArrowForward />
</IconButton>
</SettingItem>
<SettingItem onClick={openDevTools} label={t("Open Dev Tools")} />
<SettingItem
onClick={() => {
exitApp();
}}
label={t("Exit")}
/>
<SettingItem label={t("Verge Version")}>
<Typography sx={{ py: "7px", pr: 1 }}>v{version}</Typography>
+1 -1
View File
@@ -175,7 +175,7 @@ export const TestItem = (props: Props) => {
":hover": { bgcolor: alpha(palette.primary.main, 0.15) },
})}
>
Check
{t("Test")}
</Widget>
)}
+1 -1
View File
@@ -39,7 +39,7 @@ export const TestViewer = forwardRef<TestViewerRef, Props>((props, ref) => {
}
return x;
});
await patchVerge({ ...verge, test_list: newList });
await patchVerge({ test_list: newList });
};
useImperativeHandle(ref, () => ({
-21
View File
@@ -9,27 +9,6 @@
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Clash Verge</title>
<script>
(function () {
var _matchMedia = window.matchMedia;
window.matchMedia = function () {
var v = _matchMedia.apply(null, arguments);
if (!v.addEventListener) {
v.addEventListener = function () {
if (arguments.length < 2 || arguments[0] !== "change") {
console.error("Cannot proxy addEventListener:", arguments);
return;
}
if (arguments.length > 2) {
console.warn("Proxy addEventListener:", arguments);
}
v.addListener(arguments[1]);
};
}
return v;
};
})();
</script>
</head>
<body>
<div id="root"></div>
+175 -167
View File
@@ -1,60 +1,33 @@
{
"Back": "Back",
"Close": "Close",
"Cancel": "Cancel",
"Confirm": "Confirm",
"New": "New",
"Edit": "Edit",
"Save": "Save",
"Delete": "Delete",
"Enable": "Enable",
"Disable": "Disable",
"Label-Proxies": "Proxies",
"Label-Test": "Test",
"Label-Profiles": "Profiles",
"Label-Connections": "Connections",
"Label-Logs": "Logs",
"Label-Rules": "Rules",
"Label-Logs": "Logs",
"Label-Test": "Test",
"Label-Settings": "Settings",
"Connections": "Connections",
"Logs": "Logs",
"Clear": "Clear",
"Proxies": "Proxies",
"Proxy Groups": "Proxy Groups",
"Test": "Test",
"Proxy Provider": "Proxy Provider",
"Update All": "Update All",
"Update At": "Update At",
"rule": "rule",
"global": "global",
"direct": "direct",
"script": "script",
"Create Test": "Create Test",
"Edit Test": "Edit Test",
"Edit": "Edit",
"Icon": "Icon",
"Test URL": "Test URL",
"Test All": "Test All",
"Paste": "Paste",
"Profiles": "Profiles",
"Profile URL": "Profile URL",
"Import": "Import",
"New": "New",
"Create Profile": "Create Profile",
"Edit Profile": "Edit Profile",
"Choose File": "Choose File",
"Close": "Close",
"Close All": "Close All",
"Home": "Home",
"Select": "Select",
"Edit Info": "Edit Info",
"Edit File": "Edit File",
"Open File": "Open File",
"Update": "Update",
"Update(Proxy)": "Update(Proxy)",
"Delete": "Delete",
"Enable": "Enable",
"Disable": "Disable",
"Refresh": "Refresh",
"To Top": "To Top",
"To End": "To End",
"Update All Profiles": "Update All Profiles",
"View Runtime Config": "View Runtime Config",
"Reactivate Profiles": "Reactivate Profiles",
"Confirm deletion": "Confirm deletion",
"This operation is not reversible": "This operation is not reversible",
"Script Console": "Script Console",
"Location": "Location",
"Delay check": "Delay check",
"Sort by default": "Sort by default",
@@ -64,13 +37,46 @@
"Delay check to cancel fixed": "Delay check to cancel fixed",
"Proxy basic": "Proxy basic",
"Proxy detail": "Proxy detail",
"Filter": "Filter",
"Filter conditions": "Filter conditions",
"Refresh profiles": "Refresh profiles",
"Rules": "Rules",
"Update All": "Update All",
"Update At": "Update At",
"Profiles": "Profiles",
"Update All Profiles": "Update All Profiles",
"View Runtime Config": "View Runtime Config",
"Reactivate Profiles": "Reactivate Profiles",
"Paste": "Paste",
"Profile URL": "Profile URL",
"Import": "Import",
"Create Profile": "Create Profile",
"Edit Profile": "Edit Profile",
"Type": "Type",
"Name": "Name",
"Descriptions": "Descriptions",
"Subscription URL": "Subscription URL",
"Update Interval": "Update Interval",
"Choose File": "Choose File",
"Use System Proxy": "Use System Proxy",
"Use Clash Proxy": "Use Clash Proxy",
"Accept Invalid Certs (Danger)": "Allows Invalid Certificates (Danger)",
"Refresh": "Refresh",
"Home": "Home",
"Select": "Select",
"Edit Info": "Edit Info",
"Edit File": "Edit File",
"Open File": "Open File",
"Update": "Update",
"Update(Proxy)": "Update(Proxy)",
"Confirm deletion": "Confirm deletion",
"This operation is not reversible": "This operation is not reversible",
"Script Console": "Script Console",
"To Top": "To Top",
"To End": "To End",
"Connections": "Connections",
"Table View": "Table View",
"List View": "List View",
"Close All": "Close All",
"Default": "Default",
"Download Speed": "Download Speed",
"Upload Speed": "Upload Speed",
"Host": "Host",
"Downloaded": "Downloaded",
"Uploaded": "Uploaded",
@@ -84,88 +90,98 @@
"Destination IP": "Destination IP",
"Close Connection": "Close Connection",
"Type": "Type",
"Name": "Name",
"Descriptions": "Descriptions",
"Subscription URL": "Subscription URL",
"Update Interval": "Update Interval",
"Use System Proxy": "Use System Proxy",
"Use Clash Proxy": "Use Clash Proxy",
"Accept Invalid Certs (Danger)": "Allows Invalid Certificates (Danger)",
"Rules": "Rules",
"Rule Provider": "Rule Provider",
"Logs": "Logs",
"Pause": "Pause",
"Clear": "Clear",
"Test": "Test",
"Test All": "Test All",
"Create Test": "Create Test",
"Edit Test": "Edit Test",
"Icon": "Icon",
"Test URL": "Test URL",
"Settings": "Settings",
"Clash Setting": "Clash Setting",
"System Setting": "System Setting",
"Verge Setting": "Verge Setting",
"Tun Mode": "Tun Mode",
"Reset to Default": "Reset to Default",
"Tun Mode Info": "The Tun mode requires granting core-related permissions. Please enable service mode before using it",
"Stack": "Tun Stack",
"System and Mixed Can Only be Used in Service Mode": "System and Mixed Can Only be Used in Service Mode",
"Device": "Device Name",
"Auto Route": "Auto Route",
"Strict Route": "Strict Route",
"Auto Detect Interface": "Auto Detect Interface",
"DNS Hijack": "DNS Hijack",
"MTU": "Max Transmission Unit",
"Service Mode": "Service Mode",
"Current State": "Current State",
"pending": "pending",
"installed": "installed",
"uninstall": "uninstalled",
"active": "active",
"unknown": "unknown",
"Information: Please make sure that the Clash Verge Service is installed and enabled": "Information: Please make sure that the Clash Verge Service is installed and enabled",
"Install": "Install",
"Uninstall": "Uninstall",
"Disable Service Mode": "Disable Service Mode",
"System Proxy": "System Proxy",
"System Proxy Info": "Enable to modify the operating system's proxy settings. If enabling fails, modify the operating system's proxy settings manually",
"System Proxy Setting": "System Proxy Setting",
"Current System Proxy": "Current System Proxy",
"Enable status": "Enable Status:",
"Enabled": "Enabled",
"Disabled": "Disabled",
"Server Addr": "Server Addr: ",
"Not available": "Not available",
"Proxy Guard": "Proxy Guard",
"Proxy Guard Info": "Enable to prevent other software from modifying the operating system's proxy settings",
"Guard Duration": "Guard Duration",
"Proxy Bypass": "Proxy Bypass Settings: ",
"Bypass": "Bypass: ",
"Use PAC Mode": "Use PAC Mode",
"PAC Script Content": "PAC Script Content",
"PAC URL": "PAC URL: ",
"Auto Launch": "Auto Launch",
"Silent Start": "Silent Start",
"Clash Setting": "Clash Setting",
"Allow Lan": "Allow Lan",
"IPv6": "IPv6",
"Log Level": "Log Level",
"Port Config": "Port Config",
"Random Port": "Random Port",
"Restart Application to Apply Modifications": "Restart Application to Apply Modifications",
"External": "External",
"External Controller": "External Controller",
"Core Secret": "Core Secret",
"Recommended": "Recommended",
"Open URL": "Open URL",
"Replace host, port, secret with %host, %port, %secret": "Replace host, port, secret with %host, %port, %secret",
"Support %host, %port, %secret": "Support %host, %port, %secret",
"Clash Core": "Clash Core",
"Grant": "Grant",
"Upgrade": "Upgrade",
"Restart": "Restart",
"Tun mode requires": "Tun mode requires",
"Tun Mode": "Tun Mode",
"Service Mode": "Service Mode",
"Auto Launch": "Auto Launch",
"Silent Start": "Silent Start",
"System Proxy": "System Proxy",
"System Proxy Setting": "System Proxy Setting",
"Grant": "Grant",
"Open UWP tool": "Open UWP tool",
"Update GeoData": "Update GeoData",
"Use PAC Mode": "Use PAC Mode",
"PAC URL": "PAC URL",
"PAC Script Content": "PAC Script Content",
"Proxy Guard": "Proxy Guard",
"Guard Duration": "Guard Duration",
"Proxy Bypass": "Proxy Bypass",
"Current System Proxy": "Current System Proxy",
"Enable status": "Enable status",
"Server Addr": "Server Addr",
"Bypass": "Bypass",
"Verge Setting": "Verge Setting",
"Language": "Language",
"Theme Mode": "Theme Mode",
"theme.light": "Light",
"theme.dark": "Dark",
"theme.system": "System",
"Tray Click Event": "Tray Click Event",
"Show Main Window": "Show Main Window",
"Copy Env Type": "Copy Env Type",
"Start Page": "Start Page",
"Startup Script": "Startup Script",
"Browse": "Browse",
"Show Main Window": "Show Main Window",
"Theme Setting": "Theme Setting",
"Layout Setting": "Layout Setting",
"Miscellaneous": "Miscellaneous",
"Hotkey Setting": "Hotkey Setting",
"Traffic Graph": "Traffic Graph",
"Memory Usage": "Memory Usage",
"Proxy Group Icon": "Proxy Group Icon",
"Tray Icon": "Tray Icon",
"Menu Icon": "Menu Icon",
"Monochrome": "Monochrome",
"Colorful": "Colorful",
"Common Tray Icon": "Common Tray Icon",
"System Proxy Tray Icon": "System Proxy Tray Icon",
"Tun Tray Icon": "Tun Tray Icon",
"Language": "Language",
"Open App Dir": "Open App Dir",
"Open Core Dir": "Open Core Dir",
"Open Logs Dir": "Open Logs Dir",
"Check for Updates": "Check for Updates",
"Open Dev Tools": "Open Dev Tools",
"Verge Version": "Verge Version",
"theme.light": "Light",
"theme.dark": "Dark",
"theme.system": "System",
"Clash Field": "Clash Field",
"Runtime Config": "Runtime Config",
"ReadOnly": "ReadOnly",
"ReadOnlyMessage": "Cannot edit in read-only editor",
"Restart": "Restart",
"Upgrade": "Upgrade",
"Primary Color": "Primary Color",
"Secondary Color": "Secondary Color",
"Primary Text": "Primary Text",
@@ -176,82 +192,74 @@
"Success Color": "Success Color",
"Font Family": "Font Family",
"CSS Injection": "CSS Injection",
"Back": "Back",
"Save": "Save",
"Cancel": "Cancel",
"Exit": "Exit",
"Confirm": "Confirm",
"Default": "Default",
"Download Speed": "Download Speed",
"Upload Speed": "Upload Speed",
"Layout Setting": "Layout Setting",
"Traffic Graph": "Traffic Graph",
"Memory Usage": "Memory Usage",
"Proxy Group Icon": "Proxy Group Icon",
"Menu Icon": "Menu Icon",
"Monochrome": "Monochrome",
"Colorful": "Colorful",
"Tray Icon": "Tray Icon",
"Common Tray Icon": "Common Tray Icon",
"System Proxy Tray Icon": "System Proxy Tray Icon",
"Tun Tray Icon": "Tun Tray Icon",
"Miscellaneous": "Miscellaneous",
"App Log Level": "App Log Level",
"Auto Close Connections": "Auto Close Connections",
"Auto Check Update": "Auto Check Update",
"Enable Builtin Enhanced": "Enable Builtin Enhanced",
"Proxy Layout Column": "Proxy Layout Column",
"Auto Log Clean": "Auto Log Clean",
"Never Clean": "Never Clean",
"Retain 7 Days": "Retain 7 Days",
"Retain 30 Days": "Retain 30 Days",
"Retain 90 Days": "Retain 90 Days",
"Default Latency Test": "Default Latency Test",
"Default Latency Timeout": "Default Latency Timeout",
"Hotkey Setting": "Hotkey Setting",
"open_or_close_dashboard": "Open/Close Dashboard",
"clash_mode_rule": "Rule Mode",
"clash_mode_global": "Global Mode",
"clash_mode_direct": "Direct Mode",
"toggle_system_proxy": "Enable/Disable System Proxy",
"toggle_tun_mode": "Enable/Disable Tun Mode",
"App Log Level": "App Log Level",
"Auto Close Connections": "Auto Close Connections",
"Auto Check Update": "Auto Check Update",
"Enable Builtin Enhanced": "Enable Builtin Enhanced",
"Proxy Layout Column": "Proxy Layout Column",
"Default Latency Test": "Default Latency Test",
"Default Latency Timeout": "Default Latency Timeout",
"Auto Log Clean": "Auto Log Clean",
"Never Clean": "Never Clean",
"Retain 7 Days": "Retain 7 Days",
"Retain 30 Days": "Retain 30 Days",
"Retain 90 Days": "Retain 90 Days",
"Stack": "Tun Stack",
"Device": "Device Name",
"Auto Route": "Auto Route",
"Strict Route": "Strict Route",
"Auto Detect Interface": "Auto Detect Interface",
"DNS Hijack": "DNS Hijack",
"MTU": "Max Transmission Unit",
"Reset to Default": "Reset to Default",
"Current State": "Current State",
"pending": "pending",
"installed": "installed",
"uninstall": "uninstalled",
"active": "active",
"unknown": "unknown",
"Disable Service Mode": "Disable Service Mode",
"Install": "Install",
"Uninstall": "Uninstall",
"Runtime Config": "Runtime Config",
"Open App Dir": "Open App Dir",
"Open Core Dir": "Open Core Dir",
"Open Logs Dir": "Open Logs Dir",
"Check for Updates": "Check for Updates",
"Go to Release Page": "Go to Release Page",
"Portable Updater Error": "The portable version does not support in-app updates. Please manually download and replace it",
"Tun Mode Info": "The Tun mode requires granting core-related permissions. Please enable service mode before using it",
"System and Mixed Can Only be Used in Service Mode": "System and Mixed Can Only be Used in Service Mode",
"Information: Please make sure that the Clash Verge Service is installed and enabled": "Information: Please make sure that the Clash Verge Service is installed and enabled",
"Open Dev Tools": "Open Dev Tools",
"Exit": "Exit",
"Verge Version": "Verge Version",
"ReadOnly": "ReadOnly",
"ReadOnlyMessage": "Cannot edit in read-only editor",
"Filter": "Filter",
"Filter conditions": "Filter conditions",
"Match Case": "Match Case",
"Match Whole Word": "Match Whole Word",
"Use Regular Expression": "Use Regular Expression",
"External Controller Address Modified": "External Controller Address Modified",
"Clash Port Modified": "Clash Port Modified",
"Currently on the Latest Version": "Currently on the Latest Version",
"Only YAML Files Supported": "Only YAML Files Supported",
"Port Conflict": "Port Conflict",
"Proxy Daemon Duration Cannot be Less than 1 Second": "Proxy Daemon Duration Cannot be Less than 1 Second",
"Profile Imported Successfully": "Profile Imported Successfully",
"Clash Config Updated": "Clash Config Updated",
"Profile Switched": "Profile Switched",
"Profile Reactivated": "Profile Reactivated",
"Clash Config Updated": "Clash Config Updated",
"Only YAML Files Supported": "Only YAML Files Supported",
"Settings Applied": "Settings Applied",
"Service Installed Successfully": "Service Installed Successfully",
"Service Uninstalled Successfully": "Service Uninstalled Successfully",
"GeoData Updated": "GeoData Updated",
"Proxy Daemon Duration Cannot be Less than 1 Second": "Proxy Daemon Duration Cannot be Less than 1 Second",
"Invalid Bypass Format": "Invalid Bypass Format",
"Clash Port Modified": "Clash Port Modified",
"Port Conflict": "Port Conflict",
"Restart Application to Apply Modifications": "Restart Application to Apply Modifications",
"External Controller Address Modified": "External Controller Address Modified",
"Permissions Granted Successfully for _clash Core": "Permissions Granted Successfully for {{core}} Core",
"Profile Imported Successfully": "Profile Imported Successfully",
"Core Version Updated": "Core Version Updated",
"Clash Core Restarted": "Clash Core Restarted",
"Switched to _clash Core": "Switched to {{core}} Core",
"Core Version Updated": "Core Version Updated"
"GeoData Updated": "GeoData Updated",
"Currently on the Latest Version": "Currently on the Latest Version"
}
+175 -167
View File
@@ -1,60 +1,33 @@
{
"Back": "بازگشت",
"Close": "بستن",
"Cancel": "لغو",
"Confirm": "تأیید",
"New": "جدید",
"Edit": "ویرایش",
"Save": "ذخیره",
"Delete": "حذف",
"Enable": "فعال کردن",
"Disable": "غیرفعال کردن",
"Label-Proxies": "پراکسی‌ها",
"Label-Test": "آزمون",
"Label-Profiles": "پروفایل‌ها",
"Label-Connections": "اتصالات",
"Label-Logs": "لاگ‌ها",
"Label-Rules": "قوانین",
"Label-Logs": "لاگ‌ها",
"Label-Test": "آزمون",
"Label-Settings": "تنظیمات",
"Connections": "اتصالات",
"Logs": "لاگ‌ها",
"Clear": "پاک کردن",
"Proxies": "پراکسی‌ها",
"Proxy Groups": "گروه‌های پراکسی",
"Test": "آزمون",
"Proxy Provider": "تأمین‌کننده پروکسی",
"Update All": "به‌روزرسانی همه",
"Update At": "به‌روزرسانی در",
"rule": "قانون",
"global": "جهانی",
"direct": "مستقیم",
"script": "اسکریپت",
"Create Test": "ایجاد آزمون",
"Edit Test": "ویرایش آزمون",
"Edit": "ویرایش",
"Icon": "آیکون",
"Test URL": "آدرس آزمون",
"Test All": "آزمون همه",
"Paste": "چسباندن",
"Profiles": "پروفایل‌ها",
"Profile URL": "آدرس پروفایل",
"Import": "وارد کردن",
"New": "جدید",
"Create Profile": "ایجاد پروفایل",
"Edit Profile": "ویرایش پروفایل",
"Choose File": "انتخاب فایل",
"Close": "بستن",
"Close All": "بستن همه",
"Home": "خانه",
"Select": "انتخاب",
"Edit Info": "ویرایش اطلاعات",
"Edit File": "ویرایش فایل",
"Open File": "باز کردن فایل",
"Update": "به‌روزرسانی",
"Update(Proxy)": "به‌روزرسانی (پراکسی)",
"Delete": "حذف",
"Enable": "فعال کردن",
"Disable": "غیرفعال کردن",
"Refresh": "بازنشانی",
"To Top": "به بالا",
"To End": "به پایان",
"Update All Profiles": "به‌روزرسانی همه پروفایل‌ها",
"View Runtime Config": "مشاهده پیکربندی زمان اجرا",
"Reactivate Profiles": "فعال‌سازی مجدد پروفایل‌ها",
"Confirm deletion": "تأیید حذف",
"This operation is not reversible": "این عملیات قابل برگشت نیست",
"Script Console": "کنسول اسکریپت",
"Location": "موقعیت",
"Delay check": "بررسی تأخیر",
"Sort by default": "مرتب‌سازی بر اساس پیش‌فرض",
@@ -64,13 +37,46 @@
"Delay check to cancel fixed": "بررسی تأخیر برای لغو ثابت",
"Proxy basic": "پراکسی پایه",
"Proxy detail": "جزئیات پراکسی",
"Filter": "فیلتر",
"Filter conditions": "شرایط فیلتر",
"Refresh profiles": "بازنشانی پروفایل‌ها",
"Rules": "قوانین",
"Update All": "به‌روزرسانی همه",
"Update At": "به‌روزرسانی در",
"Profiles": "پروفایل‌ها",
"Update All Profiles": "به‌روزرسانی همه پروفایل‌ها",
"View Runtime Config": "مشاهده پیکربندی زمان اجرا",
"Reactivate Profiles": "فعال‌سازی مجدد پروفایل‌ها",
"Paste": "چسباندن",
"Profile URL": "آدرس پروفایل",
"Import": "وارد کردن",
"Create Profile": "ایجاد پروفایل",
"Edit Profile": "ویرایش پروفایل",
"Type": "نوع",
"Name": "نام",
"Descriptions": "توضیحات",
"Subscription URL": "آدرس اشتراک",
"Update Interval": "فاصله زمانی به‌روزرسانی",
"Choose File": "انتخاب فایل",
"Use System Proxy": "استفاده از پراکسی سیستم",
"Use Clash Proxy": "استفاده از پراکسی Clash",
"Accept Invalid Certs (Danger)": "پذیرش گواهی‌نامه‌های نامعتبر (خطرناک)",
"Refresh": "بازنشانی",
"Home": "خانه",
"Select": "انتخاب",
"Edit Info": "ویرایش اطلاعات",
"Edit File": "ویرایش فایل",
"Open File": "باز کردن فایل",
"Update": "به‌روزرسانی",
"Update(Proxy)": "به‌روزرسانی (پراکسی)",
"Confirm deletion": "تأیید حذف",
"This operation is not reversible": "این عملیات قابل برگشت نیست",
"Script Console": "کنسول اسکریپت",
"To Top": "به بالا",
"To End": "به پایان",
"Connections": "اتصالات",
"Table View": "نمای جدولی",
"List View": "نمای لیستی",
"Close All": "بستن همه",
"Default": "پیش‌فرض",
"Download Speed": "سرعت دانلود",
"Upload Speed": "سرعت بارگذاری",
"Host": "میزبان",
"Downloaded": "دانلود شده",
"Uploaded": "بارگذاری شده",
@@ -84,88 +90,98 @@
"Destination IP": "آدرس IP مقصد",
"Close Connection": "بستن اتصال",
"Type": "نوع",
"Name": "نام",
"Descriptions": "توضیحات",
"Subscription URL": "آدرس اشتراک",
"Update Interval": "فاصله زمانی به‌روزرسانی",
"Use System Proxy": "استفاده از پراکسی سیستم",
"Use Clash Proxy": "استفاده از پراکسی Clash",
"Accept Invalid Certs (Danger)": "پذیرش گواهی‌نامه‌های نامعتبر (خطرناک)",
"Rules": "قوانین",
"Rule Provider": "تأمین‌کننده قانون",
"Logs": "لاگ‌ها",
"Pause": "توقف",
"Clear": "پاک کردن",
"Test": "آزمون",
"Test All": "آزمون همه",
"Create Test": "ایجاد آزمون",
"Edit Test": "ویرایش آزمون",
"Icon": "آیکون",
"Test URL": "آدرس آزمون",
"Settings": "تنظیمات",
"Clash Setting": "تنظیمات Clash",
"System Setting": "تنظیمات سیستم",
"Verge Setting": "تنظیمات Verge",
"Tun Mode": "حالت Tun",
"Reset to Default": "بازنشانی به پیش‌فرض",
"Tun Mode Info": "حالت Tun نیاز به اعطای مجوزهای مربوط به هسته دارد. لطفاً قبل از استفاده، حالت سرویس را فعال کنید",
"Stack": "انباشته Tun",
"System and Mixed Can Only be Used in Service Mode": "سیستم و ترکیبی تنها می‌توانند در حالت سرویس استفاده شوند",
"Device": "نام دستگاه",
"Auto Route": "مسیر خودکار",
"Strict Route": "مسیر دقیق",
"Auto Detect Interface": "تشخیص خودکار رابط",
"DNS Hijack": "ربایش DNS",
"MTU": "واحد حداکثر انتقال",
"Service Mode": "حالت سرویس",
"Current State": "وضعیت فعلی",
"pending": "در انتظار",
"installed": "نصب شده",
"uninstall": "حذف شده",
"active": "فعال",
"unknown": "ناشناخته",
"Information: Please make sure that the Clash Verge Service is installed and enabled": "اطلاعات: لطفاً مطمئن شوید که سرویس Clash Verge نصب و فعال شده است",
"Install": "نصب",
"Uninstall": "حذف نصب",
"Disable Service Mode": "غیرفعال کردن حالت سرویس",
"System Proxy": "پراکسی سیستم",
"System Proxy Info": "به امکانات تنظیم پروکسی سیستم عامل دسترسی پیدا کنید. اگر فعال‌سازی ناموفق بود، پروکسی سیستم عامل را به‌صورت دستی تغییر دهید",
"System Proxy Setting": "تنظیمات پراکسی سیستم",
"Current System Proxy": "پراکسی سیستم فعلی",
"Enable status": "وضعیت فعال",
"Enabled": "توانایی فعال شد",
"Disabled": "غیرفعال شد",
"Server Addr": "آدرس سرور: ",
"Not available": "غیر فعال شد",
"Proxy Guard": "محافظ پراکسی",
"Proxy Guard Info": "امکان جلوگیری از نرم‌افزارهای دیگر از تغییر تنظیمات پروکسی سیستم عامل را فعال کنید",
"Guard Duration": "مدت محافظت",
"Proxy Bypass": "دور زدن پراکسی: ",
"Bypass": "دور زدن: ",
"Use PAC Mode": "استفاده از حالت PAC",
"PAC Script Content": "محتوای اسکریپت PAC",
"PAC URL": "PAC URL: ",
"Auto Launch": "راه‌اندازی خودکار",
"Silent Start": "شروع بی‌صدا",
"Clash Setting": "تنظیمات Clash",
"Allow Lan": "اجازه LAN",
"IPv6": "IPv6",
"Log Level": "سطح لاگ",
"Port Config": "پیکربندی پورت",
"Random Port": "پورت تصادفی",
"Restart Application to Apply Modifications": "راه‌اندازی مجدد برنامه برای اعمال تغییرات",
"External": "خارجی",
"External Controller": "کنترل‌کننده خارجی",
"Core Secret": "رمز اصلی",
"Recommended": "توصیه شده",
"Open URL": "باز کردن آدرس اینترنتی",
"Replace host, port, secret with %host, %port, %secret": "جایگزین کردن میزبان، پورت و رمز با %host، %port، %secret",
"Support %host, %port, %secret": "پشتیبانی از %host، %port و %secret",
"Clash Core": "هسته Clash",
"Grant": "اعطا",
"Upgrade": "ارتقاء",
"Restart": "راه‌اندازی مجدد",
"Tun mode requires": "Tun mode نیاز دارد",
"Tun Mode": "حالت Tun",
"Service Mode": "حالت سرویس",
"Auto Launch": "راه‌اندازی خودکار",
"Silent Start": "شروع بی‌صدا",
"System Proxy": "پراکسی سیستم",
"System Proxy Setting": "تنظیمات پراکسی سیستم",
"Grant": "اعطا",
"Open UWP tool": "باز کردن ابزار UWP",
"Update GeoData": "به‌روزرسانی GeoData",
"Use PAC Mode": "استفاده از حالت PAC",
"PAC URL": "PAC URL",
"PAC Script Content": "محتوای اسکریپت PAC",
"Proxy Guard": "محافظ پراکسی",
"Guard Duration": "مدت محافظت",
"Proxy Bypass": "دور زدن پراکسی",
"Current System Proxy": "پراکسی سیستم فعلی",
"Enable status": "وضعیت فعال",
"Server Addr": "آدرس سرور",
"Bypass": "دور زدن",
"Verge Setting": "تنظیمات Verge",
"Language": "زبان",
"Theme Mode": "حالت تم",
"theme.light": "روشن",
"theme.dark": "تاریک",
"theme.system": "سیستم",
"Tray Click Event": "رویداد کلیک در سینی سیستم",
"Show Main Window": "نمایش پنجره اصلی",
"Copy Env Type": "کپی نوع محیط",
"Start Page": "صفحه شروع",
"Startup Script": "اسکریپت راه‌اندازی",
"Browse": "مرور کردن",
"Show Main Window": "نمایش پنجره اصلی",
"Theme Setting": "تنظیمات تم",
"Layout Setting": "تنظیمات چیدمان",
"Miscellaneous": "متفرقه",
"Hotkey Setting": "تنظیمات کلیدهای میانبر",
"Traffic Graph": "نمودار ترافیک",
"Memory Usage": "استفاده از حافظه",
"Proxy Group Icon": "آیکون گروه پراکسی",
"Tray Icon": "آیکون سینی سیستم",
"Menu Icon": "آیکون منو",
"Monochrome": "تک رنگ",
"Colorful": "رنگارنگ",
"Common Tray Icon": "آیکون مشترک سینی سیستم",
"System Proxy Tray Icon": "آیکون سینی پراکسی سیستم",
"Tun Tray Icon": "آیکون سینی Tun",
"Language": "زبان",
"Open App Dir": "باز کردن پوشه برنامه",
"Open Core Dir": "باز کردن پوشه هسته",
"Open Logs Dir": "باز کردن پوشه لاگ‌ها",
"Check for Updates": "بررسی برای به‌روزرسانی‌ها",
"Open Dev Tools": "باز کردن ابزارهای توسعه‌دهنده",
"Verge Version": "نسخه Verge",
"theme.light": "روشن",
"theme.dark": "تاریک",
"theme.system": "سیستم",
"Clash Field": "زمینه Clash",
"Runtime Config": "پیکربندی زمان اجرا",
"ReadOnly": "فقط خواندنی",
"ReadOnlyMessage": "نمی‌توان در ویرایشگر فقط خواندنی ویرایش کرد",
"Restart": "راه‌اندازی مجدد",
"Upgrade": "ارتقاء",
"Primary Color": "رنگ اصلی",
"Secondary Color": "رنگ ثانویه",
"Primary Text": "متن اصلی",
@@ -176,82 +192,74 @@
"Success Color": "رنگ موفقیت",
"Font Family": "خانواده فونت",
"CSS Injection": "تزریق CSS",
"Back": "بازگشت",
"Save": "ذخیره",
"Cancel": "لغو",
"Exit": "خروج",
"Confirm": "تأیید",
"Default": "پیش‌فرض",
"Download Speed": "سرعت دانلود",
"Upload Speed": "سرعت بارگذاری",
"Layout Setting": "تنظیمات چیدمان",
"Traffic Graph": "نمودار ترافیک",
"Memory Usage": "استفاده از حافظه",
"Proxy Group Icon": "آیکون گروه پراکسی",
"Menu Icon": "آیکون منو",
"Monochrome": "تک رنگ",
"Colorful": "رنگارنگ",
"Tray Icon": "آیکون سینی سیستم",
"Common Tray Icon": "آیکون مشترک سینی سیستم",
"System Proxy Tray Icon": "آیکون سینی پراکسی سیستم",
"Tun Tray Icon": "آیکون سینی Tun",
"Miscellaneous": "متفرقه",
"App Log Level": "سطح لاگ برنامه",
"Auto Close Connections": "بستن خودکار اتصالات",
"Auto Check Update": "بررسی خودکار به‌روزرسانی",
"Enable Builtin Enhanced": "فعال کردن تقویت داخلی",
"Proxy Layout Column": "ستون چیدمان پراکسی",
"Auto Log Clean": "پاکسازی خودکار لاگ",
"Never Clean": "هرگز پاک نکن",
"Retain 7 Days": "نگهداری به مدت 7 روز",
"Retain 30 Days": "نگهداری به مدت 30 روز",
"Retain 90 Days": "نگهداری به مدت 90 روز",
"Default Latency Test": "آزمون تأخیر پیش‌فرض",
"Default Latency Timeout": "زمان انتظار تأخیر پیش‌فرض",
"Hotkey Setting": "تنظیمات کلیدهای میانبر",
"open_or_close_dashboard": "باز/بستن داشبورد",
"clash_mode_rule": "حالت قانون",
"clash_mode_global": "حالت جهانی",
"clash_mode_direct": "حالت مستقیم",
"toggle_system_proxy": "فعال/غیرفعال کردن پراکسی سیستم",
"toggle_tun_mode": "فعال/غیرفعال کردن حالت Tun",
"App Log Level": "سطح لاگ برنامه",
"Auto Close Connections": "بستن خودکار اتصالات",
"Auto Check Update": "بررسی خودکار به‌روزرسانی",
"Enable Builtin Enhanced": "فعال کردن تقویت داخلی",
"Proxy Layout Column": "ستون چیدمان پراکسی",
"Default Latency Test": "آزمون تأخیر پیش‌فرض",
"Default Latency Timeout": "زمان انتظار تأخیر پیش‌فرض",
"Auto Log Clean": "پاکسازی خودکار لاگ",
"Never Clean": "هرگز پاک نکن",
"Retain 7 Days": "نگهداری به مدت 7 روز",
"Retain 30 Days": "نگهداری به مدت 30 روز",
"Retain 90 Days": "نگهداری به مدت 90 روز",
"Stack": "انباشته Tun",
"Device": "نام دستگاه",
"Auto Route": "مسیر خودکار",
"Strict Route": "مسیر دقیق",
"Auto Detect Interface": "تشخیص خودکار رابط",
"DNS Hijack": "ربایش DNS",
"MTU": "واحد حداکثر انتقال",
"Reset to Default": "بازنشانی به پیش‌فرض",
"Current State": "وضعیت فعلی",
"pending": "در انتظار",
"installed": "نصب شده",
"uninstall": "حذف شده",
"active": "فعال",
"unknown": "ناشناخته",
"Disable Service Mode": "غیرفعال کردن حالت سرویس",
"Install": "نصب",
"Uninstall": "حذف نصب",
"Runtime Config": "پیکربندی زمان اجرا",
"Open App Dir": "باز کردن پوشه برنامه",
"Open Core Dir": "باز کردن پوشه هسته",
"Open Logs Dir": "باز کردن پوشه لاگ‌ها",
"Check for Updates": "بررسی برای به‌روزرسانی‌ها",
"Go to Release Page": "رفتن به صفحه انتشار",
"Portable Updater Error": "نسخه پرتابل از به‌روزرسانی درون برنامه‌ای پشتیبانی نمی‌کند. لطفاً به صورت دستی دانلود و جایگزین کنید",
"Tun Mode Info": "حالت Tun نیاز به اعطای مجوزهای مربوط به هسته دارد. لطفاً قبل از استفاده، حالت سرویس را فعال کنید",
"System and Mixed Can Only be Used in Service Mode": "سیستم و ترکیبی تنها می‌توانند در حالت سرویس استفاده شوند",
"Information: Please make sure that the Clash Verge Service is installed and enabled": "اطلاعات: لطفاً مطمئن شوید که سرویس Clash Verge نصب و فعال شده است",
"Open Dev Tools": "باز کردن ابزارهای توسعه‌دهنده",
"Exit": "خروج",
"Verge Version": "نسخه Verge",
"ReadOnly": "فقط خواندنی",
"ReadOnlyMessage": "نمی‌توان در ویرایشگر فقط خواندنی ویرایش کرد",
"Filter": "فیلتر",
"Filter conditions": "شرایط فیلتر",
"Match Case": "تطبیق حروف کوچک و بزرگ",
"Match Whole Word": "تطبیق کل کلمه",
"Use Regular Expression": "استفاده از عبارت منظم",
"External Controller Address Modified": "آدرس کنترل‌کننده خارجی تغییر یافت",
"Clash Port Modified": "پورت Clash تغییر یافت",
"Currently on the Latest Version": "در حال حاضر در آخرین نسخه",
"Only YAML Files Supported": "فقط فایل‌های YAML پشتیبانی می‌شوند",
"Port Conflict": "تعارض پورت",
"Proxy Daemon Duration Cannot be Less than 1 Second": "مدت زمان دیمن پراکسی نمی‌تواند کمتر از 1 ثانیه باشد",
"Profile Imported Successfully": "پروفایل با موفقیت وارد شد",
"Clash Config Updated": "پیکربندی Clash به‌روزرسانی شد",
"Profile Switched": "پروفایل تغییر یافت",
"Profile Reactivated": "پروفایل مجدداً فعال شد",
"Clash Config Updated": "پیکربندی Clash به‌روزرسانی شد",
"Only YAML Files Supported": "فقط فایل‌های YAML پشتیبانی می‌شوند",
"Settings Applied": "تنظیمات اعمال شد",
"Service Installed Successfully": "سرویس با موفقیت نصب شد",
"Service Uninstalled Successfully": "سرویس با موفقیت حذف نصب شد",
"GeoData Updated": "GeoData به‌روزرسانی شد",
"Proxy Daemon Duration Cannot be Less than 1 Second": "مدت زمان دیمن پراکسی نمی‌تواند کمتر از 1 ثانیه باشد",
"Invalid Bypass Format": "فرمت عبور نامعتبر است",
"Clash Port Modified": "پورت Clash تغییر یافت",
"Port Conflict": "تعارض پورت",
"Restart Application to Apply Modifications": "راه‌اندازی مجدد برنامه برای اعمال تغییرات",
"External Controller Address Modified": "آدرس کنترل‌کننده خارجی تغییر یافت",
"Permissions Granted Successfully for _clash Core": "مجوزها با موفقیت برای هسته {{core}} اعطا شد",
"Profile Imported Successfully": "پروفایل با موفقیت وارد شد",
"Core Version Updated": "نسخه هسته به‌روزرسانی شد",
"Clash Core Restarted": "هسته Clash مجدداً راه‌اندازی شد",
"Switched to _clash Core": "تغییر به هسته {{core}}",
"Core Version Updated": "نسخه هسته به‌روزرسانی شد"
"GeoData Updated": "GeoData به‌روزرسانی شد",
"Currently on the Latest Version": "در حال حاضر در آخرین نسخه"
}
+175 -167
View File
@@ -1,60 +1,33 @@
{
"Back": "Назад",
"Close": "Закрыть",
"Cancel": "Отмена",
"Confirm": "Подтвердить",
"New": "Новый",
"Edit": "Редактировать",
"Save": "Сохранить",
"Delete": "Удалить",
"Enable": "Включить",
"Disable": "Отключить",
"Label-Proxies": "Прокси",
"Label-Test": "Тест",
"Label-Profiles": "Профили",
"Label-Connections": "Соединения",
"Label-Logs": "Логи",
"Label-Rules": "Правила",
"Label-Logs": "Логи",
"Label-Test": "Тест",
"Label-Settings": "Настройки",
"Connections": "Соединения",
"Logs": "Логи",
"Clear": "Очистить",
"Proxies": "Прокси",
"Proxy Groups": "Группы прокси",
"Test": "Тест",
"Proxy Provider": "Провайдер прокси",
"Update All": "Обновить все",
"Update At": "Обновлено в",
"rule": "правила",
"global": "глобальный",
"direct": "прямой",
"script": "скриптовый",
"Create Test": "Создать тест",
"Edit Test": "Редактировать тест",
"Edit": "Редактировать",
"Icon": "Икона",
"Test URL": "Тестовый URL",
"Test All": "Тест Все",
"Paste": "Вставить",
"Profiles": "Профили",
"Profile URL": "URL профиля",
"Import": "Импорт",
"New": "Новый",
"Create Profile": "Создать профиль",
"Edit Profile": "Изменить профиль",
"Choose File": "Выбрать файл",
"Close": "Закрыть",
"Close All": "Закрыть всё",
"Home": "Главная",
"Select": "Выбрать",
"Edit Info": "Изменить информацию",
"Edit File": "Изменить файл",
"Open File": "Открыть файл",
"Update": "Обновить",
"Update(Proxy)": "Обновить (прокси)",
"Delete": "Удалить",
"Enable": "Включить",
"Disable": "Отключить",
"Refresh": "Обновить",
"To Top": "Наверх",
"To End": "Вниз",
"Update All Profiles": "Обновить все профили",
"View Runtime Config": "Просмотреть используемый конфиг",
"Reactivate Profiles": "Реактивировать профили",
"Confirm deletion": "Подтвердите удаление",
"This operation is not reversible": "Эта операция необратима",
"Script Console": "Консоль скрипта",
"Location": "Местоположение",
"Delay check": "Проверка задержки",
"Sort by default": "Сортировать по умолчанию",
@@ -64,13 +37,46 @@
"Delay check to cancel fixed": "Проверка задержки для отмены фиксированного",
"Proxy basic": "Резюме о прокси",
"Proxy detail": "Подробности о прокси",
"Filter": "Фильтр",
"Filter conditions": "Условия фильтрации",
"Refresh profiles": "Обновить профили",
"Rules": "Правила",
"Update All": "Обновить все",
"Update At": "Обновлено в",
"Profiles": "Профили",
"Update All Profiles": "Обновить все профили",
"View Runtime Config": "Просмотреть используемый конфиг",
"Reactivate Profiles": "Реактивировать профили",
"Paste": "Вставить",
"Profile URL": "URL профиля",
"Import": "Импорт",
"Create Profile": "Создать профиль",
"Edit Profile": "Изменить профиль",
"Type": "Тип",
"Name": "Название",
"Descriptions": "Описания",
"Subscription URL": "URL подписки",
"Update Interval": "Интервал обновления",
"Choose File": "Выбрать файл",
"Use System Proxy": "Использовать системный прокси для обновления",
"Use Clash Proxy": "Использовать прокси Clash для обновления",
"Accept Invalid Certs (Danger)": "Принимать недействительные сертификаты (Опасно)",
"Refresh": "Обновить",
"Home": "Главная",
"Select": "Выбрать",
"Edit Info": "Изменить информацию",
"Edit File": "Изменить файл",
"Open File": "Открыть файл",
"Update": "Обновить",
"Update(Proxy)": "Обновить (прокси)",
"Confirm deletion": "Подтвердите удаление",
"This operation is not reversible": "Эта операция необратима",
"Script Console": "Консоль скрипта",
"To Top": "Наверх",
"To End": "Вниз",
"Connections": "Соединения",
"Table View": "Tablichnyy vid",
"List View": "Spiskovyy vid",
"Close All": "Закрыть всё",
"Default": "По умолчанию",
"Download Speed": "Скорость загрузки",
"Upload Speed": "Скорость загрузки",
"Host": "Хост",
"Downloaded": "Скачано",
"Uploaded": "Загружено",
@@ -84,88 +90,98 @@
"Destination IP": "IP-адрес назначения",
"Close Connection": "Закрыть соединение",
"Type": "Тип",
"Name": "Название",
"Descriptions": "Описания",
"Subscription URL": "URL подписки",
"Update Interval": "Интервал обновления",
"Use System Proxy": "Использовать системный прокси для обновления",
"Use Clash Proxy": "Использовать прокси Clash для обновления",
"Accept Invalid Certs (Danger)": "Принимать недействительные сертификаты (Опасно)",
"Rules": "Правила",
"Rule Provider": "Провайдер правило",
"Logs": "Логи",
"Pause": "Пауза",
"Clear": "Очистить",
"Test": "Тест",
"Test All": "Тест Все",
"Create Test": "Создать тест",
"Edit Test": "Редактировать тест",
"Icon": "Икона",
"Test URL": "Тестовый URL",
"Settings": "Настройки",
"Clash Setting": "Настройки Clash",
"System Setting": "Настройки системы",
"Verge Setting": "Настройки Verge",
"Tun Mode": "Режим туннеля",
"Reset to Default": "Сбросить настройки по умолчанию",
"Tun Mode Info": "Режим туннеля требует предоставления разрешений, связанных с ядрам. Пожалуйста, включите сервисный режим перед его использованием",
"Stack": "Стек",
"System and Mixed Can Only be Used in Service Mode": "Система и смешанные могут использоваться только в сервисном режиме",
"Device": "Имя устройства",
"Auto Route": "Автоматическая маршрутизация",
"Strict Route": "Строгий маршрут",
"Auto Detect Interface": "Автоопределение интерфейса",
"DNS Hijack": "DNS-перехват",
"MTU": "Максимальная единица передачи",
"Service Mode": "Режим сервиса",
"Current State": "Текущее состояние",
"pending": "Ожидающий",
"installed": "Установленный",
"uninstall": "Не установленный",
"active": "Активированный",
"unknown": "неизвестный",
"Information: Please make sure that the Clash Verge Service is installed and enabled": "Информация: Пожалуйста, убедитесь, что сервис Clash Verge Service установлен и включен",
"Install": "Установить",
"Uninstall": "Удалить",
"Disable Service Mode": "Отключить режим обслуживания",
"System Proxy": "Системный прокси",
"System Proxy Info": "Разрешить изменение настроек прокси-сервера операционной системы. Если разрешение не удастся, измените настройки прокси-сервера операционной системы вручную",
"System Proxy Setting": "Настройка системного прокси",
"Current System Proxy": "Текущий системный прокси",
"Enable status": "Статус включения",
"Enabled": "Включено",
"Disabled": "Отключено",
"Server Addr": "Адрес сервера: ",
"Not available": "Недоступно",
"Proxy Guard": "Защита прокси",
"Proxy Guard Info": "Включите эту функцию чтобы предотвратить изменение настроек прокси-сервера операционной системы другим программным обеспечением",
"Guard Duration": "Период защиты",
"Proxy Bypass": "Игнорирование прокси: ",
"Bypass": "Игнорирование: ",
"Use PAC Mode": "Используйте режим PAC",
"PAC Script Content": "Содержание сценария PAC",
"PAC URL": "Адрес PAC: ",
"Auto Launch": "Автозапуск",
"Silent Start": "Тихий запуск",
"Clash Setting": "Настройки Clash",
"Allow Lan": "Разрешить локальную сеть",
"IPv6": "IPv6",
"Log Level": "Уровень логов",
"Port Config": "Настройка порта",
"Random Port": "Случайный порт",
"Restart Application to Apply Modifications": "Чтобы изменения вступили в силу, необходимо перезапустить приложение",
"External": "Внешний",
"External Controller": "Адрес прослушивания внешнего контроллера",
"Core Secret": "Секрет",
"Recommended": "Рекомендуется",
"Open URL": "Открыть URL",
"Replace host, port, secret with %host, %port, %secret": "Замените хост, порт, секрет на %host, %port, %secret",
"Support %host, %port, %secret": "Поддержка %host, %port, %secret",
"Clash Core": "Ядра Clash",
"Grant": "Предоставить",
"Upgrade": "Обновлять",
"Restart": "Перезапуск",
"Tun mode requires": "Требуется Режим туннеля",
"Tun Mode": "Режим туннеля",
"Service Mode": "Режим сервиса",
"Auto Launch": "Автозапуск",
"Silent Start": "Тихий запуск",
"System Proxy": "Системный прокси",
"System Proxy Setting": "Настройка системного прокси",
"Grant": "Предоставить",
"Open UWP tool": "Открыть UWP инструмент",
"Update GeoData": "Обновление GeoData",
"Use PAC Mode": "Используйте режим PAC.",
"PAC URL": "Адрес PAC",
"PAC Script Content": "Содержание сценария PAC",
"Proxy Guard": "Защита прокси",
"Guard Duration": "Период защиты",
"Proxy Bypass": "Игнорирование прокси",
"Current System Proxy": "Текущий системный прокси",
"Enable status": "Статус включения",
"Server Addr": "Адрес сервера",
"Bypass": "Игнорирование",
"Verge Setting": "Настройки Verge",
"Language": "Язык",
"Theme Mode": "Режим темы",
"theme.light": "Светлая",
"theme.dark": "Тёмная",
"theme.system": "Системная",
"Tray Click Event": "Событие щелчка в лотке",
"Show Main Window": "Показать главное окно",
"Copy Env Type": "Скопировать тип Env",
"Start Page": "Главная страница",
"Startup Script": "Скрипт запуска",
"Browse": "Просмотреть",
"Show Main Window": "Показать главное окно",
"Theme Setting": "Настройки темы",
"Layout Setting": "Настройки раскладки",
"Miscellaneous": "Настройки Прочие",
"Hotkey Setting": "Настройки клавиатурных сокращений",
"Traffic Graph": "График трафика",
"Memory Usage": "Использование памяти",
"Proxy Group Icon": "Иконка Группы прокси",
"Tray Icon": "Иконка лотка",
"Menu Icon": "Иконка меню",
"Monochrome": "Монохромный",
"Colorful": "Полноцветный",
"Common Tray Icon": "Общий значок в лотке",
"System Proxy Tray Icon": "Значок системного прокси в лотке",
"Tun Tray Icon": "Значок туннеля в лотке",
"Language": "Язык",
"Open App Dir": "Открыть папку приложения",
"Open Core Dir": "Открыть папку ядра",
"Open Logs Dir": "Открыть папку логов",
"Check for Updates": "Проверить обновления",
"Open Dev Tools": "Открыть инструменты разработчика",
"Verge Version": "Версия Verge",
"theme.light": "Светлая",
"theme.dark": "Тёмная",
"theme.system": "Системная",
"Clash Field": "Используемые настройки Clash",
"Runtime Config": "Используемый конфиг",
"ReadOnly": "Только для чтения",
"ReadOnlyMessage": "Невозможно редактировать в режиме только для чтения",
"Restart": "Перезапуск",
"Upgrade": "Обновлять",
"Primary Color": "Основной цвет",
"Secondary Color": "Вторичный цвет",
"Primary Text Color": "Основной текст",
@@ -176,82 +192,74 @@
"Success Color": "Цвет успеха",
"Font Family": "Семейство шрифтов",
"CSS Injection": "Внедрение CSS",
"Back": "Назад",
"Save": "Сохранить",
"Cancel": "Отмена",
"Exit": "Выход",
"Confirm": "Подтвердить",
"Default": "По умолчанию",
"Download Speed": "Скорость загрузки",
"Upload Speed": "Скорость загрузки",
"Layout Setting": "Настройки раскладки",
"Traffic Graph": "График трафика",
"Memory Usage": "Использование памяти",
"Proxy Group Icon": "Иконка Группы прокси",
"Menu Icon": "Иконка меню",
"Monochrome": "Монохромный",
"Colorful": "Полноцветный",
"Tray Icon": "Иконка лотка",
"Common Tray Icon": "Общий значок в лотке",
"System Proxy Tray Icon": "Значок системного прокси в лотке",
"Tun Tray Icon": "Значок туннеля в лотке",
"Miscellaneous": "Настройки Прочие",
"App Log Level": "Уровень журнала приложения",
"Auto Close Connections": "Автоматическое закрытие соединений",
"Auto Check Update": "Автоматическая проверка обновлений",
"Enable Builtin Enhanced": "Включить встроенные улучшения",
"Proxy Layout Column": "Количество столбцов в макете прокси",
"Auto Log Clean": "Автоматическая очистка журналов",
"Never Clean": "Никогда не очищать",
"Retain 7 Days": "Сохранять 7 дней",
"Retain 30 Days": "Сохранять 30 дней",
"Retain 90 Days": "Сохранять 90 дней",
"Default Latency Test": "Ссылка на тестирование задержки по умолчанию",
"Default Latency Timeout": "Таймаут задержки по умолчанию",
"Hotkey Setting": "Настройки клавиатурных сокращений",
"open_or_close_dashboard": "Открыть/Закрыть панель управления",
"clash_mode_rule": "Режим правил",
"clash_mode_global": "Глобальный режим",
"clash_mode_direct": "Прямой режим",
"toggle_system_proxy": "Включить/Отключить системный прокси",
"toggle_tun_mode": "Включить/Отключить режим туннеля",
"App Log Level": "Уровень журнала приложения",
"Auto Close Connections": "Автоматическое закрытие соединений",
"Auto Check Update": "Автоматическая проверка обновлений",
"Enable Builtin Enhanced": "Включить встроенные улучшения",
"Proxy Layout Column": "Количество столбцов в макете прокси",
"Default Latency Test": "Ссылка на тестирование задержки по умолчанию",
"Default Latency Timeout": "Таймаут задержки по умолчанию",
"Auto Log Clean": "Автоматическая очистка журналов",
"Never Clean": "Никогда не очищать",
"Retain 7 Days": "Сохранять 7 дней",
"Retain 30 Days": "Сохранять 30 дней",
"Retain 90 Days": "Сохранять 90 дней",
"Stack": "Стек",
"Device": "Имя устройства",
"Auto Route": "Автоматическая маршрутизация",
"Strict Route": "Строгий маршрут",
"Auto Detect Interface": "Автоопределение интерфейса",
"DNS Hijack": "DNS-перехват",
"MTU": "Максимальная единица передачи",
"Reset to Default": "Сбросить настройки по умолчанию",
"Current State": "Текущее состояние",
"pending": "Ожидающий",
"installed": "Установленный",
"uninstall": "Не установленный",
"active": "Активированный",
"unknown": "неизвестный",
"Disable Service Mode": "Отключить режим обслуживания",
"Install": "Установить",
"Uninstall": "Удалить",
"Runtime Config": "Используемый конфиг",
"Open App Dir": "Открыть папку приложения",
"Open Core Dir": "Открыть папку ядра",
"Open Logs Dir": "Открыть папку логов",
"Check for Updates": "Проверить обновления",
"Go to Release Page": "Перейти на страницу релизов",
"Portable Updater Error": "Портативная версия не поддерживает обновление внутри приложения, пожалуйста, скачайте и замените вручную",
"Tun Mode Info": "Режим туннеля требует предоставления разрешений, связанных с ядрам. Пожалуйста, включите сервисный режим перед его использованием",
"System and Mixed Can Only be Used in Service Mode": "Система и смешанные могут использоваться только в сервисном режиме",
"Information: Please make sure that the Clash Verge Service is installed and enabled": "Информация: Пожалуйста, убедитесь, что сервис Clash Verge Service установлен и включен",
"Open Dev Tools": "Открыть инструменты разработчика",
"Exit": "Выход",
"Verge Version": "Версия Verge",
"ReadOnly": "Только для чтения",
"ReadOnlyMessage": "Невозможно редактировать в режиме только для чтения",
"Filter": "Фильтр",
"Filter conditions": "Условия фильтрации",
"Match Case": "Учитывать регистр",
"Match Whole Word": "Полное совпадение слова",
"Use Regular Expression": "Использовать регулярные выражения",
"External Controller Address Modified": "Изменен адрес внешнего контроллера",
"Clash Port Modified": "Clash порт изменен",
"Currently on the Latest Version": "В настоящее время используется последняя версия",
"Only YAML Files Supported": "Поддерживаются только файлы YAML",
"Port Conflict": "Конфликт портов",
"Proxy Daemon Duration Cannot be Less than 1 Second": "Продолжительность работы прокси-демона не может быть меньше 1 секунды",
"Profile Imported Successfully": "Профиль успешно импортирован",
"Clash Config Updated": "Clash конфигурация Обновлена",
"Profile Switched": "Профиль изменен",
"Profile Reactivated": "Профиль повторно активирован",
"Clash Config Updated": "Clash конфигурация Обновлена",
"Only YAML Files Supported": "Поддерживаются только файлы YAML",
"Settings Applied": "Применены настройки",
"Service Installed Successfully": "Служба успешно установлена",
"Service Uninstalled Successfully": "Служба успешно удалена",
"GeoData Updated": "GeoData Обновлена",
"Proxy Daemon Duration Cannot be Less than 1 Second": "Продолжительность работы прокси-демона не может быть меньше 1 секунды",
"Invalid Bypass Format": "Неверный формат обхода",
"Clash Port Modified": "Clash порт изменен",
"Port Conflict": "Конфликт портов",
"Restart Application to Apply Modifications": "Чтобы изменения вступили в силу, необходимо перезапустить приложение",
"External Controller Address Modified": "Изменен адрес внешнего контроллера",
"Permissions Granted Successfully for _clash Core": "Разрешения успешно предоставлены для ядра {{core}}",
"Profile Imported Successfully": "Профиль успешно импортирован",
"Core Version Updated": "Обновлена версия ядра",
"Clash Core Restarted": "Clash ядра перезапущено",
"Switched to _clash Core": "Переключено на ядра {{core}}",
"Core Version Updated": "Обновлена версия ядра"
"GeoData Updated": "GeoData Обновлена",
"Currently on the Latest Version": "В настоящее время используется последняя версия"
}
+175 -167
View File
@@ -1,60 +1,33 @@
{
"Back": "返回",
"Close": "关闭",
"Cancel": "取消",
"Confirm": "确认",
"New": "新建",
"Edit": "编辑",
"Save": "保存",
"Delete": "删除",
"Enable": "启用",
"Disable": "禁用",
"Label-Proxies": "代 理",
"Label-Test": "测 试",
"Label-Profiles": "订 阅",
"Label-Connections": "连 接",
"Label-Logs": "日 志",
"Label-Rules": "规 则",
"Label-Logs": "日 志",
"Label-Test": "测 试",
"Label-Settings": "设 置",
"Connections": "连接",
"Logs": "日志",
"Clear": "清除",
"Proxies": "代理",
"Proxy Groups": "代理组",
"Test": "测试",
"Proxy Provider": "代理集合",
"Update All": "更新全部",
"Update At": "更新于",
"rule": "规则",
"global": "全局",
"direct": "直连",
"script": "脚本",
"Create Test": "新建测试",
"Edit Test": "编辑测试",
"Edit": "编辑",
"Icon": "图标",
"Test URL": "测试地址",
"Test All": "测试全部",
"Paste": "粘贴",
"Profiles": "订阅",
"Profile URL": "订阅文件链接",
"Import": "导入",
"New": "新建",
"Create Profile": "新建配置",
"Edit Profile": "编辑配置",
"Choose File": "选择文件",
"Close": "关闭",
"Close All": "关闭全部",
"Home": "首页",
"Select": "使用",
"Edit Info": "编辑信息",
"Edit File": "编辑文件",
"Open File": "打开文件",
"Update": "更新",
"Update(Proxy)": "更新(代理)",
"Delete": "删除",
"Enable": "启用",
"Disable": "禁用",
"Refresh": "刷新",
"To Top": "移到最前",
"To End": "移到末尾",
"Update All Profiles": "更新所有订阅",
"View Runtime Config": "查看运行时订阅",
"Reactivate Profiles": "重新激活订阅",
"Confirm deletion": "确认删除",
"This operation is not reversible": "此操作不可逆",
"Script Console": "脚本控制台输出",
"Location": "当前节点",
"Delay check": "延迟测试",
"Sort by default": "默认排序",
@@ -64,13 +37,46 @@
"Delay check to cancel fixed": "进行延迟测试,以取消固定",
"Proxy basic": "隐藏节点细节",
"Proxy detail": "展示节点细节",
"Filter": "过滤节点",
"Filter conditions": "过滤条件",
"Refresh profiles": "刷新订阅",
"Rules": "规则",
"Update All": "更新全部",
"Update At": "更新于",
"Profiles": "订阅",
"Update All Profiles": "更新所有订阅",
"View Runtime Config": "查看运行时订阅",
"Reactivate Profiles": "重新激活订阅",
"Paste": "粘贴",
"Profile URL": "订阅文件链接",
"Import": "导入",
"Create Profile": "新建配置",
"Edit Profile": "编辑配置",
"Type": "类型",
"Name": "名称",
"Descriptions": "描述",
"Subscription URL": "订阅链接",
"Update Interval": "更新间隔",
"Choose File": "选择文件",
"Use System Proxy": "使用系统代理更新",
"Use Clash Proxy": "使用 Clash 代理更新",
"Accept Invalid Certs (Danger)": "允许无效证书 (危险)",
"Refresh": "刷新",
"Home": "首页",
"Select": "使用",
"Edit Info": "编辑信息",
"Edit File": "编辑文件",
"Open File": "打开文件",
"Update": "更新",
"Update(Proxy)": "更新(代理)",
"Confirm deletion": "确认删除",
"This operation is not reversible": "此操作不可逆",
"Script Console": "脚本控制台输出",
"To Top": "移到最前",
"To End": "移到末尾",
"Connections": "连接",
"Table View": "表格视图",
"List View": "列表视图",
"Close All": "关闭全部",
"Default": "默认",
"Download Speed": "下载速度",
"Upload Speed": "上传速度",
"Host": "主机",
"Downloaded": "下载量",
"Uploaded": "上传量",
@@ -84,88 +90,98 @@
"Destination IP": "目标地址",
"Close Connection": "关闭连接",
"Type": "类型",
"Name": "名称",
"Descriptions": "描述",
"Subscription URL": "订阅链接",
"Update Interval": "更新间隔",
"Use System Proxy": "使用系统代理更新",
"Use Clash Proxy": "使用 Clash 代理更新",
"Accept Invalid Certs (Danger)": "允许无效证书 (危险)",
"Rules": "规则",
"Rule Provider": "规则集合",
"Logs": "日志",
"Pause": "暂停",
"Clear": "清除",
"Test": "测试",
"Test All": "测试全部",
"Create Test": "新建测试",
"Edit Test": "编辑测试",
"Icon": "图标",
"Test URL": "测试地址",
"Settings": "设置",
"Clash Setting": "Clash 设置",
"System Setting": "系统设置",
"Verge Setting": "Verge 设置",
"Tun Mode": "Tun 模式",
"Reset to Default": "重置为默认值",
"Tun Mode Info": "Tun模式需要授予内核相关权限,使用前请先开启服务模式",
"Stack": "Tun 模式堆栈",
"System and Mixed Can Only be Used in Service Mode": "System 和 Mixed 只能在服务模式下使用",
"Device": "Tun 网卡名称",
"Auto Route": "自动设置全局路由",
"Strict Route": "严格路由",
"Auto Detect Interface": "自动选择流量出口接口",
"DNS Hijack": "DNS 劫持",
"MTU": "最大传输单元",
"Service Mode": "服务模式",
"Current State": "当前状态",
"pending": "等待中",
"installed": "已安装",
"uninstall": "未安装",
"active": "已激活",
"unknown": "未知",
"Information: Please make sure that the Clash Verge Service is installed and enabled": "提示信息: 请确保 Clash Verge Service 已安装并启用",
"Install": "安装",
"Uninstall": "卸载",
"Disable Service Mode": "禁用服务模式",
"System Proxy": "系统代理",
"System Proxy Info": "打开此开关修改操作系统的代理设置,如果开启失败,可手动修改操作系统的代理设置",
"System Proxy Setting": "系统代理设置",
"Current System Proxy": "当前系统代理",
"Enable status": "开启状态:",
"Enabled": "已启用",
"Disabled": "未启用",
"Server Addr": "服务地址:",
"Not available": "不可用",
"Proxy Guard": "系统代理守卫",
"Proxy Guard Info": "开启以防止其他软件修改操作系统的代理设置",
"Guard Duration": "代理守卫间隔",
"Proxy Bypass": "代理绕过设置:",
"Bypass": "当前绕过:",
"Use PAC Mode": "使用PAC模式",
"PAC Script Content": "PAC脚本内容",
"PAC URL": "PAC地址:",
"Auto Launch": "开机自启",
"Silent Start": "静默启动",
"Clash Setting": "Clash 设置",
"Allow Lan": "局域网连接",
"IPv6": "IPv6",
"Log Level": "日志等级",
"Port Config": "端口设置",
"Random Port": "随机端口",
"Restart Application to Apply Modifications": "重启应用程序以应用修改",
"External": "外部控制",
"External Controller": "外部控制器监听地址",
"Core Secret": "API 访问密钥",
"Recommended": "建议设置",
"Open URL": "打开链接",
"Replace host, port, secret with %host, %port, %secret": "使用 %host, %port, %secret 表示 主机, 端口, 访问密钥",
"Support %host, %port, %secret": "支持 %host, %port, %secret",
"Clash Core": "Clash 内核",
"Grant": "授权",
"Upgrade": "升级内核",
"Restart": "重启内核",
"Tun mode requires": "如需启用 Tun 模式需要授权",
"Tun Mode": "Tun 模式",
"Service Mode": "服务模式",
"Auto Launch": "开机自启",
"Silent Start": "静默启动",
"System Proxy": "系统代理",
"System Proxy Setting": "系统代理设置",
"Grant": "授权",
"Open UWP tool": "UWP 工具",
"Update GeoData": "更新 GeoData",
"Use PAC Mode": "使用PAC模式",
"PAC URL": "PAC 地址",
"PAC Script Content": "PAC 脚本内容",
"Proxy Guard": "系统代理守卫",
"Guard Duration": "代理守卫间隔",
"Proxy Bypass": "代理绕过",
"Current System Proxy": "当前系统代理",
"Enable status": "开启状态:",
"Server Addr": "服务地址:",
"Bypass": "当前绕过:",
"Verge Setting": "Verge 设置",
"Language": "语言设置",
"Theme Mode": "主题模式",
"theme.light": "浅色",
"theme.dark": "深色",
"theme.system": "系统",
"Tray Click Event": "托盘点击事件",
"Show Main Window": "显示主窗口",
"Copy Env Type": "复制环境变量类型",
"Start Page": "启动页面",
"Startup Script": "启动脚本",
"Browse": "浏览",
"Show Main Window": "显示主窗口",
"Theme Setting": "主题设置",
"Layout Setting": "界面设置",
"Miscellaneous": "杂项设置",
"Hotkey Setting": "热键设置",
"Traffic Graph": "流量图显",
"Memory Usage": "内存使用",
"Proxy Group Icon": "代理组图标",
"Tray Icon": "托盘图标",
"Menu Icon": "菜单图标",
"Monochrome": "单色图标",
"Colorful": "彩色图标",
"Common Tray Icon": "常规托盘图标",
"System Proxy Tray Icon": "系统代理托盘图标",
"Tun Tray Icon": "Tun 模式托盘图标",
"Language": "语言设置",
"Open App Dir": "应用目录",
"Open Core Dir": "内核目录",
"Open Logs Dir": "日志目录",
"Check for Updates": "检查更新",
"Open Dev Tools": "打开开发者工具",
"Verge Version": "Verge 版本",
"theme.light": "浅色",
"theme.dark": "深色",
"theme.system": "系统",
"Clash Field": "Clash 字段",
"Runtime Config": "当前配置",
"ReadOnly": "只读",
"ReadOnlyMessage": "无法在只读模式下编辑",
"Restart": "重启内核",
"Upgrade": "升级内核",
"Primary Color": "主要颜色",
"Secondary Color": "次要颜色",
"Primary Text": "文本主要颜色",
@@ -176,82 +192,74 @@
"Success Color": "成功颜色",
"Font Family": "字体系列",
"CSS Injection": "CSS 注入",
"Back": "返回",
"Save": "保存",
"Cancel": "取消",
"Exit": "退出",
"Confirm": "确认",
"Default": "默认",
"Download Speed": "下载速度",
"Upload Speed": "上传速度",
"Layout Setting": "界面设置",
"Traffic Graph": "流量图显",
"Memory Usage": "内存使用",
"Proxy Group Icon": "代理组图标",
"Menu Icon": "菜单图标",
"Monochrome": "单色图标",
"Colorful": "彩色图标",
"Tray Icon": "托盘图标",
"Common Tray Icon": "常规托盘图标",
"System Proxy Tray Icon": "系统代理托盘图标",
"Tun Tray Icon": "Tun 模式托盘图标",
"Miscellaneous": "杂项设置",
"App Log Level": "App日志等级",
"Auto Close Connections": "自动关闭连接",
"Auto Check Update": "自动检查更新",
"Enable Builtin Enhanced": "内置增强功能",
"Proxy Layout Column": "代理页布局列数",
"Auto Log Clean": "自动清理日志",
"Never Clean": "不清理",
"Retain 7 Days": "保留7天",
"Retain 30 Days": "保留30天",
"Retain 90 Days": "保留90天",
"Default Latency Test": "默认测试链接",
"Default Latency Timeout": "测试超时时间",
"Hotkey Setting": "热键设置",
"open_or_close_dashboard": "打开/关闭面板",
"clash_mode_rule": "规则模式",
"clash_mode_global": "全局模式",
"clash_mode_direct": "直连模式",
"toggle_system_proxy": "打开/关闭系统代理",
"toggle_tun_mode": "打开/关闭 Tun 模式",
"App Log Level": "App日志等级",
"Auto Close Connections": "自动关闭连接",
"Auto Check Update": "自动检查更新",
"Enable Builtin Enhanced": "开启内建增强功能",
"Proxy Layout Column": "代理页布局列数",
"Default Latency Test": "默认测试链接",
"Default Latency Timeout": "测试超时时间",
"Auto Log Clean": "自动清理日志",
"Never Clean": "不清理",
"Retain 7 Days": "保留7天",
"Retain 30 Days": "保留30天",
"Retain 90 Days": "保留90天",
"Stack": "Tun 模式堆栈",
"Device": "Tun 网卡名称",
"Auto Route": "自动设置全局路由",
"Strict Route": "严格路由",
"Auto Detect Interface": "自动选择流量出口接口",
"DNS Hijack": "DNS 劫持",
"MTU": "最大传输单元",
"Reset to Default": "重置为默认值",
"Current State": "当前状态",
"pending": "等待中",
"installed": "已安装",
"uninstall": "未安装",
"active": "已激活",
"unknown": "未知",
"Disable Service Mode": "禁用服务模式",
"Install": "安装",
"Uninstall": "卸载",
"Runtime Config": "当前配置",
"Open App Dir": "应用目录",
"Open Core Dir": "内核目录",
"Open Logs Dir": "日志目录",
"Check for Updates": "检查更新",
"Go to Release Page": "前往发布页",
"Portable Updater Error": "便携版不支持应用内更新,请手动下载替换",
"Tun Mode Info": "Tun模式需要授予内核相关权限,使用前请先开启服务模式",
"System and Mixed Can Only be Used in Service Mode": "System 和 Mixed 只能在服务模式下使用",
"Information: Please make sure that the Clash Verge Service is installed and enabled": "提示信息: 请确保 Clash Verge Service 已安装并启用",
"Open Dev Tools": "打开开发者工具",
"Exit": "退出",
"Verge Version": "Verge 版本",
"ReadOnly": "只读",
"ReadOnlyMessage": "无法在只读模式下编辑",
"Filter": "过滤节点",
"Filter conditions": "过滤条件",
"Match Case": "区分大小写",
"Match Whole Word": "全字匹配",
"Use Regular Expression": "使用正则表达式",
"External Controller Address Modified": "外部控制器监听地址已修改",
"Clash Port Modified": "Clash 端口已修改",
"Currently on the Latest Version": "当前已是最新版本",
"Only YAML Files Supported": "仅支持 YAML 文件",
"Port Conflict": "端口冲突",
"Proxy Daemon Duration Cannot be Less than 1 Second": "代理守护间隔时间不得低于1秒",
"Profile Imported Successfully": "导入订阅成功",
"Clash Config Updated": "Clash 配置已更新",
"Profile Switched": "订阅已切换",
"Profile Reactivated": "订阅已激活",
"Clash Config Updated": "Clash 配置已更新",
"Only YAML Files Supported": "仅支持 YAML 文件",
"Settings Applied": "设置已应用",
"Service Installed Successfully": "已成功安装服务",
"Service Uninstalled Successfully": "已成功卸载服务",
"GeoData Updated": "已更新 GeoData",
"Proxy Daemon Duration Cannot be Less than 1 Second": "代理守护间隔时间不得低于1秒",
"Invalid Bypass Format": "无效的代理绕过格式",
"Clash Port Modified": "Clash 端口已修改",
"Port Conflict": "端口冲突",
"Restart Application to Apply Modifications": "重启应用程序以应用修改",
"External Controller Address Modified": "外部控制器监听地址已修改",
"Permissions Granted Successfully for _clash Core": "{{core}} 内核授权成功",
"Profile Imported Successfully": "导入订阅成功",
"Core Version Updated": "内核版本已更新",
"Clash Core Restarted": "已重启 Clash 内核",
"Switched to _clash Core": "已切换至 {{core}} 内核",
"Core Version Updated": "内核版本已更新"
"GeoData Updated": "已更新 GeoData",
"Currently on the Latest Version": "当前已是最新版本"
}
+17 -4
View File
@@ -9,11 +9,17 @@ if (!window.ResizeObserver) {
import React from "react";
import { createRoot } from "react-dom/client";
import { RecoilRoot } from "recoil";
import { ComposeContextProvider } from "foxact/compose-context-provider";
import { BrowserRouter } from "react-router-dom";
import { BaseErrorBoundary } from "./components/base";
import Layout from "./pages/_layout";
import "./services/i18n";
import {
LoadingCacheProvider,
LogDataProvider,
ThemeModeProvider,
UpdateStateProvider,
} from "./services/states";
const mainElementId = "root";
const container = document.getElementById(mainElementId);
@@ -31,20 +37,27 @@ document.addEventListener("keydown", (event) => {
}
if (
(event.ctrlKey || event.metaKey) &&
["F", "H", "P", "R", "U"].includes(event.key.toUpperCase())
["F", "H", "P", "Q", "R", "U"].includes(event.key.toUpperCase())
) {
event.preventDefault();
}
});
const contexts = [
<ThemeModeProvider />,
<LogDataProvider />,
<LoadingCacheProvider />,
<UpdateStateProvider />,
];
createRoot(container).render(
<React.StrictMode>
<RecoilRoot>
<ComposeContextProvider contexts={contexts}>
<BaseErrorBoundary>
<BrowserRouter>
<Layout />
</BrowserRouter>
</BaseErrorBoundary>
</RecoilRoot>
</ComposeContextProvider>
</React.StrictMode>
);
+2 -3
View File
@@ -14,8 +14,7 @@ import { useVerge } from "@/hooks/use-verge";
import LogoSvg from "@/assets/image/logo.svg?react";
import iconLight from "@/assets/image/icon_light.svg?react";
import iconDark from "@/assets/image/icon_dark.svg?react";
import { atomThemeMode } from "@/services/states";
import { useRecoilState } from "recoil";
import { useThemeMode } from "@/services/states";
import { Notice } from "@/components/base";
import { LayoutItem } from "@/components/layout/layout-item";
import { LayoutControl } from "@/components/layout/layout-control";
@@ -36,7 +35,7 @@ dayjs.extend(relativeTime);
const OS = getSystem();
const Layout = () => {
const [mode] = useRecoilState(atomThemeMode);
const mode = useThemeMode();
const isDark = mode === "light" ? false : true;
const { t } = useTranslation();
const { theme } = useCustomTheme();
+6 -6
View File
@@ -4,14 +4,14 @@ const OS = getSystem();
// default theme setting
export const defaultTheme = {
primary_color: "#007AFF",
secondary_color: "#fc9b76",
secondary_color: "#FC9B76",
primary_text: "#000000",
secondary_text: "#3c3c4399",
secondary_text: "#3C3C4399",
info_color: "#007AFF",
error_color: "#FF3B30",
warning_color: "#FF9500",
success_color: "#06943D",
background_color: "#f5f5f5",
background_color: "#F5F5F5",
font_family: `-apple-system, BlinkMacSystemFont,"Microsoft YaHei UI", "Microsoft YaHei", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji"${
OS === "windows" ? ", twemoji mozilla" : ""
}`,
@@ -22,9 +22,9 @@ export const defaultDarkTheme = {
...defaultTheme,
primary_color: "#0A84FF",
secondary_color: "#FF9F0A",
primary_text: "#ffffff",
background_color: "#2e303d",
secondary_text: "#ebebf599",
primary_text: "#FFFFFF",
background_color: "#2E303D",
secondary_text: "#EBEBF599",
info_color: "#0A84FF",
error_color: "#FF453A",
warning_color: "#FF9F0A",
+14 -19
View File
@@ -1,20 +1,11 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { useLockFn } from "ahooks";
import {
Box,
Button,
IconButton,
MenuItem,
Select,
SelectProps,
styled,
} from "@mui/material";
import { useRecoilState } from "recoil";
import { Box, Button, IconButton, MenuItem } from "@mui/material";
import { Virtuoso } from "react-virtuoso";
import { useTranslation } from "react-i18next";
import { TableChartRounded, TableRowsRounded } from "@mui/icons-material";
import { closeAllConnections } from "@/services/api";
import { atomConnectionSetting } from "@/services/states";
import { useConnectionSetting } from "@/services/states";
import { useClashInfo } from "@/hooks/use-clash";
import { BaseEmpty, BasePage } from "@/components/base";
import { useWebsocket } from "@/hooks/use-websocket";
@@ -34,7 +25,7 @@ const initConn = { uploadTotal: 0, downloadTotal: 0, connections: [] };
type OrderFunc = (list: IConnectionsItem[]) => IConnectionsItem[];
const ConnectionsPage = () => {
const { t, i18n } = useTranslation();
const { t } = useTranslation();
const { clashInfo } = useClashInfo();
const { theme } = useCustomTheme();
const isDark = theme.palette.mode === "dark";
@@ -42,7 +33,7 @@ const ConnectionsPage = () => {
const [curOrderOpt, setOrderOpt] = useState("Default");
const [connData, setConnData] = useState<IConnections>(initConn);
const [setting, setSetting] = useRecoilState(atomConnectionSetting);
const [setting, setSetting] = useConnectionSetting();
const isTableLayout = setting.layout === "table";
@@ -130,7 +121,7 @@ const ConnectionsPage = () => {
return (
<BasePage
full
title={t("Connections")}
title={<span style={{ whiteSpace: "nowrap" }}>{t("Connections")}</span>}
contentStyle={{ height: "100%" }}
header={
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
@@ -145,21 +136,25 @@ const ConnectionsPage = () => {
size="small"
onClick={() =>
setSetting((o) =>
o.layout === "list"
o?.layout !== "table"
? { ...o, layout: "table" }
: { ...o, layout: "list" }
)
}
>
{isTableLayout ? (
<TableChartRounded fontSize="inherit" />
<span title={t("List View")}>
<TableRowsRounded fontSize="inherit" />
</span>
) : (
<TableRowsRounded fontSize="inherit" />
<span title={t("Table View")}>
<TableChartRounded fontSize="inherit" />
</span>
)}
</IconButton>
<Button size="small" variant="contained" onClick={onCloseAll}>
{t("Close All")}
<span style={{ whiteSpace: "nowrap" }}>{t("Close All")}</span>
</Button>
</Box>
}
@@ -209,7 +204,7 @@ const ConnectionsPage = () => {
) : (
<Virtuoso
data={filterConn}
itemContent={(index, item) => (
itemContent={(_, item) => (
<ConnectionItem
value={item}
onShowDetail={() => detailRef.current?.open(item)}
+5 -4
View File
@@ -1,5 +1,4 @@
import { useMemo, useState } from "react";
import { useRecoilState } from "recoil";
import { Box, Button, IconButton, MenuItem } from "@mui/material";
import { Virtuoso } from "react-virtuoso";
import { useTranslation } from "react-i18next";
@@ -7,7 +6,7 @@ import {
PlayCircleOutlineRounded,
PauseCircleOutlineRounded,
} from "@mui/icons-material";
import { atomEnableLog, atomLogData } from "@/services/states";
import { useEnableLog, useLogData, useSetLogData } from "@/services/states";
import { BaseEmpty, BasePage } from "@/components/base";
import LogItem from "@/components/log/log-item";
import { useCustomTheme } from "@/components/layout/use-custom-theme";
@@ -16,8 +15,9 @@ import { BaseStyledSelect } from "@/components/base/base-styled-select";
const LogPage = () => {
const { t } = useTranslation();
const [logData, setLogData] = useRecoilState(atomLogData);
const [enableLog, setEnableLog] = useRecoilState(atomEnableLog);
const logData = useLogData();
const setLogData = useSetLogData();
const [enableLog, setEnableLog] = useEnableLog();
const { theme } = useCustomTheme();
const isDark = theme.palette.mode === "dark";
const [logState, setLogState] = useState("all");
@@ -39,6 +39,7 @@ const LogPage = () => {
header={
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<IconButton
title={t("Pause")}
size="small"
color="inherit"
onClick={() => setEnableLog((e) => !e)}
+3 -6
View File
@@ -1,7 +1,6 @@
import useSWR, { mutate } from "swr";
import { useEffect, useMemo, useRef, useState } from "react";
import { useLockFn } from "ahooks";
import { useSetRecoilState } from "recoil";
import { Box, Button, Grid, IconButton, Stack, Divider } from "@mui/material";
import {
DndContext,
@@ -35,7 +34,7 @@ import {
reorderProfile,
createProfile,
} from "@/services/cmds";
import { atomLoadingCache } from "@/services/states";
import { useSetLoadingCache, useThemeMode } from "@/services/states";
import { closeAllConnections } from "@/services/api";
import { BasePage, DialogRef, Notice } from "@/components/base";
import {
@@ -47,8 +46,6 @@ import { ProfileMore } from "@/components/profile/profile-more";
import { useProfiles } from "@/hooks/use-profiles";
import { ConfigViewer } from "@/components/setting/mods/config-viewer";
import { throttle } from "lodash-es";
import { useRecoilState } from "recoil";
import { atomThemeMode } from "@/services/states";
import { BaseStyledTextField } from "@/components/base/base-styled-text-field";
import { listen } from "@tauri-apps/api/event";
import { readTextFile } from "@tauri-apps/api/fs";
@@ -239,7 +236,7 @@ const ProfilePage = () => {
});
// 更新所有订阅
const setLoadingCache = useSetRecoilState(atomLoadingCache);
const setLoadingCache = useSetLoadingCache();
const onUpdateAll = useLockFn(async () => {
const throttleMutate = throttle(mutateProfiles, 2000, {
trailing: true,
@@ -271,7 +268,7 @@ const ProfilePage = () => {
const text = await readText();
if (text) setUrl(text);
};
const [mode] = useRecoilState(atomThemeMode);
const mode = useThemeMode();
const islight = mode === "light" ? true : false;
const dividercolor = islight
? "rgba(0, 0, 0, 0.06)"
+2 -3
View File
@@ -7,8 +7,7 @@ import { openWebUrl } from "@/services/cmds";
import SettingVerge from "@/components/setting/setting-verge";
import SettingClash from "@/components/setting/setting-clash";
import SettingSystem from "@/components/setting/setting-system";
import { atomThemeMode } from "@/services/states";
import { useRecoilState } from "recoil";
import { useThemeMode } from "@/services/states";
const SettingPage = () => {
const { t } = useTranslation();
@@ -25,7 +24,7 @@ const SettingPage = () => {
return openWebUrl("https://clash-verge-rev.github.io/guide/log.html");
});
const [mode] = useRecoilState(atomThemeMode);
const mode = useThemeMode();
const isDark = mode === "light" ? false : true;
return (
+15 -3
View File
@@ -22,6 +22,12 @@ import { TestItem } from "@/components/test/test-item";
import { emit } from "@tauri-apps/api/event";
import { nanoid } from "nanoid";
// test icons
import apple from "@/assets/image/test/apple.svg?raw";
import github from "@/assets/image/test/github.svg?raw";
import google from "@/assets/image/test/google.svg?raw";
import youtube from "@/assets/image/test/youtube.svg?raw";
const TestPage = () => {
const { t } = useTranslation();
const sensors = useSensors(
@@ -38,19 +44,25 @@ const TestPage = () => {
uid: nanoid(),
name: "Apple",
url: "https://www.apple.com",
icon: "https://www.apple.com/favicon.ico",
icon: apple,
},
{
uid: nanoid(),
name: "GitHub",
url: "https://www.github.com",
icon: `<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#000000"/></svg>`,
icon: github,
},
{
uid: nanoid(),
name: "Google",
url: "https://www.google.com",
icon: `<svg enable-background="new 0 0 48 48" height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg"><path d="m43.611 20.083h-1.611v-.083h-18v8h11.303c-1.649 4.657-6.08 8-11.303 8-6.627 0-12-5.373-12-12s5.373-12 12-12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657c-3.572-3.329-8.35-5.382-13.618-5.382-11.045 0-20 8.955-20 20s8.955 20 20 20 20-8.955 20-20c0-1.341-.138-2.65-.389-3.917z" fill="#ffc107"/><path d="m6.306 14.691 6.571 4.819c1.778-4.402 6.084-7.51 11.123-7.51 3.059 0 5.842 1.154 7.961 3.039l5.657-5.657c-3.572-3.329-8.35-5.382-13.618-5.382-7.682 0-14.344 4.337-17.694 10.691z" fill="#ff3d00"/><path d="m24 44c5.166 0 9.86-1.977 13.409-5.192l-6.19-5.238c-2.008 1.521-4.504 2.43-7.219 2.43-5.202 0-9.619-3.317-11.283-7.946l-6.522 5.025c3.31 6.477 10.032 10.921 17.805 10.921z" fill="#4caf50"/><path d="m43.611 20.083h-1.611v-.083h-18v8h11.303c-.792 2.237-2.231 4.166-4.087 5.571.001-.001.002-.001.003-.002l6.19 5.238c-.438.398 6.591-4.807 6.591-14.807 0-1.341-.138-2.65-.389-3.917z" fill="#1976d2"/></svg>`,
icon: google,
},
{
uid: nanoid(),
name: "Youtube",
url: "https://www.youtube.com",
icon: youtube,
},
];
+30
View File
@@ -0,0 +1,30 @@
(function () {
if (typeof window.RegExp === "undefined") {
return;
}
const originalRegExp = window.RegExp;
window.RegExp = function (pattern, flags) {
if (pattern instanceof originalRegExp && flags === undefined) {
flags = pattern.flags;
}
if (flags) {
if (!originalRegExp.prototype.hasOwnProperty("unicodeSets")) {
if (flags.includes("v")) {
flags = flags.replace("v", "u");
}
}
if (!originalRegExp.prototype.hasOwnProperty("hasIndices")) {
if (flags.includes("d")) {
flags = flags.replace("d", "");
}
}
}
return new originalRegExp(pattern, flags);
};
window.RegExp.prototype = originalRegExp.prototype;
})();
+16
View File
@@ -0,0 +1,16 @@
(function () {
if (typeof window.WeakRef !== "undefined") {
return;
}
window.WeakRef = (function (weakMap) {
function WeakRef(target) {
weakMap.set(this, target);
}
WeakRef.prototype.deref = function () {
return weakMap.get(this);
};
return WeakRef;
})(new WeakMap());
})();
+36
View File
@@ -0,0 +1,36 @@
(function () {
if (window.matchMedia && window.matchMedia("all").addEventListener) {
return;
}
const originalMatchMedia = window.matchMedia;
window.matchMedia = function (query) {
const mediaQueryList = originalMatchMedia(query);
if (!mediaQueryList.addEventListener) {
mediaQueryList.addEventListener = function (eventType, listener) {
if (eventType !== "change" || typeof listener !== "function") {
console.error("Invalid arguments for addEventListener:", arguments);
return;
}
mediaQueryList.addListener(listener);
};
}
if (!mediaQueryList.removeEventListener) {
mediaQueryList.removeEventListener = function (eventType, listener) {
if (eventType !== "change" || typeof listener !== "function") {
console.error(
"Invalid arguments for removeEventListener:",
arguments
);
return;
}
mediaQueryList.removeListener(listener);
};
}
return mediaQueryList;
};
})();
-2
View File
@@ -1,4 +1,3 @@
import axiosTauriApiAdapter from "axios-tauri-api-adapter";
import axios, { AxiosInstance } from "axios";
import { getClashInfo } from "./cmds";
@@ -26,7 +25,6 @@ export const getAxios = async (force: boolean = false) => {
} catch {}
axiosIns = axios.create({
adapter: axiosTauriApiAdapter,
baseURL: `http://${server}`,
headers: secret ? { Authorization: `Bearer ${secret}` } : {},
timeout: 15000,
+38 -60
View File
@@ -1,73 +1,51 @@
import { atom } from "recoil";
import { createContextState } from "foxact/create-context-state";
import { useLocalStorage } from "foxact/use-local-storage";
export const atomThemeMode = atom<"light" | "dark">({
key: "atomThemeMode",
default: "light",
});
const [ThemeModeProvider, useThemeMode, useSetThemeMode] = createContextState<
"light" | "dark"
>("light");
export const atomLogData = atom<ILogItem[]>({
key: "atomLogData",
default: [],
});
const [LogDataProvider, useLogData, useSetLogData] = createContextState<
ILogItem[]
>([]);
export const atomEnableLog = atom<boolean>({
key: "atomEnableLog",
effects: [
({ setSelf, onSet }) => {
const key = "enable-log";
try {
setSelf(localStorage.getItem(key) !== "false");
} catch {}
onSet((newValue, _, isReset) => {
try {
if (isReset) {
localStorage.removeItem(key);
} else {
localStorage.setItem(key, newValue.toString());
}
} catch {}
});
},
],
});
export const useEnableLog = () => useLocalStorage("enable-log", true);
interface IConnectionSetting {
layout: "table" | "list";
}
export const atomConnectionSetting = atom<IConnectionSetting>({
key: "atomConnectionSetting",
effects: [
({ setSelf, onSet }) => {
const key = "connections-setting";
const defaultConnectionSetting: IConnectionSetting = { layout: "table" };
try {
const value = localStorage.getItem(key);
const data = value == null ? { layout: "table" } : JSON.parse(value);
setSelf(data);
} catch {
setSelf({ layout: "table" });
}
onSet((newValue) => {
try {
localStorage.setItem(key, JSON.stringify(newValue));
} catch {}
});
},
],
});
export const useConnectionSetting = () =>
useLocalStorage<IConnectionSetting>(
"connections-setting",
defaultConnectionSetting,
{
serializer: JSON.stringify,
deserializer: JSON.parse,
}
);
// save the state of each profile item loading
export const atomLoadingCache = atom<Record<string, boolean>>({
key: "atomLoadingCache",
default: {},
});
const [LoadingCacheProvider, useLoadingCache, useSetLoadingCache] =
createContextState<Record<string, boolean>>({});
// save update state
export const atomUpdateState = atom<boolean>({
key: "atomUpdateState",
default: false,
});
const [UpdateStateProvider, useUpdateState, useSetUpdateState] =
createContextState<boolean>(false);
export {
ThemeModeProvider,
useThemeMode,
useSetThemeMode,
LogDataProvider,
useLogData,
useSetLogData,
LoadingCacheProvider,
useLoadingCache,
useSetLoadingCache,
UpdateStateProvider,
useUpdateState,
useSetUpdateState,
};
+3
View File
@@ -0,0 +1,3 @@
export default function isAsyncFunction(fn: Function): boolean {
return fn.constructor.name === "AsyncFunction";
}
+13 -1
View File
@@ -2,15 +2,27 @@ import { defineConfig } from "vite";
import path from "path";
import svgr from "vite-plugin-svgr";
import react from "@vitejs/plugin-react";
import legacy from "@vitejs/plugin-legacy";
import monacoEditor from "vite-plugin-monaco-editor";
// https://vitejs.dev/config/
export default defineConfig({
root: "src",
server: { port: 3000 },
plugins: [
svgr(),
react(),
legacy({
renderLegacyChunks: false,
modernTargets: ["edge>=109", "safari>=13"],
modernPolyfills: true,
additionalModernPolyfills: [
"core-js/modules/es.object.has-own.js",
"core-js/modules/web.structured-clone.js",
path.resolve("./src/polyfills/matchMedia.js"),
path.resolve("./src/polyfills/WeakRef.js"),
path.resolve("./src/polyfills/RegExp.js"),
],
}),
monacoEditor({
languageWorkers: ["editorWorkerService", "typescript", "css"],
customWorkers: [