Chore: update dependencies and add class sort lint

This commit is contained in:
Dreamacro 2022-08-07 19:32:14 +08:00
parent ae31d8097a
commit 33d3bf15f1
15 changed files with 1064 additions and 789 deletions

View File

@ -2,6 +2,8 @@ extends:
- standard-with-typescript - standard-with-typescript
- airbnb/hooks - airbnb/hooks
- plugin:@typescript-eslint/recommended - plugin:@typescript-eslint/recommended
plugins:
- tailwindcss
parser: '@typescript-eslint/parser' parser: '@typescript-eslint/parser'
parserOptions: parserOptions:
project: './tsconfig.json' project: './tsconfig.json'
@ -18,6 +20,9 @@ rules:
newlines-between: always, newlines-between: always,
alphabetize: { order: asc } alphabetize: { order: asc }
}] }]
jsx-quotes: [error, prefer-double]
'tailwindcss/classnames-order': warn
'tailwindcss/no-contradicting-classname': error
'@typescript-eslint/indent': [error, 4] '@typescript-eslint/indent': [error, 4]
'@typescript-eslint/explicit-function-return-type': off '@typescript-eslint/explicit-function-return-type': off
'@typescript-eslint/restrict-template-expressions': off '@typescript-eslint/restrict-template-expressions': off

View File

