feat(rules): renderInTwoColumns

This commit is contained in:
kunish 2023-09-16 00:17:41 +08:00
parent 9e556d959e
commit 6743ebde8f
No known key found for this signature in database
GPG Key ID: 647A12B4F782C430
10 changed files with 157 additions and 95 deletions

View File

@ -55,7 +55,6 @@
"prettier-plugin-organize-imports": "^3.2.3",
"prettier-plugin-tailwindcss": "^0.5.4",
"solid-apexcharts": "^0.3.2",
"solid-infinite-scroll": "^1.0.1",
"solid-js": "^1.7.11",
"solid-toast": "^0.5.0",
"sort-package-json": "^2.5.1",

9
pnpm-lock.yaml generated
View File

@ -131,9 +131,6 @@ dependencies:
solid-apexcharts:
specifier: ^0.3.2
version: 0.3.2(apexcharts@3.42.0)(solid-js@1.7.11)
solid-infinite-scroll:
specifier: ^1.0.1
version: 1.0.1
solid-js:
specifier: ^1.7.11
version: 1.7.11
@ -5230,12 +5227,6 @@ packages:
solid-js: 1.7.11
dev: false
/solid-infinite-scroll@1.0.1:
resolution: {integrity: sha512-yIDyr61316jyHSxuQqidMUTcauKDQyPIzIAKawTrTadqxij2wOcM3ei6/MR6WPBCcR0ZMJ8E0aQInFSnL9w2Hg==}
dependencies:
solid-js: 1.7.11
dev: false
/solid-js@1.7.11:
resolution: {integrity: sha512-JkuvsHt8jqy7USsy9xJtT18aF9r2pFO+GB8JQ2XGTvtF49rGTObB46iebD25sE3qVNvIbwglXOXdALnJq9IHtQ==}
dependencies:

View File

