diff --git a/src/components/ConfigureNodeFormModal/TrojanForm.tsx b/src/components/ConfigureNodeFormModal/TrojanForm.tsx
index a5f1e0fa..4e10af4a 100644
--- a/src/components/ConfigureNodeFormModal/TrojanForm.tsx
+++ b/src/components/ConfigureNodeFormModal/TrojanForm.tsx
@@ -43,7 +43,7 @@ export const TrojanForm = ({ onLinkGeneration }: { onLinkGeneration: (link: stri
return onLinkGeneration(
generateURL({
- protocol: protocol,
+ protocol,
username: values.password,
host: values.server,
port: values.port,
@@ -92,7 +92,7 @@ export const TrojanForm = ({ onLinkGeneration }: { onLinkGeneration: (link: stri
)}
diff --git a/src/components/ConfigureNodeFormModal/TuicForm.tsx b/src/components/ConfigureNodeFormModal/TuicForm.tsx
new file mode 100644
index 00000000..0090a0d4
--- /dev/null
+++ b/src/components/ConfigureNodeFormModal/TuicForm.tsx
@@ -0,0 +1,81 @@
+import { Checkbox, NumberInput, Select, TextInput } from '@mantine/core'
+import { useForm, zodResolver } from '@mantine/form'
+import { useTranslation } from 'react-i18next'
+import { z } from 'zod'
+
+import { FormActions } from '~/components/FormActions'
+import { DEFAULT_TUIC_FORM_VALUES, tuicSchema } from '~/constants'
+import { generateURL } from '~/utils'
+
+export const TuicForm = ({ onLinkGeneration }: { onLinkGeneration: (link: string) => void }) => {
+ const { t } = useTranslation()
+ const { onSubmit, getInputProps, reset } = useForm>({
+ initialValues: DEFAULT_TUIC_FORM_VALUES,
+ validate: zodResolver(tuicSchema),
+ })
+
+ const handleSubmit = onSubmit((values) => {
+ const query = {
+ congestion_control: values.congestion_control,
+ alpn: values.alpn,
+ sni: values.sni,
+ allow_insecure: values.allowInsecure,
+ disable_sni: values.disable_sni,
+ udp_relay_mode: values.udp_relay_mode,
+ }
+
+ return onLinkGeneration(
+ generateURL({
+ protocol: 'tuic',
+ username: values.uuid,
+ password: values.password,
+ host: values.server,
+ port: values.port,
+ hash: values.name,
+ params: query,
+ }),
+ )
+ })
+
+ return (
+
+ )
+}
diff --git a/src/components/ConfigureNodeFormModal/index.tsx b/src/components/ConfigureNodeFormModal/index.tsx
index f0f94e29..aec18ce9 100644
--- a/src/components/ConfigureNodeFormModal/index.tsx
+++ b/src/components/ConfigureNodeFormModal/index.tsx
@@ -1,4 +1,4 @@
-import { Divider, MantineProvider, Modal, Stack, Tabs, TextInput } from '@mantine/core'
+import { MantineProvider, Modal, Stack, Tabs, TextInput } from '@mantine/core'
import { useForm, zodResolver } from '@mantine/form'
import { useTranslation } from 'react-i18next'
import { z } from 'zod'
@@ -10,6 +10,7 @@ import { SSForm } from './SSForm'
import { SSRForm } from './SSRForm'
import { Socks5Form } from './Socks5Form'
import { TrojanForm } from './TrojanForm'
+import { TuicForm } from './TuicForm'
import { V2rayForm } from './V2rayForm'
const schema = z.object({ tag: z.string().nonempty() })
@@ -38,16 +39,18 @@ export const ConfigureNodeFormModal = ({ opened, onClose }: { opened: boolean; o
}
return (
-
+
-
-
SS
SSR
Trojan
+ Tuic
HTTP
SOCKS5
@@ -87,6 +91,12 @@ export const ConfigureNodeFormModal = ({ opened, onClose }: { opened: boolean; o
+
+
+
+
+
+
diff --git a/src/constants/default.ts b/src/constants/default.ts
index 8aa4fd12..8fdd6203 100644
--- a/src/constants/default.ts
+++ b/src/constants/default.ts
@@ -3,7 +3,7 @@ import { z } from 'zod'
import { GlobalInput, Policy } from '~/schemas/gql/graphql'
import { DialMode, LogLevel, TLSImplementation, TcpCheckHttpMethod, UTLSImitate } from './misc'
-import { httpSchema, socks5Schema, ssSchema, ssrSchema, trojanSchema, v2raySchema } from './schema'
+import { httpSchema, socks5Schema, ssSchema, ssrSchema, trojanSchema, tuicSchema, v2raySchema } from './schema'
export const DEFAULT_ENDPOINT_URL = `${location.protocol}//${location.hostname}:2023/graphql`
@@ -132,6 +132,20 @@ export const DEFAULT_TROJAN_FORM_VALUES: z.infer = {
ssPassword: '',
}
+export const DEFAULT_TUIC_FORM_VALUES: z.infer = {
+ name: '',
+ port: 0,
+ server: '',
+ alpn: '',
+ congestion_control: '',
+ disable_sni: false,
+ allowInsecure: false,
+ uuid: '',
+ password: '',
+ udp_relay_mode: '',
+ sni: '',
+}
+
export const DEFAULT_HTTP_FORM_VALUES: z.infer = {
host: '',
name: '',
diff --git a/src/constants/schema.ts b/src/constants/schema.ts
index 24755ca2..5f02d430 100644
--- a/src/constants/schema.ts
+++ b/src/constants/schema.ts
@@ -92,6 +92,20 @@ export const trojanSchema = z.object({
obfs: z.enum(['none', 'websocket']),
})
+export const tuicSchema = z.object({
+ name: z.string(),
+ server: z.string().nonempty(),
+ port: z.number().min(0).max(65535),
+ uuid: z.string().nonempty(),
+ password: z.string().nonempty(),
+ allowInsecure: z.boolean(),
+ disable_sni: z.boolean(),
+ sni: z.string(),
+ congestion_control: z.string(),
+ alpn: z.string(),
+ udp_relay_mode: z.string(),
+})
+
export const httpSchema = z.object({
username: z.string(),
password: z.string(),
diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index abba6006..4f37dc12 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -41,6 +41,7 @@
"collapse": "collapse",
"config": "Config",
"configureNode": {
+ "congestionControl": "Congestion Control",
"dtlsObfuscation": "Obfuscated as DTLS1.2 Packets",
"forceTLS": "forcibly TLS on",
"host": "Host",
diff --git a/src/i18n/locales/zh-Hans.json b/src/i18n/locales/zh-Hans.json
index 7564a58e..d09b715d 100644
--- a/src/i18n/locales/zh-Hans.json
+++ b/src/i18n/locales/zh-Hans.json
@@ -41,6 +41,7 @@
"collapse": "折叠",
"config": "配置",
"configureNode": {
+ "congestionControl": "拥堵控制算法",
"dtlsObfuscation": "伪装为 DTLS1.2 数据包",
"forceTLS": "强制开启 TLS",
"host": "主机地址",