mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/mihomo-party-org/clash-party.git
synced 2026-09-20 08:03:39 +08:00
feat: remember selected sider card
This commit is contained in:
@@ -50,6 +50,7 @@ export const defaultConfig: IAppConfig = {
|
||||
'substore',
|
||||
'network'
|
||||
],
|
||||
lastSelectedSiderCard: 'proxy',
|
||||
siderWidth: 250,
|
||||
sysProxy: { enable: false, mode: 'manual' },
|
||||
triggerMainWindowBehavior: 'show',
|
||||
|
||||
@@ -39,38 +39,16 @@ import { createTourDriver, getDriver, startTourIfNeeded } from '@renderer/utils/
|
||||
import 'driver.js/dist/driver.css'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import MihomoIcon from './components/base/mihomo-icon'
|
||||
import { SIDER_CARD_ROUTES, getSiderCardByPath, mergeSiderOrder } from './utils/sider'
|
||||
|
||||
let navigate: NavigateFunction
|
||||
|
||||
export { getDriver }
|
||||
|
||||
const ALL_SIDER_KEYS = [
|
||||
'sysproxy',
|
||||
'tun',
|
||||
'profile',
|
||||
'proxy',
|
||||
'rule',
|
||||
'resource',
|
||||
'override',
|
||||
'connection',
|
||||
'mihomo',
|
||||
'dns',
|
||||
'sniff',
|
||||
'log',
|
||||
'substore',
|
||||
'network',
|
||||
'usage'
|
||||
]
|
||||
|
||||
function mergeSiderOrder(saved: string[]): string[] {
|
||||
const valid = saved.filter((k) => ALL_SIDER_KEYS.includes(k))
|
||||
const missing = ALL_SIDER_KEYS.filter((k) => !valid.includes(k))
|
||||
return [...valid, ...missing]
|
||||
}
|
||||
|
||||
const App: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { appConfig, patchAppConfig } = useAppConfig()
|
||||
const hasAppConfig = Boolean(appConfig)
|
||||
const {
|
||||
enableTrafficLogger = true,
|
||||
appTheme = 'system',
|
||||
@@ -93,11 +71,12 @@ const App: React.FC = () => {
|
||||
'substore',
|
||||
'network',
|
||||
'usage'
|
||||
]
|
||||
],
|
||||
lastSelectedSiderCard = 'proxy'
|
||||
} = appConfig || {}
|
||||
useTrafficLogger(enableTrafficLogger)
|
||||
const narrowWidth = platform === 'darwin' ? 70 : 60
|
||||
const [order, setOrder] = useState(mergeSiderOrder(siderOrder))
|
||||
const [order, setOrder] = useState<SiderCardKey[]>(mergeSiderOrder(siderOrder))
|
||||
const [siderWidthValue, setSiderWidthValue] = useState(siderWidth)
|
||||
const siderWidthValueRef = useRef(siderWidthValue)
|
||||
const [resizing, setResizing] = useState(false)
|
||||
@@ -127,6 +106,13 @@ const App: React.FC = () => {
|
||||
setSiderWidthValue(siderWidth)
|
||||
}, [siderOrder, siderWidth])
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasAppConfig) return
|
||||
const currentSiderCard = getSiderCardByPath(location.pathname)
|
||||
if (!currentSiderCard || currentSiderCard === lastSelectedSiderCard) return
|
||||
patchAppConfig({ lastSelectedSiderCard: currentSiderCard })
|
||||
}, [hasAppConfig, lastSelectedSiderCard, location.pathname, patchAppConfig])
|
||||
|
||||
useEffect(() => {
|
||||
siderWidthValueRef.current = siderWidthValue
|
||||
resizingRef.current = resizing
|
||||
@@ -166,41 +152,26 @@ const App: React.FC = () => {
|
||||
|
||||
const onDragEnd = async (event: DragEndEvent): Promise<void> => {
|
||||
const { active, over } = event
|
||||
const activeId = active.id as SiderCardKey
|
||||
if (over) {
|
||||
if (active.id !== over.id) {
|
||||
const overId = over.id as SiderCardKey
|
||||
const newOrder = order.slice()
|
||||
const activeIndex = newOrder.indexOf(active.id as string)
|
||||
const overIndex = newOrder.indexOf(over.id as string)
|
||||
const activeIndex = newOrder.indexOf(activeId)
|
||||
const overIndex = newOrder.indexOf(overId)
|
||||
if (activeIndex === -1 || overIndex === -1) return
|
||||
newOrder.splice(activeIndex, 1)
|
||||
newOrder.splice(overIndex, 0, active.id as string)
|
||||
newOrder.splice(overIndex, 0, activeId)
|
||||
setOrder(newOrder)
|
||||
await patchAppConfig({ siderOrder: newOrder })
|
||||
return
|
||||
}
|
||||
}
|
||||
const dest = navigateMap[active.id as string]
|
||||
const dest = SIDER_CARD_ROUTES[activeId]
|
||||
if (dest) navigate(dest)
|
||||
}
|
||||
|
||||
const navigateMap = {
|
||||
sysproxy: 'sysproxy',
|
||||
tun: 'tun',
|
||||
profile: 'profiles',
|
||||
proxy: 'proxies',
|
||||
mihomo: 'mihomo',
|
||||
connection: 'connections',
|
||||
dns: 'dns',
|
||||
sniff: 'sniffer',
|
||||
log: 'logs',
|
||||
rule: 'rules',
|
||||
resource: 'resources',
|
||||
override: 'override',
|
||||
substore: 'substore',
|
||||
network: 'network',
|
||||
usage: 'traffic'
|
||||
}
|
||||
|
||||
const componentMap = {
|
||||
const componentMap: Record<SiderCardKey, React.FC<{ iconOnly?: boolean }>> = {
|
||||
sysproxy: SysproxySwitcher,
|
||||
tun: TunSwitcher,
|
||||
profile: ProfileCard,
|
||||
@@ -242,9 +213,8 @@ const App: React.FC = () => {
|
||||
</div>
|
||||
<div className="h-[calc(100%-110px)] overflow-y-auto no-scrollbar">
|
||||
<div className="h-full w-full flex flex-col gap-2">
|
||||
{order.map((key: string) => {
|
||||
{order.map((key) => {
|
||||
const Component = componentMap[key]
|
||||
if (!Component) return null
|
||||
return <Component key={key} iconOnly={true} />
|
||||
})}
|
||||
</div>
|
||||
@@ -299,9 +269,8 @@ const App: React.FC = () => {
|
||||
<DndContext sensors={sensors} collisionDetection={closestCorners} onDragEnd={onDragEnd}>
|
||||
<div className="grid grid-cols-2 gap-2 m-2">
|
||||
<SortableContext items={order}>
|
||||
{order.map((key: string) => {
|
||||
{order.map((key) => {
|
||||
const Component = componentMap[key]
|
||||
if (!Component) return null
|
||||
return <Component key={key} />
|
||||
})}
|
||||
</SortableContext>
|
||||
|
||||
@@ -15,6 +15,16 @@ import DNS from '@renderer/pages/dns'
|
||||
import Sniffer from '@renderer/pages/sniffer'
|
||||
import SubStore from '@renderer/pages/substore'
|
||||
import Traffic from '@renderer/pages/traffic'
|
||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||
import { getSiderCardRoute } from '@renderer/utils/sider'
|
||||
|
||||
const HomeRedirect: React.FC = () => {
|
||||
const { appConfig } = useAppConfig()
|
||||
|
||||
if (!appConfig) return null
|
||||
return <Navigate to={getSiderCardRoute(appConfig.lastSelectedSiderCard)} replace />
|
||||
}
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/network',
|
||||
@@ -82,7 +92,7 @@ const routes = [
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
element: <Navigate to="/proxies" />
|
||||
element: <HomeRedirect />
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
54
src/renderer/src/utils/sider.ts
Normal file
54
src/renderer/src/utils/sider.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
export const SIDER_CARD_KEYS: SiderCardKey[] = [
|
||||
'sysproxy',
|
||||
'tun',
|
||||
'profile',
|
||||
'proxy',
|
||||
'rule',
|
||||
'resource',
|
||||
'override',
|
||||
'connection',
|
||||
'mihomo',
|
||||
'dns',
|
||||
'sniff',
|
||||
'log',
|
||||
'substore',
|
||||
'network',
|
||||
'usage'
|
||||
]
|
||||
|
||||
export const SIDER_CARD_ROUTES: Record<SiderCardKey, string> = {
|
||||
sysproxy: '/sysproxy',
|
||||
tun: '/tun',
|
||||
profile: '/profiles',
|
||||
proxy: '/proxies',
|
||||
rule: '/rules',
|
||||
resource: '/resources',
|
||||
override: '/override',
|
||||
connection: '/connections',
|
||||
mihomo: '/mihomo',
|
||||
dns: '/dns',
|
||||
sniff: '/sniffer',
|
||||
log: '/logs',
|
||||
substore: '/substore',
|
||||
network: '/network',
|
||||
usage: '/traffic'
|
||||
}
|
||||
|
||||
export function mergeSiderOrder(saved: string[] = []): SiderCardKey[] {
|
||||
const valid = saved.filter((key): key is SiderCardKey =>
|
||||
SIDER_CARD_KEYS.includes(key as SiderCardKey)
|
||||
)
|
||||
const missing = SIDER_CARD_KEYS.filter((key) => !valid.includes(key))
|
||||
return [...valid, ...missing]
|
||||
}
|
||||
|
||||
export function getSiderCardRoute(card?: string): string {
|
||||
if (!card || !SIDER_CARD_KEYS.includes(card as SiderCardKey)) {
|
||||
return SIDER_CARD_ROUTES.proxy
|
||||
}
|
||||
return SIDER_CARD_ROUTES[card as SiderCardKey]
|
||||
}
|
||||
|
||||
export function getSiderCardByPath(pathname: string): SiderCardKey | undefined {
|
||||
return SIDER_CARD_KEYS.find((key) => SIDER_CARD_ROUTES[key] === pathname)
|
||||
}
|
||||
17
src/shared/types.d.ts
vendored
17
src/shared/types.d.ts
vendored
@@ -2,6 +2,22 @@ type OutboundMode = 'rule' | 'global' | 'direct'
|
||||
type LogLevel = 'info' | 'debug' | 'warning' | 'error' | 'silent'
|
||||
type SysProxyMode = 'auto' | 'manual'
|
||||
type CardStatus = 'col-span-2' | 'col-span-1' | 'hidden'
|
||||
type SiderCardKey =
|
||||
| 'sysproxy'
|
||||
| 'tun'
|
||||
| 'profile'
|
||||
| 'proxy'
|
||||
| 'rule'
|
||||
| 'resource'
|
||||
| 'override'
|
||||
| 'connection'
|
||||
| 'mihomo'
|
||||
| 'dns'
|
||||
| 'sniff'
|
||||
| 'log'
|
||||
| 'substore'
|
||||
| 'network'
|
||||
| 'usage'
|
||||
type AppTheme = 'system' | 'light' | 'dark'
|
||||
type MihomoGroupType = 'Selector' | 'URLTest' | 'Fallback' | 'LoadBalance' | 'Relay'
|
||||
type Priority =
|
||||
@@ -310,6 +326,7 @@ interface IAppConfig {
|
||||
showCurrentProxyInTray: boolean
|
||||
enableTrafficLogger?: boolean
|
||||
siderOrder: string[]
|
||||
lastSelectedSiderCard?: SiderCardKey
|
||||
siderWidth: number
|
||||
appTheme: AppTheme
|
||||
customTheme?: string
|
||||
|
||||
Reference in New Issue
Block a user