@ -1,6 +1,6 @@
import { JSX, ParentComponent, Show, createMemo } from 'solid-js'
import { twMerge } from 'tailwind-merge'
import { renderInTwoColumns } from '~/signals'
import { proxiesRenderInTwoColumns } from '~/signals'
type Props = {
title: JSX.Element
@ -27,7 +27,7 @@ export const Collapse: ParentComponent<Props> = (props) => {
}
const mediaQueryClassName = createMemo(() => {
if (renderInTwoColumns()) {
if (proxiesRenderInTwoColumns()) {
return 'lg:grid-cols-3 xl:grid-cols-4'
} else {
return 'sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-7'

View File

@ -1,11 +1,11 @@
import { createWindowSize } from '@solid-primitives/resize-observer'
import { JSX, Show, createMemo } from 'solid-js'
import { renderInTwoColumns } from '~/signals'
import { proxiesRenderInTwoColumns } from '~/signals'
export const ForTwoColumns = (props: { subChild: JSX.Element[] }) => {
const windowSize = createWindowSize()
const isShowTwoColumns = createMemo(
() => windowSize.width >= 640 && renderInTwoColumns(),
() => windowSize.width >= 640 && proxiesRenderInTwoColumns(),
) // 640 is sm size in daisyui
const leftColumns = createMemo(() =>
props.subChild.filter((_, index) => index % 2 === 0 || !isShowTwoColumns()),

View File

@ -8,11 +8,13 @@ import {
latencyTestTimeoutDuration,
proxiesOrderingType,
proxiesPreviewType,
proxiesRenderInTwoColumns,
setAutoCloseConns,
setHideUnAvailableProxies,
setLatencyTestTimeoutDuration,
setProxiesOrderingType,
setProxiesPreviewType,
setProxiesRenderInTwoColumns,
setUrlForLatencyTest,
urlForLatencyTest,
} from '~/signals'
@ -112,6 +114,19 @@ export const ProxiesSettingsModal = () => {
</For>
</select>
</div>
<div>
<ConfigTitle withDivider>{t('renderInTwoColumns')}</ConfigTitle>
<div class="flex w-full justify-center">
<input
type="checkbox"
class="toggle"
checked={proxiesRenderInTwoColumns()}
onChange={(e) => setProxiesRenderInTwoColumns(e.target.checked)}
/>
</div>
</div>
</div>
<form method="dialog" class="modal-backdrop">

View File

@ -0,0 +1,34 @@
import { useI18n } from '@solid-primitives/i18n'
import { ConfigTitle } from '~/components'
import { MODAL } from '~/constants'
import { rulesRenderInTwoColumns, setRulesRenderInTwoColumns } from '~/signals'
export const RulesSettingsModal = () => {
const [t] = useI18n()
return (
<dialog
id={MODAL.RULES_SETTINGS}
class="modal modal-bottom sm:modal-middle"
>
<div class="modal-box flex flex-col gap-4">
<div>
<ConfigTitle withDivider>{t('renderInTwoColumns')}</ConfigTitle>
<div class="flex w-full justify-center">
<input
type="checkbox"
class="toggle"
checked={rulesRenderInTwoColumns()}
onChange={(e) => setRulesRenderInTwoColumns(e.target.checked)}
/>
</div>
</div>
</div>
<form method="dialog" class="modal-backdrop">
<button />
</form>
</dialog>
)
}

View File

@ -14,4 +14,5 @@ export * from './ProxyNodeCard'
export * from './ProxyNodePreview'
export * from './ProxyPreviewBar'
export * from './ProxyPreviewDots'
export * from './RulesSettingsModal'
export * from './SubscriptionInfo'

View File

@ -22,12 +22,10 @@ import {
backendConfig,
favDayTheme,
favNightTheme,
renderInTwoColumns,
setAutoSwitchTheme,
setBackendConfig,
setFavDayTheme,
setFavNightTheme,
setRenderInTwoColumns,
setSelectedEndpoint,
setTwemoji,
useRequest,
@ -238,11 +236,6 @@ const ConfigForXd = () => {
)
const checkboxList = [
{
label: t('renderInTwoColumns'),
value: renderInTwoColumns,
onChange: setRenderInTwoColumns,
},
{
label: t('autoSwitchTheme'),
value: autoSwitchTheme,

View File

@ -1,11 +1,11 @@
import { useI18n } from '@solid-primitives/i18n'
import { IconReload } from '@tabler/icons-solidjs'
import InfiniteScroll from 'solid-infinite-scroll'
import { For, Show, createMemo, createSignal, onMount } from 'solid-js'
import { IconReload, IconSettings } from '@tabler/icons-solidjs'
import { For, Show, createSignal, onMount } from 'solid-js'
import { twMerge } from 'tailwind-merge'
import { Button, ForTwoColumns } from '~/components'
import { Button, RulesSettingsModal } from '~/components'
import { MODAL } from '~/constants'
import { formatTimeFromNow, useStringBooleanMap } from '~/helpers'
import { useRules } from '~/signals'
import { rulesRenderInTwoColumns, useRules } from '~/signals'
enum ActiveTab {
ruleProviders = 'ruleProviders',
@ -21,8 +21,6 @@ export default () => {
updateAllRuleProvider,
updateRuleProviderByName,
} = useRules()
const [maxRuleRender, setMaxRuleRender] = createSignal(100)
const renderRules = createMemo(() => rules().slice(0, maxRuleRender()))
onMount(updateRules)
@ -61,55 +59,102 @@ export default () => {
return (
<div class="flex h-full flex-col gap-2">
<Show when={ruleProviders().length > 0}>
<div class="flex items-center gap-2">
<div class="tabs tabs-boxed gap-2">
<For each={tabs()}>
{(tab) => (
<button
class={twMerge(
activeTab() === tab.type && 'tab-active',
'tab tab-sm gap-2 px-2 md:tab-md',
)}
onClick={() => setActiveTab(tab.type)}
>
<span>{tab.name}</span>
<div class="badge badge-sm">{tab.count}</div>
</button>
<div class="flex items-center gap-2">
<div class="tabs-boxed tabs gap-2">
<For each={tabs()}>
{(tab) => (
<button
class={twMerge(
activeTab() === tab.type && 'tab-active',
'tab tab-sm gap-2 px-2 md:tab-md',
)}
onClick={() => setActiveTab(tab.type)}
>
<span>{tab.name}</span>
<div class="badge badge-sm">{tab.count}</div>
</button>
)}
</For>
</div>
<Show when={activeTab() === ActiveTab.ruleProviders}>
<Button
class="btn btn-circle btn-sm"
disabled={allProviderIsUpdating()}
onClick={(e) => onUpdateAllProviderClick(e)}
>
<IconReload
class={twMerge(
allProviderIsUpdating() && 'animate-spin text-success',
)}
/>
</Button>
</Show>
<div class="ml-auto">
<Button
class="btn-circle btn-sm sm:btn-md"
onClick={() => {
const modal = document.querySelector(
`#${MODAL.RULES_SETTINGS}`,
) as HTMLDialogElement | null
modal?.showModal()
}}
>
<IconSettings />
</Button>
</div>
</div>
<div class="flex-1 overflow-y-auto">
<Show when={activeTab() === ActiveTab.rules}>
<div
class="grid gap-2"
classList={{
'grid-cols-2': rulesRenderInTwoColumns(),
}}
>
<For each={rules()}>
{(rule) => (
<div class="card card-bordered card-compact bg-base-200 p-4">
<div class="flex items-center gap-2">
<span class="break-all">{rule.payload}</span>
<Show
when={typeof rule.size === 'number' && rule.size !== -1}
>
<div class="badge badge-sm">{rule.size}</div>
</Show>
</div>
<div class="text-xs text-slate-500">
{rule.type} :: {rule.proxy}
</div>
</div>
)}
</For>
</div>
</Show>
<Show when={activeTab() === ActiveTab.ruleProviders}>
<Button
class="btn btn-circle btn-sm"
disabled={allProviderIsUpdating()}
onClick={(e) => onUpdateAllProviderClick(e)}
>
<IconReload
class={twMerge(
allProviderIsUpdating() && 'animate-spin text-success',
)}
/>
</Button>
</Show>
</div>
</Show>
<div class="flex-1 overflow-y-auto">
<Show when={activeTab() === ActiveTab.ruleProviders}>
<ForTwoColumns
subChild={ruleProviders().map((ruleProvider) => {
return (
<div class="card card-bordered card-compact mb-2 bg-base-200 p-4">
<div
class="grid gap-2"
classList={{
'grid-cols-2': rulesRenderInTwoColumns(),
}}
>
<For each={ruleProviders()}>
{(ruleProvider) => (
<div class="card card-bordered card-compact bg-base-200 p-4">
<div class="flex items-center gap-2 pr-8">
<span class="break-all">{ruleProvider.name}</span>
<div class="badge badge-sm">{ruleProvider.ruleCount}</div>
</div>
<div class="text-xs text-slate-500">
{ruleProvider.vehicleType} / {ruleProvider.behavior} /
{t('updated')} {formatTimeFromNow(ruleProvider.updatedAt)}
</div>
<Button
class="btn-circle btn-sm absolute right-2 top-2 mr-2 h-4"
disabled={updatingMap()[ruleProvider.name]}
@ -123,35 +168,13 @@ export default () => {
/>
</Button>
</div>
)
})}
/>
</Show>
<Show when={activeTab() === ActiveTab.rules}>
<InfiniteScroll
each={renderRules()}
hasMore={renderRules().length < rules().length}
next={() => setMaxRuleRender(maxRuleRender() + 100)}
>
{(rule) => (
<div class="card card-bordered card-compact mb-2 bg-base-200 p-4">
<div class="flex items-center gap-2">
<span class="break-all">{rule.payload}</span>
<Show
when={typeof rule.size === 'number' && rule.size !== -1}
>
<div class="badge badge-sm">{rule.size}</div>
</Show>
</div>
<div class="text-xs text-slate-500">
{rule.type} :: {rule.proxy}
</div>
</div>
)}
</InfiniteScroll>
)}
</For>
</div>
</Show>
</div>
<RulesSettingsModal />
</div>
)
}

View File

@ -51,10 +51,16 @@ export const [favNightTheme, setFavNightTheme] = makePersisted(
createSignal('night'),
{ name: 'favNightTheme', storage: localStorage },
)
export const [renderInTwoColumns, setRenderInTwoColumns] = makePersisted(
createSignal(true),
{ name: 'renderInTwoColumn', storage: localStorage },
)
export const [proxiesRenderInTwoColumns, setProxiesRenderInTwoColumns] =
makePersisted(createSignal(true), {
name: 'proxiesRenderInTwoColumns',
storage: localStorage,
})
export const [rulesRenderInTwoColumns, setRulesRenderInTwoColumns] =
makePersisted(createSignal(true), {
name: 'rulesRenderInTwoColumns',
storage: localStorage,
})
export const [connectionsTableSize, setConnectionsTableSize] = makePersisted(
createSignal<TAILWINDCSS_SIZE>(TAILWINDCSS_SIZE.XS),
{ name: 'connectionsTableSize', storage: localStorage },