diff --git a/package.json b/package.json index 93353af..ffc3ef7 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,9 @@ "yaml": "^2.5.0" }, "devDependencies": { + "@dnd-kit/core": "^6.1.0", + "@dnd-kit/sortable": "^8.0.0", + "@dnd-kit/utilities": "^3.2.2", "@electron-toolkit/eslint-config-prettier": "^2.0.0", "@electron-toolkit/eslint-config-ts": "^2.0.0", "@electron-toolkit/tsconfig": "^1.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f494ab..45f78e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,6 +27,15 @@ importers: specifier: ^2.5.0 version: 2.5.0 devDependencies: + '@dnd-kit/core': + specifier: ^6.1.0 + version: 6.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@dnd-kit/sortable': + specifier: ^8.0.0 + version: 8.0.0(@dnd-kit/core@6.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + '@dnd-kit/utilities': + specifier: ^3.2.2 + version: 3.2.2(react@18.3.1) '@electron-toolkit/eslint-config-prettier': specifier: ^2.0.0 version: 2.0.0(eslint@8.57.0)(prettier@3.3.3) @@ -262,6 +271,28 @@ packages: resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} engines: {node: '>= 8.9.0'} + '@dnd-kit/accessibility@3.1.0': + resolution: {integrity: sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.1.0': + resolution: {integrity: sha512-J3cQBClB4TVxwGo3KEjssGEXNJqGVWx17aRTZ1ob0FliR5IjYgTxl5YJbKTzA6IzrtelotH19v6y7uoIRUZPSg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@8.0.0': + resolution: {integrity: sha512-U3jk5ebVXe1Lr7c2wU7SBZjcWdQP+j7peHJfCspnA81enlu88Mgd7CC8Q+pub9ubP7eKVETzJW+IBAhsqbSu/g==} + peerDependencies: + '@dnd-kit/core': ^6.1.0 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + '@electron-toolkit/eslint-config-prettier@2.0.0': resolution: {integrity: sha512-L+uG1FvJcAZkPZpSi6B1pmdpyJFyOxWDTjr1Vs47vSryxv/EX1Ch6o4HVsachlDq3fMEkDgojuP2F3ZvVZMoLw==} peerDependencies: @@ -4545,6 +4576,31 @@ snapshots: ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) + '@dnd-kit/accessibility@3.1.0(react@18.3.1)': + dependencies: + react: 18.3.1 + tslib: 2.6.3 + + '@dnd-kit/core@6.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@dnd-kit/accessibility': 3.1.0(react@18.3.1) + '@dnd-kit/utilities': 3.2.2(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tslib: 2.6.3 + + '@dnd-kit/sortable@8.0.0(@dnd-kit/core@6.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + dependencies: + '@dnd-kit/core': 6.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@dnd-kit/utilities': 3.2.2(react@18.3.1) + react: 18.3.1 + tslib: 2.6.3 + + '@dnd-kit/utilities@3.2.2(react@18.3.1)': + dependencies: + react: 18.3.1 + tslib: 2.6.3 + '@electron-toolkit/eslint-config-prettier@2.0.0(eslint@8.57.0)(prettier@3.3.3)': dependencies: eslint: 8.57.0 diff --git a/src/main/utils/template.ts b/src/main/utils/template.ts index 9a421b1..492fa2f 100644 --- a/src/main/utils/template.ts +++ b/src/main/utils/template.ts @@ -8,6 +8,21 @@ export const defaultConfig: IAppConfig = { autoCloseConnection: true, useNameserverPolicy: false, nameserverPolicy: {}, + siderOrder: [ + 'mode', + 'sysproxy', + 'tun', + 'profile', + 'proxy', + 'mihomo', + 'connection', + 'dns', + 'sniff', + 'log', + 'rule', + 'resource', + 'override' + ], sysProxy: { enable: false, mode: 'manual' } } diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index dff9064..0d48a57 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -1,5 +1,5 @@ import { useTheme } from 'next-themes' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { useLocation, useNavigate, useRoutes } from 'react-router-dom' import OutboundModeSwitcher from '@renderer/components/sider/outbound-mode-switcher' import SysproxySwitcher from '@renderer/components/sider/sysproxy-switcher' @@ -7,6 +7,15 @@ import TunSwitcher from '@renderer/components/sider/tun-switcher' import { Button, Divider } from '@nextui-org/react' import { IoSettings } from 'react-icons/io5' import routes from '@renderer/routes' +import { + DndContext, + closestCenter, + PointerSensor, + useSensor, + useSensors, + DragEndEvent +} from '@dnd-kit/core' +import { SortableContext } from '@dnd-kit/sortable' import ProfileCard from '@renderer/components/sider/profile-card' import ProxyCard from '@renderer/components/sider/proxy-card' import RuleCard from '@renderer/components/sider/rule-card' @@ -21,8 +30,31 @@ import UpdaterButton from '@renderer/components/updater/updater-button' import { useAppConfig } from './hooks/use-app-config' const App: React.FC = () => { - const { appConfig } = useAppConfig() - const { appTheme = 'system' } = appConfig || {} + const { appConfig, patchAppConfig } = useAppConfig() + const { + appTheme = 'system', + siderOrder = [ + 'sysproxy', + 'tun', + 'profile', + 'proxy', + 'mihomo', + 'connection', + 'dns', + 'sniff', + 'log', + 'rule', + 'resource', + 'override' + ] + } = appConfig || {} + const [order, setOrder] = useState(siderOrder) + const sensors = useSensors( + useSensor(PointerSensor) + // useSensor(KeyboardSensor, { + // coordinateGetter: sortableKeyboardCoordinates + // }) + ) const { setTheme } = useTheme() const navigate = useNavigate() const location = useLocation() @@ -32,6 +64,36 @@ const App: React.FC = () => { setTheme(appTheme) }, [appTheme]) + const onDragEnd = async (event: DragEndEvent): Promise => { + const { active, over } = event + if (over) { + if (active.id !== over.id) { + const newOrder = order.slice() + const activeIndex = newOrder.indexOf(active.id as string) + const overIndex = newOrder.indexOf(over.id as string) + newOrder.splice(activeIndex, 1) + newOrder.splice(overIndex, 0, active.id as string) + setOrder(newOrder) + await patchAppConfig({ siderOrder: newOrder }) + } + } + } + + const componentMap = { + sysproxy: , + tun: , + profile: , + proxy: , + mihomo: , + connection: , + dns: , + sniff: , + log: , + rule: , + resource: , + override: + } + return (
@@ -51,44 +113,22 @@ const App: React.FC = () => { />
-
+
- - - - - - - - - - - -
- {/*
- - -
-
- - - - -
- -
- - -
-
- - -
-
- - -
*/} + +
+ { + return x + })} + > + {order.map((key: string) => { + return componentMap[key] + })} + +
+
{page}
diff --git a/src/renderer/src/components/sider/conn-card.tsx b/src/renderer/src/components/sider/conn-card.tsx index 498b1ca..2bb0a40 100644 --- a/src/renderer/src/components/sider/conn-card.tsx +++ b/src/renderer/src/components/sider/conn-card.tsx @@ -3,6 +3,8 @@ import { FaCircleArrowDown, FaCircleArrowUp } from 'react-icons/fa6' import { useLocation, useNavigate } from 'react-router-dom' import { calcTraffic } from '@renderer/utils/calc' import { useEffect, useState } from 'react' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' import { IoLink } from 'react-icons/io5' const ConnCard: React.FC = () => { @@ -12,6 +14,9 @@ const ConnCard: React.FC = () => { const [upload, setUpload] = useState(0) const [download, setDownload] = useState(0) + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'connection' + }) useEffect(() => { window.electron.ipcRenderer.on('mihomoTraffic', (_e, info: IMihomoTrafficInfo) => { @@ -24,41 +29,51 @@ const ConnCard: React.FC = () => { }, []) return ( - navigate('/connections')} +
- -
- -
-
-
{calcTraffic(upload)}/s
- -
-
-
{calcTraffic(download)}/s
- + > + + +
+
+
{calcTraffic(upload)}/s
+ +
+
+
{calcTraffic(download)}/s
+ +
-
- - -

