feat(proxies): overhaul the look of proxies page, drop renderInTwoColumns support

This commit is contained in:
kunish 2024-10-10 18:52:24 +08:00
parent 2e92dd20cf
commit 698362f1c7
No known key found for this signature in database
GPG Key ID: 647A12B4F782C430
13 changed files with 88 additions and 159 deletions

View File

@ -29,7 +29,7 @@
"@solid-primitives/timer": "^1.3.10",
"@solid-primitives/websocket": "^1.2.2",
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.14.7",
"@solidjs/router": "^0.14.8",
"@tabler/icons-solidjs": "^3.19.0",
"@tanstack/match-sorter-utils": "^8.19.4",
"@tanstack/solid-table": "^8.20.5",

View File

@ -53,8 +53,8 @@ importers:
specifier: ^0.29.4
version: 0.29.4(solid-js@1.9.2)
'@solidjs/router':
specifier: ^0.14.7
version: 0.14.7(solid-js@1.9.2)
specifier: ^0.14.8
version: 0.14.8(solid-js@1.9.2)
'@tabler/icons-solidjs':
specifier: ^3.19.0
version: 3.19.0(solid-js@1.9.2)
@ -1984,10 +1984,10 @@ packages:
peerDependencies:
solid-js: '>=1.8.4'
'@solidjs/router@0.14.7':
'@solidjs/router@0.14.8':
resolution:
{
integrity: sha512-agLf8AUz5XnW6+F64a4Iq+QQQobI5zGHQ/gUYd/WHSwcbnFpavbsiwRLob3YhWMXVX3sQyn4ekUN+uchMCRupw==,
integrity: sha512-S+rD5Twp0820cM03wEIYtb7/4KN7Cfr3BP+qPIqb7IXO/SZ72tWqHEMQsmcjDbr4yVfpA+5Sq0Y+xcq09y1gQA==,
}
peerDependencies:
solid-js: ^1.8.6
@ -7577,7 +7577,7 @@ snapshots:
dependencies:
solid-js: 1.9.2
'@solidjs/router@0.14.7(solid-js@1.9.2)':
'@solidjs/router@0.14.8(solid-js@1.9.2)':
dependencies:
solid-js: 1.9.2

View File

