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-organize-imports": "^3.2.3",
"prettier-plugin-tailwindcss": "^0.5.4", "prettier-plugin-tailwindcss": "^0.5.4",
"solid-apexcharts": "^0.3.2", "solid-apexcharts": "^0.3.2",
"solid-infinite-scroll": "^1.0.1",
"solid-js": "^1.7.11", "solid-js": "^1.7.11",
"solid-toast": "^0.5.0", "solid-toast": "^0.5.0",
"sort-package-json": "^2.5.1", "sort-package-json": "^2.5.1",

View File

@ -131,9 +131,6 @@ dependencies:
solid-apexcharts: solid-apexcharts:
specifier: ^0.3.2 specifier: ^0.3.2
version: 0.3.2(apexcharts@3.42.0)(solid-js@1.7.11) 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: solid-js:
specifier: ^1.7.11 specifier: ^1.7.11
version: 1.7.11 version: 1.7.11
@ -5230,12 +5227,6 @@ packages:
solid-js: 1.7.11 solid-js: 1.7.11
dev: false 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: /solid-js@1.7.11:
resolution: {integrity: sha512-JkuvsHt8jqy7USsy9xJtT18aF9r2pFO+GB8JQ2XGTvtF49rGTObB46iebD25sE3qVNvIbwglXOXdALnJq9IHtQ==} resolution: {integrity: sha512-JkuvsHt8jqy7USsy9xJtT18aF9r2pFO+GB8JQ2XGTvtF49rGTObB46iebD25sE3qVNvIbwglXOXdALnJq9IHtQ==}
dependencies: dependencies:

View File