连接

-
- + + +

连接

+
+ +
) } diff --git a/src/renderer/src/components/sider/dns-card.tsx b/src/renderer/src/components/sider/dns-card.tsx index 0de9e8a..87e88f5 100644 --- a/src/renderer/src/components/sider/dns-card.tsx +++ b/src/renderer/src/components/sider/dns-card.tsx @@ -4,7 +4,8 @@ import BorderSwitch from '@renderer/components/base/border-swtich' import { LuServer } from 'react-icons/lu' import { useLocation, useNavigate } from 'react-router-dom' import { patchMihomoConfig } from '@renderer/utils/ipc' - +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' const DNSCard: React.FC = () => { const navigate = useNavigate() const location = useLocation() @@ -12,42 +13,55 @@ const DNSCard: React.FC = () => { const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig(true) const { dns, tun } = controledMihomoConfig || {} const { enable } = dns || {} - + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'dns' + }) const onChange = async (enable: boolean): Promise => { await patchControledMihomoConfig({ dns: { enable } }) await patchMihomoConfig({ dns: { enable } }) } return ( - navigate('/dns')} +
- -
- + - - -
-
- -

DNS

-
- +
+
+ +

DNS

+
+ +
) } diff --git a/src/renderer/src/components/sider/log-card.tsx b/src/renderer/src/components/sider/log-card.tsx index edb8a28..f3d4fad 100644 --- a/src/renderer/src/components/sider/log-card.tsx +++ b/src/renderer/src/components/sider/log-card.tsx @@ -1,36 +1,51 @@ import { Button, Card, CardBody, CardFooter } from '@nextui-org/react' import { IoJournal } from 'react-icons/io5' import { useLocation, useNavigate } from 'react-router-dom' - +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' const LogCard: React.FC = () => { const navigate = useNavigate() const location = useLocation() const match = location.pathname.includes('/logs') + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'log' + }) return ( - navigate('/logs')} +
- -
- -
-
- -

