mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-12-26 07:24:10 +08:00
feat(config): rearrange settings
This commit is contained in:
parent
04cae65805
commit
90c3d15616
@ -108,7 +108,7 @@ export default {
|
|||||||
enableTunDevice: 'Enable TUN Device',
|
enableTunDevice: 'Enable TUN Device',
|
||||||
tunModeStack: 'TUN Mode Stack',
|
tunModeStack: 'TUN Mode Stack',
|
||||||
tunDeviceName: 'TUN Device Name',
|
tunDeviceName: 'TUN Device Name',
|
||||||
interfaceName: 'Interface Name',
|
outboundInterfaceName: 'Outbound Interface Name',
|
||||||
en: 'English',
|
en: 'English',
|
||||||
zh: 'Chinese',
|
zh: 'Chinese',
|
||||||
port: '{{ name }} Port',
|
port: '{{ name }} Port',
|
||||||
|
@ -24,3 +24,5 @@ export const [I18nProvider, useMaybeI18n] = createContextProvider<
|
|||||||
])
|
])
|
||||||
|
|
||||||
export const useI18n = () => useMaybeI18n()!
|
export const useI18n = () => useMaybeI18n()!
|
||||||
|
|
||||||
|
export { type Dict }
|
||||||
|
@ -110,7 +110,7 @@ export default {
|
|||||||
enableTunDevice: '开启 TUN 转发',
|
enableTunDevice: '开启 TUN 转发',
|
||||||
tunModeStack: 'TUN 模式堆栈',
|
tunModeStack: 'TUN 模式堆栈',
|
||||||
tunDeviceName: 'TUN 设备名称',
|
tunDeviceName: 'TUN 设备名称',
|
||||||
interfaceName: '接口名称',
|
outboundInterfaceName: '出站接口名称',
|
||||||
en: '英文',
|
en: '英文',
|
||||||
zh: '中文',
|
zh: '中文',
|
||||||
port: '{{ name }} 端口',
|
port: '{{ name }} 端口',
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { createForm } from '@felte/solid'
|
import { createForm } from '@felte/solid'
|
||||||
import { validator } from '@felte/validator-zod'
|
import { validator } from '@felte/validator-zod'
|
||||||
import type { Accessor, Component, ParentComponent } from 'solid-js'
|
import type { Accessor, Component, JSX, ParentComponent } from 'solid-js'
|
||||||
import { toast } from 'solid-toast'
|
import { toast } from 'solid-toast'
|
||||||
|
import { twMerge } from 'tailwind-merge'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
import {
|
import {
|
||||||
fetchBackendConfigAPI,
|
fetchBackendConfigAPI,
|
||||||
@ -25,7 +26,7 @@ import {
|
|||||||
import { Button, ConfigTitle } from '~/components'
|
import { Button, ConfigTitle } from '~/components'
|
||||||
import DocumentTitle from '~/components/DocumentTitle'
|
import DocumentTitle from '~/components/DocumentTitle'
|
||||||
import { LANG, ROUTES, themes } from '~/constants'
|
import { LANG, ROUTES, themes } from '~/constants'
|
||||||
import { locale, setLocale, useI18n } from '~/i18n'
|
import { Dict, locale, setLocale, useI18n } from '~/i18n'
|
||||||
import {
|
import {
|
||||||
autoSwitchTheme,
|
autoSwitchTheme,
|
||||||
endpoint,
|
endpoint,
|
||||||
@ -41,6 +42,55 @@ import {
|
|||||||
} from '~/signals'
|
} from '~/signals'
|
||||||
import type { DNSQuery } from '~/types'
|
import type { DNSQuery } from '~/types'
|
||||||
|
|
||||||
|
const Toggle: ParentComponent<JSX.InputHTMLAttributes<HTMLInputElement>> = (
|
||||||
|
props,
|
||||||
|
) => {
|
||||||
|
const [local, others] = splitProps(props, ['class'])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input type="checkbox" class={twMerge('toggle', local.class)} {...others} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Input: ParentComponent<JSX.InputHTMLAttributes<HTMLInputElement>> = (
|
||||||
|
props,
|
||||||
|
) => {
|
||||||
|
const [local, others] = splitProps(props, ['class'])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
class={twMerge('input input-bordered min-w-0', local.class)}
|
||||||
|
{...others}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Select: ParentComponent<JSX.SelectHTMLAttributes<HTMLSelectElement>> = (
|
||||||
|
props,
|
||||||
|
) => {
|
||||||
|
const [local, others] = splitProps(props, ['class'])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select class={twMerge('select select-bordered', local.class)} {...others}>
|
||||||
|
{children(() => others.children)()}
|
||||||
|
</select>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Label: ParentComponent<JSX.LabelHTMLAttributes<HTMLLabelElement>> = (
|
||||||
|
props,
|
||||||
|
) => {
|
||||||
|
const [local, others] = splitProps(props, ['class'])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label class={twMerge('label', local.class)} {...others}>
|
||||||
|
<span class="label-text truncate">
|
||||||
|
{children(() => others.children)()}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const dnsQueryFormSchema = z.object({
|
const dnsQueryFormSchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
type: z.string(),
|
type: z.string(),
|
||||||
@ -71,10 +121,10 @@ const DNSQueryForm = () => {
|
|||||||
return (
|
return (
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<form use:form={form} class="flex gap-2 sm:flex-row">
|
<form use:form={form} class="flex gap-2 sm:flex-row">
|
||||||
<input
|
<Input
|
||||||
type="search"
|
type="search"
|
||||||
name="name"
|
name="name"
|
||||||
class="input input-bordered min-w-0 flex-1"
|
class="flex-1"
|
||||||
placeholder="google.com"
|
placeholder="google.com"
|
||||||
onInput={(e) => {
|
onInput={(e) => {
|
||||||
if (!e.target.value) setDNSQueryResult([])
|
if (!e.target.value) setDNSQueryResult([])
|
||||||
@ -82,11 +132,11 @@ const DNSQueryForm = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<select name="type" class="select select-bordered">
|
<Select name="type">
|
||||||
<option>A</option>
|
<option>A</option>
|
||||||
<option>AAAA</option>
|
<option>AAAA</option>
|
||||||
<option>MX</option>
|
<option>MX</option>
|
||||||
</select>
|
</Select>
|
||||||
|
|
||||||
<Button type="submit" class="btn-primary" loading={isSubmitting()}>
|
<Button type="submit" class="btn-primary" loading={isSubmitting()}>
|
||||||
{t('dnsQuery')}
|
{t('dnsQuery')}
|
||||||
@ -188,75 +238,63 @@ const ConfigForm: ParentComponent<{ isSingBox: Accessor<boolean> }> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<select
|
<div class="grid grid-cols-3 gap-2">
|
||||||
class="select select-bordered"
|
<div class="form-control">
|
||||||
value={configsData()?.mode}
|
<Label for="enable-allow-lan">{t('allowLan')}</Label>
|
||||||
onChange={(e) =>
|
|
||||||
void updateBackendConfigAPI('mode', e.target.value, refetch)
|
<Toggle
|
||||||
}
|
id="enable-allow-lan"
|
||||||
>
|
checked={configsData()?.['allow-lan']}
|
||||||
<For each={modes()}>
|
onChange={(e) =>
|
||||||
{(name) => (
|
void updateBackendConfigAPI(
|
||||||
<option value={name}>
|
'allow-lan',
|
||||||
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
|
e.target.checked,
|
||||||
{t(name as any) ?? name}
|
refetch,
|
||||||
</option>
|
)
|
||||||
)}
|
}
|
||||||
</For>
|
/>
|
||||||
</select>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<Label for="mode">{t('rule')}</Label>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
id="mode"
|
||||||
|
value={configsData()?.mode}
|
||||||
|
onChange={(e) =>
|
||||||
|
void updateBackendConfigAPI('mode', e.target.value, refetch)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<For each={modes()}>
|
||||||
|
{(name) => <option value={name}>{t(name as keyof Dict)}</option>}
|
||||||
|
</For>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<Label for="interface-name">{t('outboundInterfaceName')}</Label>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
id="interface-name"
|
||||||
|
value={configsData()?.['interface-name']}
|
||||||
|
onChange={(e) =>
|
||||||
|
void updateBackendConfigAPI(
|
||||||
|
'interface-name',
|
||||||
|
e.target.value,
|
||||||
|
refetch,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Show when={!isSingBox()}>
|
<Show when={!isSingBox()}>
|
||||||
<form class="grid grid-cols-3 gap-2 sm:grid-cols-5" use:form={form}>
|
<div class="grid grid-cols-3 gap-2">
|
||||||
<For each={portList}>
|
|
||||||
{(item) => (
|
|
||||||
<div class="form-control">
|
|
||||||
<label for={item.key} class="label">
|
|
||||||
<span class="label-text">{item.label()}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<input
|
|
||||||
id={item.key}
|
|
||||||
name={item.key}
|
|
||||||
type="number"
|
|
||||||
class="input input-bordered"
|
|
||||||
placeholder={item.label()}
|
|
||||||
onChange={item.onChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-2 sm:grid-cols-4">
|
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label for="enable-allow-lan" class="label gap-2">
|
<Label for="enable-tun-device">{t('enableTunDevice')}</Label>
|
||||||
<span class="label-text">{t('allowLan')}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<input
|
<Toggle
|
||||||
id="enable-allow-lan"
|
|
||||||
type="checkbox"
|
|
||||||
class="toggle"
|
|
||||||
checked={configsData()?.['allow-lan']}
|
|
||||||
onChange={(e) =>
|
|
||||||
void updateBackendConfigAPI(
|
|
||||||
'allow-lan',
|
|
||||||
e.target.checked,
|
|
||||||
refetch,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label for="enable-tun-device" class="label gap-2">
|
|
||||||
<span class="label-text">{t('enableTunDevice')}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<input
|
|
||||||
id="enable-tun-device"
|
id="enable-tun-device"
|
||||||
type="checkbox"
|
|
||||||
class="toggle"
|
|
||||||
checked={configsData()?.tun?.enable}
|
checked={configsData()?.tun?.enable}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
void updateBackendConfigAPI(
|
void updateBackendConfigAPI(
|
||||||
@ -269,13 +307,10 @@ const ConfigForm: ParentComponent<{ isSingBox: Accessor<boolean> }> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label for="tun-ip-stack" class="label gap-2">
|
<Label for="tun-ip-stack">{t('tunModeStack')}</Label>
|
||||||
<span class="label-text">{t('tunModeStack')}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<select
|
<Select
|
||||||
id="tun-ip-stack"
|
id="tun-ip-stack"
|
||||||
class="select select-bordered flex-1"
|
|
||||||
value={configsData()?.tun?.stack}
|
value={configsData()?.tun?.stack}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
void updateBackendConfigAPI(
|
void updateBackendConfigAPI(
|
||||||
@ -289,17 +324,14 @@ const ConfigForm: ParentComponent<{ isSingBox: Accessor<boolean> }> = ({
|
|||||||
<option>gVisor</option>
|
<option>gVisor</option>
|
||||||
<option>System</option>
|
<option>System</option>
|
||||||
<option>LWIP</option>
|
<option>LWIP</option>
|
||||||
</select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label for="device-name" class="label gap-2">
|
<Label for="device-name">{t('tunDeviceName')}</Label>
|
||||||
<span class="label-text">{t('tunDeviceName')}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<input
|
<Input
|
||||||
id="device-name"
|
id="device-name"
|
||||||
class="input input-bordered min-w-0"
|
|
||||||
value={configsData()?.tun?.device}
|
value={configsData()?.tun?.device}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
void updateBackendConfigAPI(
|
void updateBackendConfigAPI(
|
||||||
@ -310,29 +342,28 @@ const ConfigForm: ParentComponent<{ isSingBox: Accessor<boolean> }> = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label for="interface-name" class="label gap-2">
|
|
||||||
<span class="label-text">{t('interfaceName')}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<input
|
|
||||||
id="interface-name"
|
|
||||||
class="input input-bordered min-w-0"
|
|
||||||
value={configsData()?.['interface-name']}
|
|
||||||
onChange={(e) =>
|
|
||||||
void updateBackendConfigAPI(
|
|
||||||
'interface-name',
|
|
||||||
e.target.value,
|
|
||||||
refetch,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<form class="grid grid-cols-3 gap-2 sm:grid-cols-5" use:form={form}>
|
||||||
|
<For each={portList}>
|
||||||
|
{(item) => (
|
||||||
|
<div class="form-control">
|
||||||
|
<Label for={item.key}>{item.label()}</Label>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
id={item.key}
|
||||||
|
name={item.key}
|
||||||
|
type="number"
|
||||||
|
placeholder={item.label()}
|
||||||
|
onChange={item.onChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</form>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-2 sm:grid-cols-3">
|
<div class="grid grid-cols-2 gap-4 sm:grid-cols-3">
|
||||||
<Button
|
<Button
|
||||||
class="btn-primary"
|
class="btn-primary"
|
||||||
loading={reloadingConfigFile()}
|
loading={reloadingConfigFile()}
|
||||||
@ -407,9 +438,7 @@ const ConfigForXd = () => {
|
|||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<ConfigTitle>{t('useTwemoji')}</ConfigTitle>
|
<ConfigTitle>{t('useTwemoji')}</ConfigTitle>
|
||||||
|
|
||||||
<input
|
<Toggle
|
||||||
type="checkbox"
|
|
||||||
class="toggle"
|
|
||||||
checked={useTwemoji()}
|
checked={useTwemoji()}
|
||||||
onChange={(e) => setUseTwemoji(e.target.checked)}
|
onChange={(e) => setUseTwemoji(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
@ -418,10 +447,7 @@ const ConfigForXd = () => {
|
|||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<ConfigTitle>{t('switchLanguage')}</ConfigTitle>
|
<ConfigTitle>{t('switchLanguage')}</ConfigTitle>
|
||||||
|
|
||||||
<select
|
<Select onChange={(e) => setLocale(e.target.value as LANG)}>
|
||||||
class="select select-bordered"
|
|
||||||
onChange={(e) => setLocale(e.target.value as LANG)}
|
|
||||||
>
|
|
||||||
<For each={languages}>
|
<For each={languages}>
|
||||||
{(lang) => (
|
{(lang) => (
|
||||||
<option selected={locale() === lang.value} value={lang.value}>
|
<option selected={locale() === lang.value} value={lang.value}>
|
||||||
@ -429,7 +455,7 @@ const ConfigForXd = () => {
|
|||||||
</option>
|
</option>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@ -450,9 +476,7 @@ const ConfigForXd = () => {
|
|||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<ConfigTitle>{t('autoSwitchTheme')}</ConfigTitle>
|
<ConfigTitle>{t('autoSwitchTheme')}</ConfigTitle>
|
||||||
|
|
||||||
<input
|
<Toggle
|
||||||
type="checkbox"
|
|
||||||
class="toggle"
|
|
||||||
checked={autoSwitchTheme()}
|
checked={autoSwitchTheme()}
|
||||||
onChange={(e) => setAutoSwitchTheme(e.target.checked)}
|
onChange={(e) => setAutoSwitchTheme(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
@ -463,8 +487,7 @@ const ConfigForXd = () => {
|
|||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<ConfigTitle>{t('favDayTheme')}</ConfigTitle>
|
<ConfigTitle>{t('favDayTheme')}</ConfigTitle>
|
||||||
|
|
||||||
<select
|
<Select
|
||||||
class="select select-bordered"
|
|
||||||
value={favDayTheme()}
|
value={favDayTheme()}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setFavDayTheme(e.target.value as (typeof themes)[number])
|
setFavDayTheme(e.target.value as (typeof themes)[number])
|
||||||
@ -473,14 +496,13 @@ const ConfigForXd = () => {
|
|||||||
<For each={themes}>
|
<For each={themes}>
|
||||||
{(theme) => <option value={theme}>{theme}</option>}
|
{(theme) => <option value={theme}>{theme}</option>}
|
||||||
</For>
|
</For>
|
||||||
</select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<ConfigTitle>{t('favNightTheme')}</ConfigTitle>
|
<ConfigTitle>{t('favNightTheme')}</ConfigTitle>
|
||||||
|
|
||||||
<select
|
<Select
|
||||||
class="select select-bordered"
|
|
||||||
value={favNightTheme()}
|
value={favNightTheme()}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setFavNightTheme(e.target.value as (typeof themes)[number])
|
setFavNightTheme(e.target.value as (typeof themes)[number])
|
||||||
@ -489,7 +511,7 @@ const ConfigForXd = () => {
|
|||||||
<For each={themes}>
|
<For each={themes}>
|
||||||
{(theme) => <option value={theme}>{theme}</option>}
|
{(theme) => <option value={theme}>{theme}</option>}
|
||||||
</For>
|
</For>
|
||||||
</select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user