mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 05:51:56 +08:00
Chore: use unocss instead of windicss
This commit is contained in:
parent
cc111b69d3
commit
6b2992de32
@ -2,8 +2,7 @@ extends:
|
|||||||
- standard-with-typescript
|
- standard-with-typescript
|
||||||
- airbnb/hooks
|
- airbnb/hooks
|
||||||
- plugin:@typescript-eslint/recommended
|
- plugin:@typescript-eslint/recommended
|
||||||
plugins:
|
- '@unocss'
|
||||||
- tailwindcss
|
|
||||||
parser: '@typescript-eslint/parser'
|
parser: '@typescript-eslint/parser'
|
||||||
parserOptions:
|
parserOptions:
|
||||||
project: './tsconfig.json'
|
project: './tsconfig.json'
|
||||||
@ -21,8 +20,6 @@ rules:
|
|||||||
alphabetize: { order: asc }
|
alphabetize: { order: asc }
|
||||||
}]
|
}]
|
||||||
jsx-quotes: [error, prefer-double]
|
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
|
||||||
|
51
package.json
51
package.json
@ -26,53 +26,54 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash-es": "^4.17.6",
|
"@types/lodash-es": "^4.17.6",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.14.0",
|
||||||
"@types/react": "^18.0.27",
|
"@types/react": "^18.0.28",
|
||||||
"@types/react-dom": "^18.0.10",
|
"@types/react-dom": "^18.0.11",
|
||||||
"@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.48.2",
|
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
||||||
"@typescript-eslint/parser": "^5.48.2",
|
"@typescript-eslint/parser": "^5.53.0",
|
||||||
"@vitejs/plugin-react": "^3.0.1",
|
"@unocss/eslint-config": "^0.49.7",
|
||||||
"eslint": "^8.32.0",
|
"@unocss/preset-wind": "^0.49.7",
|
||||||
|
"@unocss/reset": "^0.49.7",
|
||||||
|
"@vitejs/plugin-react": "^3.1.0",
|
||||||
|
"eslint": "^8.34.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": "^31.0.0",
|
"eslint-config-standard-with-typescript": "^34.0.0",
|
||||||
"eslint-import-resolver-typescript": "^3.5.3",
|
"eslint-import-resolver-typescript": "^3.5.3",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||||
"eslint-plugin-n": "^15.6.1",
|
"eslint-plugin-n": "^15.6.1",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"eslint-plugin-react": "^7.32.1",
|
"eslint-plugin-react": "^7.32.2",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-tailwindcss": "^3.8.0",
|
"sass": "^1.58.3",
|
||||||
"sass": "^1.57.1",
|
"type-fest": "^3.6.0",
|
||||||
"type-fest": "^3.5.2",
|
"typescript": "^4.9.5",
|
||||||
"typescript": "^4.9.4",
|
"unocss": "^0.49.7",
|
||||||
"vite": "^4.0.4",
|
"vite": "^4.1.3",
|
||||||
"vite-plugin-pwa": "^0.14.1",
|
"vite-plugin-pwa": "^0.14.4",
|
||||||
"vite-plugin-windicss": "^1.8.10",
|
"vite-tsconfig-paths": "^4.0.5"
|
||||||
"vite-tsconfig-paths": "^4.0.5",
|
|
||||||
"windicss": "^3.5.6"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-hookz/web": "^22.0.0",
|
"@react-hookz/web": "^22.0.0",
|
||||||
"@tanstack/react-table": "^8.7.6",
|
"@tanstack/react-table": "^8.7.9",
|
||||||
"axios": "^1.2.3",
|
"axios": "^1.3.3",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"eventemitter3": "^5.0.0",
|
"eventemitter3": "^5.0.0",
|
||||||
"immer": "^9.0.18",
|
"immer": "^9.0.19",
|
||||||
"jotai": "^1.13.1",
|
"jotai": "^2.0.2",
|
||||||
"jotai-immer": "^0.1.0",
|
"jotai-immer": "^0.2.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"neverthrow": "^6.0.0",
|
"neverthrow": "^6.0.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^6.7.0",
|
"react-router-dom": "^6.8.1",
|
||||||
"react-virtualized-auto-sizer": "^1.0.7",
|
"react-virtualized-auto-sizer": "^1.0.7",
|
||||||
"react-window": "^1.8.8",
|
"react-window": "^1.8.8",
|
||||||
"swr": "^2.0.1",
|
"swr": "^2.0.3",
|
||||||
"use-immer": "^0.8.1"
|
"use-immer": "^0.8.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2113
pnpm-lock.yaml
generated
2113
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
import { Icon } from '@components'
|
import { Icon } from '@components'
|
||||||
import { BaseComponentProps } from '@models'
|
import { type BaseComponentProps } from '@models'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface AlertProps extends BaseComponentProps {
|
interface AlertProps extends BaseComponentProps {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { MouseEventHandler } from 'react'
|
import { type MouseEventHandler } from 'react'
|
||||||
|
|
||||||
import { noop } from '@lib/helper'
|
import { noop } from '@lib/helper'
|
||||||
import { BaseComponentProps } from '@models'
|
import { type BaseComponentProps } from '@models'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface ButtonProps extends BaseComponentProps {
|
interface ButtonProps extends BaseComponentProps {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
export interface ButtonSelectOptions<T = string> {
|
export interface ButtonSelectOptions<T = string> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { forwardRef } from 'react'
|
import { forwardRef } from 'react'
|
||||||
|
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface CardProps extends BaseComponentProps {
|
interface CardProps extends BaseComponentProps {
|
||||||
|
@ -2,7 +2,7 @@ import classnames from 'classnames'
|
|||||||
|
|
||||||
import { Icon } from '@components'
|
import { Icon } from '@components'
|
||||||
import { noop } from '@lib/helper'
|
import { noop } from '@lib/helper'
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface CheckboxProps extends BaseComponentProps {
|
interface CheckboxProps extends BaseComponentProps {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { useLayoutEffect, useRef, RefObject } from 'react'
|
import { useLayoutEffect, useRef, type RefObject } from 'react'
|
||||||
import { createPortal } from 'react-dom'
|
import { createPortal } from 'react-dom'
|
||||||
|
|
||||||
import { Card } from '@components'
|
import { Card } from '@components'
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
|
|
||||||
interface DrawerProps extends BaseComponentProps {
|
interface DrawerProps extends BaseComponentProps {
|
||||||
visible?: boolean
|
visible?: boolean
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface HeaderProps extends BaseComponentProps {
|
interface HeaderProps extends BaseComponentProps {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
|
|
||||||
interface IconProps extends BaseComponentProps {
|
interface IconProps extends BaseComponentProps {
|
||||||
// icon type
|
// icon type
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { KeyboardEvent, FocusEvent, ChangeEvent } from 'react'
|
import { type KeyboardEvent, type FocusEvent, type ChangeEvent } from 'react'
|
||||||
|
|
||||||
import { noop } from '@lib/helper'
|
import { noop } from '@lib/helper'
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface InputProps extends BaseComponentProps {
|
interface InputProps extends BaseComponentProps {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
|
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
|
|
||||||
import { Spinner } from './Spinner'
|
import { Spinner } from './Spinner'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { useRef, useLayoutEffect, MouseEvent } from 'react'
|
import { useRef, useLayoutEffect, type MouseEvent } from 'react'
|
||||||
import { createPortal } from 'react-dom'
|
import { createPortal } from 'react-dom'
|
||||||
|
|
||||||
import { Button } from '@components'
|
import { Button } from '@components'
|
||||||
import { noop } from '@lib/helper'
|
import { noop } from '@lib/helper'
|
||||||
import { BaseComponentProps } from '@models'
|
import { type BaseComponentProps } from '@models'
|
||||||
import { useI18n } from '@stores'
|
import { useI18n } from '@stores'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ export function Modal (props: ModalProps) {
|
|||||||
footer && (
|
footer && (
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
{footerExtra}
|
{footerExtra}
|
||||||
<div className="flex flex-1 justify-end space-x-3">
|
<div className="flex justify-end flex-1 space-x-3">
|
||||||
<Button onClick={() => onClose()}>{ t('cancel') }</Button>
|
<Button onClick={() => onClose()}>{ t('cancel') }</Button>
|
||||||
<Button type="primary" onClick={() => onOk()}>{ t('ok') }</Button>
|
<Button type="primary" onClick={() => onOk()}>{ t('ok') }</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { useRef, useState, useMemo, useLayoutEffect, ReactNode } from 'react'
|
import { useRef, useState, useMemo, useLayoutEffect, type ReactNode } from 'react'
|
||||||
import { createPortal } from 'react-dom'
|
import { createPortal } from 'react-dom'
|
||||||
|
|
||||||
import { Icon } from '@components'
|
import { Icon } from '@components'
|
||||||
import { noop } from '@lib/helper'
|
import { noop } from '@lib/helper'
|
||||||
import { BaseComponentProps } from '@models'
|
import { type BaseComponentProps } from '@models'
|
||||||
|
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import classnames from 'classnames'
|
|||||||
|
|
||||||
import { Icon } from '@components'
|
import { Icon } from '@components'
|
||||||
import { noop } from '@lib/helper'
|
import { noop } from '@lib/helper'
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface SwitchProps extends BaseComponentProps {
|
interface SwitchProps extends BaseComponentProps {
|
||||||
@ -23,7 +23,7 @@ export function Switch (props: SwitchProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classname} onClick={handleClick}>
|
<div className={classname} onClick={handleClick}>
|
||||||
<Icon className="switch-icon font-bold" type="check" size={20} />
|
<Icon className="font-bold switch-icon" type="check" size={20} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { type BaseComponentProps } from '@models/BaseProps'
|
||||||
|
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import classnames from 'classnames'
|
|||||||
import { useState, useRef, useLayoutEffect } from 'react'
|
import { useState, useRef, useLayoutEffect } from 'react'
|
||||||
|
|
||||||
import { noop } from '@lib/helper'
|
import { noop } from '@lib/helper'
|
||||||
import { BaseComponentProps } from '@models'
|
import { type BaseComponentProps } from '@models'
|
||||||
import { useI18n } from '@stores'
|
import { useI18n } from '@stores'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ export function Tags (props: TagsProps) {
|
|||||||
</ul>
|
</ul>
|
||||||
{
|
{
|
||||||
showExtend &&
|
showExtend &&
|
||||||
<span className="h-7 cursor-pointer select-none px-5 leading-7" onClick={toggleExtend}>{ expand ? t('collapseText') : t('expandText') }</span>
|
<span className="select-none cursor-pointer h-7 leading-7 px-5" onClick={toggleExtend}>{ expand ? t('collapseText') : t('expandText') }</span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { BaseComponentProps } from '@models'
|
import { type BaseComponentProps } from '@models'
|
||||||
import { useI18n } from '@stores'
|
import { useI18n } from '@stores'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
|
@ -2,10 +2,10 @@ import classnames from 'classnames'
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { basePath, formatTraffic } from '@lib/helper'
|
import { basePath, formatTraffic } from '@lib/helper'
|
||||||
import { BaseComponentProps } from '@models'
|
import { type BaseComponentProps } from '@models'
|
||||||
import { useI18n } from '@stores'
|
import { useI18n } from '@stores'
|
||||||
|
|
||||||
import { Connection } from '../store'
|
import { type Connection } from '../store'
|
||||||
|
|
||||||
interface ConnectionsInfoProps extends BaseComponentProps {
|
interface ConnectionsInfoProps extends BaseComponentProps {
|
||||||
connection: Partial<Connection>
|
connection: Partial<Connection>
|
||||||
@ -17,82 +17,82 @@ export function ConnectionInfo (props: ConnectionsInfoProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames(props.className, 'flex flex-col overflow-y-auto text-sm')}>
|
<div className={classnames(props.className, 'flex flex-col overflow-y-auto text-sm')}>
|
||||||
<div className="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.id')}</span>
|
<span className="font-bold w-20">{t('info.id')}</span>
|
||||||
<span className="font-mono">{props.connection.id}</span>
|
<span className="font-mono">{props.connection.id}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="my-3 flex justify-between">
|
<div className="flex justify-between my-3">
|
||||||
<div className="flex flex-1">
|
<div className="flex flex-1">
|
||||||
<span className="w-20 font-bold">{t('info.network')}</span>
|
<span className="font-bold w-20">{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="w-20 font-bold">{t('info.inbound')}</span>
|
<span className="font-bold w-20">{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="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.host')}</span>
|
<span className="font-bold w-20">{t('info.host')}</span>
|
||||||
<span className="flex-1 break-all font-mono">{
|
<span className="flex-1 font-mono break-all">{
|
||||||
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="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.dstIP')}</span>
|
<span className="font-bold w-20">{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="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.srcIP')}</span>
|
<span className="font-bold w-20">{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="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.process')}</span>
|
<span className="font-bold w-20">{t('info.process')}</span>
|
||||||
<span className="flex-1 break-all font-mono">{
|
<span className="break-all flex-1 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="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.processPath')}</span>
|
<span className="font-bold w-20">{t('info.processPath')}</span>
|
||||||
<span className="flex-1 break-all font-mono">{
|
<span className="break-all flex-1 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="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.rule')}</span>
|
<span className="font-bold w-20">{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="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.chains')}</span>
|
<span className="font-bold w-20">{t('info.chains')}</span>
|
||||||
<span className="flex-1 break-all font-mono">
|
<span className="break-all flex-1 font-mono">
|
||||||
{ props.connection.chains?.slice().reverse().join(' / ') }
|
{ props.connection.chains?.slice().reverse().join(' / ') }
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="my-3 flex justify-between">
|
<div className="flex justify-between my-3">
|
||||||
<div className="flex flex-1">
|
<div className="flex flex-1">
|
||||||
<span className="w-20 font-bold">{t('info.upload')}</span>
|
<span className="font-bold w-20">{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="w-20 font-bold">{t('info.download')}</span>
|
<span className="font-bold w-20">{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="my-3 flex">
|
<div className="flex my-3">
|
||||||
<span className="w-20 font-bold">{t('info.status')}</span>
|
<span className="font-bold w-20">{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>
|
||||||
|
@ -8,12 +8,12 @@ import { Header, Checkbox, Modal, Icon, Drawer, Card, Button } from '@components
|
|||||||
import { fromNow } from '@lib/date'
|
import { fromNow } from '@lib/date'
|
||||||
import { basePath, formatTraffic } from '@lib/helper'
|
import { basePath, formatTraffic } from '@lib/helper'
|
||||||
import { useObject, useVisible } from '@lib/hook'
|
import { useObject, useVisible } from '@lib/hook'
|
||||||
import * as API from '@lib/request'
|
import type * as API from '@lib/request'
|
||||||
import { useClient, useConnectionStreamReader, useI18n } from '@stores'
|
import { useClient, useConnectionStreamReader, useI18n } from '@stores'
|
||||||
|
|
||||||
import { Devices } from './Devices'
|
import { Devices } from './Devices'
|
||||||
import { ConnectionInfo } from './Info'
|
import { ConnectionInfo } from './Info'
|
||||||
import { Connection, FormatConnection, useConnections } from './store'
|
import { type Connection, type FormatConnection, useConnections } from './store'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
const Columns = {
|
const Columns = {
|
||||||
@ -180,7 +180,7 @@ export default function Connections () {
|
|||||||
const [device, setDevice] = useState('')
|
const [device, setDevice] = useState('')
|
||||||
function handleDeviceSelected (label: string) {
|
function handleDeviceSelected (label: string) {
|
||||||
setDevice(label)
|
setDevice(label)
|
||||||
instance.getColumn(Columns.SourceIP).setFilterValue(label || undefined)
|
instance.getColumn(Columns.SourceIP)?.setFilterValue(label || undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
// click item
|
// click item
|
||||||
@ -243,7 +243,7 @@ export default function Connections () {
|
|||||||
const content = instance.getRowModel().rows.map(row => {
|
const content = instance.getRowModel().rows.map(row => {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
className="cursor-default select-none"
|
className="select-none cursor-default"
|
||||||
key={row.original?.id}
|
key={row.original?.id}
|
||||||
onClick={() => setDrawerState({ visible: true, selectedID: row.original?.id })}>
|
onClick={() => setDrawerState({ visible: true, selectedID: row.original?.id })}>
|
||||||
{
|
{
|
||||||
@ -271,9 +271,9 @@ export default function Connections () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page !h-100vh">
|
<div className="!h-100vh page">
|
||||||
<Header title={t('title')}>
|
<Header title={t('title')}>
|
||||||
<span className="connections-filter flex-1 cursor-default">
|
<span className="cursor-default flex-1 connections-filter">
|
||||||
{`(${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>
|
||||||
@ -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 items-center justify-between">
|
<div className="flex items-center justify-between h-8">
|
||||||
<span className="pl-3 font-bold">{t('info.title')}</span>
|
<span className="font-bold pl-3">{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="px-5 mt-3" connection={drawerState.connection} />
|
||||||
<div className="mt-3 flex justify-end pr-3">
|
<div className="flex justify-end mt-3 pr-3">
|
||||||
<Button type="danger" disabled={drawerState.connection.completed} onClick={() => handleConnectionClosed()}>{ t('info.closeConnection') }</Button>
|
<Button type="danger" disabled={drawerState.connection.completed} onClick={() => handleConnectionClosed()}>{ t('info.closeConnection') }</Button>
|
||||||
</div>
|
</div>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import { useState, useMemo, useRef, useCallback } from 'react'
|
import { useState, useMemo, useRef, useCallback } from 'react'
|
||||||
|
|
||||||
import * as API from '@lib/request'
|
import type * as API from '@lib/request'
|
||||||
|
|
||||||
export type Connection = API.Connections & { completed?: boolean, uploadSpeed: number, downloadSpeed: number }
|
export type Connection = API.Connections & { completed?: boolean, uploadSpeed: number, downloadSpeed: number }
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ export default function ExternalController () {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className="!w-105 !<sm:w-84"
|
className="!<sm:w-84 !w-105"
|
||||||
show={!identity}
|
show={!identity}
|
||||||
title={t('externalControllerSetting.title')}
|
title={t('externalControllerSetting.title')}
|
||||||
bodyClassName="external-controller"
|
bodyClassName="external-controller"
|
||||||
@ -73,9 +73,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="my-1 w-14 font-bold md:my-3">{t('externalControllerSetting.host')}</span>
|
<span className="font-bold md:my-3 my-1 w-14">{t('externalControllerSetting.host')}</span>
|
||||||
<Input
|
<Input
|
||||||
className="my-1 flex-1 md:my-3"
|
className="flex-1 md:my-3 my-1"
|
||||||
align="left"
|
align="left"
|
||||||
inside={true}
|
inside={true}
|
||||||
value={value.hostname}
|
value={value.hostname}
|
||||||
@ -84,9 +84,9 @@ export default function ExternalController () {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="my-1 w-14 font-bold md:my-3">{t('externalControllerSetting.port')}</div>
|
<div className="font-bold md:my-3 my-1 w-14">{t('externalControllerSetting.port')}</div>
|
||||||
<Input
|
<Input
|
||||||
className="my-1 w-14 flex-1 md:my-3"
|
className="flex-1 md:my-3 my-1 w-14"
|
||||||
align="left"
|
align="left"
|
||||||
inside={true}
|
inside={true}
|
||||||
value={value.port}
|
value={value.port}
|
||||||
@ -95,9 +95,9 @@ export default function ExternalController () {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="my-1 w-14 font-bold md:my-3">{t('externalControllerSetting.secret')}</div>
|
<div className="font-bold md:my-3 my-1 w-14">{t('externalControllerSetting.secret')}</div>
|
||||||
<Input
|
<Input
|
||||||
className="my-1 w-14 flex-1 md:my-3"
|
className="flex-1 md:my-3 my-1 w-14"
|
||||||
align="left"
|
align="left"
|
||||||
inside={true}
|
inside={true}
|
||||||
value={value.secret}
|
value={value.secret}
|
||||||
|
@ -3,7 +3,7 @@ import { lowerCase } from 'lodash-es'
|
|||||||
import { useLayoutEffect, useEffect, useRef, useState } from 'react'
|
import { useLayoutEffect, useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
import { Select, Card, Header } from '@components'
|
import { Select, Card, Header } from '@components'
|
||||||
import { Log } from '@models/Log'
|
import { type Log } from '@models/Log'
|
||||||
import { useConfig, useGeneral, useI18n, useLogsStreamReader } from '@stores'
|
import { useConfig, useGeneral, useI18n, useLogsStreamReader } from '@stores'
|
||||||
|
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
@ -61,7 +61,7 @@ export default function Logs () {
|
|||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<Header title={ t('title') } >
|
<Header title={ t('title') } >
|
||||||
<span className="text-primary-darken mr-2 text-sm">{t('levelLabel')}:</span>
|
<span className="mr-2 text-primary-darken text-sm">{t('levelLabel')}:</span>
|
||||||
<Select
|
<Select
|
||||||
disabled={isConfigSilent}
|
disabled={isConfigSilent}
|
||||||
options={logLevelOptions}
|
options={logLevelOptions}
|
||||||
@ -70,12 +70,12 @@ export default function Logs () {
|
|||||||
/>
|
/>
|
||||||
</Header>
|
</Header>
|
||||||
|
|
||||||
<Card className="mt-2.5 flex flex-1 flex-col md:mt-4">
|
<Card className="flex flex-1 flex-col md:mt-4 mt-2.5">
|
||||||
<ul className="logs-panel" ref={listRef}>
|
<ul className="logs-panel" ref={listRef}>
|
||||||
{
|
{
|
||||||
logs.map(
|
logs.map(
|
||||||
(log, index) => (
|
(log, index) => (
|
||||||
<li className="inline-block text-[11px] leading-5" key={index}>
|
<li className="inline-block leading-5 text-[11px]" 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>
|
||||||
|
@ -2,7 +2,7 @@ import { useAtom } from 'jotai'
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { Tags, Tag } from '@components'
|
import { Tags, Tag } from '@components'
|
||||||
import { Group as IGroup } from '@lib/request'
|
import { type Group as IGroup } from '@lib/request'
|
||||||
import { useProxy, useConfig, proxyMapping, useClient } from '@stores'
|
import { useProxy, useConfig, proxyMapping, useClient } from '@stores'
|
||||||
|
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
@ -49,13 +49,13 @@ 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="md:h-15 mt-4 flex h-10 w-full items-center justify-between md:mt-0 md:w-auto">
|
<div className="flex items-center justify-between h-10 md:h-15 md:mt-0 md:w-auto mt-4 w-full">
|
||||||
<span className="w-35 md:w-30 h-6 overflow-hidden overflow-ellipsis whitespace-nowrap px-5">{ config.name }</span>
|
<span className="px-5 h-6 md:w-30 overflow-ellipsis overflow-hidden w-35 whitespace-nowrap">{ config.name }</span>
|
||||||
<Tag className="mr-5 md:mr-0">{ config.type }</Tag>
|
<Tag className="md:mr-0 mr-5">{ config.type }</Tag>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 py-2 md:py-4">
|
<div className="flex-1 md:py-4 py-2">
|
||||||
<Tags
|
<Tags
|
||||||
className="ml-5 md:ml-8"
|
className="md:ml-8 ml-5"
|
||||||
data={config.all}
|
data={config.all}
|
||||||
onClick={handleChangeProxySelected}
|
onClick={handleChangeProxySelected}
|
||||||
errSet={errSet}
|
errSet={errSet}
|
||||||
|
@ -5,7 +5,7 @@ import { compareDesc } from '@containers/Proxies'
|
|||||||
import { Proxy } from '@containers/Proxies/components/Proxy'
|
import { Proxy } from '@containers/Proxies/components/Proxy'
|
||||||
import { fromNow } from '@lib/date'
|
import { fromNow } from '@lib/date'
|
||||||
import { useVisible } from '@lib/hook'
|
import { useVisible } from '@lib/hook'
|
||||||
import { Provider as IProvider, Proxy as IProxy } from '@lib/request'
|
import { type Provider as IProvider, type Proxy as IProxy } from '@lib/request'
|
||||||
import { useClient, useI18n, useProxyProviders } from '@stores'
|
import { useClient, useI18n, useProxyProviders } from '@stores'
|
||||||
|
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
@ -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="md:(flex-row items-center) flex flex-col justify-between">
|
<div className="flex flex-col justify-between md:flex-row md:items-center">
|
||||||
<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 items-center pt-3 md:pt-0">
|
<div className="flex items-center md:pt-0 pt-3">
|
||||||
{
|
{
|
||||||
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="text-red cursor-pointer pl-5" type="healthcheck" size={18} onClick={handleHealthChech} />
|
<Icon className="cursor-pointer text-red 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>
|
||||||
|
@ -5,8 +5,8 @@ import { useMemo, useLayoutEffect, useCallback } from 'react'
|
|||||||
|
|
||||||
import EE, { Action } from '@lib/event'
|
import EE, { Action } from '@lib/event'
|
||||||
import { isClashX, jsBridge } from '@lib/jsBridge'
|
import { isClashX, jsBridge } from '@lib/jsBridge'
|
||||||
import { Proxy as IProxy } from '@lib/request'
|
import { type Proxy as IProxy } from '@lib/request'
|
||||||
import { BaseComponentProps } from '@models'
|
import { type BaseComponentProps } from '@models'
|
||||||
import { useClient, useProxy } from '@stores'
|
import { useClient, useProxy } from '@stores'
|
||||||
|
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
@ -79,9 +79,9 @@ export function Proxy (props: ProxyProps) {
|
|||||||
</span>
|
</span>
|
||||||
<p className="proxy-name">{config.name}</p>
|
<p className="proxy-name">{config.name}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex h-full flex-col items-center justify-center space-y-3 text-[10px] md:h-[18px] md:flex-row md:justify-between md:space-y-0">
|
<div className="flex flex-col h-full items-center justify-center md:flex-row md:h-[18px] md:justify-between md:space-y-0 space-y-3 text-[10px]">
|
||||||
<p>{delay === 0 ? '-' : `${delay}ms`}</p>
|
<p>{delay === 0 ? '-' : `${delay}ms`}</p>
|
||||||
{ config.udp && <p className="rounded bg-gray-200 p-[3px] text-gray-600">UDP</p> }
|
{ config.udp && <p className="bg-gray-200 p-[3px] rounded text-gray-600">UDP</p> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -3,7 +3,7 @@ import { useMemo } from 'react'
|
|||||||
import { Card, Header, Icon, Checkbox } from '@components'
|
import { Card, Header, Icon, Checkbox } from '@components'
|
||||||
import EE from '@lib/event'
|
import EE from '@lib/event'
|
||||||
import { useRound } from '@lib/hook'
|
import { useRound } from '@lib/hook'
|
||||||
import * as API from '@lib/request'
|
import type * as API from '@lib/request'
|
||||||
import { useI18n, useConfig, useProxy, useProxyProviders, useGeneral } from '@stores'
|
import { useI18n, useConfig, useProxy, useProxyProviders, useGeneral } from '@stores'
|
||||||
|
|
||||||
import { Proxy, Group, Provider } from './components'
|
import { Proxy, Group, Provider } from './components'
|
||||||
@ -45,14 +45,14 @@ function ProxyGroups () {
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Header title={t('groupTitle')}>
|
<Header title={t('groupTitle')}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className="text-shadow-primary text-primary-600 cursor-pointer text-sm"
|
className="cursor-pointer text-sm text-primary-600 text-shadow-primary"
|
||||||
checked={config.breakConnections}
|
checked={config.breakConnections}
|
||||||
onChange={value => setConfig('breakConnections', value)}>
|
onChange={value => setConfig('breakConnections', value)}>
|
||||||
{t('breakConnectionsText')}
|
{t('breakConnectionsText')}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</Header>
|
</Header>
|
||||||
<Card className="my-2.5 p-0 md:my-4">
|
<Card className="md:my-4 my-2.5 p-0">
|
||||||
<ul className="list-none divide-y divide-gray-300">
|
<ul className="divide-gray-300 divide-y list-none">
|
||||||
{
|
{
|
||||||
list.map(p => (
|
list.map(p => (
|
||||||
<li key={p.name}>
|
<li key={p.name}>
|
||||||
@ -80,7 +80,7 @@ function ProxyProviders () {
|
|||||||
<ul className="list-none">
|
<ul className="list-none">
|
||||||
{
|
{
|
||||||
providers.map(p => (
|
providers.map(p => (
|
||||||
<li className="my-2.5 md:my-4" key={p.name}>
|
<li className="md:my-4 my-2.5" key={p.name}>
|
||||||
<Provider provider={p} />
|
<Provider provider={p} />
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
|
@ -3,7 +3,7 @@ import classnames from 'classnames'
|
|||||||
import { Tag, Icon } from '@components'
|
import { Tag, Icon } from '@components'
|
||||||
import { fromNow } from '@lib/date'
|
import { fromNow } from '@lib/date'
|
||||||
import { useVisible } from '@lib/hook'
|
import { useVisible } from '@lib/hook'
|
||||||
import { RuleProvider } from '@lib/request'
|
import { type RuleProvider } from '@lib/request'
|
||||||
import { useClient, useI18n, useRuleProviders } from '@stores'
|
import { useClient, useI18n, useRuleProviders } from '@stores'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
|
@ -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="shadow-primary mt-4 divide-y rounded p-0">
|
<Card className="divide-y mt-4 p-0 rounded shadow-primary">
|
||||||
{
|
{
|
||||||
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="rule-type w-40 text-center">{ rule.type }</div>
|
<div className="rule-type text-center w-40">{ rule.type }</div>
|
||||||
<div className="payload flex-1 text-center">{ rule.payload }</div>
|
<div className="flex-1 text-center payload">{ rule.payload }</div>
|
||||||
<div className="rule-proxy w-40 text-center">{ rule.proxy }</div>
|
<div className="text-center w-40 rule-proxy">{ 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="mt-2.5 flex flex-1 flex-col p-0 focus:outline-none md:mt-4">
|
<Card className="flex flex-1 flex-col md:mt-4 mt-2.5 p-0 focus:outline-none">
|
||||||
<AutoSizer className="min-h-120">
|
<AutoSizer className="min-h-120">
|
||||||
{
|
{
|
||||||
({ height, width }) => (
|
({ height, width }) => (
|
||||||
|
@ -3,8 +3,8 @@ import { useAtom, useAtomValue, useSetAtom } from 'jotai'
|
|||||||
import { capitalize } from 'lodash-es'
|
import { capitalize } from 'lodash-es'
|
||||||
import { useEffect, useMemo } from 'react'
|
import { useEffect, useMemo } from 'react'
|
||||||
|
|
||||||
import { Header, Card, Switch, ButtonSelect, ButtonSelectOptions, Input, Select } from '@components'
|
import { Header, Card, Switch, ButtonSelect, type ButtonSelectOptions, Input, Select } from '@components'
|
||||||
import { Lang } from '@i18n'
|
import { type Lang } from '@i18n'
|
||||||
import { useObject } from '@lib/hook'
|
import { useObject } from '@lib/hook'
|
||||||
import { jsBridge } from '@lib/jsBridge'
|
import { jsBridge } from '@lib/jsBridge'
|
||||||
import { useI18n, useClashXData, useGeneral, useVersion, useClient, identityAtom, hostSelectIdxStorageAtom, hostsStorageAtom } from '@stores'
|
import { useI18n, useClashXData, useGeneral, useVersion, useClient, identityAtom, hostSelectIdxStorageAtom, hostsStorageAtom } from '@stores'
|
||||||
@ -92,7 +92,7 @@ export default function Settings () {
|
|||||||
}, [t, premium])
|
}, [t, premium])
|
||||||
|
|
||||||
const controllerOptions = hostsStorage.map(
|
const controllerOptions = hostsStorage.map(
|
||||||
(h, idx) => ({ value: idx, label: <span className="truncate text-right">{h.hostname}</span> }),
|
(h, idx) => ({ value: idx, label: <span className="text-right truncate">{h.hostname}</span> }),
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -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 items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between w-full md:w-1/2 px-8 py-3">
|
||||||
<span className="label font-bold">{t('labels.startAtLogin')}</span>
|
<span className="font-bold label">{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 items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between md:w-1/2 px-8 py-3 w-full">
|
||||||
<span className="label font-bold">{t('labels.language')}</span>
|
<span className="font-bold label">{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 items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between md:w-1/2 px-8 py-3 w-full">
|
||||||
<span className="label font-bold">{t('labels.setAsSystemProxy')}</span>
|
<span className="font-bold label">{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 items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between md:w-1/2 px-8 py-3 w-full">
|
||||||
<span className="label font-bold">{t('labels.allowConnectFromLan')}</span>
|
<span className="font-bold label">{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 items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between md:w-1/2 px-8 py-3 w-full">
|
||||||
<span className="label font-bold">{t('labels.proxyMode')}</span>
|
<span className="font-bold label">{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 items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between md:w-1/2 px-8 py-3 w-full">
|
||||||
<span className="label font-bold">{t('labels.socks5ProxyPort')}</span>
|
<span className="font-bold label">{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 items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between md:w-1/2 px-8 py-3 w-full">
|
||||||
<span className="label font-bold">{t('labels.httpProxyPort')}</span>
|
<span className="font-bold label">{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 items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between md:w-1/2 px-8 py-3 w-full">
|
||||||
<span className="label font-bold">{t('labels.mixedProxyPort')}</span>
|
<span className="font-bold label">{t('labels.mixedProxyPort')}</span>
|
||||||
<Input
|
<Input
|
||||||
className="w-28"
|
className="w-28"
|
||||||
disabled={isClashX}
|
disabled={isClashX}
|
||||||
@ -169,8 +169,8 @@ export default function Settings () {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap">
|
<div className="flex flex-wrap">
|
||||||
<div className="flex w-full items-center justify-between py-3 px-8 md:w-1/2">
|
<div className="flex items-center justify-between md:w-1/2 px-8 py-3 w-full">
|
||||||
<span className="label font-bold">{t('labels.externalController')}</span>
|
<span className="font-bold label">{t('labels.externalController')}</span>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Select
|
<Select
|
||||||
disabled={hostsStorage.length < 2 && !isClashX}
|
disabled={hostsStorage.length < 2 && !isClashX}
|
||||||
@ -185,7 +185,7 @@ export default function Settings () {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-1/2 px-8"></div>
|
<div className="px-8 w-1/2"></div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
{/* <Card className="clash-version hidden">
|
{/* <Card className="clash-version hidden">
|
||||||
|
@ -2,7 +2,7 @@ import classnames from 'classnames'
|
|||||||
import { NavLink, useLocation } from 'react-router-dom'
|
import { NavLink, useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
import logo from '@assets/logo.png'
|
import logo from '@assets/logo.png'
|
||||||
import { Lang, Language } from '@i18n'
|
import { type Lang, type Language } from '@i18n'
|
||||||
import { useI18n, useVersion, useClashXData } from '@stores'
|
import { useI18n, useVersion, useClashXData } from '@stores'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { IsEqual } from 'type-fest'
|
import { type IsEqual } from 'type-fest'
|
||||||
|
|
||||||
import { Infer } from '@lib/type'
|
import { type Infer } from '@lib/type'
|
||||||
|
|
||||||
import en_US from './en_US'
|
import en_US from './en_US'
|
||||||
import zh_CN from './zh_CN'
|
import zh_CN from './zh_CN'
|
||||||
|
@ -2,7 +2,7 @@ import dayjs from 'dayjs'
|
|||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
import 'dayjs/locale/zh-cn'
|
import 'dayjs/locale/zh-cn'
|
||||||
|
|
||||||
import { Lang } from '@i18n'
|
import { type Lang } from '@i18n'
|
||||||
|
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable no-redeclare */
|
/* eslint-disable no-redeclare */
|
||||||
import { Draft } from 'immer'
|
import { type Draft } from 'immer'
|
||||||
import { useRef, useEffect, useState, useMemo } from 'react'
|
import { useRef, useEffect, useState, useMemo } from 'react'
|
||||||
import { useImmer } from 'use-immer'
|
import { useImmer } from 'use-immer'
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import produce, { Draft } from 'immer'
|
import produce, { type Draft } from 'immer'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
export type WritableDraft<T> = (draft: Draft<T>) => void
|
export type WritableDraft<T> = (draft: Draft<T>) => void
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import axios, { AxiosInstance } from 'axios'
|
import axios, { type AxiosInstance } from 'axios'
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
port: number
|
port: number
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import EventEmitter from 'eventemitter3'
|
import EventEmitter from 'eventemitter3'
|
||||||
import { SetRequired } from 'type-fest'
|
import { type SetRequired } from 'type-fest'
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
bufferLength?: number
|
bufferLength?: number
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CSSProperties, ReactNode } from 'react'
|
import { type CSSProperties, type ReactNode } from 'react'
|
||||||
|
|
||||||
export interface BaseComponentProps {
|
export interface BaseComponentProps {
|
||||||
className?: string
|
className?: string
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as API from '@lib/request'
|
import type * as API from '@lib/request'
|
||||||
|
|
||||||
import { Proxy, ProxyGroup } from './Proxy'
|
import { type Proxy, type ProxyGroup } from './Proxy'
|
||||||
import { Rule } from './Rule'
|
import { type Rule } from './Rule'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clash config
|
* clash config
|
||||||
|
@ -4,7 +4,8 @@ import { HashRouter } from 'react-router-dom'
|
|||||||
|
|
||||||
import { Loading } from '@components'
|
import { Loading } from '@components'
|
||||||
import App from '@containers/App'
|
import App from '@containers/App'
|
||||||
import 'virtual:windi.css'
|
import '@unocss/reset/tailwind.css'
|
||||||
|
import 'uno.css'
|
||||||
|
|
||||||
export default function renderApp () {
|
export default function renderApp () {
|
||||||
const rootEl = document.getElementById('root')
|
const rootEl = document.getElementById('root')
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { usePreviousDistinct, useSyncedRef } from '@react-hookz/web'
|
import { usePreviousDistinct, useSyncedRef } from '@react-hookz/web'
|
||||||
import { AxiosError } from 'axios'
|
import { type AxiosError } from 'axios'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
|
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
|
||||||
import { atomWithStorage } from 'jotai/utils'
|
import { atomWithStorage } from 'jotai/utils'
|
||||||
@ -8,18 +8,17 @@ import { get } from 'lodash-es'
|
|||||||
import { ResultAsync } from 'neverthrow'
|
import { ResultAsync } from 'neverthrow'
|
||||||
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { Get } from 'type-fest'
|
import { type Get } from 'type-fest'
|
||||||
|
|
||||||
import { Language, locales, Lang, getDefaultLanguage, LocalizedType } from '@i18n'
|
import { Language, locales, type Lang, getDefaultLanguage, type LocalizedType } from '@i18n'
|
||||||
import { partition } from '@lib/helper'
|
import { partition } from '@lib/helper'
|
||||||
import { useWarpImmerSetter, WritableDraft } from '@lib/jotai'
|
import { useWarpImmerSetter, type WritableDraft } from '@lib/jotai'
|
||||||
import { isClashX, jsBridge } from '@lib/jsBridge'
|
import { isClashX, jsBridge } from '@lib/jsBridge'
|
||||||
import { Snapshot } from '@lib/request'
|
import type * as API from '@lib/request'
|
||||||
import * as API from '@lib/request'
|
|
||||||
import { StreamReader } from '@lib/streamer'
|
import { StreamReader } from '@lib/streamer'
|
||||||
import { Infer } from '@lib/type'
|
import { type Infer } from '@lib/type'
|
||||||
import * as Models from '@models'
|
import type * as Models from '@models'
|
||||||
import { Log } from '@models/Log'
|
import { type Log } from '@models/Log'
|
||||||
|
|
||||||
import { useAPIInfo, useClient } from './request'
|
import { useAPIInfo, useClient } from './request'
|
||||||
|
|
||||||
@ -277,7 +276,7 @@ export function useLogsStreamReader () {
|
|||||||
export function useConnectionStreamReader () {
|
export function useConnectionStreamReader () {
|
||||||
const apiInfo = useAPIInfo()
|
const apiInfo = useAPIInfo()
|
||||||
|
|
||||||
const connection = useRef(new StreamReader<Snapshot>({ bufferLength: 200 }))
|
const connection = useRef(new StreamReader<API.Snapshot>({ bufferLength: 200 }))
|
||||||
|
|
||||||
const protocol = apiInfo.protocol === 'http:' ? 'ws:' : 'wss:'
|
const protocol = apiInfo.protocol === 'http:' ? 'ws:' : 'wss:'
|
||||||
const url = `${protocol}//${apiInfo.hostname}:${apiInfo.port}/connections?token=${encodeURIComponent(apiInfo.secret)}`
|
const url = `${protocol}//${apiInfo.hostname}:${apiInfo.port}/connections?token=${encodeURIComponent(apiInfo.secret)}`
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src",
|
"src",
|
||||||
"windi.config.ts",
|
|
||||||
"vite.config.ts"
|
"vite.config.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
import presetWind from '@unocss/preset-wind'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
import jotaiDebugLabel from 'jotai/babel/plugin-debug-label'
|
import jotaiDebugLabel from 'jotai/babel/plugin-debug-label'
|
||||||
import jotaiReactRefresh from 'jotai/babel/plugin-react-refresh'
|
import jotaiReactRefresh from 'jotai/babel/plugin-react-refresh'
|
||||||
|
import UnoCSS from 'unocss/vite'
|
||||||
import { defineConfig, splitVendorChunkPlugin } from 'vite'
|
import { defineConfig, splitVendorChunkPlugin } from 'vite'
|
||||||
import { VitePWA } from 'vite-plugin-pwa'
|
import { VitePWA } from 'vite-plugin-pwa'
|
||||||
import windiCSS from 'vite-plugin-windicss'
|
|
||||||
import tsConfigPath from 'vite-tsconfig-paths'
|
import tsConfigPath from 'vite-tsconfig-paths'
|
||||||
|
|
||||||
export default defineConfig(
|
export default defineConfig(
|
||||||
@ -14,7 +15,26 @@ export default defineConfig(
|
|||||||
babel: { plugins: [jotaiDebugLabel, jotaiReactRefresh] },
|
babel: { plugins: [jotaiDebugLabel, jotaiReactRefresh] },
|
||||||
}),
|
}),
|
||||||
tsConfigPath(),
|
tsConfigPath(),
|
||||||
windiCSS(),
|
UnoCSS({
|
||||||
|
presets: [presetWind()],
|
||||||
|
theme: {
|
||||||
|
colors: {
|
||||||
|
primary: {
|
||||||
|
500: '#57befc',
|
||||||
|
600: '#2c8af8',
|
||||||
|
darken: '#54759a',
|
||||||
|
},
|
||||||
|
red: '#f56c6c',
|
||||||
|
green: '#67c23a',
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
primary: '2px 5px 20px -3px rgb(44 138 248 / 18%)',
|
||||||
|
},
|
||||||
|
textShadow: {
|
||||||
|
primary: '0 0 6px rgb(44 138 248 / 40%)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
injectRegister: 'inline',
|
injectRegister: 'inline',
|
||||||
manifest: {
|
manifest: {
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import { defineConfig } from 'windicss/helpers'
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
primary: {
|
|
||||||
500: '#57befc',
|
|
||||||
600: '#2c8af8',
|
|
||||||
},
|
|
||||||
red: '#f56c6c',
|
|
||||||
green: '#67c23a',
|
|
||||||
},
|
|
||||||
textColor: {
|
|
||||||
primary: {
|
|
||||||
darken: '#54759a',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
textShadow: {
|
|
||||||
primary: '0 0 6px rgb(44 138 248 / 40%)',
|
|
||||||
},
|
|
||||||
boxShadow: {
|
|
||||||
primary: '2px 5px 20px -3px rgb(44 138 248 / 18%)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
Loading…
x
Reference in New Issue
Block a user