日志

-
- + > + + +
+ + +

日志

+
+
+ ) } diff --git a/src/renderer/src/components/sider/mihomo-core-card.tsx b/src/renderer/src/components/sider/mihomo-core-card.tsx index d2e4e30..9b4e911 100644 --- a/src/renderer/src/components/sider/mihomo-core-card.tsx +++ b/src/renderer/src/components/sider/mihomo-core-card.tsx @@ -3,6 +3,8 @@ import { calcTraffic } from '@renderer/utils/calc' import { mihomoVersion, restartCore } from '@renderer/utils/ipc' import { useEffect, useState } from 'react' import { IoMdRefresh } from 'react-icons/io' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' import { useLocation, useNavigate } from 'react-router-dom' import useSWR from 'swr' @@ -11,6 +13,9 @@ const MihomoCoreCard: React.FC = () => { const navigate = useNavigate() const location = useLocation() const match = location.pathname.includes('/mihomo') + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'mihomo' + }) const [mem, setMem] = useState(0) @@ -31,46 +36,61 @@ const MihomoCoreCard: React.FC = () => { }, []) return ( - navigate('/mihomo')} - className={`col-span-2 ${match ? 'bg-primary' : ''}`} +
- -
-

navigate('/mihomo')} + className={`${match ? 'bg-primary' : ''}`} + > + +
- {version?.version ?? '-'} -

+

+ {version?.version ?? '-'} +

- +
+
+ +
- - -
- - -
-

内核设置

-

{calcTraffic(mem)}

-
-
- +

内核设置

+

{calcTraffic(mem)}

+
+ +
+ ) } diff --git a/src/renderer/src/components/sider/outbound-mode-switcher.tsx b/src/renderer/src/components/sider/outbound-mode-switcher.tsx index b70bfc3..42b4ac7 100644 --- a/src/renderer/src/components/sider/outbound-mode-switcher.tsx +++ b/src/renderer/src/components/sider/outbound-mode-switcher.tsx @@ -22,7 +22,6 @@ const OutboundModeSwitcher: React.FC = () => { onChangeMode(key as OutboundMode)} > diff --git a/src/renderer/src/components/sider/override-card.tsx b/src/renderer/src/components/sider/override-card.tsx index 9a91e17..1facbea 100644 --- a/src/renderer/src/components/sider/override-card.tsx +++ b/src/renderer/src/components/sider/override-card.tsx @@ -3,43 +3,58 @@ import BorderSwitch from '@renderer/components/base/border-swtich' import React, { useState } from 'react' import { MdFormatOverline } from 'react-icons/md' import { useLocation, useNavigate } from 'react-router-dom' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' const OverrideCard: React.FC = () => { const navigate = useNavigate() const location = useLocation() const match = location.pathname.includes('/override') const [enable, setEnable] = useState(false) - + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'override' + }) return ( - navigate('/override')} +
- -
- + - - -
-
- -

覆写

-
- +
+ + +

覆写

