feat: preview by bar

This commit is contained in:
Zephyruso 2023-09-02 11:52:51 +08:00
parent f9c63d6e85
commit 4d29e7c16e
8 changed files with 164 additions and 62 deletions

21
src/components/Delay.tsx Normal file
View 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

View File

@ -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>
) )

View File

@ -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>
)
}

View 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>
</>
)
}

View File

@ -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
View File

View 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) => (

View File

@ -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) ?? []
} }