@ -26,28 +26,29 @@
}, },
"devDependencies": { "devDependencies": {
"@types/lodash-es": "^4.17.6", "@types/lodash-es": "^4.17.6",
"@types/node": "^18.6.1", "@types/node": "^18.6.4",
"@types/react": "^18.0.15", "@types/react": "^18.0.16",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/react-virtualized-auto-sizer": "^1.0.1", "@types/react-virtualized-auto-sizer": "^1.0.1",
"@types/react-window": "^1.8.5", "@types/react-window": "^1.8.5",
"@typescript-eslint/eslint-plugin": "^5.31.0", "@typescript-eslint/eslint-plugin": "^5.32.0",
"@typescript-eslint/parser": "^5.31.0", "@typescript-eslint/parser": "^5.32.0",
"@vitejs/plugin-react": "^2.0.0", "@vitejs/plugin-react": "^2.0.0",
"eslint": "^8.20.0", "eslint": "^8.21.0",
"eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0", "eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-standard-with-typescript": "^22.0.0", "eslint-config-standard-with-typescript": "^22.0.0",
"eslint-import-resolver-typescript": "^3.3.0", "eslint-import-resolver-typescript": "^3.4.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.2.4", "eslint-plugin-n": "^15.2.4",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0", "eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"sass": "^1.54.0", "eslint-plugin-tailwindcss": "^3.6.0",
"type-fest": "^2.17.0", "sass": "^1.54.3",
"type-fest": "^2.18.0",
"typescript": "^4.7.4", "typescript": "^4.7.4",
"vite": "^3.0.3", "vite": "^3.0.4",
"vite-plugin-pwa": "^0.12.3", "vite-plugin-pwa": "^0.12.3",
"vite-plugin-windicss": "^1.8.7", "vite-plugin-windicss": "^1.8.7",
"vite-tsconfig-paths": "^3.5.0", "vite-tsconfig-paths": "^3.5.0",
@ -55,15 +56,15 @@
}, },
"dependencies": { "dependencies": {
"@react-hookz/web": "^15.0.1", "@react-hookz/web": "^15.0.1",
"@tanstack/react-table": "^8.3.3", "@tanstack/react-table": "^8.5.11",
"axios": "^0.27.2", "axios": "^0.27.2",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"dayjs": "^1.11.4", "dayjs": "^1.11.4",
"eventemitter3": "^4.0.7", "eventemitter3": "^4.0.7",
"immer": "^9.0.15", "immer": "^9.0.15",
"jotai": "^1.7.6", "jotai": "^1.7.7",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"neverthrow": "^4.4.2", "neverthrow": "^5.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",

1669
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@ export function Drawer (props: DrawerProps) {
const cardStyle = 'absolute h-full right-0 transition-transform transform translate-x-full duration-100 pointer-events-auto' const cardStyle = 'absolute h-full right-0 transition-transform transform translate-x-full duration-100 pointer-events-auto'
const container = ( const container = (
<div className={classnames(props.className, 'absolute inset-0 pointer-events-none z-9999')}> <div className={classnames(props.className, 'z-9999 pointer-events-none absolute inset-0')}>
<Card className={classnames(cardStyle, props.bodyClassName, { 'translate-x-0': props.visible })} style={{ width: props.width ?? 400 }}>{props.children}</Card> <Card className={classnames(cardStyle, props.bodyClassName, { 'translate-x-0': props.visible })} style={{ width: props.width ?? 400 }}>{props.children}</Card>
</div> </div>
) )

View File

@ -52,7 +52,7 @@ export function Tags (props: TagsProps) {
</ul> </ul>
{ {
showExtend && showExtend &&
<span className="h-7 px-5 select-none cursor-pointer leading-7" onClick={toggleExtend}>{ expand ? t('collapseText') : t('expandText') }</span> <span className="h-7 cursor-pointer select-none px-5 leading-7" onClick={toggleExtend}>{ expand ? t('collapseText') : t('expandText') }</span>
} }
</div> </div>
) )

View File

@ -23,7 +23,7 @@ export function Devices (props: DevicesProps) {
return ( return (
<div className={classname} style={style}> <div className={classname} style={style}>
<div className={classnames('connections-devices-item pt-2 mb-2', { selected: props.selected === '' })} onClick={() => handleSelected('')}> <div className={classnames('connections-devices-item mb-2 pt-2', { selected: props.selected === '' })} onClick={() => handleSelected('')}>
{ t('filter.all') } { t('filter.all') }
</div> </div>
{ {
@ -31,7 +31,7 @@ export function Devices (props: DevicesProps) {
device => ( device => (
<div <div
key={device.label} key={device.label}
className={classnames('connections-devices-item pt-2 mb-2', { selected: props.selected === device.label })} className={classnames('connections-devices-item mb-2 pt-2', { selected: props.selected === device.label })}
onClick={() => handleSelected(device.label)}> onClick={() => handleSelected(device.label)}>
{ device.label } ({ device.number }) { device.label } ({ device.number })
</div> </div>

View File

@ -16,83 +16,83 @@ export function ConnectionInfo (props: ConnectionsInfoProps) {
const t = useMemo(() => translation('Connections').t, [translation]) const t = useMemo(() => translation('Connections').t, [translation])
return ( return (
<div className={classnames(props.className, 'text-sm flex flex-col overflow-y-auto')}> <div className={classnames(props.className, 'flex flex-col overflow-y-auto text-sm')}>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.id')}</span> <span className="w-20 font-bold">{t('info.id')}</span>
<span className="font-mono">{props.connection.id}</span> <span className="font-mono">{props.connection.id}</span>
</div> </div>
<div className="flex my-3 justify-between"> <div className="my-3 flex justify-between">
<div className="flex flex-1"> <div className="flex flex-1">
<span className="font-bold w-20">{t('info.network')}</span> <span className="w-20 font-bold">{t('info.network')}</span>
<span className="font-mono">{props.connection.metadata?.network}</span> <span className="font-mono">{props.connection.metadata?.network}</span>
</div> </div>
<div className="flex flex-1"> <div className="flex flex-1">
<span className="font-bold w-20">{t('info.inbound')}</span> <span className="w-20 font-bold">{t('info.inbound')}</span>
<span className="font-mono">{props.connection.metadata?.type}</span> <span className="font-mono">{props.connection.metadata?.type}</span>
</div> </div>
</div> </div>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.host')}</span> <span className="w-20 font-bold">{t('info.host')}</span>
<span className="font-mono flex-1 break-all">{ <span className="flex-1 break-all font-mono">{
props.connection.metadata?.host props.connection.metadata?.host
? `${props.connection.metadata.host}:${props.connection.metadata?.destinationPort}` ? `${props.connection.metadata.host}:${props.connection.metadata?.destinationPort}`
: t('info.hostEmpty') : t('info.hostEmpty')
}</span> }</span>
</div> </div>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.dstIP')}</span> <span className="w-20 font-bold">{t('info.dstIP')}</span>
<span className="font-mono">{ <span className="font-mono">{
props.connection.metadata?.destinationIP props.connection.metadata?.destinationIP
? `${props.connection.metadata.destinationIP}:${props.connection.metadata?.destinationPort}` ? `${props.connection.metadata.destinationIP}:${props.connection.metadata?.destinationPort}`
: t('info.hostEmpty') : t('info.hostEmpty')
}</span> }</span>
</div> </div>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.srcIP')}</span> <span className="w-20 font-bold">{t('info.srcIP')}</span>
<span className="font-mono">{ <span className="font-mono">{
`${props.connection.metadata?.sourceIP}:${props.connection.metadata?.sourcePort}` `${props.connection.metadata?.sourceIP}:${props.connection.metadata?.sourcePort}`
}</span> }</span>
</div> </div>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.process')}</span> <span className="w-20 font-bold">{t('info.process')}</span>
<span className="font-mono flex-1 break-all">{ <span className="flex-1 break-all font-mono">{
props.connection.metadata?.processPath props.connection.metadata?.processPath
? `${basePath(props.connection.metadata.processPath)}` ? `${basePath(props.connection.metadata.processPath)}`
: t('info.hostEmpty') : t('info.hostEmpty')
}</span> }</span>
</div> </div>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.processPath')}</span> <span className="w-20 font-bold">{t('info.processPath')}</span>
<span className="font-mono flex-1 break-all">{ <span className="flex-1 break-all font-mono">{
props.connection.metadata?.processPath props.connection.metadata?.processPath
? `${props.connection.metadata.processPath}` ? `${props.connection.metadata.processPath}`
: t('info.hostEmpty') : t('info.hostEmpty')
}</span> }</span>
</div> </div>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.rule')}</span> <span className="w-20 font-bold">{t('info.rule')}</span>
<span className="font-mono"> <span className="font-mono">
{ props.connection.rule && `${props.connection.rule}${props.connection.rulePayload && ` :: ${props.connection.rulePayload}`}` } { props.connection.rule && `${props.connection.rule}${props.connection.rulePayload && ` :: ${props.connection.rulePayload}`}` }
</span> </span>
</div> </div>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.chains')}</span> <span className="w-20 font-bold">{t('info.chains')}</span>
<span className="font-mono flex-1 break-all"> <span className="flex-1 break-all font-mono">
{ props.connection.chains?.slice().reverse().join(' / ') } { props.connection.chains?.slice().reverse().join(' / ') }
</span> </span>
</div> </div>
<div className="flex my-3 justify-between"> <div className="my-3 flex justify-between">
<div className="flex flex-1"> <div className="flex flex-1">
<span className="font-bold w-20">{t('info.upload')}</span> <span className="w-20 font-bold">{t('info.upload')}</span>
<span className="font-mono">{formatTraffic(props.connection.upload ?? 0)}</span> <span className="font-mono">{formatTraffic(props.connection.upload ?? 0)}</span>
</div> </div>
<div className="flex flex-1"> <div className="flex flex-1">
<span className="font-bold w-20">{t('info.download')}</span> <span className="w-20 font-bold">{t('info.download')}</span>
<span className="font-mono">{formatTraffic(props.connection.download ?? 0)}</span> <span className="font-mono">{formatTraffic(props.connection.download ?? 0)}</span>
</div> </div>
</div> </div>
<div className="flex my-3"> <div className="my-3 flex">
<span className="font-bold w-20">{t('info.status')}</span> <span className="w-20 font-bold">{t('info.status')}</span>
<span className="font-mono">{ <span className="font-mono">{
!props.connection.completed !props.connection.completed
? <span className="text-green">{t('info.opening')}</span> ? <span className="text-green">{t('info.opening')}</span>

View File

@ -273,7 +273,7 @@ export default function Connections () {
return ( return (
<div className="page !h-100vh"> <div className="page !h-100vh">
<Header title={t('title')}> <Header title={t('title')}>
<span className="cursor-default flex-1 connections-filter"> <span className="connections-filter flex-1 cursor-default">
{`(${t('total.text')}: ${t('total.upload')} ${formatTraffic(traffic.uploadTotal)} ${t('total.download')} ${formatTraffic(traffic.downloadTotal)})`} {`(${t('total.text')}: ${t('total.upload')} ${formatTraffic(traffic.uploadTotal)} ${t('total.download')} ${formatTraffic(traffic.downloadTotal)})`}
</span> </span>
<Checkbox className="connections-filter" checked={save} onChange={toggleSave}>{t('keepClosed')}</Checkbox> <Checkbox className="connections-filter" checked={save} onChange={toggleSave}>{t('keepClosed')}</Checkbox>
@ -281,7 +281,7 @@ export default function Connections () {
</Header> </Header>
{ devices.length > 1 && <Devices devices={devices} selected={device} onChange={handleDeviceSelected} /> } { devices.length > 1 && <Devices devices={devices} selected={device} onChange={handleDeviceSelected} /> }
<Card ref={cardRef} className="connections-card relative"> <Card ref={cardRef} className="connections-card relative">
<div className="overflow-auto min-h-full min-w-full"> <div className="min-h-full min-w-full overflow-auto">
<table> <table>
<thead> <thead>
<tr className="connections-header"> <tr className="connections-header">
@ -296,12 +296,12 @@ export default function Connections () {
</Card> </Card>
<Modal title={t('closeAll.title')} show={visible} onClose={hide} onOk={handleCloseConnections}>{t('closeAll.content')}</Modal> <Modal title={t('closeAll.title')} show={visible} onClose={hide} onOk={handleCloseConnections}>{t('closeAll.content')}</Modal>
<Drawer containerRef={cardRef} bodyClassName="flex flex-col" visible={drawerState.visible} width={450}> <Drawer containerRef={cardRef} bodyClassName="flex flex-col" visible={drawerState.visible} width={450}>
<div className="flex h-8 justify-between items-center"> <div className="flex h-8 items-center justify-between">
<span className="font-bold pl-3">{t('info.title')}</span> <span className="pl-3 font-bold">{t('info.title')}</span>
<Icon type="close" size={16} className="cursor-pointer" onClick={() => setDrawerState('visible', false)} /> <Icon type="close" size={16} className="cursor-pointer" onClick={() => setDrawerState('visible', false)} />
</div> </div>
<ConnectionInfo className="mt-3 px-5" connection={drawerState.connection} /> <ConnectionInfo className="mt-3 px-5" connection={drawerState.connection} />
<div className="flex mt-3 pr-3 justify-end"> <div className="mt-3 flex justify-end pr-3">
<Button type="danger" disiabled={drawerState.connection.completed} onClick={() => handleConnectionClosed()}>{ t('info.closeConnection') }</Button> <Button type="danger" disiabled={drawerState.connection.completed} onClick={() => handleConnectionClosed()}>{ t('info.closeConnection') }</Button>
</div> </div>
</Drawer> </Drawer>

View File

@ -42,9 +42,9 @@ export default function ExternalController () {
<p>{t('externalControllerSetting.note')}</p> <p>{t('externalControllerSetting.note')}</p>
</Alert> </Alert>
<div className="flex items-center"> <div className="flex items-center">
<span className="font-bold my-1 w-14 md:my-3">{t('externalControllerSetting.host')}</span> <span className="my-1 w-14 font-bold md:my-3">{t('externalControllerSetting.host')}</span>
<Input <Input
className="flex-1 my-1 md:my-3" className="my-1 flex-1 md:my-3"
align="left" align="left"
inside={true} inside={true}
value={value.hostname} value={value.hostname}
@ -53,9 +53,9 @@ export default function ExternalController () {
/> />
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<div className="font-bold my-1 w-14 md:my-3">{t('externalControllerSetting.port')}</div> <div className="my-1 w-14 font-bold md:my-3">{t('externalControllerSetting.port')}</div>
<Input <Input
className="flex-1 my-1 w-14 md:my-3" className="my-1 w-14 flex-1 md:my-3"
align="left" align="left"
inside={true} inside={true}
value={value.port} value={value.port}
@ -64,9 +64,9 @@ export default function ExternalController () {
/> />
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<div className="font-bold my-1 w-14 md:my-3">{t('externalControllerSetting.secret')}</div> <div className="my-1 w-14 font-bold md:my-3">{t('externalControllerSetting.secret')}</div>
<Input <Input
className="flex-1 my-1 w-14 md:my-3" className="my-1 w-14 flex-1 md:my-3"
align="left" align="left"
inside={true} inside={true}
value={value.secret} value={value.secret}

View File

@ -58,7 +58,7 @@ export default function Logs () {
return ( return (
<div className="page"> <div className="page">
<Header title={ t('title') } > <Header title={ t('title') } >
<span className="text-sm text-primary-darken mr-2">{t('levelLabel')}:</span> <span className="text-primary-darken mr-2 text-sm">{t('levelLabel')}:</span>
<Select <Select
options={logLevelOptions} options={logLevelOptions}
value={camelCase(logLevel)} value={camelCase(logLevel)}
@ -66,12 +66,12 @@ export default function Logs () {
/> />
</Header> </Header>
<Card className="flex flex-col flex-1 mt-2.5 md:mt-4"> <Card className="mt-2.5 flex flex-1 flex-col md:mt-4">
<ul className="logs-panel" ref={listRef}> <ul className="logs-panel" ref={listRef}>
{ {
logs.map( logs.map(
(log, index) => ( (log, index) => (
<li className="leading-5 inline-block text-[11px]" key={index}> <li className="inline-block text-[11px] leading-5" key={index}>
<span className="mr-2 text-orange-400">[{ dayjs(log.time).format('YYYY-MM-DD HH:mm:ss') }]</span> <span className="mr-2 text-orange-400">[{ dayjs(log.time).format('YYYY-MM-DD HH:mm:ss') }]</span>
<span className={logMap.get(log.type)}>[{ log.type.toUpperCase() }]</span> <span className={logMap.get(log.type)}>[{ log.type.toUpperCase() }]</span>
<span> { log.payload }</span> <span> { log.payload }</span>

View File

@ -49,8 +49,8 @@ export function Group (props: GroupProps) {
const canClick = config.type === 'Selector' const canClick = config.type === 'Selector'
return ( return (
<div className="proxy-group"> <div className="proxy-group">
<div className="flex h-10 mt-4 w-full items-center justify-between md:(h-15 mt-0 w-auto) "> <div className="md:h-15 mt-4 flex h-10 w-full items-center justify-between md:mt-0 md:w-auto">
<span className="h-6 px-5 w-35 overflow-hidden overflow-ellipsis whitespace-nowrap md:w-30">{ config.name }</span> <span className="w-35 md:w-30 h-6 overflow-hidden overflow-ellipsis whitespace-nowrap px-5">{ config.name }</span>
<Tag className="mr-5 md:mr-0">{ config.type }</Tag> <Tag className="mr-5 md:mr-0">{ config.type }</Tag>
</div> </div>
<div className="flex-1 py-2 md:py-4"> <div className="flex-1 py-2 md:py-4">

View File

@ -41,17 +41,17 @@ export function Provider (props: ProvidersProps) {
return ( return (
<Card className="proxy-provider"> <Card className="proxy-provider">
<Loading visible={visible} /> <Loading visible={visible} />
<div className="flex flex-col justify-between md:(flex-row items-center) "> <div className="md:(flex-row items-center) flex flex-col justify-between ">
<div className="flex items-center"> <div className="flex items-center">
<span className="mr-6">{ provider.name }</span> <span className="mr-6">{ provider.name }</span>
<Tag>{ provider.vehicleType }</Tag> <Tag>{ provider.vehicleType }</Tag>
</div> </div>
<div className="flex pt-3 items-center md:pt-0"> <div className="flex items-center pt-3 md:pt-0">
{ {
provider.updatedAt && provider.updatedAt &&
<span className="text-sm">{ `${t('providerUpdateTime')}: ${fromNow(new Date(provider.updatedAt), lang)}`}</span> <span className="text-sm">{ `${t('providerUpdateTime')}: ${fromNow(new Date(provider.updatedAt), lang)}`}</span>
} }
<Icon className="cursor-pointer text-red pl-5" type="healthcheck" size={18} onClick={handleHealthChech} /> <Icon className="text-red cursor-pointer pl-5" type="healthcheck" size={18} onClick={handleHealthChech} />
<Icon className="cursor-pointer pl-5" type="update" size={18} onClick={handleUpdate} /> <Icon className="cursor-pointer pl-5" type="update" size={18} onClick={handleUpdate} />
</div> </div>
</div> </div>

View File

@ -45,7 +45,7 @@ function ProxyGroups () {
<div className="flex flex-col"> <div className="flex flex-col">
<Header title={t('groupTitle')}> <Header title={t('groupTitle')}>
<Checkbox <Checkbox
className="cursor-pointer text-sm text-shadow-primary text-primary-600" className="text-shadow-primary text-primary-600 cursor-pointer text-sm"
checked={config.breakConnections} checked={config.breakConnections}
onChange={value => setConfig('breakConnections', value)}> onChange={value => setConfig('breakConnections', value)}>
{t('breakConnectionsText')} {t('breakConnectionsText')}

View File

@ -18,7 +18,7 @@ function RuleProviders () {
providers.length !== 0 && providers.length !== 0 &&
<div className="flex flex-col"> <div className="flex flex-col">
<Header title={t('providerTitle')} /> <Header title={t('providerTitle')} />
<Card className="divide-y rounded shadow-primary mt-4 p-0"> <Card className="shadow-primary mt-4 divide-y rounded p-0">
{ {
providers.map(p => ( providers.map(p => (
<Provider key={p.name} provider={p} /> <Provider key={p.name} provider={p} />
@ -42,9 +42,9 @@ export default function Rules () {
return ( return (
<li className="rule-item" style={style}> <li className="rule-item" style={style}>
<div className="flex py-1"> <div className="flex py-1">
<div className="text-center w-40 rule-type">{ rule.type }</div> <div className="rule-type w-40 text-center">{ rule.type }</div>
<div className="flex-1 text-center payload">{ rule.payload }</div> <div className="payload flex-1 text-center">{ rule.payload }</div>
<div className="text-center w-40 rule-proxy">{ rule.proxy }</div> <div className="rule-proxy w-40 text-center">{ rule.proxy }</div>
</div> </div>
</li> </li>
) )
@ -54,7 +54,7 @@ export default function Rules () {
<div className="page"> <div className="page">
<RuleProviders /> <RuleProviders />
<Header className="not-first:mt-7.5" title={t('title')} /> <Header className="not-first:mt-7.5" title={t('title')} />
<Card className="flex flex-col flex-1 mt-2.5 p-0 md:mt-4 focus:outline-none"> <Card className="mt-2.5 flex flex-1 flex-col p-0 focus:outline-none md:mt-4">
<AutoSizer className="min-h-120"> <AutoSizer className="min-h-120">
{ {
({ height, width }) => ( ({ height, width }) => (

View File

@ -100,26 +100,26 @@ export default function Settings () {
<Header title={t('title')} /> <Header title={t('title')} />
<Card className="settings-card"> <Card className="settings-card">
<div className="flex flex-wrap"> <div className="flex flex-wrap">
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.startAtLogin')}</span> <span className="label font-bold">{t('labels.startAtLogin')}</span>
<Switch disabled={!clashXData?.isClashX} checked={startAtLogin} onChange={handleStartAtLoginChange} /> <Switch disabled={!clashXData?.isClashX} checked={startAtLogin} onChange={handleStartAtLoginChange} />
</div> </div>
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.language')}</span> <span className="label font-bold">{t('labels.language')}</span>
<ButtonSelect options={languageOptions} value={lang} onSelect={(lang) => changeLanguage(lang as Lang)} /> <ButtonSelect options={languageOptions} value={lang} onSelect={(lang) => changeLanguage(lang as Lang)} />
</div> </div>
</div> </div>
<div className="flex flex-wrap"> <div className="flex flex-wrap">
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.setAsSystemProxy')}</span> <span className="label font-bold">{t('labels.setAsSystemProxy')}</span>
<Switch <Switch
disabled={!isClashX} disabled={!isClashX}
checked={systemProxy} checked={systemProxy}
onChange={handleSetSystemProxy} onChange={handleSetSystemProxy}
/> />
</div> </div>
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.allowConnectFromLan')}</span> <span className="label font-bold">{t('labels.allowConnectFromLan')}</span>
<Switch checked={allowLan} onChange={handleAllowLanChange} /> <Switch checked={allowLan} onChange={handleAllowLanChange} />
</div> </div>
</div> </div>
@ -127,16 +127,16 @@ export default function Settings () {
<Card className="settings-card"> <Card className="settings-card">
<div className="flex flex-wrap"> <div className="flex flex-wrap">
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.proxyMode')}</span> <span className="label font-bold">{t('labels.proxyMode')}</span>
<ButtonSelect <ButtonSelect
options={proxyModeOptions} options={proxyModeOptions}
value={capitalize(mode)} value={capitalize(mode)}
onSelect={handleProxyModeChange} onSelect={handleProxyModeChange}
/> />
</div> </div>
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.socks5ProxyPort')}</span> <span className="label font-bold">{t('labels.socks5ProxyPort')}</span>
<Input <Input
className="w-28" className="w-28"
disabled={isClashX} disabled={isClashX}
@ -147,8 +147,8 @@ export default function Settings () {
</div> </div>
</div> </div>
<div className="flex flex-wrap"> <div className="flex flex-wrap">
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.httpProxyPort')}</span> <span className="label font-bold">{t('labels.httpProxyPort')}</span>
<Input <Input
className="w-28" className="w-28"
disabled={isClashX} disabled={isClashX}
@ -157,8 +157,8 @@ export default function Settings () {
onBlur={handleHttpPortSave} onBlur={handleHttpPortSave}
/> />
</div> </div>
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.mixedProxyPort')}</span> <span className="label font-bold">{t('labels.mixedProxyPort')}</span>
<Input <Input
className="w-28" className="w-28"
disabled={isClashX} disabled={isClashX}
@ -169,15 +169,15 @@ export default function Settings () {
</div> </div>
</div> </div>
<div className="flex flex-wrap"> <div className="flex flex-wrap">
<div className="flex w-full py-3 px-8 items-center justify-between md:w-1/2"> <div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
<span className="font-bold label">{t('labels.externalController')}</span> <span className="label font-bold">{t('labels.externalController')}</span>
<span <span
className={classnames({ 'modify-btn': !isClashX }, 'external-controller')} className={classnames({ 'modify-btn': !isClashX }, 'external-controller')}
onClick={() => !isClashX && setIdentity(false)}> onClick={() => !isClashX && setIdentity(false)}>
{`${externalControllerHost}:${externalControllerPort}`} {`${externalControllerHost}:${externalControllerPort}`}
</span> </span>
</div> </div>
<div className="px-8 w-1/2"></div> <div className="w-1/2 px-8"></div>
</div> </div>
</Card> </Card>
{/* <Card className="clash-version hidden"> {/* <Card className="clash-version hidden">