@ -1,6 +1,6 @@
import { JSX, ParentComponent, Show, createMemo } from 'solid-js' import { JSX, ParentComponent, Show, createMemo } from 'solid-js'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import { renderInTwoColumns } from '~/signals' import { proxiesRenderInTwoColumns } from '~/signals'
type Props = { type Props = {
title: JSX.Element title: JSX.Element
@ -27,7 +27,7 @@ export const Collapse: ParentComponent<Props> = (props) => {
} }
const mediaQueryClassName = createMemo(() => { const mediaQueryClassName = createMemo(() => {
if (renderInTwoColumns()) { if (proxiesRenderInTwoColumns()) {
return 'lg:grid-cols-3 xl:grid-cols-4' return 'lg:grid-cols-3 xl:grid-cols-4'
} else { } else {
return 'sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-7' 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 { createWindowSize } from '@solid-primitives/resize-observer'
import { JSX, Show, createMemo } from 'solid-js' import { JSX, Show, createMemo } from 'solid-js'
import { renderInTwoColumns } from '~/signals' import { proxiesRenderInTwoColumns } from '~/signals'
export const ForTwoColumns = (props: { subChild: JSX.Element[] }) => { export const ForTwoColumns = (props: { subChild: JSX.Element[] }) => {
const windowSize = createWindowSize() const windowSize = createWindowSize()
const isShowTwoColumns = createMemo( const isShowTwoColumns = createMemo(
() => windowSize.width >= 640 && renderInTwoColumns(), () => windowSize.width >= 640 && proxiesRenderInTwoColumns(),
) // 640 is sm size in daisyui ) // 640 is sm size in daisyui
const leftColumns = createMemo(() => const leftColumns = createMemo(() =>
props.subChild.filter((_, index) => index % 2 === 0 || !isShowTwoColumns()), props.subChild.filter((_, index) => index % 2 === 0 || !isShowTwoColumns()),

View File

@ -8,11 +8,13 @@ import {
latencyTestTimeoutDuration, latencyTestTimeoutDuration,
proxiesOrderingType, proxiesOrderingType,
proxiesPreviewType, proxiesPreviewType,
proxiesRenderInTwoColumns,
setAutoCloseConns, setAutoCloseConns,
setHideUnAvailableProxies, setHideUnAvailableProxies,
setLatencyTestTimeoutDuration, setLatencyTestTimeoutDuration,
setProxiesOrderingType, setProxiesOrderingType,
setProxiesPreviewType, setProxiesPreviewType,
setProxiesRenderInTwoColumns,
setUrlForLatencyTest, setUrlForLatencyTest,
urlForLatencyTest, urlForLatencyTest,
} from '~/signals' } from '~/signals'
@ -112,6 +114,19 @@ export const ProxiesSettingsModal = () => {
</For> </For>
</select> </select>
</div> </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> </div>
<form method="dialog" class="modal-backdrop"> <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 './ProxyNodePreview'
export * from './ProxyPreviewBar' export * from './ProxyPreviewBar'
export * from './ProxyPreviewDots' export * from './ProxyPreviewDots'
export * from './RulesSettingsModal'
export * from './SubscriptionInfo' export * from './SubscriptionInfo'

View File

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

View File

@ -1,11 +1,11 @@
import { useI18n } from '@solid-primitives/i18n' import { useI18n } from '@solid-primitives/i18n'
import { IconReload } from '@tabler/icons-solidjs' import { IconReload, IconSettings } from '@tabler/icons-solidjs'
import InfiniteScroll from 'solid-infinite-scroll' import { For, Show, createSignal, onMount } from 'solid-js'
import { For, Show, createMemo, createSignal, onMount } from 'solid-js'
import { twMerge } from 'tailwind-merge' 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 { formatTimeFromNow, useStringBooleanMap } from '~/helpers'
import { useRules } from '~/signals' import { rulesRenderInTwoColumns, useRules } from '~/signals'
enum ActiveTab { enum ActiveTab {
ruleProviders = 'ruleProviders', ruleProviders = 'ruleProviders',
@ -21,8 +21,6 @@ export default () => {
updateAllRuleProvider, updateAllRuleProvider,
updateRuleProviderByName, updateRuleProviderByName,
} = useRules() } = useRules()
const [maxRuleRender, setMaxRuleRender] = createSignal(100)
const renderRules = createMemo(() => rules().slice(0, maxRuleRender()))
onMount(updateRules) onMount(updateRules)
@ -61,9 +59,8 @@ export default () => {
return ( return (
<div class="flex h-full flex-col gap-2"> <div class="flex h-full flex-col gap-2">
<Show when={ruleProviders().length > 0}>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="tabs tabs-boxed gap-2"> <div class="tabs-boxed tabs gap-2">
<For each={tabs()}> <For each={tabs()}>
{(tab) => ( {(tab) => (
<button <button
@ -93,49 +90,34 @@ export default () => {
/> />
</Button> </Button>
</Show> </Show>
</div>
</Show>
<div class="flex-1 overflow-y-auto"> <div class="ml-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="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 <Button
class="btn-circle btn-sm absolute right-2 top-2 mr-2 h-4" class="btn-circle btn-sm sm:btn-md"
disabled={updatingMap()[ruleProvider.name]} onClick={() => {
onClick={(e) => onUpdateProviderClick(e, ruleProvider.name)} const modal = document.querySelector(
`#${MODAL.RULES_SETTINGS}`,
) as HTMLDialogElement | null
modal?.showModal()
}}
> >
<IconReload <IconSettings />
class={twMerge(
updatingMap()[ruleProvider.name] &&
'animate-spin text-success',
)}
/>
</Button> </Button>
</div> </div>
) </div>
})}
/>
</Show>
<div class="flex-1 overflow-y-auto">
<Show when={activeTab() === ActiveTab.rules}> <Show when={activeTab() === ActiveTab.rules}>
<InfiniteScroll <div
each={renderRules()} class="grid gap-2"
hasMore={renderRules().length < rules().length} classList={{
next={() => setMaxRuleRender(maxRuleRender() + 100)} 'grid-cols-2': rulesRenderInTwoColumns(),
}}
> >
<For each={rules()}>
{(rule) => ( {(rule) => (
<div class="card card-bordered card-compact mb-2 bg-base-200 p-4"> <div class="card card-bordered card-compact bg-base-200 p-4">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="break-all">{rule.payload}</span> <span class="break-all">{rule.payload}</span>
<Show <Show
@ -149,9 +131,50 @@ export default () => {
</div> </div>
</div> </div>
)} )}
</InfiniteScroll> </For>
</div>
</Show>
<Show when={activeTab() === ActiveTab.ruleProviders}>
<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]}
onClick={(e) => onUpdateProviderClick(e, ruleProvider.name)}
>
<IconReload
class={twMerge(
updatingMap()[ruleProvider.name] &&
'animate-spin text-success',
)}
/>
</Button>
</div>
)}
</For>
</div>
</Show> </Show>
</div> </div>
<RulesSettingsModal />
</div> </div>
) )
} }

View File

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