@ -19,6 +19,7 @@ interface ButtonWithoutIconProps extends ButtonBaseProps {
export const Button: ParentComponent<
ButtonWithIconProps | ButtonWithoutIconProps
> = (props) => {
// @ts-expect-error Expression produces a union type that is too complex to represent
const [local, others] = splitProps(props, ['class', 'loading', 'icon'])
return (

View File

@ -1,6 +1,5 @@
import type { JSX, ParentComponent } from 'solid-js'
import { twMerge } from 'tailwind-merge'
import { renderProxiesInTwoColumns } from '~/signals'
type Props = {
title: JSX.Element
@ -25,14 +24,6 @@ export const Collapse: ParentComponent<Props> = (props) => {
return props.isOpen ? openedClassName : closedClassName
}
const gridStyle = createMemo(() => {
if (renderProxiesInTwoColumns()) {
return 'lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5'
}
return 'sm:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10'
})
return (
<div
class={twMerge(
@ -50,8 +41,7 @@ export const Collapse: ParentComponent<Props> = (props) => {
<div
class={twMerge(
getCollapseContentClassName(),
gridStyle(),
'collapse-content grid grid-cols-2 gap-2 transition-opacity duration-1000',
'collapse-content grid grid-cols-1 gap-2 transition-opacity duration-1000 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5',
)}
>
<Show when={props.isOpen}>{children(() => props.children)()}</Show>

View File

@ -1,15 +0,0 @@
import { useProxies } from '~/signals'
export const IPv6Support = (props: { name?: string }) => {
const { getNowProxyNodeName, proxyIPv6SupportMap } = useProxies()
const support = createMemo(() => {
return proxyIPv6SupportMap()[getNowProxyNodeName(props.name || '')]
})
return (
<Show when={support()}>
<span class={`text-xs`}>IPv6</span>
</Show>
)
}

View File

@ -11,7 +11,6 @@ import {
latencyTestTimeoutDuration,
proxiesOrderingType,
proxiesPreviewType,
renderProxiesInTwoColumns,
setAutoCloseConns,
setHideUnAvailableProxies,
setIconHeight,
@ -19,7 +18,6 @@ import {
setLatencyTestTimeoutDuration,
setProxiesOrderingType,
setProxiesPreviewType,
setRenderProxiesInTwoColumns,
setUrlForLatencyTest,
setUrlIPv6SupportTest,
urlForIPv6SupportTest,
@ -107,7 +105,7 @@ export const ProxiesSettingsModal: Component<{
</div>
<div>
<ConfigTitle withDivider>{t('hideUnAvailableProxies')}</ConfigTitle>
<ConfigTitle withDivider>{t('hideUnavailableProxies')}</ConfigTitle>
<div class="flex w-full justify-center">
<input
@ -119,19 +117,6 @@ export const ProxiesSettingsModal: Component<{
</div>
</div>
<div>
<ConfigTitle withDivider>{t('renderInTwoColumns')}</ConfigTitle>
<div class="flex w-full justify-center">
<input
class="toggle"
type="checkbox"
checked={renderProxiesInTwoColumns()}
onChange={(e) => setRenderProxiesInTwoColumns(e.target.checked)}
/>
</div>
</div>
<div>
<ConfigTitle withDivider>{t('proxiesPreviewType')}</ConfigTitle>

View File

@ -1,6 +1,6 @@
import { IconBrandSpeedtest } from '@tabler/icons-solidjs'
import { twMerge } from 'tailwind-merge'
import { Button, IPv6Support, Latency } from '~/components'
import { Button, Latency } from '~/components'
import { filterSpecialProxyType, formatProxyType } from '~/helpers'
import { useProxies } from '~/signals'
@ -9,10 +9,19 @@ export const ProxyNodeCard = (props: {
isSelected?: boolean
onClick?: () => void
}) => {
const { proxyLatencyTest, proxyLatencyTestingMap } = useProxies()
const { proxyName, isSelected, onClick } = props
const { proxyNodeMap } = useProxies()
const {
getNowProxyNodeName,
proxyIPv6SupportMap,
proxyNodeMap,
proxyLatencyTest,
proxyLatencyTestingMap,
} = useProxies()
const supportIPv6 = createMemo(
() => proxyIPv6SupportMap()[getNowProxyNodeName(props.proxyName || '')],
)
const proxyNode = createMemo(() => proxyNodeMap()[proxyName])
const specialType = () =>
filterSpecialProxyType(proxyNode()?.type)
? proxyNode()?.xudp
@ -25,55 +34,61 @@ export const ProxyNodeCard = (props: {
return (
<div
class={twMerge(
'border-neutral-focus card card-bordered tooltip-bottom flex flex-col justify-between gap-1 bg-neutral p-2 text-neutral-content',
'card tooltip card-compact tooltip-accent bg-neutral text-neutral-content',
isSelected &&
'bg-gradient-to-br from-primary to-secondary text-primary-content',
'bg-gradient-to-l from-primary to-secondary text-primary-content',
onClick && 'cursor-pointer',
)}
data-tip={proxyName}
onClick={onClick}
title={proxyName}
>
<div class="flex items-center justify-between gap-2">
<span class="break-all text-left text-sm">{proxyName}</span>
<div class="card-body">
<span class="card-title truncate text-sm">{proxyName}</span>
<span class="flex items-center gap-1">
<IPv6Support name={props.proxyName} />
<Button
class="btn-circle btn-ghost h-auto min-h-0 w-auto"
icon={
<IconBrandSpeedtest
size={20}
class={twMerge(
proxyLatencyTestingMap()[proxyName] &&
'animate-pulse text-success',
)}
/>
}
onClick={(e) => {
e.stopPropagation()
<div class="flex items-center justify-between gap-2">
<div class="flex items-center gap-2">
<Show when={specialType()}>
<div class="badge badge-primary badge-sm font-bold uppercase">
{formatProxyType(proxyNode()?.type)}
</div>
void proxyLatencyTest(proxyName, proxyNode().provider)
}}
/>
</span>
</div>
<Show when={specialType()}>
<div class="badge badge-secondary badge-sm">
{specialType()}
</div>
</Show>
</Show>
<div class="flex items-center justify-between gap-1">
<div
class={twMerge(
'text-xs text-slate-500',
isSelected && 'text-primary-content',
)}
>
{formatProxyType(proxyNode()?.type)}
<Show when={supportIPv6()}>
<div class="badge badge-accent badge-sm">IPv6</div>
</Show>
</div>
<Show when={specialType()}>{` :: ${specialType()}`}</Show>
<div class="flex items-center gap-2">
<Latency
name={props.proxyName}
class={twMerge(isSelected && 'badge')}
/>
<Button
class="btn-square btn-sm"
icon={
<IconBrandSpeedtest
class={twMerge(
'size-6',
proxyLatencyTestingMap()[proxyName] &&
'animate-pulse text-success',
)}
/>
}
onClick={(e) => {
e.stopPropagation()
void proxyLatencyTest(proxyName, proxyNode().provider)
}}
/>
</div>
</div>
<Latency
name={props.proxyName}
class={twMerge(isSelected && 'badge badge-sm px-1')}
/>
</div>
</div>
)

View File

@ -1,26 +0,0 @@
import { createWindowSize } from '@solid-primitives/resize-observer'
import type { ParentComponent } from 'solid-js'
export const RenderInTwoColumns: ParentComponent = (props) => {
const resolvedChildren = children(() => props.children)
const windowSize = createWindowSize()
// 640 is sm size in default tailwindcss breakpoint
const showTwoColumns = createMemo(() => windowSize.width >= 640)
const leftColumns = createMemo(() =>
resolvedChildren.toArray().filter((_, index) => index % 2 === 0),
)
const rightColumns = createMemo(() =>
resolvedChildren.toArray().filter((_, index) => index % 2 === 1),
)
return (
<div class="flex flex-col gap-2 sm:flex-row">
<Show when={showTwoColumns()} fallback={props.children}>
<div class="flex flex-1 flex-col gap-2">{leftColumns()}</div>
<div class="flex flex-1 flex-col gap-2">{rightColumns()}</div>
</Show>
</div>
)
}

View File

@ -4,7 +4,6 @@ export * from './ConfigTitle'
export * from './ConnectionsSettingsModal'
export * from './ConnectionsTableDetailsModal'
export * from './Header'
export * from './IPv6Support'
export * from './Latency'
export * from './LogoText'
export * from './LogsSettingsModal'
@ -14,5 +13,4 @@ export * from './ProxyNodeCard'
export * from './ProxyNodePreview'
export * from './ProxyPreviewBar'
export * from './ProxyPreviewDots'
export * from './RenderInTwoColumns'
export * from './SubscriptionInfo'

View File

@ -47,15 +47,14 @@ export default {
bar: 'Bar',
auto: 'Auto',
off: 'Off',
proxiesPreviewType: 'Proxies preview type',
urlForIPv6SupportTest: 'URL for IPv6 support test',
urlForLatencyTest: 'URL for latency test',
autoCloseConns: 'Automatically Close connections',
proxiesPreviewType: 'Proxies Preview Type',
urlForIPv6SupportTest: 'URL for IPv6 Support Test',
urlForLatencyTest: 'URL for Latency Test',
autoCloseConns: 'Automatically Close Connections',
useTwemoji: 'Use Twemoji Mozilla Font',
autoSwitchTheme: 'Automatically switch theme',
favDayTheme: 'Favorite light theme',
favNightTheme: 'Favorite dark theme',
renderInTwoColumns: 'Render in two columns',
updateGEODatabases: 'Update GEO Databases',
restartCore: 'Restart Core',
upgradeCore: 'Upgrade Core',
@ -95,7 +94,7 @@ export default {
active: 'Active',
closed: 'Closed',
sort: 'Sort',
hideUnAvailableProxies: 'Hide UnAvailable Proxies',
hideUnavailableProxies: 'Hide Unavailable Proxies',
reloadConfig: 'Reload Config',
flushFakeIP: 'Flush Fake-IP',
tagClientSourceIPWithName: 'Tag Client Source IP With Name',

View File

@ -57,7 +57,6 @@ export default {
autoSwitchTheme: '自动切换主题',
favDayTheme: '浅色主题偏好',
favNightTheme: '深色主题偏好',
renderInTwoColumns: '双列渲染',
updateGEODatabases: '更新 GEO 数据库',
restartCore: '重启核心',
upgradeCore: '更新核心',
@ -97,7 +96,7 @@ export default {
active: '活动',
closed: '已关闭',
sort: '排序',
hideUnAvailableProxies: '隐藏不可用节点',
hideUnavailableProxies: '隐藏不可用节点',
reloadConfig: '重载配置',
flushFakeIP: '清空 Fake-IP',
tagClientSourceIPWithName: '为客户端源 IP 地址添加名称标记',

View File

@ -27,7 +27,6 @@ import {
iconHeight,
iconMarginRight,
proxiesOrderingType,
renderProxiesInTwoColumns,
useConnections,
useProxies,
} from '~/signals'
@ -174,14 +173,7 @@ export default () => {
<div class="flex-1 overflow-y-auto">
<Show when={activeTab() === ActiveTab.proxies}>
<div
class={twMerge(
'grid grid-cols-1 place-items-start gap-2',
renderProxiesInTwoColumns()
? 'sm:grid-cols-2'
: 'sm:grid-cols-1',
)}
>
<div class="flex flex-col gap-2">
<For each={renderProxies()}>
{(proxyGroup) => {
const sortedProxyNames = createMemo(() =>
@ -195,7 +187,7 @@ export default () => {
)
const title = (
<>
<div class="space-y-2">
<div class="flex items-center justify-between pr-8">
<div class="flex items-center">
<Show when={proxyGroup.icon}>
@ -233,18 +225,21 @@ export default () => {
/>
</div>
<div class="flex items-center justify-between text-sm text-slate-500">
<span>
{proxyGroup.type}{' '}
{proxyGroup.now?.length > 0 &&
` :: ${proxyGroup.now}`}
</span>
<span>
<div class="flex flex-wrap items-center justify-between gap-2">
<div class="badge badge-primary badge-sm">
<span class="font-bold">{proxyGroup.type}</span>
<Show when={proxyGroup.now?.length > 0}>
<pre>{` :: ${proxyGroup.now}`}</pre>
</Show>
</div>
<div class="badge badge-secondary badge-sm">
{byteSize(
speedGroupByName()[proxyGroup.name] ?? 0,
).toString()}
/s
</span>
</div>
</div>
<Show when={!collapsedMap()[proxyGroup.name]}>
@ -253,7 +248,7 @@ export default () => {
now={proxyGroup.now}
/>
</Show>
</>
</div>
)
return (
@ -283,14 +278,7 @@ export default () => {
</Show>
<Show when={activeTab() === ActiveTab.proxyProviders}>
<div
class={twMerge(
'grid grid-cols-1 place-items-start gap-2',
renderProxiesInTwoColumns()
? 'sm:grid-cols-2'
: 'sm:grid-cols-1',
)}
>
<div class="flex flex-col gap-2">
<For each={proxyProviders()}>
{(proxyProvider) => {
const sortedProxyNames = createMemo(() =>
@ -305,6 +293,7 @@ export default () => {
<div class="flex items-center justify-between pr-8">
<div class="flex items-center gap-2">
<span>{proxyProvider.name}</span>
<div class="badge badge-sm">
{proxyProvider.proxies.length}
</div>

View File

@ -31,12 +31,6 @@ export const [hideUnAvailableProxies, setHideUnAvailableProxies] =
storage: localStorage,
})
export const [renderProxiesInTwoColumns, setRenderProxiesInTwoColumns] =
makePersisted(createSignal(true), {
name: 'renderProxiesInTwoColumns',
storage: localStorage,
})
export const [urlForLatencyTest, setUrlForLatencyTest] = makePersisted(
createSignal('https://www.gstatic.com/generate_204'),
{ name: 'urlForLatencyTest', storage: localStorage },