+
+
+ ) } diff --git a/src/renderer/src/components/sider/profile-card.tsx b/src/renderer/src/components/sider/profile-card.tsx index 9222d0b..408d581 100644 --- a/src/renderer/src/components/sider/profile-card.tsx +++ b/src/renderer/src/components/sider/profile-card.tsx @@ -5,6 +5,8 @@ import { calcTraffic, calcPercent } from '@renderer/utils/calc' import { CgLoadbarDoc } from 'react-icons/cg' import { IoMdRefresh } from 'react-icons/io' import relativeTime from 'dayjs/plugin/relativeTime' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' import 'dayjs/locale/zh-cn' import dayjs from 'dayjs' import { useState } from 'react' @@ -21,6 +23,9 @@ const ProfileCard: React.FC = () => { const [showRuntimeConfig, setShowRuntimeConfig] = useState(false) const { profileConfig, addProfileItem } = useProfileConfig() const { current, items } = profileConfig ?? {} + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'profile' + }) const info = items?.find((item) => item.id === current) ?? { id: 'default', type: 'local', @@ -32,16 +37,29 @@ const ProfileCard: React.FC = () => { const total = extra?.total ?? 0 return ( - <> +
{showRuntimeConfig && setShowRuntimeConfig(false)} />} navigate('/profiles')} > -
+

@@ -115,7 +133,7 @@ const ProfileCard: React.FC = () => { )} - +

) } diff --git a/src/renderer/src/components/sider/proxy-card.tsx b/src/renderer/src/components/sider/proxy-card.tsx index ec6b7ff..327b973 100644 --- a/src/renderer/src/components/sider/proxy-card.tsx +++ b/src/renderer/src/components/sider/proxy-card.tsx @@ -1,6 +1,8 @@ import { Button, Card, CardBody, CardFooter, Chip } from '@nextui-org/react' import { mihomoProxies } from '@renderer/utils/ipc' import { useMemo } from 'react' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' import { LuGroup } from 'react-icons/lu' import { useLocation, useNavigate } from 'react-router-dom' import useSWR from 'swr' @@ -10,54 +12,68 @@ const ProxyCard: React.FC = () => { const location = useLocation() const match = location.pathname.includes('/proxies') const { data: proxies = { proxies: {} } } = useSWR('mihomoProxies', mihomoProxies) - + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'proxy' + }) const filtered = useMemo(() => { return Object.keys(proxies.proxies).filter((key) => 'all' in proxies.proxies[key]) }, [proxies]) return ( - navigate('/proxies')} +
- -
- - - {filtered.length} - -
-
- -

代理组

-
- + navigate('/proxies')} + > + +
+ + + {filtered.length} + +
+
+ +

+ 代理组 +

+
+
+
) } diff --git a/src/renderer/src/components/sider/resource-card.tsx b/src/renderer/src/components/sider/resource-card.tsx index 9e173cf..158305a 100644 --- a/src/renderer/src/components/sider/resource-card.tsx +++ b/src/renderer/src/components/sider/resource-card.tsx @@ -2,39 +2,53 @@ import { Button, Card, CardBody, CardFooter } from '@nextui-org/react' import React from 'react' import { FaLayerGroup } from 'react-icons/fa6' import { useLocation, useNavigate } from 'react-router-dom' - +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' const ResourceCard: React.FC = () => { const navigate = useNavigate() const location = useLocation() const match = location.pathname.includes('/resources') - + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'resource' + }) return ( - navigate('/resources')} +
- -
- -
-
- -

- 外部资源 -

-
- + > + + +
+ + +

+ 外部资源 +

+
+
+
) } diff --git a/src/renderer/src/components/sider/rule-card.tsx b/src/renderer/src/components/sider/rule-card.tsx index a3dd5b8..59c1a37 100644 --- a/src/renderer/src/components/sider/rule-card.tsx +++ b/src/renderer/src/components/sider/rule-card.tsx @@ -2,6 +2,8 @@ import { Button, Card, CardBody, CardFooter, Chip } from '@nextui-org/react' import { mihomoRules } from '@renderer/utils/ipc' import { MdOutlineAltRoute } from 'react-icons/md' import { useLocation, useNavigate } from 'react-router-dom' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' import useSWR from 'swr' const RuleCard: React.FC = () => { @@ -11,50 +13,64 @@ const RuleCard: React.FC = () => { const { data: rules } = useSWR('mihomoRules', mihomoRules, { refreshInterval: 5000 }) + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'rule' + }) return ( - navigate('/rules')} +
- -
- - - {rules?.rules?.length ?? 0} - -
-
- -

规则

-
- + > + + + + {rules?.rules?.length ?? 0} + +
+
+ +

规则

