diff --git a/package.json b/package.json index 4cb1785..8b0e5e7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mihomo-party", "version": "1.0.0", - "description": "An Electron application with React and TypeScript", + "description": "Mihomo Party", "main": "./out/main/index.js", "author": "mihomo-party", "homepage": "https://mihomo.party", @@ -26,7 +26,9 @@ "@nextui-org/react": "^2.4.6", "electron-updater": "^6.2.1", "framer-motion": "^11.3.19", - "next-themes": "^0.3.0" + "next-themes": "^0.3.0", + "react-icons": "^5.2.1", + "react-router-dom": "^6.25.1" }, "devDependencies": { "@electron-toolkit/eslint-config-prettier": "^2.0.0", @@ -36,17 +38,17 @@ "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.19", "electron": "^31.3.1", "electron-builder": "^25.0.2", "electron-vite": "^2.3.0", "eslint": "^8.57.0", "eslint-plugin-react": "^7.35.0", - "autoprefixer": "^10.4.19", "postcss": "^8.4.40", - "tailwindcss": "^3.4.7", "prettier": "^3.3.3", "react": "^18.3.1", "react-dom": "^18.3.1", + "tailwindcss": "^3.4.7", "typescript": "^5.5.4", "vite": "^5.3.5" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4fa791b..23a1462 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,12 @@ importers: next-themes: specifier: ^0.3.0 version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-icons: + specifier: ^5.2.1 + version: 5.2.1(react@18.3.1) + react-router-dom: + specifier: ^6.25.1 + version: 6.25.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) devDependencies: '@electron-toolkit/eslint-config-prettier': specifier: ^2.0.0 @@ -1556,6 +1562,10 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@remix-run/router@1.18.0': + resolution: {integrity: sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==} + engines: {node: '>=14.0.0'} + '@rollup/rollup-android-arm-eabi@4.19.1': resolution: {integrity: sha512-XzqSg714++M+FXhHfXpS1tDnNZNpgxxuGZWlRG/jSj+VEPmZ0yg6jV4E0AL3uyBKxO8mO3xtOsP5mQ+XLfrlww==} cpu: [arm] @@ -3467,6 +3477,11 @@ packages: peerDependencies: react: ^18.3.1 + react-icons@5.2.1: + resolution: {integrity: sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==} + peerDependencies: + react: '*' + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -3494,6 +3509,19 @@ packages: '@types/react': optional: true + react-router-dom@6.25.1: + resolution: {integrity: sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + react-router@6.25.1: + resolution: {integrity: sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-style-singleton@2.2.1: resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} @@ -6471,6 +6499,8 @@ snapshots: '@react-types/shared': 3.24.1(react@18.3.1) react: 18.3.1 + '@remix-run/router@1.18.0': {} + '@rollup/rollup-android-arm-eabi@4.19.1': optional: true @@ -8662,6 +8692,10 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 + react-icons@5.2.1(react@18.3.1): + dependencies: + react: 18.3.1 + react-is@16.13.1: {} react-refresh@0.14.2: {} @@ -8685,6 +8719,18 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + react-router-dom@6.25.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@remix-run/router': 1.18.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 6.25.1(react@18.3.1) + + react-router@6.25.1(react@18.3.1): + dependencies: + '@remix-run/router': 1.18.0 + react: 18.3.1 + react-style-singleton@2.2.1(@types/react@18.3.3)(react@18.3.1): dependencies: get-nonce: 1.0.1 diff --git a/src/main/index.ts b/src/main/index.ts index 7aaf1e7..5ba3a33 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -6,8 +6,10 @@ import icon from '../../resources/icon.png?asset' function createWindow(): void { // Create the browser window. const mainWindow = new BrowserWindow({ - width: 900, - height: 670, + minWidth: 800, + minHeight: 600, + width: 800, + height: 600, show: false, autoHideMenuBar: true, ...(process.platform === 'linux' ? { icon } : {}), diff --git a/src/renderer/index.html b/src/renderer/index.html index e198e05..27d4b4e 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -2,7 +2,7 @@ - Electron + Mihomo Party { try { if (window.matchMedia('(prefers-color-scheme: dark)').matches) { @@ -24,7 +37,38 @@ function App(): JSX.Element { } }, []) - return + return ( +
+
+
+

出站

+
+ + +

代理

+
+ + +
+

配置

