mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 05:00:30 +08:00
support custom sidebar
This commit is contained in:
parent
9bd4841b6e
commit
79b3da1da6
@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
- 1.2.x YAML覆写语法有所变动,请更新后参考文档进行修改
|
- 1.2.x YAML覆写语法有所变动,请更新后参考文档进行修改
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
- 支持自定义侧边栏卡片大小
|
||||||
|
- 支持隐藏侧边栏卡片
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
- 修复Ubuntu下每次开启Tun都需要密码的问题
|
- 修复Ubuntu下每次开启Tun都需要密码的问题
|
||||||
|
- 修复Sub-Store无法读取剪切板的问题
|
||||||
|
|||||||
@ -126,14 +126,14 @@ async function migration(): Promise<void> {
|
|||||||
'tun',
|
'tun',
|
||||||
'profile',
|
'profile',
|
||||||
'proxy',
|
'proxy',
|
||||||
'mihomo',
|
|
||||||
'connection',
|
|
||||||
'dns',
|
|
||||||
'sniff',
|
|
||||||
'log',
|
|
||||||
'rule',
|
'rule',
|
||||||
'resource',
|
'resource',
|
||||||
'override',
|
'override',
|
||||||
|
'connection',
|
||||||
|
'mihomo',
|
||||||
|
'dns',
|
||||||
|
'sniff',
|
||||||
|
'log',
|
||||||
'substore'
|
'substore'
|
||||||
],
|
],
|
||||||
useSubStore = true
|
useSubStore = true
|
||||||
|
|||||||
@ -18,19 +18,18 @@ export const defaultConfig: IAppConfig = {
|
|||||||
controlSniff: true,
|
controlSniff: true,
|
||||||
nameserverPolicy: {},
|
nameserverPolicy: {},
|
||||||
siderOrder: [
|
siderOrder: [
|
||||||
'mode',
|
|
||||||
'sysproxy',
|
'sysproxy',
|
||||||
'tun',
|
'tun',
|
||||||
'profile',
|
'profile',
|
||||||
'proxy',
|
'proxy',
|
||||||
'mihomo',
|
|
||||||
'connection',
|
|
||||||
'dns',
|
|
||||||
'sniff',
|
|
||||||
'log',
|
|
||||||
'rule',
|
'rule',
|
||||||
'resource',
|
'resource',
|
||||||
'override',
|
'override',
|
||||||
|
'connection',
|
||||||
|
'mihomo',
|
||||||
|
'dns',
|
||||||
|
'sniff',
|
||||||
|
'log',
|
||||||
'substore'
|
'substore'
|
||||||
],
|
],
|
||||||
sysProxy: { enable: false, mode: 'manual' }
|
sysProxy: { enable: false, mode: 'manual' }
|
||||||
|
|||||||
@ -37,23 +37,20 @@ const App: React.FC = () => {
|
|||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
const {
|
const {
|
||||||
appTheme = 'system',
|
appTheme = 'system',
|
||||||
controlDns = true,
|
|
||||||
controlSniff = true,
|
|
||||||
useSubStore = true,
|
|
||||||
useWindowFrame = false,
|
useWindowFrame = false,
|
||||||
siderOrder = [
|
siderOrder = [
|
||||||
'sysproxy',
|
'sysproxy',
|
||||||
'tun',
|
'tun',
|
||||||
'profile',
|
'profile',
|
||||||
'proxy',
|
'proxy',
|
||||||
'mihomo',
|
|
||||||
'connection',
|
|
||||||
'dns',
|
|
||||||
'sniff',
|
|
||||||
'log',
|
|
||||||
'rule',
|
'rule',
|
||||||
'resource',
|
'resource',
|
||||||
'override',
|
'override',
|
||||||
|
'connection',
|
||||||
|
'mihomo',
|
||||||
|
'dns',
|
||||||
|
'sniff',
|
||||||
|
'log',
|
||||||
'substore'
|
'substore'
|
||||||
]
|
]
|
||||||
} = appConfig || {}
|
} = appConfig || {}
|
||||||
@ -169,9 +166,6 @@ const App: React.FC = () => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{order.map((key: string) => {
|
{order.map((key: string) => {
|
||||||
if (key === 'dns' && controlDns === false) return null
|
|
||||||
if (key === 'sniff' && controlSniff === false) return null
|
|
||||||
if (key === 'substore' && useSubStore === false) return null
|
|
||||||
return componentMap[key]
|
return componentMap[key]
|
||||||
})}
|
})}
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
|
|||||||
78
src/renderer/src/components/settings/sider-config.tsx
Normal file
78
src/renderer/src/components/settings/sider-config.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import SettingCard from '../base/base-setting-card'
|
||||||
|
import SettingItem from '../base/base-setting-item'
|
||||||
|
import { RadioGroup, Radio } from '@nextui-org/react'
|
||||||
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
|
const titleMap = {
|
||||||
|
sysproxyCardStatus: '系统代理',
|
||||||
|
tunCardStatus: '虚拟网卡',
|
||||||
|
profileCardStatus: '订阅管理',
|
||||||
|
proxyCardStatus: '代理组',
|
||||||
|
ruleCardStatus: '规则',
|
||||||
|
resourceCardStatus: '外部资源',
|
||||||
|
overrideCardStatus: '覆写',
|
||||||
|
connectionCardStatus: '连接',
|
||||||
|
mihomoCoreCardStatus: '内核',
|
||||||
|
dnsCardStatus: 'DNS',
|
||||||
|
sniffCardStatus: '域名嗅探',
|
||||||
|
logCardStatus: '日志',
|
||||||
|
substoreCardStatus: 'Sub-Store'
|
||||||
|
}
|
||||||
|
const SiderConfig: React.FC = () => {
|
||||||
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
|
const {
|
||||||
|
sysproxyCardStatus = 'col-span-1',
|
||||||
|
tunCardStatus = 'col-span-1',
|
||||||
|
profileCardStatus = 'col-span-2',
|
||||||
|
proxyCardStatus = 'col-span-1',
|
||||||
|
ruleCardStatus = 'col-span-1',
|
||||||
|
resourceCardStatus = 'col-span-1',
|
||||||
|
overrideCardStatus = 'col-span-1',
|
||||||
|
connectionCardStatus = 'col-span-2',
|
||||||
|
mihomoCoreCardStatus = 'col-span-2',
|
||||||
|
dnsCardStatus = 'col-span-1',
|
||||||
|
sniffCardStatus = 'col-span-1',
|
||||||
|
logCardStatus = 'col-span-1',
|
||||||
|
substoreCardStatus = 'col-span-1'
|
||||||
|
} = appConfig || {}
|
||||||
|
|
||||||
|
const cardStatus = {
|
||||||
|
sysproxyCardStatus,
|
||||||
|
tunCardStatus,
|
||||||
|
profileCardStatus,
|
||||||
|
proxyCardStatus,
|
||||||
|
ruleCardStatus,
|
||||||
|
resourceCardStatus,
|
||||||
|
overrideCardStatus,
|
||||||
|
connectionCardStatus,
|
||||||
|
mihomoCoreCardStatus,
|
||||||
|
dnsCardStatus,
|
||||||
|
sniffCardStatus,
|
||||||
|
logCardStatus,
|
||||||
|
substoreCardStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingCard>
|
||||||
|
{Object.keys(cardStatus).map((key, index, array) => {
|
||||||
|
return (
|
||||||
|
<SettingItem title={titleMap[key]} key={key} divider={index !== array.length - 1}>
|
||||||
|
<RadioGroup
|
||||||
|
orientation="horizontal"
|
||||||
|
value={cardStatus[key]}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
patchAppConfig({ [key]: v as CardStatus })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Radio value="col-span-2">大</Radio>
|
||||||
|
<Radio value="col-span-1">小</Radio>
|
||||||
|
<Radio value="hidden">隐藏</Radio>
|
||||||
|
</RadioGroup>
|
||||||
|
</SettingItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</SettingCard>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SiderConfig
|
||||||
@ -20,7 +20,7 @@ let drawing = false
|
|||||||
const ConnCard: React.FC = () => {
|
const ConnCard: React.FC = () => {
|
||||||
const { theme = 'system', systemTheme = 'dark' } = useTheme()
|
const { theme = 'system', systemTheme = 'dark' } = useTheme()
|
||||||
const { appConfig } = useAppConfig()
|
const { appConfig } = useAppConfig()
|
||||||
const { showTraffic } = appConfig || {}
|
const { showTraffic, connectionCardStatus = 'col-span-2' } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/connections')
|
const match = location.pathname.includes('/connections')
|
||||||
@ -172,52 +172,86 @@ const ConnCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-2"
|
className={connectionCardStatus}
|
||||||
>
|
>
|
||||||
<Card
|
{connectionCardStatus === 'col-span-2' ? (
|
||||||
fullWidth
|
<>
|
||||||
className={`${match ? 'bg-primary' : ''}`}
|
<Card
|
||||||
isPressable
|
fullWidth
|
||||||
onPress={() => navigate('/connections')}
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
>
|
isPressable
|
||||||
<CardBody className="pb-0 pt-0 px-0">
|
onPress={() => navigate('/connections')}
|
||||||
<div ref={setNodeRef} {...attributes} {...listeners} className="flex justify-between">
|
>
|
||||||
<Button
|
<CardBody className="pb-1 pt-0 px-0">
|
||||||
isIconOnly
|
<div ref={setNodeRef} {...attributes} {...listeners} className="flex justify-between">
|
||||||
className="bg-transparent pointer-events-none"
|
<Button
|
||||||
variant="flat"
|
isIconOnly
|
||||||
color="default"
|
className="bg-transparent pointer-events-none"
|
||||||
>
|
variant="flat"
|
||||||
<IoLink
|
color="default"
|
||||||
color="default"
|
>
|
||||||
className={`${match ? 'text-white' : 'text-foreground'} text-[24px]`}
|
<IoLink
|
||||||
/>
|
color="default"
|
||||||
</Button>
|
className={`${match ? 'text-white' : 'text-foreground'} text-[24px]`}
|
||||||
<div className={`p-2 w-full ${match ? 'text-white' : 'text-foreground'} `}>
|
/>
|
||||||
<div className="flex justify-between">
|
</Button>
|
||||||
<div className="w-full text-right mr-2">{calcTraffic(upload)}/s</div>
|
<div className={`p-2 w-full ${match ? 'text-white' : 'text-foreground'} `}>
|
||||||
<FaCircleArrowUp className="h-[24px] leading-[24px]" />
|
<div className="flex justify-between">
|
||||||
|
<div className="w-full text-right mr-2">{calcTraffic(upload)}/s</div>
|
||||||
|
<FaCircleArrowUp className="h-[24px] leading-[24px]" />
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<div className="w-full text-right mr-2">{calcTraffic(download)}/s</div>
|
||||||
|
<FaCircleArrowDown className="h-[24px] leading-[24px]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between">
|
</CardBody>
|
||||||
<div className="w-full text-right mr-2">{calcTraffic(download)}/s</div>
|
<CardFooter className="pt-1">
|
||||||
<FaCircleArrowDown className="h-[24px] leading-[24px]" />
|
<h3 className={`text-md font-bold ${match ? 'text-white' : 'text-foreground'}`}>
|
||||||
</div>
|
连接
|
||||||
</div>
|
</h3>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
<div className="w-full h-full absolute top-0 left-0 pointer-events-none rounded-[14px] overflow-hidden">
|
||||||
|
<Chart
|
||||||
|
options={getApexChartOptions()}
|
||||||
|
series={[{ name: 'Total', data: series }]}
|
||||||
|
height={'100%'}
|
||||||
|
width={'100%'}
|
||||||
|
type="area"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CardBody>
|
</>
|
||||||
<CardFooter className="pt-1">
|
) : (
|
||||||
<h3 className={`text-md font-bold ${match ? 'text-white' : 'text-foreground'}`}>连接</h3>
|
<Card
|
||||||
</CardFooter>
|
fullWidth
|
||||||
</Card>
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
<div className="w-full h-full absolute top-0 left-0 pointer-events-none rounded-[14px] overflow-hidden">
|
isPressable
|
||||||
<Chart
|
onPress={() => navigate('/logs')}
|
||||||
options={getApexChartOptions()}
|
>
|
||||||
series={[{ name: 'Total', data: series }]}
|
<CardBody className="pb-1 pt-0 px-0">
|
||||||
height={'100%'}
|
<div ref={setNodeRef} {...attributes} {...listeners} className="flex justify-between">
|
||||||
width={'100%'}
|
<Button
|
||||||
type="area"
|
isIconOnly
|
||||||
/>
|
className="bg-transparent pointer-events-none"
|
||||||
</div>
|
variant="flat"
|
||||||
|
color="default"
|
||||||
|
>
|
||||||
|
<IoLink
|
||||||
|
color="default"
|
||||||
|
className={`${match ? 'text-white' : 'text-foreground'} text-[24px] font-bold`}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
<CardFooter className="pt-1">
|
||||||
|
<h3 className={`text-md font-bold ${match ? 'text-white' : 'text-foreground'}`}>
|
||||||
|
连接
|
||||||
|
</h3>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,10 @@ 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'
|
||||||
const DNSCard: React.FC = () => {
|
const DNSCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { dnsCardStatus = 'col-span-1', controlDns = true } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/dns')
|
const match = location.pathname.includes('/dns')
|
||||||
@ -37,7 +40,7 @@ const DNSCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1"
|
className={`${dnsCardStatus} ${!controlDns ? 'hidden' : ''}`}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@ -3,7 +3,10 @@ import { IoJournalOutline } from 'react-icons/io5'
|
|||||||
import { useLocation, useNavigate } 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'
|
||||||
const LogCard: React.FC = () => {
|
const LogCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { logCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/logs')
|
const match = location.pathname.includes('/logs')
|
||||||
@ -26,11 +29,11 @@ const LogCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1"
|
className={logCardStatus}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
className={`col-span-1 ${match ? 'bg-primary' : ''}`}
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
isPressable
|
isPressable
|
||||||
onPress={() => navigate('/logs')}
|
onPress={() => navigate('/logs')}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -8,8 +8,12 @@ import { CSS } from '@dnd-kit/utilities'
|
|||||||
import { useLocation, useNavigate } 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 { LuCpu } from 'react-icons/lu'
|
||||||
|
|
||||||
const MihomoCoreCard: React.FC = () => {
|
const MihomoCoreCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { mihomoCoreCardStatus = 'col-span-2' } = appConfig || {}
|
||||||
const { data: version, mutate } = useSWR('mihomoVersion', mihomoVersion)
|
const { data: version, mutate } = useSWR('mihomoVersion', mihomoVersion)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
@ -48,55 +52,87 @@ const MihomoCoreCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-2"
|
className={mihomoCoreCardStatus}
|
||||||
>
|
>
|
||||||
<Card
|
{mihomoCoreCardStatus === 'col-span-2' ? (
|
||||||
fullWidth
|
<Card
|
||||||
isPressable
|
fullWidth
|
||||||
onPress={() => navigate('/mihomo')}
|
isPressable
|
||||||
className={`${match ? 'bg-primary' : ''}`}
|
onPress={() => navigate('/mihomo')}
|
||||||
>
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
<CardBody>
|
>
|
||||||
<div
|
<CardBody>
|
||||||
ref={setNodeRef}
|
<div
|
||||||
{...attributes}
|
ref={setNodeRef}
|
||||||
{...listeners}
|
{...attributes}
|
||||||
className="flex justify-between h-[32px]"
|
{...listeners}
|
||||||
>
|
className="flex justify-between h-[32px]"
|
||||||
<h3
|
|
||||||
className={`text-md font-bold leading-[32px] ${match ? 'text-white' : 'text-foreground'} `}
|
|
||||||
>
|
>
|
||||||
{version?.version ?? '-'}
|
<h3
|
||||||
</h3>
|
className={`text-md font-bold leading-[32px] ${match ? 'text-white' : 'text-foreground'} `}
|
||||||
|
>
|
||||||
|
{version?.version ?? '-'}
|
||||||
|
</h3>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="light"
|
variant="light"
|
||||||
color="default"
|
color="default"
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
try {
|
try {
|
||||||
await restartCore()
|
await restartCore()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert(e)
|
alert(e)
|
||||||
} finally {
|
} finally {
|
||||||
mutate()
|
mutate()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<IoMdRefresh
|
||||||
|
className={`${match ? 'text-white' : 'text-foreground'} text-[24px]`}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
<CardFooter className="pt-1">
|
||||||
|
<div
|
||||||
|
className={`flex justify-between w-full text-md font-bold ${match ? 'text-white' : 'text-foreground'}`}
|
||||||
>
|
>
|
||||||
<IoMdRefresh className={`${match ? 'text-white' : 'text-foreground'} text-[24px]`} />
|
<h4>内核设置</h4>
|
||||||
</Button>
|
<h4>{calcTraffic(mem)}</h4>
|
||||||
</div>
|
</div>
|
||||||
</CardBody>
|
</CardFooter>
|
||||||
<CardFooter className="pt-1">
|
</Card>
|
||||||
<div
|
) : (
|
||||||
className={`flex justify-between w-full text-md font-bold ${match ? 'text-white' : 'text-foreground'}`}
|
<Card
|
||||||
>
|
fullWidth
|
||||||
<h4>内核设置</h4>
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
<h4>{calcTraffic(mem)}</h4>
|
isPressable
|
||||||
</div>
|
onPress={() => navigate('/mihomo')}
|
||||||
</CardFooter>
|
>
|
||||||
</Card>
|
<CardBody className="pb-1 pt-0 px-0">
|
||||||
|
<div ref={setNodeRef} {...attributes} {...listeners} className="flex justify-between">
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
className="bg-transparent pointer-events-none"
|
||||||
|
variant="flat"
|
||||||
|
color="default"
|
||||||
|
>
|
||||||
|
<LuCpu
|
||||||
|
color="default"
|
||||||
|
className={`${match ? 'text-white' : 'text-foreground'} text-[24px] font-bold`}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
<CardFooter className="pt-1">
|
||||||
|
<h3 className={`text-md font-bold ${match ? 'text-white' : 'text-foreground'}`}>
|
||||||
|
内核设置
|
||||||
|
</h3>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,11 @@ import { MdFormatOverline } from 'react-icons/md'
|
|||||||
import { useLocation, useNavigate } 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'
|
||||||
|
|
||||||
const OverrideCard: React.FC = () => {
|
const OverrideCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { overrideCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/override')
|
const match = location.pathname.includes('/override')
|
||||||
@ -28,11 +31,11 @@ const OverrideCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1"
|
className={overrideCardStatus}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
className={`col-span-1 ${match ? 'bg-primary' : ''}`}
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
isPressable
|
isPressable
|
||||||
onPress={() => navigate('/override')}
|
onPress={() => navigate('/override')}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -11,11 +11,15 @@ import 'dayjs/locale/zh-cn'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import ConfigViewer from './config-viewer'
|
import ConfigViewer from './config-viewer'
|
||||||
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
|
import { TiFolder } from 'react-icons/ti'
|
||||||
|
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
dayjs.locale('zh-cn')
|
dayjs.locale('zh-cn')
|
||||||
|
|
||||||
const ProfileCard: React.FC = () => {
|
const ProfileCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { profileCardStatus = 'col-span-2' } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/profiles')
|
const match = location.pathname.includes('/profiles')
|
||||||
@ -52,98 +56,128 @@ const ProfileCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-2"
|
className={profileCardStatus}
|
||||||
>
|
>
|
||||||
{showRuntimeConfig && <ConfigViewer onClose={() => setShowRuntimeConfig(false)} />}
|
{showRuntimeConfig && <ConfigViewer onClose={() => setShowRuntimeConfig(false)} />}
|
||||||
<Card
|
{profileCardStatus === 'col-span-2' ? (
|
||||||
fullWidth
|
<Card
|
||||||
className={`${match ? 'bg-primary' : ''}`}
|
fullWidth
|
||||||
isPressable
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
onPress={() => navigate('/profiles')}
|
isPressable
|
||||||
>
|
onPress={() => navigate('/profiles')}
|
||||||
<CardBody className="pb-1">
|
>
|
||||||
<div
|
<CardBody className="pb-1">
|
||||||
ref={setNodeRef}
|
<div
|
||||||
{...attributes}
|
ref={setNodeRef}
|
||||||
{...listeners}
|
{...attributes}
|
||||||
className="flex justify-between h-[32px]"
|
{...listeners}
|
||||||
>
|
className="flex justify-between h-[32px]"
|
||||||
<h3
|
|
||||||
title={info?.name}
|
|
||||||
className={`text-ellipsis whitespace-nowrap overflow-hidden text-md font-bold leading-[32px] ${match ? 'text-white' : 'text-foreground'} `}
|
|
||||||
>
|
>
|
||||||
{info?.name}
|
<h3
|
||||||
</h3>
|
title={info?.name}
|
||||||
<div className="flex">
|
className={`text-ellipsis whitespace-nowrap overflow-hidden text-md font-bold leading-[32px] ${match ? 'text-white' : 'text-foreground'} `}
|
||||||
<Button
|
|
||||||
isIconOnly
|
|
||||||
size="sm"
|
|
||||||
title="查看当前运行时配置"
|
|
||||||
variant="light"
|
|
||||||
color="default"
|
|
||||||
onPress={() => {
|
|
||||||
setShowRuntimeConfig(true)
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<CgLoadbarDoc
|
{info?.name}
|
||||||
className={`text-[24px] ${match ? 'text-white' : 'text-foreground'}`}
|
</h3>
|
||||||
/>
|
<div className="flex">
|
||||||
</Button>
|
|
||||||
{info.type === 'remote' && (
|
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
size="sm"
|
size="sm"
|
||||||
title={dayjs(info.updated).fromNow()}
|
title="查看当前运行时配置"
|
||||||
disabled={updating}
|
|
||||||
variant="light"
|
variant="light"
|
||||||
color="default"
|
color="default"
|
||||||
onPress={async () => {
|
onPress={() => {
|
||||||
setUpdating(true)
|
setShowRuntimeConfig(true)
|
||||||
await addProfileItem(info)
|
|
||||||
setUpdating(false)
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IoMdRefresh
|
<CgLoadbarDoc
|
||||||
className={`text-[24px] ${match ? 'text-white' : 'text-foreground'} ${updating ? 'animate-spin' : ''}`}
|
className={`text-[24px] ${match ? 'text-white' : 'text-foreground'}`}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
{info.type === 'remote' && (
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
size="sm"
|
||||||
|
title={dayjs(info.updated).fromNow()}
|
||||||
|
disabled={updating}
|
||||||
|
variant="light"
|
||||||
|
color="default"
|
||||||
|
onPress={async () => {
|
||||||
|
setUpdating(true)
|
||||||
|
await addProfileItem(info)
|
||||||
|
setUpdating(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IoMdRefresh
|
||||||
|
className={`text-[24px] ${match ? 'text-white' : 'text-foreground'} ${updating ? 'animate-spin' : ''}`}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{info.type === 'remote' && extra && (
|
||||||
{info.type === 'remote' && extra && (
|
<div
|
||||||
<div
|
className={`mt-2 flex justify-between ${match ? 'text-white' : 'text-foreground'} `}
|
||||||
className={`mt-2 flex justify-between ${match ? 'text-white' : 'text-foreground'} `}
|
|
||||||
>
|
|
||||||
<small>{`${calcTraffic(usage)}/${calcTraffic(total)}`}</small>
|
|
||||||
<small>
|
|
||||||
{extra.expire ? dayjs.unix(extra.expire).format('YYYY-MM-DD') : '长期有效'}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{info.type === 'local' && (
|
|
||||||
<div
|
|
||||||
className={`mt-2 flex justify-between ${match ? 'text-white' : 'text-foreground'}`}
|
|
||||||
>
|
|
||||||
<Chip
|
|
||||||
size="sm"
|
|
||||||
variant="bordered"
|
|
||||||
className={`${match ? 'text-white border-white' : 'border-primary text-primary'}`}
|
|
||||||
>
|
>
|
||||||
本地
|
<small>{`${calcTraffic(usage)}/${calcTraffic(total)}`}</small>
|
||||||
</Chip>
|
<small>
|
||||||
|
{extra.expire ? dayjs.unix(extra.expire).format('YYYY-MM-DD') : '长期有效'}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{info.type === 'local' && (
|
||||||
|
<div
|
||||||
|
className={`mt-2 flex justify-between ${match ? 'text-white' : 'text-foreground'}`}
|
||||||
|
>
|
||||||
|
<Chip
|
||||||
|
size="sm"
|
||||||
|
variant="bordered"
|
||||||
|
className={`${match ? 'text-white border-white' : 'border-primary text-primary'}`}
|
||||||
|
>
|
||||||
|
本地
|
||||||
|
</Chip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardBody>
|
||||||
|
<CardFooter className="pt-0">
|
||||||
|
{extra && (
|
||||||
|
<Progress
|
||||||
|
className="w-full"
|
||||||
|
classNames={{ indicator: match ? 'bg-white' : 'bg-foreground' }}
|
||||||
|
value={calcPercent(extra?.upload, extra?.download, extra?.total)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<Card
|
||||||
|
fullWidth
|
||||||
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
|
isPressable
|
||||||
|
onPress={() => navigate('/profiles')}
|
||||||
|
>
|
||||||
|
<CardBody className="pb-1 pt-0 px-0">
|
||||||
|
<div ref={setNodeRef} {...attributes} {...listeners} className="flex justify-between">
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
className="bg-transparent pointer-events-none"
|
||||||
|
variant="flat"
|
||||||
|
color="default"
|
||||||
|
>
|
||||||
|
<TiFolder
|
||||||
|
color="default"
|
||||||
|
className={`${match ? 'text-white' : 'text-foreground'} text-[24px]`}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</CardBody>
|
||||||
</CardBody>
|
<CardFooter className="pt-1">
|
||||||
<CardFooter className="pt-0">
|
<h3 className={`text-md font-bold ${match ? 'text-white' : 'text-foreground'}`}>
|
||||||
{extra && (
|
订阅管理
|
||||||
<Progress
|
</h3>
|
||||||
className="w-full"
|
</CardFooter>
|
||||||
classNames={{ indicator: match ? 'bg-white' : 'bg-foreground' }}
|
</Card>
|
||||||
value={calcPercent(extra?.upload, extra?.download, extra?.total)}
|
)}
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</CardFooter>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,11 @@ import { CSS } from '@dnd-kit/utilities'
|
|||||||
import { LuGroup } from 'react-icons/lu'
|
import { LuGroup } from 'react-icons/lu'
|
||||||
import { useLocation, useNavigate } 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'
|
||||||
|
|
||||||
const ProxyCard: React.FC = () => {
|
const ProxyCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { proxyCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/proxies')
|
const match = location.pathname.includes('/proxies')
|
||||||
@ -30,7 +33,7 @@ const ProxyCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-2"
|
className={proxyCardStatus}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@ -4,7 +4,10 @@ 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'
|
||||||
const ResourceCard: React.FC = () => {
|
const ResourceCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { resourceCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/resources')
|
const match = location.pathname.includes('/resources')
|
||||||
@ -27,11 +30,11 @@ const ResourceCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1"
|
className={resourceCardStatus}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
className={`col-span-1 ${match ? 'bg-primary' : ''}`}
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
isPressable
|
isPressable
|
||||||
onPress={() => navigate('/resources')}
|
onPress={() => navigate('/resources')}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -4,8 +4,11 @@ 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'
|
||||||
|
|
||||||
const RuleCard: React.FC = () => {
|
const RuleCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { ruleCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/rules')
|
const match = location.pathname.includes('/rules')
|
||||||
@ -29,11 +32,11 @@ const RuleCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1"
|
className={ruleCardStatus}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
className={`col-span-1 ${match ? 'bg-primary' : ''}`}
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
isPressable
|
isPressable
|
||||||
onPress={() => navigate('/rules')}
|
onPress={() => navigate('/rules')}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -6,8 +6,11 @@ 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'
|
||||||
|
|
||||||
const SniffCard: React.FC = () => {
|
const SniffCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { sniffCardStatus = 'col-span-1', controlSniff = true } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/sniffer')
|
const match = location.pathname.includes('/sniffer')
|
||||||
@ -38,11 +41,11 @@ const SniffCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1"
|
className={`${sniffCardStatus} ${!controlSniff ? 'hidden' : ''}`}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
className={`col-span-1 ${match ? 'bg-primary' : ''}`}
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
isPressable
|
isPressable
|
||||||
onPress={() => navigate('/sniffer')}
|
onPress={() => navigate('/sniffer')}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -3,7 +3,10 @@ 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'
|
||||||
const SubStoreCard: React.FC = () => {
|
const SubStoreCard: React.FC = () => {
|
||||||
|
const { appConfig } = useAppConfig()
|
||||||
|
const { substoreCardStatus = 'col-span-1', useSubStore = true } = appConfig || {}
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/substore')
|
const match = location.pathname.includes('/substore')
|
||||||
@ -26,11 +29,11 @@ const SubStoreCard: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1"
|
className={`${substoreCardStatus} ${!useSubStore ? 'hidden' : ''}`}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
className={`col-span-1 ${match ? 'bg-primary' : ''}`}
|
className={`${match ? 'bg-primary' : ''}`}
|
||||||
isPressable
|
isPressable
|
||||||
onPress={() => navigate('/substore')}
|
onPress={() => navigate('/substore')}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -13,7 +13,7 @@ const SysproxySwitcher: React.FC = () => {
|
|||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/sysproxy')
|
const match = location.pathname.includes('/sysproxy')
|
||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
const { sysProxy } = appConfig || {}
|
const { sysProxy, sysproxyCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const { enable } = sysProxy || {}
|
const { enable } = sysProxy || {}
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
@ -44,7 +44,7 @@ const SysproxySwitcher: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1 "
|
className={sysproxyCardStatus}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@ -17,6 +17,7 @@ const TunSwitcher: React.FC = () => {
|
|||||||
const match = location.pathname.includes('/tun') || false
|
const match = location.pathname.includes('/tun') || false
|
||||||
const [openPasswordModal, setOpenPasswordModal] = useState(false)
|
const [openPasswordModal, setOpenPasswordModal] = useState(false)
|
||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
|
const { tunCardStatus = 'col-span-1' } = appConfig || {}
|
||||||
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
||||||
const { tun } = controledMihomoConfig || {}
|
const { tun } = controledMihomoConfig || {}
|
||||||
const { enable } = tun || {}
|
const { enable } = tun || {}
|
||||||
@ -62,7 +63,7 @@ const TunSwitcher: React.FC = () => {
|
|||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
className="col-span-1"
|
className={tunCardStatus}
|
||||||
>
|
>
|
||||||
{openPasswordModal && (
|
{openPasswordModal && (
|
||||||
<BasePasswordModal
|
<BasePasswordModal
|
||||||
|
|||||||
@ -96,7 +96,13 @@ const Connections: React.FC = () => {
|
|||||||
↓ {calcTraffic(connectionsInfo?.downloadTotal ?? 0)}{' '}
|
↓ {calcTraffic(connectionsInfo?.downloadTotal ?? 0)}{' '}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Badge color="primary" variant="flat" content={`${filteredConnections.length}`}>
|
<Badge
|
||||||
|
className="mt-2"
|
||||||
|
color="primary"
|
||||||
|
variant="flat"
|
||||||
|
showOutline={false}
|
||||||
|
content={`${filteredConnections.length}`}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
className="app-nodrag ml-1"
|
className="app-nodrag ml-1"
|
||||||
title="关闭全部连接"
|
title="关闭全部连接"
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import MihomoConfig from '@renderer/components/settings/mihomo-config'
|
|||||||
import Actions from '@renderer/components/settings/actions'
|
import Actions from '@renderer/components/settings/actions'
|
||||||
import ShortcutConfig from '@renderer/components/settings/shortcut-config'
|
import ShortcutConfig from '@renderer/components/settings/shortcut-config'
|
||||||
import { FaTelegramPlane } from 'react-icons/fa'
|
import { FaTelegramPlane } from 'react-icons/fa'
|
||||||
|
import SiderConfig from '@renderer/components/settings/sider-config'
|
||||||
|
|
||||||
const Settings: React.FC = () => {
|
const Settings: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
@ -55,6 +56,7 @@ const Settings: React.FC = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<GeneralConfig />
|
<GeneralConfig />
|
||||||
|
<SiderConfig />
|
||||||
<WebdavConfig />
|
<WebdavConfig />
|
||||||
<MihomoConfig />
|
<MihomoConfig />
|
||||||
<ShortcutConfig />
|
<ShortcutConfig />
|
||||||
|
|||||||
14
src/shared/types.d.ts
vendored
14
src/shared/types.d.ts
vendored
@ -1,6 +1,7 @@
|
|||||||
type OutboundMode = 'rule' | 'global' | 'direct'
|
type OutboundMode = 'rule' | 'global' | 'direct'
|
||||||
type LogLevel = 'info' | 'debug' | 'warning' | 'error' | 'silent'
|
type LogLevel = 'info' | 'debug' | 'warning' | 'error' | 'silent'
|
||||||
type SysProxyMode = 'auto' | 'manual'
|
type SysProxyMode = 'auto' | 'manual'
|
||||||
|
type CardStatus = 'col-span-2' | 'col-span-1' | 'hidden'
|
||||||
type AppTheme =
|
type AppTheme =
|
||||||
| 'system'
|
| 'system'
|
||||||
| 'light'
|
| 'light'
|
||||||
@ -219,6 +220,19 @@ interface IAppConfig {
|
|||||||
proxyCols: 'auto' | '1' | '2' | '3' | '4'
|
proxyCols: 'auto' | '1' | '2' | '3' | '4'
|
||||||
connectionDirection: 'asc' | 'desc'
|
connectionDirection: 'asc' | 'desc'
|
||||||
connectionOrderBy: 'time' | 'upload' | 'download' | 'uploadSpeed' | 'downloadSpeed'
|
connectionOrderBy: 'time' | 'upload' | 'download' | 'uploadSpeed' | 'downloadSpeed'
|
||||||
|
connectionCardStatus?: CardStatus
|
||||||
|
dnsCardStatus?: CardStatus
|
||||||
|
logCardStatus?: CardStatus
|
||||||
|
mihomoCoreCardStatus?: CardStatus
|
||||||
|
overrideCardStatus?: CardStatus
|
||||||
|
profileCardStatus?: CardStatus
|
||||||
|
proxyCardStatus?: CardStatus
|
||||||
|
resourceCardStatus?: CardStatus
|
||||||
|
ruleCardStatus?: CardStatus
|
||||||
|
sniffCardStatus?: CardStatus
|
||||||
|
substoreCardStatus?: CardStatus
|
||||||
|
sysproxyCardStatus?: CardStatus
|
||||||
|
tunCardStatus?: CardStatus
|
||||||
useSubStore: boolean
|
useSubStore: boolean
|
||||||
useCustomSubStore?: boolean
|
useCustomSubStore?: boolean
|
||||||
customSubStoreUrl?: string
|
customSubStoreUrl?: string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user