+
+
+
) } diff --git a/src/renderer/src/components/sider/sniff-card.tsx b/src/renderer/src/components/sider/sniff-card.tsx index 924b06b..1dbf044 100644 --- a/src/renderer/src/components/sider/sniff-card.tsx +++ b/src/renderer/src/components/sider/sniff-card.tsx @@ -4,6 +4,8 @@ import { RiScan2Fill } from 'react-icons/ri' import { useLocation, useNavigate } from 'react-router-dom' import { patchMihomoConfig } from '@renderer/utils/ipc' import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' const SniffCard: React.FC = () => { const navigate = useNavigate() @@ -12,6 +14,9 @@ const SniffCard: React.FC = () => { const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig(true) const { sniffer } = controledMihomoConfig || {} const { enable } = sniffer || {} + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'sniff' + }) const onChange = async (enable: boolean): Promise => { await patchControledMihomoConfig({ sniffer: { enable } }) @@ -19,37 +24,48 @@ const SniffCard: React.FC = () => { } return ( - navigate('/sniffer')} +
- -
- + - - -
-
- -

- 域名嗅探 -

-
- +
+ + +

+ 域名嗅探 +

+
+
+ ) } diff --git a/src/renderer/src/components/sider/sysproxy-switcher.tsx b/src/renderer/src/components/sider/sysproxy-switcher.tsx index 1d64b3b..7dd2fe5 100644 --- a/src/renderer/src/components/sider/sysproxy-switcher.tsx +++ b/src/renderer/src/components/sider/sysproxy-switcher.tsx @@ -5,6 +5,8 @@ import { useAppConfig } from '@renderer/hooks/use-app-config' import { triggerSysProxy } from '@renderer/utils/ipc' import { AiOutlineGlobal } from 'react-icons/ai' import React from 'react' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' const SysproxySwitcher: React.FC = () => { const navigate = useNavigate() @@ -13,7 +15,9 @@ const SysproxySwitcher: React.FC = () => { const { appConfig, patchAppConfig } = useAppConfig(true) const { sysProxy } = appConfig || {} const { enable } = sysProxy || {} - + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'sysproxy' + }) const onChange = async (enable: boolean): Promise => { try { await triggerSysProxy(enable) @@ -24,36 +28,47 @@ const SysproxySwitcher: React.FC = () => { } return ( - navigate('/sysproxy')} +
- -
- + - - -
-
- -

- 系统代理 -

-
- +
+ + +

+ 系统代理 +

+
+
+ ) } diff --git a/src/renderer/src/components/sider/tun-switcher.tsx b/src/renderer/src/components/sider/tun-switcher.tsx index 7c599e1..6a659bd 100644 --- a/src/renderer/src/components/sider/tun-switcher.tsx +++ b/src/renderer/src/components/sider/tun-switcher.tsx @@ -4,6 +4,8 @@ import BorderSwitch from '@renderer/components/base/border-swtich' import { TbDeviceIpadHorizontalBolt } from 'react-icons/tb' import { useLocation, useNavigate } from 'react-router-dom' import { encryptString, patchMihomoConfig, isEncryptionAvailable } from '@renderer/utils/ipc' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' import { platform } from '@renderer/utils/init' import React, { useState } from 'react' import { useAppConfig } from '@renderer/hooks/use-app-config' @@ -12,12 +14,15 @@ import BasePasswordModal from '../base/base-password-modal' const TunSwitcher: React.FC = () => { const navigate = useNavigate() const location = useLocation() - const match = location.pathname.includes('/tun') + const match = location.pathname.includes('/tun') || false const [openPasswordModal, setOpenPasswordModal] = useState(false) const { appConfig, patchAppConfig } = useAppConfig() const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig(true) const { tun } = controledMihomoConfig || {} const { enable } = tun || {} + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ + id: 'tun' + }) const onChange = async (enable: boolean): Promise => { if (enable && platform !== 'win32') { @@ -40,7 +45,15 @@ const TunSwitcher: React.FC = () => { } return ( - <> +
{openPasswordModal && ( setOpenPasswordModal(false)} @@ -51,13 +64,15 @@ const TunSwitcher: React.FC = () => { }} /> )} + navigate('/tun')} > -
+
) } diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts index 5342af1..2004cef 100644 --- a/src/shared/types.d.ts +++ b/src/shared/types.d.ts @@ -194,6 +194,7 @@ interface IAppConfig { core: 'mihomo' | 'mihomo-alpha' proxyDisplayMode: 'simple' | 'full' proxyDisplayOrder: 'default' | 'delay' | 'name' + siderOrder: string[] appTheme: AppTheme autoCheckUpdate: boolean silentStart: boolean