feat(config): rearrange settings

This commit is contained in:
kunish 2024-10-11 00:48:50 +08:00
parent 04cae65805
commit 90c3d15616
No known key found for this signature in database
GPG Key ID: 647A12B4F782C430
4 changed files with 144 additions and 120 deletions

View File

@ -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',

View File

@ -24,3 +24,5 @@ export const [I18nProvider, useMaybeI18n] = createContextProvider<
]) ])
export const useI18n = () => useMaybeI18n()! export const useI18n = () => useMaybeI18n()!
export { type Dict }

View File

@ -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 }} 端口',

View File

@ -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>