mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-11-23 21:35:36 +08:00
feat(rules): renderInTwoColumns
This commit is contained in:
parent
9e556d959e
commit
6743ebde8f
@ -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",
|
||||
|
@ -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:
|
||||
|
@ -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'
|
||||
|
@ -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()),
|
||||
|
@ -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">
|
||||
|
34
src/components/RulesSettingsModal.tsx
Normal file
34
src/components/RulesSettingsModal.tsx
Normal 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>
|
||||
)
|
||||
}
|
@ -14,4 +14,5 @@ export * from './ProxyNodeCard'
|
||||
export * from './ProxyNodePreview'
|
||||
export * from './ProxyPreviewBar'
|
||||
export * from './ProxyPreviewDots'
|
||||
export * from './RulesSettingsModal'
|
||||
export * from './SubscriptionInfo'
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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 },
|
||||
|
Loading…
Reference in New Issue
Block a user