mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 13:10:30 +08:00
support narrow sidebar style
This commit is contained in:
parent
a5f825d5ca
commit
f193dbe696
@ -37,6 +37,7 @@ import { driver } from 'driver.js'
|
|||||||
import 'driver.js/dist/driver.css'
|
import 'driver.js/dist/driver.css'
|
||||||
|
|
||||||
let navigate: NavigateFunction
|
let navigate: NavigateFunction
|
||||||
|
const narrowWidth = platform === 'darwin' ? 70 : 60
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
@ -142,19 +143,19 @@ const App: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const componentMap = {
|
const componentMap = {
|
||||||
sysproxy: <SysproxySwitcher key="sysproxy" />,
|
sysproxy: SysproxySwitcher,
|
||||||
tun: <TunSwitcher key="tun" />,
|
tun: TunSwitcher,
|
||||||
profile: <ProfileCard key="profile" />,
|
profile: ProfileCard,
|
||||||
proxy: <ProxyCard key="proxy" />,
|
proxy: ProxyCard,
|
||||||
mihomo: <MihomoCoreCard key="mihomo" />,
|
mihomo: MihomoCoreCard,
|
||||||
connection: <ConnCard key="connection" />,
|
connection: ConnCard,
|
||||||
dns: <DNSCard key="dns" />,
|
dns: DNSCard,
|
||||||
sniff: <SniffCard key="sniff" />,
|
sniff: SniffCard,
|
||||||
log: <LogCard key="log" />,
|
log: LogCard,
|
||||||
rule: <RuleCard key="rule" />,
|
rule: RuleCard,
|
||||||
resource: <ResourceCard key="resource" />,
|
resource: ResourceCard,
|
||||||
override: <OverrideCard key="override" />,
|
override: OverrideCard,
|
||||||
substore: <SubStoreCard key="substore" />
|
substore: SubStoreCard
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -167,7 +168,9 @@ const App: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
onMouseMove={(e) => {
|
onMouseMove={(e) => {
|
||||||
if (!resizing) return
|
if (!resizing) return
|
||||||
if (e.clientX <= 250) {
|
if (e.clientX <= 150) {
|
||||||
|
setSiderWidthValue(narrowWidth)
|
||||||
|
} else if (e.clientX <= 250) {
|
||||||
setSiderWidthValue(250)
|
setSiderWidthValue(250)
|
||||||
} else if (e.clientX >= 400) {
|
} else if (e.clientX >= 400) {
|
||||||
setSiderWidthValue(400)
|
setSiderWidthValue(400)
|
||||||
@ -177,19 +180,23 @@ const App: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className={`w-full h-[100vh] flex ${resizing ? 'cursor-ew-resize' : ''}`}
|
className={`w-full h-[100vh] flex ${resizing ? 'cursor-ew-resize' : ''}`}
|
||||||
>
|
>
|
||||||
<div
|
{siderWidthValue === narrowWidth ? (
|
||||||
style={{ width: `${siderWidthValue}px` }}
|
<div style={{ width: `${narrowWidth}px` }} className="side h-full">
|
||||||
className="side h-full overflow-y-auto no-scrollbar"
|
<div className="app-drag flex justify-center items-center z-40 bg-transparent h-[49px]">
|
||||||
>
|
{platform !== 'darwin' && (
|
||||||
<div className="app-drag sticky top-0 z-40 backdrop-blur bg-transparent h-[49px]">
|
|
||||||
<div
|
|
||||||
className={`flex justify-between p-2 ${!useWindowFrame && platform === 'darwin' ? 'ml-[60px]' : ''}`}
|
|
||||||
>
|
|
||||||
<div className="flex ml-1">
|
|
||||||
<MihomoIcon className="h-[32px] leading-[32px] text-lg mx-[1px]" />
|
<MihomoIcon className="h-[32px] leading-[32px] text-lg mx-[1px]" />
|
||||||
<h3 className="text-lg font-bold leading-[32px]">ihomo Party</h3>
|
)}
|
||||||
|
</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) => {
|
||||||
|
const Component = componentMap[key]
|
||||||
|
if (!Component) return null
|
||||||
|
return <Component key={key} iconOnly={true} />
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<UpdaterButton />
|
</div>
|
||||||
|
<div className="mt-2 flex justify-center items-center h-[48px]">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="app-nodrag"
|
className="app-nodrag"
|
||||||
@ -199,23 +206,56 @@ const App: React.FC = () => {
|
|||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigate('/settings')
|
navigate('/settings')
|
||||||
}}
|
}}
|
||||||
startContent={<IoSettings className="text-[20px]" />}
|
>
|
||||||
/>
|
<IoSettings className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 mx-2">
|
) : (
|
||||||
<OutboundModeSwitcher />
|
<div
|
||||||
</div>
|
style={{ width: `${siderWidthValue}px` }}
|
||||||
<DndContext sensors={sensors} collisionDetection={closestCorners} onDragEnd={onDragEnd}>
|
className="side h-full overflow-y-auto no-scrollbar"
|
||||||
<div className="grid grid-cols-2 gap-2 m-2">
|
>
|
||||||
<SortableContext items={order}>
|
<div className="app-drag sticky top-0 z-40 backdrop-blur bg-transparent h-[49px]">
|
||||||
{order.map((key: string) => {
|
<div
|
||||||
return componentMap[key]
|
className={`flex justify-between p-2 ${!useWindowFrame && platform === 'darwin' ? 'ml-[60px]' : ''}`}
|
||||||
})}
|
>
|
||||||
</SortableContext>
|
<div className="flex ml-1">
|
||||||
|
<MihomoIcon className="h-[32px] leading-[32px] text-lg mx-[1px]" />
|
||||||
|
<h3 className="text-lg font-bold leading-[32px]">ihomo Party</h3>
|
||||||
|
</div>
|
||||||
|
<UpdaterButton />
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
className="app-nodrag"
|
||||||
|
isIconOnly
|
||||||
|
color={location.pathname.includes('/settings') ? 'primary' : 'default'}
|
||||||
|
variant={location.pathname.includes('/settings') ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/settings')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IoSettings className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DndContext>
|
<div className="mt-2 mx-2">
|
||||||
</div>
|
<OutboundModeSwitcher />
|
||||||
|
</div>
|
||||||
|
<DndContext sensors={sensors} collisionDetection={closestCorners} onDragEnd={onDragEnd}>
|
||||||
|
<div className="grid grid-cols-2 gap-2 m-2">
|
||||||
|
<SortableContext items={order}>
|
||||||
|
{order.map((key: string) => {
|
||||||
|
const Component = componentMap[key]
|
||||||
|
if (!Component) return null
|
||||||
|
return <Component key={key} />
|
||||||
|
})}
|
||||||
|
</SortableContext>
|
||||||
|
</div>
|
||||||
|
</DndContext>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
onMouseDown={() => {
|
onMouseDown={() => {
|
||||||
setResizing(true)
|
setResizing(true)
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import { FaCircleArrowDown, FaCircleArrowUp } from 'react-icons/fa6'
|
import { FaCircleArrowDown, FaCircleArrowUp } from 'react-icons/fa6'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { calcTraffic } from '@renderer/utils/calc'
|
import { calcTraffic } from '@renderer/utils/calc'
|
||||||
import { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { IoLink } from 'react-icons/io5'
|
import { IoLink } from 'react-icons/io5'
|
||||||
@ -16,11 +16,16 @@ let currentDownload: number | undefined = undefined
|
|||||||
let hasShowTraffic = false
|
let hasShowTraffic = false
|
||||||
let drawing = false
|
let drawing = false
|
||||||
|
|
||||||
const ConnCard: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
const ConnCard: React.FC<Props> = (props) => {
|
||||||
const { theme = 'system', systemTheme = 'dark' } = useTheme()
|
const { theme = 'system', systemTheme = 'dark' } = useTheme()
|
||||||
|
const { iconOnly } = props
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
const { showTraffic = false, connectionCardStatus = 'col-span-2', customTheme } = appConfig || {}
|
const { showTraffic = false, connectionCardStatus = 'col-span-2', customTheme } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/connections')
|
const match = location.pathname.includes('/connections')
|
||||||
|
|
||||||
const [upload, setUpload] = useState(0)
|
const [upload, setUpload] = useState(0)
|
||||||
@ -87,6 +92,26 @@ const ConnCard: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [showTraffic])
|
}, [showTraffic])
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${connectionCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="连接" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/connections')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IoLink className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,16 +1,23 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
||||||
import BorderSwitch from '@renderer/components/base/border-swtich'
|
import BorderSwitch from '@renderer/components/base/border-swtich'
|
||||||
import { LuServer } from 'react-icons/lu'
|
import { LuServer } from 'react-icons/lu'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { patchMihomoConfig } from '@renderer/utils/ipc'
|
import { patchMihomoConfig } from '@renderer/utils/ipc'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
const DNSCard: React.FC = () => {
|
import React from 'react'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
const DNSCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { dnsCardStatus = 'col-span-1', controlDns = true } = appConfig || {}
|
const { dnsCardStatus = 'col-span-1', controlDns = true } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/dns')
|
const match = location.pathname.includes('/dns')
|
||||||
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
||||||
const { dns, tun } = controledMihomoConfig || {}
|
const { dns, tun } = controledMihomoConfig || {}
|
||||||
@ -31,6 +38,26 @@ const DNSCard: React.FC = () => {
|
|||||||
await patchMihomoConfig({ dns: { enable } })
|
await patchMihomoConfig({ dns: { enable } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${dnsCardStatus} ${!controlDns ? 'hidden' : ''} flex justify-center`}>
|
||||||
|
<Tooltip content="DNS" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/dns')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LuServer className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import { IoJournalOutline } from 'react-icons/io5'
|
import { IoJournalOutline } from 'react-icons/io5'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
const LogCard: React.FC = () => {
|
import React from 'react'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { logCardStatus = 'col-span-1' } = appConfig || {}
|
const { logCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/logs')
|
const match = location.pathname.includes('/logs')
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
@ -20,6 +28,26 @@ const LogCard: React.FC = () => {
|
|||||||
id: 'log'
|
id: 'log'
|
||||||
})
|
})
|
||||||
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${logCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="日志" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/logs')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IoJournalOutline className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,21 +1,27 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import { calcTraffic } from '@renderer/utils/calc'
|
import { calcTraffic } from '@renderer/utils/calc'
|
||||||
import { mihomoVersion, restartCore } from '@renderer/utils/ipc'
|
import { mihomoVersion, restartCore } from '@renderer/utils/ipc'
|
||||||
import { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { IoMdRefresh } from 'react-icons/io'
|
import { IoMdRefresh } from 'react-icons/io'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import PubSub from 'pubsub-js'
|
import PubSub from 'pubsub-js'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
import { LuCpu } from 'react-icons/lu'
|
import { LuCpu } from 'react-icons/lu'
|
||||||
|
|
||||||
const MihomoCoreCard: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const MihomoCoreCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { mihomoCoreCardStatus = 'col-span-2' } = appConfig || {}
|
const { mihomoCoreCardStatus = 'col-span-2' } = appConfig || {}
|
||||||
const { data: version, mutate } = useSWR('mihomoVersion', mihomoVersion)
|
const { data: version, mutate } = useSWR('mihomoVersion', mihomoVersion)
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/mihomo')
|
const match = location.pathname.includes('/mihomo')
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
@ -43,6 +49,26 @@ const MihomoCoreCard: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${mihomoCoreCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="内核设置" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/mihomo')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LuCpu className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,15 +1,21 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { MdFormatOverline } from 'react-icons/md'
|
import { MdFormatOverline } from 'react-icons/md'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
|
|
||||||
const OverrideCard: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const OverrideCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { overrideCardStatus = 'col-span-1' } = appConfig || {}
|
const { overrideCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/override')
|
const match = location.pathname.includes('/override')
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
@ -22,6 +28,25 @@ const OverrideCard: React.FC = () => {
|
|||||||
id: 'override'
|
id: 'override'
|
||||||
})
|
})
|
||||||
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${overrideCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="覆写" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/override')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdFormatOverline className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Button, Card, CardBody, CardFooter, Chip, Progress, Tooltip } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Chip, Progress, Tooltip } from '@nextui-org/react'
|
||||||
import { useProfileConfig } from '@renderer/hooks/use-profile-config'
|
import { useProfileConfig } from '@renderer/hooks/use-profile-config'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { calcTraffic, calcPercent } from '@renderer/utils/calc'
|
import { calcTraffic, calcPercent } from '@renderer/utils/calc'
|
||||||
import { CgLoadbarDoc } from 'react-icons/cg'
|
import { CgLoadbarDoc } from 'react-icons/cg'
|
||||||
import { IoMdRefresh } from 'react-icons/io'
|
import { IoMdRefresh } from 'react-icons/io'
|
||||||
@ -9,7 +9,7 @@ import { useSortable } from '@dnd-kit/sortable'
|
|||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import 'dayjs/locale/zh-cn'
|
import 'dayjs/locale/zh-cn'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import ConfigViewer from './config-viewer'
|
import ConfigViewer from './config-viewer'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
import { TiFolder } from 'react-icons/ti'
|
import { TiFolder } from 'react-icons/ti'
|
||||||
@ -17,10 +17,16 @@ import { TiFolder } from 'react-icons/ti'
|
|||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
dayjs.locale('zh-cn')
|
dayjs.locale('zh-cn')
|
||||||
|
|
||||||
const ProfileCard: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProfileCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { profileCardStatus = 'col-span-2', profileDisplayDate = 'expire' } = appConfig || {}
|
const { profileCardStatus = 'col-span-2', profileDisplayDate = 'expire' } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/profiles')
|
const match = location.pathname.includes('/profiles')
|
||||||
const [updating, setUpdating] = useState(false)
|
const [updating, setUpdating] = useState(false)
|
||||||
const [showRuntimeConfig, setShowRuntimeConfig] = useState(false)
|
const [showRuntimeConfig, setShowRuntimeConfig] = useState(false)
|
||||||
@ -47,6 +53,26 @@ const ProfileCard: React.FC = () => {
|
|||||||
const usage = (extra?.upload ?? 0) + (extra?.download ?? 0)
|
const usage = (extra?.upload ?? 0) + (extra?.download ?? 0)
|
||||||
const total = extra?.total ?? 0
|
const total = extra?.total ?? 0
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${profileCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="订阅管理" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/profiles')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TiFolder className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,15 +1,22 @@
|
|||||||
import { Button, Card, CardBody, CardFooter, Chip } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Chip, Tooltip } from '@nextui-org/react'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { LuGroup } from 'react-icons/lu'
|
import { LuGroup } from 'react-icons/lu'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useGroups } from '@renderer/hooks/use-groups'
|
import { useGroups } from '@renderer/hooks/use-groups'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
const ProxyCard: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProxyCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { proxyCardStatus = 'col-span-1' } = appConfig || {}
|
const { proxyCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/proxies')
|
const match = location.pathname.includes('/proxies')
|
||||||
const { groups = [] } = useGroups()
|
const { groups = [] } = useGroups()
|
||||||
const {
|
const {
|
||||||
@ -24,6 +31,25 @@ const ProxyCard: React.FC = () => {
|
|||||||
})
|
})
|
||||||
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${proxyCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="代理组" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/proxies')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LuGroup className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,14 +1,21 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { IoLayersOutline } from 'react-icons/io5'
|
import { IoLayersOutline } from 'react-icons/io5'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
const ResourceCard: React.FC = () => {
|
|
||||||
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const ResourceCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { resourceCardStatus = 'col-span-1' } = appConfig || {}
|
const { resourceCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/resources')
|
const match = location.pathname.includes('/resources')
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
@ -21,6 +28,26 @@ const ResourceCard: React.FC = () => {
|
|||||||
id: 'resource'
|
id: 'resource'
|
||||||
})
|
})
|
||||||
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${resourceCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="外部资源" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/resources')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IoLayersOutline className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,15 +1,22 @@
|
|||||||
import { Button, Card, CardBody, CardFooter, Chip } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Chip, Tooltip } from '@nextui-org/react'
|
||||||
import { MdOutlineAltRoute } from 'react-icons/md'
|
import { MdOutlineAltRoute } from 'react-icons/md'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { useRules } from '@renderer/hooks/use-rules'
|
import { useRules } from '@renderer/hooks/use-rules'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
const RuleCard: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const RuleCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { ruleCardStatus = 'col-span-1' } = appConfig || {}
|
const { ruleCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/rules')
|
const match = location.pathname.includes('/rules')
|
||||||
const { rules } = useRules()
|
const { rules } = useRules()
|
||||||
const {
|
const {
|
||||||
@ -23,6 +30,26 @@ const RuleCard: React.FC = () => {
|
|||||||
id: 'rule'
|
id: 'rule'
|
||||||
})
|
})
|
||||||
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${ruleCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="规则" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/rules')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdOutlineAltRoute className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,17 +1,23 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import BorderSwitch from '@renderer/components/base/border-swtich'
|
import BorderSwitch from '@renderer/components/base/border-swtich'
|
||||||
import { RiScan2Fill } from 'react-icons/ri'
|
import { RiScan2Fill } from 'react-icons/ri'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { patchMihomoConfig } from '@renderer/utils/ipc'
|
import { patchMihomoConfig } from '@renderer/utils/ipc'
|
||||||
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
const SniffCard: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
const SniffCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { sniffCardStatus = 'col-span-1', controlSniff = true } = appConfig || {}
|
const { sniffCardStatus = 'col-span-1', controlSniff = true } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/sniffer')
|
const match = location.pathname.includes('/sniffer')
|
||||||
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
||||||
const { sniffer } = controledMihomoConfig || {}
|
const { sniffer } = controledMihomoConfig || {}
|
||||||
@ -32,6 +38,26 @@ const SniffCard: React.FC = () => {
|
|||||||
await patchMihomoConfig({ sniffer: { enable } })
|
await patchMihomoConfig({ sniffer: { enable } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${sniffCardStatus} ${!controlSniff ? 'hidden' : ''} flex justify-center`}>
|
||||||
|
<Tooltip content="域名嗅探" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/sniffer')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RiScan2Fill className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import SubStoreIcon from '../base/substore-icon'
|
import SubStoreIcon from '../base/substore-icon'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
const SubStoreCard: React.FC = () => {
|
import React from 'react'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubStoreCard: React.FC<Props> = (props) => {
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
|
const { iconOnly } = props
|
||||||
const { substoreCardStatus = 'col-span-1', useSubStore = true } = appConfig || {}
|
const { substoreCardStatus = 'col-span-1', useSubStore = true } = appConfig || {}
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/substore')
|
const match = location.pathname.includes('/substore')
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
@ -20,6 +28,27 @@ const SubStoreCard: React.FC = () => {
|
|||||||
id: 'substore'
|
id: 'substore'
|
||||||
})
|
})
|
||||||
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${substoreCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="Sub-Store" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/substore')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SubStoreIcon className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import BorderSwitch from '@renderer/components/base/border-swtich'
|
import BorderSwitch from '@renderer/components/base/border-swtich'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
import { triggerSysProxy } from '@renderer/utils/ipc'
|
import { triggerSysProxy } from '@renderer/utils/ipc'
|
||||||
import { AiOutlineGlobal } from 'react-icons/ai'
|
import { AiOutlineGlobal } from 'react-icons/ai'
|
||||||
@ -8,8 +8,14 @@ import React from 'react'
|
|||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
|
|
||||||
const SysproxySwitcher: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const SysproxySwitcher: React.FC<Props> = (props) => {
|
||||||
|
const { iconOnly } = props
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/sysproxy')
|
const match = location.pathname.includes('/sysproxy')
|
||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
const { sysProxy, sysproxyCardStatus = 'col-span-1' } = appConfig || {}
|
const { sysProxy, sysproxyCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
@ -36,6 +42,26 @@ const SysproxySwitcher: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${sysproxyCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="系统代理" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/sysproxy')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AiOutlineGlobal className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,16 +1,22 @@
|
|||||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Tooltip } from '@nextui-org/react'
|
||||||
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
||||||
import BorderSwitch from '@renderer/components/base/border-swtich'
|
import BorderSwitch from '@renderer/components/base/border-swtich'
|
||||||
import { TbDeviceIpadHorizontalBolt } from 'react-icons/tb'
|
import { TbDeviceIpadHorizontalBolt } from 'react-icons/tb'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { restartCore } from '@renderer/utils/ipc'
|
import { restartCore } from '@renderer/utils/ipc'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
|
|
||||||
const TunSwitcher: React.FC = () => {
|
interface Props {
|
||||||
|
iconOnly?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const TunSwitcher: React.FC<Props> = (props) => {
|
||||||
|
const { iconOnly } = props
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
const match = location.pathname.includes('/tun') || false
|
const match = location.pathname.includes('/tun') || false
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
const { tunCardStatus = 'col-span-1' } = appConfig || {}
|
const { tunCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
@ -39,6 +45,26 @@ const TunSwitcher: React.FC = () => {
|
|||||||
window.electron.ipcRenderer.send('updateTrayMenu')
|
window.electron.ipcRenderer.send('updateTrayMenu')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iconOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`${tunCardStatus} flex justify-center`}>
|
||||||
|
<Tooltip content="虚拟网卡" placement="right">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
color={match ? 'primary' : 'default'}
|
||||||
|
variant={match ? 'solid' : 'light'}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('/tun')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TbDeviceIpadHorizontalBolt className="text-[20px]" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user