+ + + + + +
+
{page}
+
+ ) } export default App diff --git a/src/renderer/src/components/sider/outbound-mode-switcher.tsx b/src/renderer/src/components/sider/outbound-mode-switcher.tsx new file mode 100644 index 0000000..c7ea3c9 --- /dev/null +++ b/src/renderer/src/components/sider/outbound-mode-switcher.tsx @@ -0,0 +1,30 @@ +import { Tabs, Tab } from '@nextui-org/react' +import { Key, useState } from 'react' + +export default function OutboundModeSwitcher(): JSX.Element { + const [mode, setMode] = useState('rule') + return ( + setMode(key as OutboundMode)} + > + + + + + ) +} diff --git a/src/renderer/src/components/sider/profile-switcher.tsx b/src/renderer/src/components/sider/profile-switcher.tsx new file mode 100644 index 0000000..a61fe9a --- /dev/null +++ b/src/renderer/src/components/sider/profile-switcher.tsx @@ -0,0 +1,29 @@ +import { Button, Card, CardBody, CardFooter, Slider } from '@nextui-org/react' +import { IoMdRefresh } from 'react-icons/io' +import { useLocation, useNavigate } from 'react-router-dom' + +export default function ProfileSwitcher(): JSX.Element { + const navigate = useNavigate() + const location = useLocation() + + return ( + navigate('/profiles')} + > + +
+

订阅名称

+ +
+
+ + + +
+ ) +} diff --git a/src/renderer/src/components/sider/route-item.tsx b/src/renderer/src/components/sider/route-item.tsx new file mode 100644 index 0000000..c66955c --- /dev/null +++ b/src/renderer/src/components/sider/route-item.tsx @@ -0,0 +1,28 @@ +import { Button } from '@nextui-org/react' +import { IconType } from 'react-icons' +import { useLocation, useNavigate } from 'react-router-dom' + +interface Props { + title: string + pathname: string + icon: IconType +} + +export default function RouteItem(props: Props): JSX.Element { + const { pathname, icon: Icon, title } = props + const navigate = useNavigate() + const location = useLocation() + + return ( + + ) +} diff --git a/src/renderer/src/components/sider/sysproxy-switcher.tsx b/src/renderer/src/components/sider/sysproxy-switcher.tsx new file mode 100644 index 0000000..2a2b990 --- /dev/null +++ b/src/renderer/src/components/sider/sysproxy-switcher.tsx @@ -0,0 +1,20 @@ +import { Button, Card, CardBody, CardFooter, Switch } from '@nextui-org/react' +import { IoSettings } from 'react-icons/io5' + +export default function SysproxySwitcher(): JSX.Element { + return ( + + +
+ + +
+
+ +

系统代理

+
+
+ ) +} diff --git a/src/renderer/src/components/sider/tun-switcher.tsx b/src/renderer/src/components/sider/tun-switcher.tsx new file mode 100644 index 0000000..ab72bf3 --- /dev/null +++ b/src/renderer/src/components/sider/tun-switcher.tsx @@ -0,0 +1,20 @@ +import { Button, Card, CardBody, CardFooter, Switch } from '@nextui-org/react' +import { IoSettings } from 'react-icons/io5' + +export default function SysproxySwitcher(): JSX.Element { + return ( + + +
+ + +
+
+ +

虚拟网卡

+
+
+ ) +} diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx index 6cccdfe..790a28e 100644 --- a/src/renderer/src/main.tsx +++ b/src/renderer/src/main.tsx @@ -1,5 +1,6 @@ import React from 'react' import ReactDOM from 'react-dom/client' +import { BrowserRouter } from 'react-router-dom' import { ThemeProvider as NextThemesProvider } from 'next-themes' import { NextUIProvider } from '@nextui-org/react' @@ -10,7 +11,9 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - + + + diff --git a/src/renderer/src/pages/overview.tsx b/src/renderer/src/pages/overview.tsx new file mode 100644 index 0000000..b9ccdad --- /dev/null +++ b/src/renderer/src/pages/overview.tsx @@ -0,0 +1,3 @@ +export default function Overview(): JSX.Element { + return
Overview
+} diff --git a/src/renderer/src/pages/profiles.tsx b/src/renderer/src/pages/profiles.tsx new file mode 100644 index 0000000..d31690b --- /dev/null +++ b/src/renderer/src/pages/profiles.tsx @@ -0,0 +1,3 @@ +export default function Profiles(): JSX.Element { + return
Profiles
+} diff --git a/src/renderer/src/pages/proxies.tsx b/src/renderer/src/pages/proxies.tsx new file mode 100644 index 0000000..df7545f --- /dev/null +++ b/src/renderer/src/pages/proxies.tsx @@ -0,0 +1,3 @@ +export default function Proxies(): JSX.Element { + return
Proxies
+} diff --git a/src/renderer/src/pages/rules.tsx b/src/renderer/src/pages/rules.tsx new file mode 100644 index 0000000..7f91eaa --- /dev/null +++ b/src/renderer/src/pages/rules.tsx @@ -0,0 +1,3 @@ +export default function Rules(): JSX.Element { + return
Rules
+} diff --git a/src/renderer/src/pages/settings.tsx b/src/renderer/src/pages/settings.tsx new file mode 100644 index 0000000..f851b6b --- /dev/null +++ b/src/renderer/src/pages/settings.tsx @@ -0,0 +1,3 @@ +export default function Settings(): JSX.Element { + return
Settings
+} diff --git a/src/renderer/src/routes/index.tsx b/src/renderer/src/routes/index.tsx new file mode 100644 index 0000000..b3b3ce4 --- /dev/null +++ b/src/renderer/src/routes/index.tsx @@ -0,0 +1,35 @@ +import { Navigate } from 'react-router-dom' +import Overview from '@renderer/pages/overview' +import Proxies from '@renderer/pages/proxies' +import Rules from '@renderer/pages/rules' +import Settings from '@renderer/pages/settings' +import Profiles from '@renderer/pages/profiles' + +const routes = [ + { + path: '/overview', + element: + }, + { + path: '/proxies', + element: + }, + { + path: '/rules', + element: + }, + { + path: '/profiles', + element: + }, + { + path: '/settings', + element: + }, + { + path: '/', + element: + } +] + +export default routes diff --git a/src/renderer/src/env.d.ts b/src/renderer/src/utils/env.d.ts similarity index 100% rename from src/renderer/src/env.d.ts rename to src/renderer/src/utils/env.d.ts diff --git a/src/renderer/src/utils/types.d.ts b/src/renderer/src/utils/types.d.ts new file mode 100644 index 0000000..fd2a435 --- /dev/null +++ b/src/renderer/src/utils/types.d.ts @@ -0,0 +1 @@ +type OutboundMode = 'rule' | 'global' | 'direct' diff --git a/tsconfig.web.json b/tsconfig.web.json index 9c16b66..7ce117a 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -1,7 +1,7 @@ { "extends": "@electron-toolkit/tsconfig/tsconfig.web.json", "include": [ - "src/renderer/src/env.d.ts", + "src/renderer/src/utils/env.d.ts", "src/renderer/src/**/*", "src/renderer/src/**/*.tsx", "src/preload/*.d.ts"