mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-11-24 09:45:35 +08:00
feat: preview by bar
This commit is contained in:
parent
f9c63d6e85
commit
4d29e7c16e
21
src/components/Delay.tsx
Normal file
21
src/components/Delay.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { DELAY } from '~/config/enum'
|
||||||
|
|
||||||
|
const Delay = (props: { delay: number | undefined }) => {
|
||||||
|
const delay = props.delay
|
||||||
|
|
||||||
|
if (typeof delay !== 'number' || delay === DELAY.NOT_CONNECTED) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
let textClassName = 'text-success'
|
||||||
|
|
||||||
|
if (delay > DELAY.HIGH) {
|
||||||
|
textClassName = 'text-error'
|
||||||
|
} else if (delay > DELAY.MEDIUM) {
|
||||||
|
textClassName = 'text-warning'
|
||||||
|
}
|
||||||
|
|
||||||
|
return <span class={textClassName}>{delay}ms</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Delay
|
@ -1,6 +1,6 @@
|
|||||||
import { createMemo } from 'solid-js'
|
import { createMemo } from 'solid-js'
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
import { DELAY } from '~/config/enum'
|
import Delay from '~/components/Delay'
|
||||||
import { useProxies } from '~/signals/proxies'
|
import { useProxies } from '~/signals/proxies'
|
||||||
|
|
||||||
export default (props: {
|
export default (props: {
|
||||||
@ -12,22 +12,6 @@ export default (props: {
|
|||||||
const { proxyNodeMap } = useProxies()
|
const { proxyNodeMap } = useProxies()
|
||||||
const proxyNode = createMemo(() => proxyNodeMap()[proxyName])
|
const proxyNode = createMemo(() => proxyNodeMap()[proxyName])
|
||||||
|
|
||||||
const Delay = (delay: number | undefined) => {
|
|
||||||
if (typeof delay !== 'number' || delay === DELAY.NOT_CONNECTED) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
let textClassName = 'text-success'
|
|
||||||
|
|
||||||
if (delay > DELAY.HIGH) {
|
|
||||||
textClassName = 'text-error'
|
|
||||||
} else if (delay > DELAY.MEDIUM) {
|
|
||||||
textClassName = 'text-warning'
|
|
||||||
}
|
|
||||||
|
|
||||||
return <span class={textClassName}>{delay}ms</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatProxyType = (type = '') => {
|
const formatProxyType = (type = '') => {
|
||||||
const t = type.toLowerCase()
|
const t = type.toLowerCase()
|
||||||
|
|
||||||
@ -59,7 +43,9 @@ export default (props: {
|
|||||||
{formatProxyType(proxyNode()?.type)}
|
{formatProxyType(proxyNode()?.type)}
|
||||||
{proxyNode()?.udp && ' :: udp'}
|
{proxyNode()?.udp && ' :: udp'}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs">{Delay(proxyNode()?.delay)}</div>
|
<div class="text-xs">
|
||||||
|
<Delay delay={proxyNode()?.delay} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
import { For } from 'solid-js'
|
|
||||||
import { twMerge } from 'tailwind-merge'
|
|
||||||
import { DELAY } from '~/config/enum'
|
|
||||||
import { useProxies } from '~/signals/proxies'
|
|
||||||
|
|
||||||
const Delay = (p: { delay: number | undefined; selected: boolean }) => {
|
|
||||||
let dotClassName = p.selected
|
|
||||||
? 'bg-white border-4 border-success'
|
|
||||||
: 'bg-success'
|
|
||||||
|
|
||||||
if (typeof p.delay !== 'number' || p.delay === DELAY.NOT_CONNECTED) {
|
|
||||||
dotClassName = p.selected
|
|
||||||
? 'bg-white border-4 border-neutral'
|
|
||||||
: 'bg-neutral'
|
|
||||||
} else if (p.delay > DELAY.HIGH) {
|
|
||||||
dotClassName = p.selected ? 'bg-white border-4 border-error' : 'bg-error'
|
|
||||||
} else if (p.delay > DELAY.MEDIUM) {
|
|
||||||
dotClassName = p.selected
|
|
||||||
? 'bg-white border-4 border-warning'
|
|
||||||
: 'bg-warning'
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div class={twMerge('m-1 h-4 w-4 rounded-full', dotClassName)}></div>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (props: { proxyNameList: string[]; now?: string }) => {
|
|
||||||
const { proxyNodeMap } = useProxies()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class="flex w-full flex-wrap">
|
|
||||||
<For each={props.proxyNameList.map((name) => proxyNodeMap()[name]!)}>
|
|
||||||
{(proxy) => {
|
|
||||||
const delay = proxy?.delay
|
|
||||||
const isSelected = props.now === proxy.name
|
|
||||||
|
|
||||||
return <Delay delay={delay} selected={isSelected} />
|
|
||||||
}}
|
|
||||||
</For>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
92
src/components/ProxyNodePreview.tsx
Normal file
92
src/components/ProxyNodePreview.tsx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { For, Show } from 'solid-js'
|
||||||
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
import Delay from '~/components/Delay'
|
||||||
|
import { DELAY, PROXIES_PREVIEW_TYPE } from '~/config/enum'
|
||||||
|
import { proxiesPreviewType } from '~/pages/Config'
|
||||||
|
import { useProxies } from '~/signals/proxies'
|
||||||
|
|
||||||
|
const DelayDots = (p: { delay: number | undefined; selected: boolean }) => {
|
||||||
|
let dotClassName = p.selected
|
||||||
|
? 'bg-white border-4 border-success'
|
||||||
|
: 'bg-success'
|
||||||
|
|
||||||
|
if (typeof p.delay !== 'number' || p.delay === DELAY.NOT_CONNECTED) {
|
||||||
|
dotClassName = p.selected
|
||||||
|
? 'bg-white border-4 border-neutral'
|
||||||
|
: 'bg-neutral'
|
||||||
|
} else if (p.delay > DELAY.HIGH) {
|
||||||
|
dotClassName = p.selected ? 'bg-white border-4 border-error' : 'bg-error'
|
||||||
|
} else if (p.delay > DELAY.MEDIUM) {
|
||||||
|
dotClassName = p.selected
|
||||||
|
? 'bg-white border-4 border-warning'
|
||||||
|
: 'bg-warning'
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div class={twMerge('m-1 h-4 w-4 rounded-full', dotClassName)}></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (props: { proxyNameList: string[]; now?: string }) => {
|
||||||
|
const { proxyNodeMap } = useProxies()
|
||||||
|
const allNodesDelay = props.proxyNameList.map((i) => proxyNodeMap()[i].delay!)
|
||||||
|
const all = allNodesDelay.length
|
||||||
|
const good = allNodesDelay.filter(
|
||||||
|
(delay) => delay > DELAY.NOT_CONNECTED && delay <= DELAY.MEDIUM,
|
||||||
|
).length
|
||||||
|
const middle = allNodesDelay.filter(
|
||||||
|
(delay) => delay > DELAY.MEDIUM && delay <= DELAY.HIGH,
|
||||||
|
).length
|
||||||
|
const slow = allNodesDelay.filter((delay) => delay > DELAY.HIGH).length
|
||||||
|
const notConnected = allNodesDelay.filter(
|
||||||
|
(delay) => delay === DELAY.NOT_CONNECTED,
|
||||||
|
).length
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Show when={proxiesPreviewType() === PROXIES_PREVIEW_TYPE.BAR}>
|
||||||
|
<div class="flex w-full items-center">
|
||||||
|
<div class="flex flex-1 overflow-hidden rounded-2xl">
|
||||||
|
<div
|
||||||
|
class={twMerge('h-2 w-auto bg-success')}
|
||||||
|
style={{
|
||||||
|
width: `${(good * 100) / all}%`, // cant use tw class cause dynamic classname wont import
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class={twMerge('h-2 w-auto bg-warning')}
|
||||||
|
style={{
|
||||||
|
width: `${(middle * 100) / all}%`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class={twMerge('h-2 w-auto bg-error')}
|
||||||
|
style={{
|
||||||
|
width: `${(slow * 100) / all}%`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class={twMerge('h-2 w-auto bg-neutral')}
|
||||||
|
style={{
|
||||||
|
width: `${(notConnected * 100) / all}%`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-4 text-xs">
|
||||||
|
<Delay delay={proxyNodeMap()[props.now!]?.delay} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
<Show when={proxiesPreviewType() === PROXIES_PREVIEW_TYPE.DOTS}>
|
||||||
|
<div class="flex w-full flex-wrap items-center">
|
||||||
|
<For each={props.proxyNameList.map((name) => proxyNodeMap()[name]!)}>
|
||||||
|
{(proxy) => {
|
||||||
|
const delay = proxy?.delay
|
||||||
|
const isSelected = props.now === proxy.name
|
||||||
|
|
||||||
|
return <DelayDots delay={delay} selected={isSelected} />
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -19,3 +19,8 @@ export enum DELAY {
|
|||||||
MEDIUM = 200,
|
MEDIUM = 200,
|
||||||
HIGH = 500,
|
HIGH = 500,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum PROXIES_PREVIEW_TYPE {
|
||||||
|
DOTS = 'dots',
|
||||||
|
BAR = 'bar',
|
||||||
|
}
|
||||||
|
0
src/config/user
Normal file
0
src/config/user
Normal file
@ -13,6 +13,17 @@ const schema = z.object({
|
|||||||
'mixed-port': z.number(),
|
'mixed-port': z.number(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
import { makePersisted } from '@solid-primitives/storage'
|
||||||
|
import { PROXIES_PREVIEW_TYPE } from '~/config/enum'
|
||||||
|
|
||||||
|
export const [proxiesPreviewType, setProxiesPreviewType] = makePersisted(
|
||||||
|
createSignal(PROXIES_PREVIEW_TYPE.BAR),
|
||||||
|
{
|
||||||
|
name: 'proxiesPreviewType',
|
||||||
|
storage: localStorage,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const request = useRequest()
|
const request = useRequest()
|
||||||
|
|
||||||
@ -94,6 +105,34 @@ export default () => {
|
|||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<div>Proxies preview type:</div>
|
||||||
|
<div class="join">
|
||||||
|
<label class="flex items-center">
|
||||||
|
Bar
|
||||||
|
<input
|
||||||
|
class="radio m-4"
|
||||||
|
aria-label="Bar"
|
||||||
|
type="radio"
|
||||||
|
name="proxiesPreviewType"
|
||||||
|
checked={PROXIES_PREVIEW_TYPE.BAR === proxiesPreviewType()}
|
||||||
|
onChange={() => setProxiesPreviewType(PROXIES_PREVIEW_TYPE.BAR)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center">
|
||||||
|
Dots
|
||||||
|
<input
|
||||||
|
class="radio m-4"
|
||||||
|
aria-label="Dots"
|
||||||
|
type="radio"
|
||||||
|
name="proxiesPreviewType"
|
||||||
|
checked={PROXIES_PREVIEW_TYPE.DOTS === proxiesPreviewType()}
|
||||||
|
onChange={() => setProxiesPreviewType(PROXIES_PREVIEW_TYPE.DOTS)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form class="contents" use:form={form}>
|
<form class="contents" use:form={form}>
|
||||||
<For each={portsList}>
|
<For each={portsList}>
|
||||||
{(item) => (
|
{(item) => (
|
||||||
|
@ -4,7 +4,7 @@ import { Show, createSignal, onMount } from 'solid-js'
|
|||||||
import Collapse from '~/components/Collpase'
|
import Collapse from '~/components/Collpase'
|
||||||
import ForTwoLine from '~/components/ForTwoLine'
|
import ForTwoLine from '~/components/ForTwoLine'
|
||||||
import ProxyCardGroups from '~/components/ProxyCardGroups'
|
import ProxyCardGroups from '~/components/ProxyCardGroups'
|
||||||
import ProxyNodeDots from '~/components/ProxyNodeDots'
|
import ProxyNodePreview from '~/components/ProxyNodePreview'
|
||||||
import SubscriptionInfo from '~/components/SubscriptionInfo'
|
import SubscriptionInfo from '~/components/SubscriptionInfo'
|
||||||
import { useProxies } from '~/signals/proxies'
|
import { useProxies } from '~/signals/proxies'
|
||||||
import type { Proxy } from '~/types'
|
import type { Proxy } from '~/types'
|
||||||
@ -83,7 +83,7 @@ export default () => {
|
|||||||
{proxy.type} :: {proxy.now}
|
{proxy.type} :: {proxy.now}
|
||||||
</div>
|
</div>
|
||||||
<Show when={!collapsedMap()[`group-${proxy.name}`]}>
|
<Show when={!collapsedMap()[`group-${proxy.name}`]}>
|
||||||
<ProxyNodeDots
|
<ProxyNodePreview
|
||||||
proxyNameList={proxy.all ?? []}
|
proxyNameList={proxy.all ?? []}
|
||||||
now={proxy.now}
|
now={proxy.now}
|
||||||
/>
|
/>
|
||||||
@ -157,7 +157,7 @@ export default () => {
|
|||||||
<Show
|
<Show
|
||||||
when={!collapsedMap()[`provider-${proxyProvider.name}`]}
|
when={!collapsedMap()[`provider-${proxyProvider.name}`]}
|
||||||
>
|
>
|
||||||
<ProxyNodeDots
|
<ProxyNodePreview
|
||||||
proxyNameList={
|
proxyNameList={
|
||||||
proxyProvider.proxies.map((i) => i.name) ?? []
|
proxyProvider.proxies.map((i) => i.name) ?? []
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user