SubscriptionGeneralTab.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import { Alert, Button, Input, InputNumber, Switch, Tabs } from 'antd';
  2. import { BranchesOutlined, CompassOutlined, IdcardOutlined, InfoCircleOutlined, NodeIndexOutlined, SafetyCertificateOutlined, SettingOutlined } from '@ant-design/icons';
  3. import { useTranslation } from 'react-i18next';
  4. import { useNavigate } from 'react-router-dom';
  5. import type { AllSetting } from '@/models/setting';
  6. import { SettingListItem } from '@/components/ui';
  7. import { RemarkTemplateField } from '@/components/form';
  8. import { useMediaQuery } from '@/hooks/useMediaQuery';
  9. import { catTabLabel } from './catTabLabel';
  10. import { sanitizePath, normalizePath } from './uriPath';
  11. interface SubscriptionGeneralTabProps {
  12. allSetting: AllSetting;
  13. updateSetting: (patch: Partial<AllSetting>) => void;
  14. }
  15. export default function SubscriptionGeneralTab({ allSetting, updateSetting }: SubscriptionGeneralTabProps) {
  16. const { t } = useTranslation();
  17. const navigate = useNavigate();
  18. const { isMobile } = useMediaQuery();
  19. return (
  20. <Tabs defaultActiveKey="1" items={[
  21. {
  22. key: '1',
  23. label: catTabLabel(<SettingOutlined />, t('pages.settings.panelSettings'), isMobile),
  24. children: (
  25. <>
  26. <SettingListItem paddings="small" title={t('pages.settings.subEnable')} description={t('pages.settings.subEnableDesc')}>
  27. <Switch checked={allSetting.subEnable} onChange={(v) => updateSetting({ subEnable: v })} />
  28. </SettingListItem>
  29. <SettingListItem paddings="small" title={t('pages.settings.subJsonEnableTitle')} description={t('pages.settings.subJsonEnable')}>
  30. <Switch checked={allSetting.subJsonEnable} onChange={(v) => updateSetting({ subJsonEnable: v })} />
  31. </SettingListItem>
  32. <SettingListItem paddings="small" title={t('pages.settings.subClashEnableTitle')}>
  33. <Switch checked={allSetting.subClashEnable} onChange={(v) => updateSetting({ subClashEnable: v })} />
  34. </SettingListItem>
  35. {(allSetting.subJsonEnable || allSetting.subClashEnable) && (
  36. <Alert
  37. type="info"
  38. showIcon
  39. style={{ margin: '12px 20px' }}
  40. title={t('pages.settings.subFormatsTipTitle')}
  41. description={t('pages.settings.subFormatsTipDesc')}
  42. action={(
  43. <Button size="small" onClick={() => navigate('/settings#subscription-formats')}>
  44. {t('pages.settings.subFormatsTipAction')}
  45. </Button>
  46. )}
  47. />
  48. )}
  49. <SettingListItem paddings="small" title={t('pages.settings.subListen')} description={t('pages.settings.subListenDesc')}>
  50. <Input value={allSetting.subListen} onChange={(e) => updateSetting({ subListen: e.target.value })} />
  51. </SettingListItem>
  52. <SettingListItem paddings="small" title={t('pages.settings.subDomain')} description={t('pages.settings.subDomainDesc')}>
  53. <Input value={allSetting.subDomain} onChange={(e) => updateSetting({ subDomain: e.target.value })} />
  54. </SettingListItem>
  55. <SettingListItem paddings="small" title={t('pages.settings.subPort')} description={t('pages.settings.subPortDesc')}>
  56. <InputNumber value={allSetting.subPort} min={1} max={65535} style={{ width: '100%' }}
  57. onChange={(v) => updateSetting({ subPort: Number(v) || 0 })} />
  58. </SettingListItem>
  59. <SettingListItem paddings="small" title={t('pages.settings.subPath')} description={t('pages.settings.subPathDesc')}>
  60. <Input
  61. value={allSetting.subPath}
  62. placeholder="/sub/"
  63. onChange={(e) => updateSetting({ subPath: sanitizePath(e.target.value) })}
  64. onBlur={() => updateSetting({ subPath: normalizePath(allSetting.subPath) })}
  65. />
  66. </SettingListItem>
  67. <SettingListItem paddings="small" title={t('pages.settings.subURI')} description={t('pages.settings.subURIDesc')}>
  68. <Input value={allSetting.subURI} placeholder="(http|https)://domain[:port]/path/"
  69. onChange={(e) => updateSetting({ subURI: e.target.value })} />
  70. </SettingListItem>
  71. </>
  72. ),
  73. },
  74. {
  75. key: '2',
  76. label: catTabLabel(<InfoCircleOutlined />, t('pages.settings.information'), isMobile),
  77. children: (
  78. <>
  79. <SettingListItem paddings="small" title={t('pages.settings.subEncrypt')} description={t('pages.settings.subEncryptDesc')}>
  80. <Switch checked={allSetting.subEncrypt} onChange={(v) => updateSetting({ subEncrypt: v })} />
  81. </SettingListItem>
  82. <SettingListItem
  83. paddings="small"
  84. title={t('pages.settings.remarkTemplate')}
  85. description={t('pages.settings.remarkTemplateDesc')}
  86. >
  87. <RemarkTemplateField
  88. value={allSetting.remarkTemplate}
  89. onChange={(v) => updateSetting({ remarkTemplate: v })}
  90. maxLength={256}
  91. />
  92. </SettingListItem>
  93. <SettingListItem paddings="small" title={t('pages.settings.subUpdates')} description={t('pages.settings.subUpdatesDesc')}>
  94. <InputNumber value={allSetting.subUpdates} min={0} max={525600} style={{ width: '100%' }}
  95. onChange={(v) => updateSetting({ subUpdates: Number(v) || 0 })} />
  96. </SettingListItem>
  97. </>
  98. ),
  99. },
  100. {
  101. key: '3',
  102. label: catTabLabel(<IdcardOutlined />, t('pages.settings.profile'), isMobile),
  103. children: (
  104. <>
  105. <SettingListItem paddings="small" title={t('pages.settings.subTitle')} description={t('pages.settings.subTitleDesc')}>
  106. <Input value={allSetting.subTitle} onChange={(e) => updateSetting({ subTitle: e.target.value })} />
  107. </SettingListItem>
  108. <SettingListItem paddings="small" title={t('pages.settings.subSupportUrl')} description={t('pages.settings.subSupportUrlDesc')}>
  109. <Input value={allSetting.subSupportUrl} placeholder="https://example.com"
  110. onChange={(e) => updateSetting({ subSupportUrl: e.target.value })} />
  111. </SettingListItem>
  112. <SettingListItem paddings="small" title={t('pages.settings.subProfileUrl')} description={t('pages.settings.subProfileUrlDesc')}>
  113. <Input value={allSetting.subProfileUrl} placeholder="https://example.com"
  114. onChange={(e) => updateSetting({ subProfileUrl: e.target.value })} />
  115. </SettingListItem>
  116. <SettingListItem paddings="small" title={t('pages.settings.subAnnounce')} description={t('pages.settings.subAnnounceDesc')}>
  117. <Input.TextArea value={allSetting.subAnnounce}
  118. onChange={(e) => updateSetting({ subAnnounce: e.target.value })} />
  119. </SettingListItem>
  120. <SettingListItem
  121. paddings="small"
  122. title={t('pages.settings.subThemeDir')}
  123. description={(
  124. <>
  125. {t('pages.settings.subThemeDirDesc')}{' '}
  126. <a
  127. href="https://github.com/MHSanaei/3x-ui/blob/main/docs/custom-subscription-templates.md"
  128. target="_blank"
  129. rel="noopener noreferrer"
  130. >
  131. {t('pages.settings.subThemeDirDocs')}
  132. </a>
  133. </>
  134. )}
  135. >
  136. <Input value={allSetting.subThemeDir} placeholder="/etc/3x-ui/sub_templates/my-theme/"
  137. onChange={(e) => updateSetting({ subThemeDir: e.target.value })} />
  138. </SettingListItem>
  139. </>
  140. ),
  141. },
  142. {
  143. key: '4',
  144. label: catTabLabel(<SafetyCertificateOutlined />, t('pages.settings.certs'), isMobile),
  145. children: (
  146. <>
  147. <SettingListItem paddings="small" title={t('pages.settings.subCertPath')} description={t('pages.settings.subCertPathDesc')}>
  148. <Input value={allSetting.subCertFile} onChange={(e) => updateSetting({ subCertFile: e.target.value })} />
  149. </SettingListItem>
  150. <SettingListItem paddings="small" title={t('pages.settings.subKeyPath')} description={t('pages.settings.subKeyPathDesc')}>
  151. <Input value={allSetting.subKeyFile} onChange={(e) => updateSetting({ subKeyFile: e.target.value })} />
  152. </SettingListItem>
  153. </>
  154. ),
  155. },
  156. {
  157. key: '5',
  158. label: catTabLabel(<BranchesOutlined />, 'Happ', isMobile),
  159. children: (
  160. <>
  161. <SettingListItem paddings="small" title={t('pages.settings.subEnableRouting')} description={t('pages.settings.subEnableRoutingDesc')}>
  162. <Switch checked={allSetting.subEnableRouting} onChange={(v) => updateSetting({ subEnableRouting: v })} />
  163. </SettingListItem>
  164. <SettingListItem paddings="small" title={t('pages.settings.subRoutingRules')} description={t('pages.settings.subRoutingRulesDesc')}>
  165. <Input.TextArea value={allSetting.subRoutingRules} placeholder="happ://routing/add/..."
  166. onChange={(e) => updateSetting({ subRoutingRules: e.target.value })} />
  167. </SettingListItem>
  168. <SettingListItem paddings="small" title={t('pages.settings.subHideSettings')} description={t('pages.settings.subHideSettingsDesc')}>
  169. <Switch checked={allSetting.subHideSettings} onChange={(v) => updateSetting({ subHideSettings: v })} />
  170. </SettingListItem>
  171. </>
  172. ),
  173. },
  174. {
  175. key: '6',
  176. label: catTabLabel(<NodeIndexOutlined />, 'Clash / Mihomo', isMobile),
  177. children: (
  178. <>
  179. <SettingListItem paddings="small" title={t('pages.settings.subClashEnableRouting')} description={t('pages.settings.subClashEnableRoutingDesc')}>
  180. <Switch checked={allSetting.subClashEnableRouting} onChange={(v) => updateSetting({ subClashEnableRouting: v })} />
  181. </SettingListItem>
  182. <SettingListItem paddings="small" title={t('pages.settings.subClashRoutingRules')} description={t('pages.settings.subClashRoutingRulesDesc')}>
  183. <Input.TextArea
  184. value={allSetting.subClashRules}
  185. rows={8}
  186. placeholder={'GEOSITE,category-ir,DIRECT\nGEOIP,private,DIRECT'}
  187. onChange={(e) => updateSetting({ subClashRules: e.target.value })}
  188. />
  189. </SettingListItem>
  190. </>
  191. ),
  192. },
  193. {
  194. key: '7',
  195. label: catTabLabel(<CompassOutlined />, 'Incy', isMobile),
  196. children: (
  197. <>
  198. <SettingListItem paddings="small" title={t('pages.settings.subIncyEnableRouting')} description={t('pages.settings.subIncyEnableRoutingDesc')}>
  199. <Switch checked={allSetting.subIncyEnableRouting} onChange={(v) => updateSetting({ subIncyEnableRouting: v })} />
  200. </SettingListItem>
  201. <SettingListItem paddings="small" title={t('pages.settings.subIncyRoutingRules')} description={t('pages.settings.subIncyRoutingRulesDesc')}>
  202. <Input.TextArea value={allSetting.subIncyRoutingRules} placeholder="incy://routing/onadd/..."
  203. onChange={(e) => updateSetting({ subIncyRoutingRules: e.target.value })} />
  204. </SettingListItem>
  205. </>
  206. ),
  207. },
  208. ]} />
  209. );
  210. }