diff --git a/web/assets/element-ui/theme-chalk/display.css b/web/assets/element-ui/theme-chalk/display.css deleted file mode 100644 index 1d8790ba..00000000 --- a/web/assets/element-ui/theme-chalk/display.css +++ /dev/null @@ -1 +0,0 @@ -@media only screen and (max-width:767px){.hidden-xs-only{display:none!important}}@media only screen and (min-width:768px){.hidden-sm-and-up{display:none!important}}@media only screen and (min-width:768px) and (max-width:991px){.hidden-sm-only{display:none!important}}@media only screen and (max-width:991px){.hidden-sm-and-down{display:none!important}}@media only screen and (min-width:992px){.hidden-md-and-up{display:none!important}}@media only screen and (min-width:992px) and (max-width:1199px){.hidden-md-only{display:none!important}}@media only screen and (max-width:1199px){.hidden-md-and-down{display:none!important}}@media only screen and (min-width:1200px){.hidden-lg-and-up{display:none!important}}@media only screen and (min-width:1200px) and (max-width:1919px){.hidden-lg-only{display:none!important}}@media only screen and (max-width:1919px){.hidden-lg-and-down{display:none!important}}@media only screen and (min-width:1920px){.hidden-xl-only{display:none!important}} \ No newline at end of file diff --git a/web/assets/js/util/index.js b/web/assets/js/util/index.js index 85d53352..625af8b9 100644 --- a/web/assets/js/util/index.js +++ b/web/assets/js/util/index.js @@ -780,4 +780,10 @@ class LanguageManager { return languageFilter.length > 0; } +} + +class DeviceUtils { + static isMobile() { + return window.innerWidth <= 768; + } } \ No newline at end of file diff --git a/web/html/common/head.html b/web/html/common/head.html index ca854a30..35901769 100644 --- a/web/html/common/head.html +++ b/web/html/common/head.html @@ -2,10 +2,9 @@ <head> <meta charset="UTF-8"> <meta name="renderer" content="webkit"> - <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="robots" content="noindex,nofollow"> <link rel="stylesheet" href="{{ .base_path }}assets/ant-design-vue/antd.min.css"> - <link rel="stylesheet" href="{{ .base_path }}assets/element-ui/theme-chalk/display.css"> <link rel="stylesheet" href="{{ .base_path }}assets/css/custom.min.css?{{ .cur_ver }}"> <style> [v-cloak] { @@ -26,7 +25,7 @@ 'Segoe UI Emoji', 'Segoe UI Symbol'; } </style> - <title>{{ .host }}-{{ i18n .title}}</title> + <title>{{ .host }} – {{ i18n .title}}</title> </head> <div id="message"></div> {{end}} \ No newline at end of file diff --git a/web/html/xui/common_sider.html b/web/html/xui/common_sider.html deleted file mode 100644 index 97114c15..00000000 --- a/web/html/xui/common_sider.html +++ /dev/null @@ -1,55 +0,0 @@ -{{define "menuItems"}} -<a-menu-item key="{{ .base_path }}panel/"> - <a-icon type="dashboard"></a-icon> - <span>{{ i18n "menu.dashboard"}}</span> -</a-menu-item> -<a-menu-item key="{{ .base_path }}panel/inbounds"> - <a-icon type="user"></a-icon> - <span>{{ i18n "menu.inbounds"}}</span> -</a-menu-item> -<a-menu-item key="{{ .base_path }}panel/settings"> - <a-icon type="setting"></a-icon> - <span>{{ i18n "menu.settings"}}</span> -</a-menu-item> -<a-menu-item key="{{ .base_path }}panel/xray"> - <a-icon type="tool"></a-icon> - <span>{{ i18n "menu.xray"}}</span> -</a-menu-item> -<a-menu-item key="{{ .base_path }}logout"> - <a-icon type="logout"></a-icon> - <span>{{ i18n "menu.logout"}}</span> -</a-menu-item> -{{end}} - - -{{define "commonSider"}} -<a-layout-sider :theme="themeSwitcher.currentTheme" id="sider" collapsible breakpoint="md"> - <a-theme-switch></a-theme-switch> - <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="['{{ .request_uri }}']" @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> - {{template "menuItems" .}} - </a-menu> -</a-layout-sider> -<a-drawer id="sider-drawer" placement="left" :closable="false" @close="siderDrawer.close()" :visible="siderDrawer.visible" :wrap-class-name="themeSwitcher.currentTheme" :wrap-style="{ padding: 0 }"> - <div class="drawer-handle" @click="siderDrawer.change()" slot="handle"> - <a-icon :type="siderDrawer.visible ? 'close' : 'menu-fold'"></a-icon> - </div> - <a-theme-switch></a-theme-switch> - <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="['{{ .request_uri }}']" @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> - {{template "menuItems" .}} - </a-menu> -</a-drawer> -<script> - const siderDrawer = { - visible: false, - show() { - this.visible = true; - }, - close() { - this.visible = false; - }, - change() { - this.visible = !this.visible; - }, - }; -</script> -{{end}} diff --git a/web/html/xui/inbound_client_table.html b/web/html/xui/component/aClientTable.html similarity index 99% rename from web/html/xui/inbound_client_table.html rename to web/html/xui/component/aClientTable.html index fbf0699a..2bea96e8 100644 --- a/web/html/xui/inbound_client_table.html +++ b/web/html/xui/component/aClientTable.html @@ -1,4 +1,4 @@ -{{define "client_table"}} +{{define "component/aClientTable"}} <template slot="actions" slot-scope="text, client, index"> <a-tooltip> <template slot="title">{{ i18n "qrCode" }}</template> diff --git a/web/html/xui/component/aSidebar.html b/web/html/xui/component/aSidebar.html new file mode 100644 index 00000000..0ddaa176 --- /dev/null +++ b/web/html/xui/component/aSidebar.html @@ -0,0 +1,101 @@ +{{define "component/sidebar/content"}} +<template> + <div class="ant-sidebar"> + <a-layout-sider :theme="themeSwitcher.currentTheme" collapsible :collapsed="collapsed" + @collapse="(isCollapsed, type) => collapseHandle(isCollapsed, type)" breakpoint="md"> + <a-theme-switch></a-theme-switch> + <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="activeTab" + @click="({key}) => openLink(key)"> + <a-menu-item v-for="tab in tabs" :key="tab.key"> + <a-icon :type="tab.icon"></a-icon> + <span v-text="tab.title"></span> + </a-menu-item> + </a-menu> + </a-layout-sider> + <a-drawer placement="left" :closable="false" @close="closeDrawer" :visible="visible" + :wrap-class-name="themeSwitcher.currentTheme" :wrap-style="{ padding: 0 }" :style="{ height: '100%' }"> + <div class="drawer-handle" @click="toggleDrawer" slot="handle"> + <a-icon :type="visible ? 'close' : 'menu-fold'"></a-icon> + </div> + <a-theme-switch></a-theme-switch> + <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="activeTab" + @click="({key}) => openLink(key)"> + <a-menu-item v-for="tab in tabs" :key="tab.key"> + <a-icon :type="tab.icon"></a-icon> + <span v-text="tab.title"></span> + </a-menu-item> + </a-menu> + </a-drawer> + </div> +</template> +{{end}} + +{{define "component/aSidebar"}} +<style> + .ant-sidebar>.ant-layout-sider { + height: 100%; + } +</style> + +<script> + const SIDEBAR_COLLAPSED_KEY = "isSidebarCollapsed" + + Vue.component('a-sidebar', { + data() { + return { + tabs: [ + { + key: '/panel/', + icon: 'dashboard', + title: '{{ i18n "menu.dashboard"}}' + }, + { + key: '/panel/inbounds', + icon: 'user', + title: '{{ i18n "menu.inbounds"}}' + }, + { + key: '/panel/settings', + icon: 'setting', + title: '{{ i18n "menu.settings"}}' + }, + { + key: '/panel/xray', + icon: 'tool', + title: '{{ i18n "menu.xray"}}' + }, + { + key: '/logout/', + icon: 'logout', + title: '{{ i18n "menu.logout"}}' + }, + ], + activeTab: [ + '{{ .request_uri }}' + ], + visible: false, + collapsed: JSON.parse(localStorage.getItem(SIDEBAR_COLLAPSED_KEY)), + } + }, + methods: { + openLink(key) { + return key.startsWith('http') ? window.open(key) : location.href = key + }, + closeDrawer() { + this.visible = false; + }, + toggleDrawer() { + this.visible = !this.visible; + }, + collapseHandle(collapsed, type) { + if (type === "clickTrigger") { + localStorage.setItem(SIDEBAR_COLLAPSED_KEY, collapsed); + + this.collapsed = JSON.parse(localStorage.getItem(SIDEBAR_COLLAPSED_KEY)); + } + } + }, + template: `{{template "component/sidebar/content"}}`, + }); +</script> +{{end}} \ No newline at end of file diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html index 758de9e8..6c16bfa7 100644 --- a/web/html/xui/inbounds.html +++ b/web/html/xui/inbounds.html @@ -133,7 +133,7 @@ <body> <a-layout id="app" v-cloak :class="themeSwitcher.currentTheme"> - {{ template "commonSider" . }} + <a-sidebar></a-sidebar> <a-layout id="content-layout"> <a-layout-content> <a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'> @@ -568,7 +568,7 @@ :data-source="getInboundClients(record)" :pagination=pagination(getInboundClients(record)) :style="isMobile ? 'margin: -10px 2px -11px;' : 'margin: -10px 22px -11px;'"> - {{template "client_table"}} + {{template "component/aClientTable"}} </a-table> </template> </a-table> @@ -584,6 +584,7 @@ <script src="{{ .base_path }}assets/uri/URI.min.js?{{ .cur_ver }}"></script> <script src="{{ .base_path }}assets/js/model/inbound.js?{{ .cur_ver }}"></script> <script src="{{ .base_path }}assets/js/model/dbinbound.js?{{ .cur_ver }}"></script> +{{template "component/aSidebar" .}} {{template "component/aThemeSwitch" .}} {{template "component/aCustomStatistic" .}} {{template "component/aPersianDatepicker" .}} @@ -678,7 +679,6 @@ delimiters: ['[[', ']]'], el: '#app', data: { - siderDrawer, themeSwitcher, persianDatepicker, spinning: false, @@ -709,7 +709,7 @@ showAlert: false, ipLimitEnable: false, pageSize: 50, - isMobile: window.innerWidth <= 768, + isMobile: DeviceUtils.isMobile(), }, methods: { loading(spinning = true) { @@ -1473,7 +1473,7 @@ return false }, onResize() { - this.isMobile = window.innerWidth <= 768; + this.isMobile = DeviceUtils.isMobile(); } }, watch: { @@ -1524,12 +1524,12 @@ }); </script> -{{template "inboundModal"}} -{{template "promptModal"}} -{{template "qrcodeModal"}} -{{template "textModal"}} -{{template "inboundInfoModal"}} -{{template "clientsModal"}} -{{template "clientsBulkModal"}} +{{template "modals/inboundModal"}} +{{template "modals/promptModal"}} +{{template "modals/qrcodeModal"}} +{{template "modals/textModal"}} +{{template "modals/inboundInfoModal"}} +{{template "modals/clientsModal"}} +{{template "modals/clientsBulkModal"}} </body> </html> diff --git a/web/html/xui/index.html b/web/html/xui/index.html index 92b25d5c..20b44bd8 100644 --- a/web/html/xui/index.html +++ b/web/html/xui/index.html @@ -22,6 +22,11 @@ .ant-backup-list-item { gap: 10px; } + .ant-xray-version-list-item { + --padding: 12px; + padding: var(--padding) !important; + gap: var(--padding); + } .dark .ant-backup-list-item svg, .dark .ant-badge-status-text, .dark .ant-card-extra { @@ -74,7 +79,7 @@ <body> <a-layout id="app" v-cloak :class="themeSwitcher.currentTheme"> - {{ template "commonSider" . }} + <a-sidebar></a-sidebar> <a-layout id="content-layout"> <a-layout-content> <a-spin :spinning="spinning" :delay="200" :tip="loadingTip"> @@ -417,9 +422,10 @@ </a-modal> </a-layout> {{template "js" .}} +{{template "component/aSidebar" .}} {{template "component/aThemeSwitch" .}} {{template "component/aCustomStatistic" .}} -{{template "textModal"}} +{{template "modals/textModal"}} <script> const State = { Running: "running", @@ -591,7 +597,6 @@ delimiters: ['[[', ']]'], el: '#app', data: { - siderDrawer, themeSwitcher, status: new Status(), versionModal, @@ -601,7 +606,7 @@ loadingTip: '{{ i18n "loading"}}', showAlert: false, showIp: false, - isMobile: window.innerWidth <= 768 + isMobile: DeviceUtils.isMobile() }, methods: { loading(spinning, tip = '{{ i18n "loading"}}') { diff --git a/web/html/xui/client_bulk_modal.html b/web/html/xui/modals/client_bulk_modal.html similarity index 99% rename from web/html/xui/client_bulk_modal.html rename to web/html/xui/modals/client_bulk_modal.html index 82e68c74..88e8e645 100644 --- a/web/html/xui/client_bulk_modal.html +++ b/web/html/xui/modals/client_bulk_modal.html @@ -1,4 +1,4 @@ -{{define "clientsBulkModal"}} +{{define "modals/clientsBulkModal"}} <a-modal id="client-bulk-modal" v-model="clientsBulkModal.visible" :title="clientsBulkModal.title" @ok="clientsBulkModal.ok" :confirm-loading="clientsBulkModal.confirmLoading" :closable="true" :mask-closable="false" :ok-text="clientsBulkModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> diff --git a/web/html/xui/client_modal.html b/web/html/xui/modals/client_modal.html similarity index 99% rename from web/html/xui/client_modal.html rename to web/html/xui/modals/client_modal.html index aa62e02a..b6d2a554 100644 --- a/web/html/xui/client_modal.html +++ b/web/html/xui/modals/client_modal.html @@ -1,4 +1,4 @@ -{{define "clientsModal"}} +{{define "modals/clientsModal"}} <a-modal id="client-modal" v-model="clientModal.visible" :title="clientModal.title" @ok="clientModal.ok" :confirm-loading="clientModal.confirmLoading" :closable="true" :mask-closable="false" :class="themeSwitcher.currentTheme" diff --git a/web/html/xui/dns_modal.html b/web/html/xui/modals/dns_modal.html similarity index 99% rename from web/html/xui/dns_modal.html rename to web/html/xui/modals/dns_modal.html index f61cd8b2..a1ebaa9f 100644 --- a/web/html/xui/dns_modal.html +++ b/web/html/xui/modals/dns_modal.html @@ -1,4 +1,4 @@ -{{define "dnsModal"}} +{{define "modals/dnsModal"}} <a-modal id="dns-modal" v-model="dnsModal.visible" :title="dnsModal.title" @ok="dnsModal.ok" :closable="true" :mask-closable="false" :ok-text="dnsModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> diff --git a/web/html/xui/fakedns_modal.html b/web/html/xui/modals/fakedns_modal.html similarity index 98% rename from web/html/xui/fakedns_modal.html rename to web/html/xui/modals/fakedns_modal.html index 1b4dbe77..8e554ac0 100644 --- a/web/html/xui/fakedns_modal.html +++ b/web/html/xui/modals/fakedns_modal.html @@ -1,4 +1,4 @@ -{{define "fakednsModal"}} +{{define "modals/fakednsModal"}} <a-modal id="fakedns-modal" v-model="fakednsModal.visible" :title="fakednsModal.title" @ok="fakednsModal.ok" :closable="true" :mask-closable="false" :ok-text="fakednsModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> diff --git a/web/html/xui/inbound_info_modal.html b/web/html/xui/modals/inbound_info_modal.html similarity index 99% rename from web/html/xui/inbound_info_modal.html rename to web/html/xui/modals/inbound_info_modal.html index 5ac5e9ab..50a52190 100644 --- a/web/html/xui/inbound_info_modal.html +++ b/web/html/xui/modals/inbound_info_modal.html @@ -1,4 +1,4 @@ -{{define "inboundInfoModal"}} +{{define "modals/inboundInfoModal"}} <a-modal id="inbound-info-modal" v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}' :closable="true" :mask-closable="true" :footer="null" width="600px" :class="themeSwitcher.currentTheme"> <a-row> <a-col :xs="24" :md="12"> diff --git a/web/html/xui/inbound_modal.html b/web/html/xui/modals/inbound_modal.html similarity index 99% rename from web/html/xui/inbound_modal.html rename to web/html/xui/modals/inbound_modal.html index 4de3518c..99d182b9 100644 --- a/web/html/xui/inbound_modal.html +++ b/web/html/xui/modals/inbound_modal.html @@ -1,4 +1,4 @@ -{{define "inboundModal"}} +{{define "modals/inboundModal"}} <a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" :dialog-style="{ top: '20px' }" @ok="inModal.ok" :confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false" diff --git a/web/html/common/prompt_modal.html b/web/html/xui/modals/prompt_modal.html similarity index 98% rename from web/html/common/prompt_modal.html rename to web/html/xui/modals/prompt_modal.html index b91ede03..5073650f 100644 --- a/web/html/common/prompt_modal.html +++ b/web/html/xui/modals/prompt_modal.html @@ -1,4 +1,4 @@ -{{define "promptModal"}} +{{define "modals/promptModal"}} <a-modal id="prompt-modal" v-model="promptModal.visible" :title="promptModal.title" :closable="true" @ok="promptModal.ok" :mask-closable="false" :confirm-loading="promptModal.confirmLoading" diff --git a/web/html/common/qrcode_modal.html b/web/html/xui/modals/qrcode_modal.html similarity index 97% rename from web/html/common/qrcode_modal.html rename to web/html/xui/modals/qrcode_modal.html index 5ea1ca95..7046ca9b 100644 --- a/web/html/common/qrcode_modal.html +++ b/web/html/xui/modals/qrcode_modal.html @@ -1,6 +1,6 @@ -{{define "qrcodeModal"}} +{{define "modals/qrcodeModal"}} <a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title" - :dialog-style="isMobileQr ? { top: '18px' } : {}" + :dialog-style="DeviceUtils.isMobile() ? { top: '18px' } : {}" :closable="true" :class="themeSwitcher.currentTheme" :footer="null" width="fit-content"> @@ -35,7 +35,6 @@ </a-modal> <script> - const isMobileQr = window.innerWidth <= 768; const qrModal = { title: '', dbInbound: new DBInbound(), diff --git a/web/html/common/text_modal.html b/web/html/xui/modals/text_modal.html similarity index 98% rename from web/html/common/text_modal.html rename to web/html/xui/modals/text_modal.html index c15282b9..77cb719e 100644 --- a/web/html/common/text_modal.html +++ b/web/html/xui/modals/text_modal.html @@ -1,4 +1,4 @@ -{{define "textModal"}} +{{define "modals/textModal"}} <a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title" :closable="true" :class="themeSwitcher.currentTheme"> diff --git a/web/html/xui/warp_modal.html b/web/html/xui/modals/warp_modal.html similarity index 99% rename from web/html/xui/warp_modal.html rename to web/html/xui/modals/warp_modal.html index 20ce8139..7fb55847 100644 --- a/web/html/xui/warp_modal.html +++ b/web/html/xui/modals/warp_modal.html @@ -1,4 +1,4 @@ -{{define "warpModal"}} +{{define "modals/warpModal"}} <a-modal id="warp-modal" v-model="warpModal.visible" title="Cloudflare WARP" :confirm-loading="warpModal.confirmLoading" :closable="true" :mask-closable="true" :footer="null" :class="themeSwitcher.currentTheme"> diff --git a/web/html/xui/xray_balancer_modal.html b/web/html/xui/modals/xray_balancer_modal.html similarity index 99% rename from web/html/xui/xray_balancer_modal.html rename to web/html/xui/modals/xray_balancer_modal.html index de2a0acb..fea4019a 100644 --- a/web/html/xui/xray_balancer_modal.html +++ b/web/html/xui/modals/xray_balancer_modal.html @@ -1,4 +1,4 @@ -{{define "balancerModal"}} +{{define "modals/balancerModal"}} <a-modal id="balancer-modal" v-model="balancerModal.visible" diff --git a/web/html/xui/xray_outbound_modal.html b/web/html/xui/modals/xray_outbound_modal.html similarity index 99% rename from web/html/xui/xray_outbound_modal.html rename to web/html/xui/modals/xray_outbound_modal.html index fd9cf99c..b3c5d6b1 100644 --- a/web/html/xui/xray_outbound_modal.html +++ b/web/html/xui/modals/xray_outbound_modal.html @@ -1,4 +1,4 @@ -{{define "outModal"}} +{{define "modals/outModal"}} <a-modal id="out-modal" v-model="outModal.visible" :title="outModal.title" @ok="outModal.ok" :confirm-loading="outModal.confirmLoading" :closable="true" :mask-closable="false" :ok-button-props="{ props: { disabled: !outModal.isValid } }" style="overflow: hidden;" diff --git a/web/html/xui/xray_reverse_modal.html b/web/html/xui/modals/xray_reverse_modal.html similarity index 99% rename from web/html/xui/xray_reverse_modal.html rename to web/html/xui/modals/xray_reverse_modal.html index bb1e4bdf..22f04317 100644 --- a/web/html/xui/xray_reverse_modal.html +++ b/web/html/xui/modals/xray_reverse_modal.html @@ -1,4 +1,4 @@ -{{define "reverseModal"}} +{{define "modals/reverseModal"}} <a-modal id="reverse-modal" v-model="reverseModal.visible" :title="reverseModal.title" @ok="reverseModal.ok" :confirm-loading="reverseModal.confirmLoading" :closable="true" :mask-closable="false" :ok-text="reverseModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> diff --git a/web/html/xui/xray_rule_modal.html b/web/html/xui/modals/xray_rule_modal.html similarity index 99% rename from web/html/xui/xray_rule_modal.html rename to web/html/xui/modals/xray_rule_modal.html index aba5ba9e..4be74a8f 100644 --- a/web/html/xui/xray_rule_modal.html +++ b/web/html/xui/modals/xray_rule_modal.html @@ -1,4 +1,4 @@ -{{define "ruleModal"}} +{{define "modals/ruleModal"}} <a-modal id="rule-modal" v-model="ruleModal.visible" :title="ruleModal.title" @ok="ruleModal.ok" :confirm-loading="ruleModal.confirmLoading" :closable="true" :mask-closable="false" :ok-text="ruleModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> <a-form-item label='Domain Matcher'> diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html index febb26e8..cab41e5a 100644 --- a/web/html/xui/settings.html +++ b/web/html/xui/settings.html @@ -53,24 +53,10 @@ color: inherit; font-size: 24px; } - .collapse-title { - color: inherit; - font-weight: bold; - font-size: 18px; - padding: 10px 20px; - border-bottom: 2px solid; - } - .collapse-title>i { - color: inherit; - font-size: 24px; - } - .ant-collapse-content-box .ant-list-item { - border-bottom: none !important; - } </style> <body> <a-layout id="app" v-cloak :class="themeSwitcher.currentTheme"> - {{ template "commonSider" . }} + <a-sidebar></a-sidebar> <a-layout id="content-layout"> <a-layout-content> <a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'> @@ -109,551 +95,19 @@ </a-card> <a-tabs default-active-key="1"> <a-tab-pane key="1" tab='{{ i18n "pages.settings.panelSettings" }}' style="padding-top: 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> - <a-setting-list-item paddings="small"> - <template #title> - {{ i18n "pages.settings.remarkModel"}} - </template> - <template #description> - {{ i18n "pages.settings.sampleRemark"}}: <i>#[[ remarkSample ]]</i> - </template> - <template #control> - <a-input-group style="width: 100%;"> - <a-select style="padding-right: .5rem; min-width: 80%; width: auto;" - mode="multiple" - v-model="remarkModel" - :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option v-for="(value, key) in remarkModels" :value="key">[[ value ]]</a-select-option> - </a-select> - <a-select style="width: 20%;" v-model="remarkSeparator" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option v-for="key in remarkSeparators" :value="key">[[ key ]]</a-select-option> - </a-select> - </a-input-group> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.panelListeningIP"}}</template> - <template #description>{{ i18n "pages.settings.panelListeningIPDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.webListen"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.panelListeningDomain"}}</template> - <template #description>{{ i18n "pages.settings.panelListeningDomainDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.webDomain"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.panelPort"}}</template> - <template #description>{{ i18n "pages.settings.panelPortDesc"}}</template> - <template #control> - <a-input-number :min="1" :min="65531" v-model="allSetting.webPort" style="width: 100%;"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.panelUrlPath"}}</template> - <template #description>{{ i18n "pages.settings.panelUrlPathDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.webBasePath"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.sessionMaxAge" }}</template> - <template #description>{{ i18n "pages.settings.sessionMaxAgeDesc" }}</template> - <template #control> - <a-input-number :min="60" v-model="allSetting.sessionMaxAge" style="width: 100%;"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.pageSize" }}</template> - <template #description>{{ i18n "pages.settings.pageSizeDesc" }}</template> - <template #control> - <a-input-number :min="0" step="5" v-model="allSetting.pageSize" style="width: 100%;"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.language"}}</template> - <template #control> - <a-select ref="selectLang" - v-model="lang" - @change="LanguageManager.setLanguage(lang)" - :dropdown-class-name="themeSwitcher.currentTheme" - style="width: 100%"> - <a-select-option :value="l.value" :label="l.value" v-for="l in LanguageManager.supportedLanguages"> - <span role="img" :aria-label="l.name" v-text="l.icon"></span> <span v-text="l.name"></span> - </a-select-option> - </a-select> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.notifications" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.expireTimeDiff" }}</template> - <template #description>{{ i18n "pages.settings.expireTimeDiffDesc" }}</template> - <template #control> - <a-input-number :min="0" v-model="allSetting.expireDiff" style="width: 100%;"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.trafficDiff" }}</template> - <template #description>{{ i18n "pages.settings.trafficDiffDesc" }}</template> - <template #control> - <a-input-number :min="0" v-model="allSetting.trafficDiff" style="width: 100%;"></a-input> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.certs" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.publicKeyPath"}}</template> - <template #description>{{ i18n "pages.settings.publicKeyPathDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.webCertFile"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.privateKeyPath"}}</template> - <template #description>{{ i18n "pages.settings.privateKeyPathDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.webKeyFile"></a-input> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.externalTraffic" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.externalTrafficInformEnable"}}</template> - <template #description>{{ i18n "pages.settings.externalTrafficInformEnableDesc"}}</template> - <template #control> - <a-switch v-model="allSetting.externalTrafficInformEnable"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.externalTrafficInformURI"}}</template> - <template #description>{{ i18n "pages.settings.externalTrafficInformURIDesc"}}</template> - <template #control> - <a-input type="text" placeholder="(http|https)://domain[:port]/path/" v-model="allSetting.externalTrafficInformURI"></a-input> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.dateAndTime" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.timeZone"}}</template> - <template #description>{{ i18n "pages.settings.timeZoneDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.timeLocation"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.datepicker"}}</template> - <template #description>{{ i18n "pages.settings.datepickerDescription"}}</template> - <template #control> - <a-select style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme" v-model="datepicker"> - <a-select-option v-for="item in datepickerList" :value="item.value"> - <span v-text="item.name"></span> - </a-select-option> - </a-select> - </template> - </a-setting-list-item> - </a-collapse-panel> - </a-collapse> + {{ template "settings/panel/general" . }} </a-tab-pane> <a-tab-pane key="2" tab='{{ i18n "pages.settings.securitySettings" }}' style="padding-top: 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.settings.security.admin"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.oldUsername"}}</template> - <template #control> - <a-input autocomplete="username" v-model="user.oldUsername"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.currentPassword"}}</template> - <template #control> - <a-password-input autocomplete="current-password" v-model="user.oldPassword"></a-password-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.newUsername"}}</template> - <template #control> - <a-input v-model="user.newUsername"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.newPassword"}}</template> - <template #control> - <a-password-input autocomplete="new-password" v-model="user.newPassword"></a-password-input> - </template> - </a-setting-list-item> - <a-list-item> - <a-space direction="horizontal" style="padding: 0 20px;"> - <a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button> - </a-space> - </a-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.security.secret"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.security.loginSecurity" }}</template> - <template #description>{{ i18n "pages.settings.security.loginSecurityDesc" }}</template> - <template #control> - <a-switch @change="toggleToken(allSetting.secretEnable)" v-model="allSetting.secretEnable"></a-switch> - <a-icon style="margin-left: 1rem;" v-if="allSetting.secretEnable" :spin="this.changeSecret" type="sync" @click="getNewSecret"></a-icon> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.security.secretToken" }}</template> - <template #description>{{ i18n "pages.settings.security.secretTokenDesc" }}</template> - <template #control> - <a-textarea type="text" :disabled="!allSetting.secretEnable" v-model="user.loginSecret"></a-textarea> - </template> - </a-setting-list-item> - <a-list-item> - <a-space direction="horizontal" style="padding: 0 20px;"> - <a-button type="primary" :loading="this.changeSecret" @click="updateSecret">{{ i18n "confirm" }}</a-button> - </a-space> - </a-list-item> - </a-collapse-panel> - </a-collapse> + {{ template "settings/panel/security" . }} </a-tab-pane> <a-tab-pane key="3" tab='{{ i18n "pages.settings.TGBotSettings" }}' style="padding-top: 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.telegramBotEnable" }}</template> - <template #description>{{ i18n "pages.settings.telegramBotEnableDesc" }}</template> - <template #control> - <a-switch v-model="allSetting.tgBotEnable"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.telegramToken"}}</template> - <template #description>{{ i18n "pages.settings.telegramTokenDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.tgBotToken"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.telegramChatId"}}</template> - <template #description>{{ i18n "pages.settings.telegramChatIdDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.tgBotChatId"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.telegramBotLanguage"}}</template> - <template #control> - <a-select ref="selectBotLang" v-model="allSetting.tgLang" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> - <a-select-option :value="l.value" :label="l.value" v-for="l in LanguageManager.supportedLanguages"> - <span role="img" :aria-label="l.name" v-text="l.icon"></span> <span v-text="l.name"></span> - </a-select-option> - </a-select> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.notifications" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.telegramNotifyTime"}}</template> - <template #description>{{ i18n "pages.settings.telegramNotifyTimeDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.tgRunTime"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.tgNotifyBackup" }}</template> - <template #description>{{ i18n "pages.settings.tgNotifyBackupDesc" }}</template> - <template #control> - <a-switch v-model="allSetting.tgBotBackup"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.tgNotifyLogin" }}</template> - <template #description>{{ i18n "pages.settings.tgNotifyLoginDesc" }}</template> - <template #control> - <a-switch v-model="allSetting.tgBotLoginNotify"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.tgNotifyCpu" }}</template> - <template #description>{{ i18n "pages.settings.tgNotifyCpuDesc" }}</template> - <template #control> - <a-input-number :min="0" :min="100" v-model="allSetting.tgCpu" style="width: 100%;"></a-switch> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.proxyAndServer" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.telegramProxy"}}</template> - <template #description>{{ i18n "pages.settings.telegramProxyDesc"}}</template> - <template #control> - <a-input type="text" placeholder="socks5://user:pass@host:port" v-model="allSetting.tgBotProxy"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.telegramAPIServer"}}</template> - <template #description>{{ i18n "pages.settings.telegramAPIServerDesc"}}</template> - <template #control> - <a-input type="text" placeholder="https://api.example.com" v-model="allSetting.tgBotAPIServer"></a-input> - </template> - </a-setting-list-item> - </a-collapse-panel> - </a-collapse> + {{ template "settings/panel/telegram" . }} </a-tab-pane> <a-tab-pane key="4" tab='{{ i18n "pages.settings.subSettings" }}' style="padding-top: 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subEnable"}}</template> - <template #description>{{ i18n "pages.settings.subEnableDesc"}}</template> - <template #control> - <a-switch v-model="allSetting.subEnable"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subTitle"}}</template> - <template #description>{{ i18n "pages.settings.subTitleDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.subTitle"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subListen"}}</template> - <template #description>{{ i18n "pages.settings.subListenDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.subListen"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subDomain"}}</template> - <template #description>{{ i18n "pages.settings.subDomainDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.subDomain"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subPort"}}</template> - <template #description>{{ i18n "pages.settings.subPortDesc"}}</template> - <template #control> - <a-input-number v-model="allSetting.subPort" :min="1" :min="65531" style="width: 100%;"></a-input-number> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subPath"}}</template> - <template #description>{{ i18n "pages.settings.subPathDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.subPath"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subURI"}}</template> - <template #description>{{ i18n "pages.settings.subURIDesc"}}</template> - <template #control> - <a-input type="text" placeholder="(http|https)://domain[:port]/path/" v-model="allSetting.subURI"></a-input> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.information" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subEncrypt"}}</template> - <template #description>{{ i18n "pages.settings.subEncryptDesc"}}</template> - <template #control> - <a-switch v-model="allSetting.subEncrypt"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subShowInfo"}}</template> - <template #description>{{ i18n "pages.settings.subShowInfoDesc"}}</template> - <template #control> - <a-switch v-model="allSetting.subShowInfo"></a-switch> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.certs" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subCertPath"}}</template> - <template #description>{{ i18n "pages.settings.subCertPathDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.subCertFile"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subKeyPath"}}</template> - <template #description>{{ i18n "pages.settings.subKeyPathDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.subKeyFile"></a-input> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.intervals"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subUpdates"}}</template> - <template #description>{{ i18n "pages.settings.subUpdatesDesc"}}</template> - <template #control> - <a-input-number :min="1" v-model="allSetting.subUpdates" style="width: 100%;"></a-input-number> - </template> - </a-setting-list-item> - </a-collapse-panel> - </a-collapse> + {{ template "settings/panel/subscription/general" . }} </a-tab-pane> <a-tab-pane key="5" tab='{{ i18n "pages.settings.subSettings" }} Json' v-if="allSetting.subEnable" style="padding-top: 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subPath"}}</template> - <template #description>{{ i18n "pages.settings.subPathDesc"}}</template> - <template #control> - <a-input type="text" v-model="allSetting.subJsonPath"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.subURI"}}</template> - <template #description>{{ i18n "pages.settings.subURIDesc"}}</template> - <template #control> - <a-input type="text" placeholder="(http|https)://domain[:port]/path/" v-model="allSetting.subJsonURI"></a-input> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.fragment"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.fragment"}}</template> - <template #description>{{ i18n "pages.settings.fragmentDesc"}}</template> - <template #control> - <a-switch v-model="fragment"></a-switch> - </template> - </a-setting-list-item> - <a-list-item v-if="fragment" style="padding: 10px 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.settings.fragmentSett"}}' v-if="fragment"> - <a-setting-list-item paddings="small"> - <template #title>Packets</template> - <template #control> - <a-input type="text" v-model="fragmentPackets" placeholder="1-1 | 1-3 | tlshello | ..."></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>Length</template> - <template #control> - <a-input type="text" v-model="fragmentLength" placeholder="100-200"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>Interval</template> - <template #control> - <a-input type="text" v-model="fragmentInterval" placeholder="10-20"></a-input> - </template> - </a-setting-list-item> - </a-collapse-panel> - </a-collapse> - </a-list-item> - </a-collapse-panel> - <a-collapse-panel header="Noises"> - <a-setting-list-item paddings="small"> - <template #title>Noises</template> - <template #description>{{ i18n "pages.settings.noisesDesc"}}</template> - <template #control> - <a-switch v-model="noises"></a-switch> - </template> - </a-setting-list-item> - <a-list-item v-if="noises" style="padding: 10px 20px;"> - <a-collapse> - <a-collapse-panel v-for="(noise, index) in noisesArray" :key="index" :header="`Noise №${index + 1}`"> - <a-setting-list-item paddings="small"> - <template #title>Type</template> - <template #control> - <a-select :value="noise.type" style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme" - @change="(value) => updateNoiseType(index, value)"> - <a-select-option :value="p" :label="p" v-for="p in ['rand', 'base64', 'str', 'hex']" :key="p"> - [[ p ]] </a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>Packet</template> - <template #control> - <a-input type="text" :value="noise.packet" @input="(value) => updateNoisePacket(index, event.target.value)" placeholder="5-10"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>Delay (ms)</template> - <template #control> - <a-input type="text" :value="noise.delay" @input="(value) => updateNoiseDelay(index, event.target.value)" placeholder="10-20"></a-input> - </template> - </a-setting-list-item> - <a-space direction="horizontal" style="padding: 10px 20px;"> - <a-button v-if="noisesArray.length > 1" type="danger" @click="removeNoise(index)">Remove</a-button> - </a-space> - </a-collapse-panel> - </a-collapse> - <a-button v-if="noises" type="primary" @click="addNoise" style="margin-top: 10px">Add Noise</a-button> - </a-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.mux"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.mux"}}</template> - <template #description>{{ i18n "pages.settings.muxDesc"}}</template> - <template #control> - <a-switch v-model="enableMux"></a-switch> - </template> - </a-setting-list-item> - <a-list-item v-if="enableMux" style="padding: 10px 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.settings.muxSett"}}'> - <a-setting-list-item paddings="small"> - <template #title>Concurrency</template> - <template #control> - <a-input-number v-model="muxConcurrency" :min="-1" :max="1024" style="width: 100%;"></a-input-number> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>xudp Concurrency</template> - <template #control> - <a-input-number v-model="muxXudpConcurrency" :min="-1" :max="1024" style="width: 100%;"></a-input-number> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>xudp UDP 443</template> - <template #control> - <a-select v-model="muxXudpProxyUDP443" style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p" :label="p" v-for="p in ['reject', 'allow', 'skip']"> [[ p ]] </a-select-option> - </a-select> - </template> - </a-setting-list-item> - </a-collapse-panel> - </a-collapse> - </a-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.direct" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.settings.direct"}}</template> - <template #description>{{ i18n "pages.settings.directDesc"}}</template> - <template #control> - <a-switch v-model="enableDirect"></a-switch> - </template> - </a-setting-list-item> - <a-list-item v-if="enableDirect" style="padding: 10px 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.settings.direct"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.directips" }}</template> - <template #control> - <a-select mode="tags" style="width: 100%" v-model="directIPs" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p.value" :label="p.label" v-for="p in directIPsOptions">[[ p.label ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.directdomains" }}</template> - <template #control> - <a-select mode="tags" style="width: 100%" v-model="directDomains" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p.value" :label="p.label" v-for="p in diretDomainsOptions">[[ p.label ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - </a-collapse-panel> - </a-collapse> - </a-list-item> - </a-collapse-panel> - </a-collapse> + {{ template "settings/panel/subscription/json" . }} </a-tab-pane> </a-tabs> </a-space> @@ -663,6 +117,7 @@ </a-layout> {{template "js" .}} <script src="{{ .base_path }}assets/js/model/setting.js?{{ .cur_ver }}"></script> +{{template "component/aSidebar" .}} {{template "component/aThemeSwitch" .}} {{template "component/aPasswordInput" .}} {{template "component/aSettingListItem" .}} @@ -671,7 +126,6 @@ delimiters: ['[[', ']]'], el: '#app', data: { - siderDrawer, themeSwitcher, spinning: false, changeSecret: false, diff --git a/web/html/xui/settings/panel/general.html b/web/html/xui/settings/panel/general.html new file mode 100644 index 00000000..2f801c49 --- /dev/null +++ b/web/html/xui/settings/panel/general.html @@ -0,0 +1,149 @@ +{{define "settings/panel/general"}} +<a-collapse> + <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> + <a-setting-list-item paddings="small"> + <template #title> + {{ i18n "pages.settings.remarkModel"}} + </template> + <template #description> + {{ i18n "pages.settings.sampleRemark"}}: <i>#[[ remarkSample ]]</i> + </template> + <template #control> + <a-input-group style="width: 100%;"> + <a-select style="padding-right: .5rem; min-width: 80%; width: auto;" mode="multiple" + v-model="remarkModel" :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option v-for="(value, key) in remarkModels" :value="key">[[ value ]]</a-select-option> + </a-select> + <a-select style="width: 20%;" v-model="remarkSeparator" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option v-for="key in remarkSeparators" :value="key">[[ key ]]</a-select-option> + </a-select> + </a-input-group> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.panelListeningIP"}}</template> + <template #description>{{ i18n "pages.settings.panelListeningIPDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.webListen"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.panelListeningDomain"}}</template> + <template #description>{{ i18n "pages.settings.panelListeningDomainDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.webDomain"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.panelPort"}}</template> + <template #description>{{ i18n "pages.settings.panelPortDesc"}}</template> + <template #control> + <a-input-number :min="1" :min="65531" v-model="allSetting.webPort" style="width: 100%;"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.panelUrlPath"}}</template> + <template #description>{{ i18n "pages.settings.panelUrlPathDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.webBasePath"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.sessionMaxAge" }}</template> + <template #description>{{ i18n "pages.settings.sessionMaxAgeDesc" }}</template> + <template #control> + <a-input-number :min="60" v-model="allSetting.sessionMaxAge" style="width: 100%;"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.pageSize" }}</template> + <template #description>{{ i18n "pages.settings.pageSizeDesc" }}</template> + <template #control> + <a-input-number :min="0" step="5" v-model="allSetting.pageSize" style="width: 100%;"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.language"}}</template> + <template #control> + <a-select ref="selectLang" v-model="lang" @change="LanguageManager.setLanguage(lang)" + :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> + <a-select-option :value="l.value" :label="l.value" v-for="l in LanguageManager.supportedLanguages"> + <span role="img" :aria-label="l.name" v-text="l.icon"></span> <span + v-text="l.name"></span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.notifications" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.expireTimeDiff" }}</template> + <template #description>{{ i18n "pages.settings.expireTimeDiffDesc" }}</template> + <template #control> + <a-input-number :min="0" v-model="allSetting.expireDiff" style="width: 100%;"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.trafficDiff" }}</template> + <template #description>{{ i18n "pages.settings.trafficDiffDesc" }}</template> + <template #control> + <a-input-number :min="0" v-model="allSetting.trafficDiff" style="width: 100%;"></a-input> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.certs" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.publicKeyPath"}}</template> + <template #description>{{ i18n "pages.settings.publicKeyPathDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.webCertFile"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.privateKeyPath"}}</template> + <template #description>{{ i18n "pages.settings.privateKeyPathDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.webKeyFile"></a-input> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.externalTraffic" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.externalTrafficInformEnable"}}</template> + <template #description>{{ i18n "pages.settings.externalTrafficInformEnableDesc"}}</template> + <template #control> + <a-switch v-model="allSetting.externalTrafficInformEnable"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.externalTrafficInformURI"}}</template> + <template #description>{{ i18n "pages.settings.externalTrafficInformURIDesc"}}</template> + <template #control> + <a-input type="text" placeholder="(http|https)://domain[:port]/path/" + v-model="allSetting.externalTrafficInformURI"></a-input> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.dateAndTime" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.timeZone"}}</template> + <template #description>{{ i18n "pages.settings.timeZoneDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.timeLocation"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.datepicker"}}</template> + <template #description>{{ i18n "pages.settings.datepickerDescription"}}</template> + <template #control> + <a-select style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme" v-model="datepicker"> + <a-select-option v-for="item in datepickerList" :value="item.value"> + <span v-text="item.name"></span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + </a-collapse-panel> +</a-collapse> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/panel/security.html b/web/html/xui/settings/panel/security.html new file mode 100644 index 00000000..89ff0d96 --- /dev/null +++ b/web/html/xui/settings/panel/security.html @@ -0,0 +1,60 @@ +{{define "settings/panel/security"}} +<a-collapse> + <a-collapse-panel header='{{ i18n "pages.settings.security.admin"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.oldUsername"}}</template> + <template #control> + <a-input autocomplete="username" v-model="user.oldUsername"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.currentPassword"}}</template> + <template #control> + <a-password-input autocomplete="current-password" v-model="user.oldPassword"></a-password-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.newUsername"}}</template> + <template #control> + <a-input v-model="user.newUsername"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.newPassword"}}</template> + <template #control> + <a-password-input autocomplete="new-password" v-model="user.newPassword"></a-password-input> + </template> + </a-setting-list-item> + <a-list-item> + <a-space direction="horizontal" style="padding: 0 20px;"> + <a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button> + </a-space> + </a-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.security.secret"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.security.loginSecurity" }}</template> + <template #description>{{ i18n "pages.settings.security.loginSecurityDesc" }}</template> + <template #control> + <a-switch @change="toggleToken(allSetting.secretEnable)" v-model="allSetting.secretEnable"></a-switch> + <a-icon style="margin-left: 1rem;" v-if="allSetting.secretEnable" :spin="this.changeSecret" type="sync" + @click="getNewSecret"></a-icon> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.security.secretToken" }}</template> + <template #description>{{ i18n "pages.settings.security.secretTokenDesc" }}</template> + <template #control> + <a-textarea type="text" :disabled="!allSetting.secretEnable" v-model="user.loginSecret"></a-textarea> + </template> + </a-setting-list-item> + <a-list-item> + <a-space direction="horizontal" style="padding: 0 20px;"> + <a-button type="primary" :loading="this.changeSecret" @click="updateSecret"> + <span>{{ i18n "confirm"}}</span> + </a-button> + </a-space> + </a-list-item> + </a-collapse-panel> +</a-collapse> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/panel/subscription/general.html b/web/html/xui/settings/panel/subscription/general.html new file mode 100644 index 00000000..bcf6a432 --- /dev/null +++ b/web/html/xui/settings/panel/subscription/general.html @@ -0,0 +1,98 @@ +{{define "settings/panel/subscription/general"}} +<a-collapse> + <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subEnable"}}</template> + <template #description>{{ i18n "pages.settings.subEnableDesc"}}</template> + <template #control> + <a-switch v-model="allSetting.subEnable"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subTitle"}}</template> + <template #description>{{ i18n "pages.settings.subTitleDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.subTitle"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subListen"}}</template> + <template #description>{{ i18n "pages.settings.subListenDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.subListen"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subDomain"}}</template> + <template #description>{{ i18n "pages.settings.subDomainDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.subDomain"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subPort"}}</template> + <template #description>{{ i18n "pages.settings.subPortDesc"}}</template> + <template #control> + <a-input-number v-model="allSetting.subPort" :min="1" :min="65531" + style="width: 100%;"></a-input-number> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subPath"}}</template> + <template #description>{{ i18n "pages.settings.subPathDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.subPath"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subURI"}}</template> + <template #description>{{ i18n "pages.settings.subURIDesc"}}</template> + <template #control> + <a-input type="text" placeholder="(http|https)://domain[:port]/path/" + v-model="allSetting.subURI"></a-input> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.information" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subEncrypt"}}</template> + <template #description>{{ i18n "pages.settings.subEncryptDesc"}}</template> + <template #control> + <a-switch v-model="allSetting.subEncrypt"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subShowInfo"}}</template> + <template #description>{{ i18n "pages.settings.subShowInfoDesc"}}</template> + <template #control> + <a-switch v-model="allSetting.subShowInfo"></a-switch> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.certs" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subCertPath"}}</template> + <template #description>{{ i18n "pages.settings.subCertPathDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.subCertFile"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subKeyPath"}}</template> + <template #description>{{ i18n "pages.settings.subKeyPathDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.subKeyFile"></a-input> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.intervals"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subUpdates"}}</template> + <template #description>{{ i18n "pages.settings.subUpdatesDesc"}}</template> + <template #control> + <a-input-number :min="1" v-model="allSetting.subUpdates" style="width: 100%;"></a-input-number> + </template> + </a-setting-list-item> + </a-collapse-panel> +</a-collapse> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/panel/subscription/json.html b/web/html/xui/settings/panel/subscription/json.html new file mode 100644 index 00000000..48273586 --- /dev/null +++ b/web/html/xui/settings/panel/subscription/json.html @@ -0,0 +1,180 @@ +{{define "settings/panel/subscription/json"}} +<a-collapse> + <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subPath"}}</template> + <template #description>{{ i18n "pages.settings.subPathDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.subJsonPath"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.subURI"}}</template> + <template #description>{{ i18n "pages.settings.subURIDesc"}}</template> + <template #control> + <a-input type="text" placeholder="(http|https)://domain[:port]/path/" + v-model="allSetting.subJsonURI"></a-input> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.fragment"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.fragment"}}</template> + <template #description>{{ i18n "pages.settings.fragmentDesc"}}</template> + <template #control> + <a-switch v-model="fragment"></a-switch> + </template> + </a-setting-list-item> + <a-list-item v-if="fragment" style="padding: 10px 20px;"> + <a-collapse> + <a-collapse-panel header='{{ i18n "pages.settings.fragmentSett"}}' v-if="fragment"> + <a-setting-list-item paddings="small"> + <template #title>Packets</template> + <template #control> + <a-input type="text" v-model="fragmentPackets" + placeholder="1-1 | 1-3 | tlshello | ..."></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>Length</template> + <template #control> + <a-input type="text" v-model="fragmentLength" placeholder="100-200"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>Interval</template> + <template #control> + <a-input type="text" v-model="fragmentInterval" placeholder="10-20"></a-input> + </template> + </a-setting-list-item> + </a-collapse-panel> + </a-collapse> + </a-list-item> + </a-collapse-panel> + <a-collapse-panel header="Noises"> + <a-setting-list-item paddings="small"> + <template #title>Noises</template> + <template #description>{{ i18n "pages.settings.noisesDesc"}}</template> + <template #control> + <a-switch v-model="noises"></a-switch> + </template> + </a-setting-list-item> + <a-list-item v-if="noises" style="padding: 10px 20px;"> + <a-collapse> + <a-collapse-panel v-for="(noise, index) in noisesArray" :key="index" :header="`Noise №${index + 1}`"> + <a-setting-list-item paddings="small"> + <template #title>Type</template> + <template #control> + <a-select :value="noise.type" style="width: 100%" + :dropdown-class-name="themeSwitcher.currentTheme" + @change="(value) => updateNoiseType(index, value)"> + <a-select-option :value="p" :label="p" v-for="p in ['rand', 'base64', 'str', 'hex']" :key="p"> + <span>[[ p ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>Packet</template> + <template #control> + <a-input type="text" :value="noise.packet" + @input="(value) => updateNoisePacket(index, event.target.value)" + placeholder="5-10"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>Delay (ms)</template> + <template #control> + <a-input type="text" :value="noise.delay" + @input="(value) => updateNoiseDelay(index, event.target.value)" + placeholder="10-20"></a-input> + </template> + </a-setting-list-item> + <a-space direction="horizontal" style="padding: 10px 20px;"> + <a-button v-if="noisesArray.length > 1" type="danger" + @click="removeNoise(index)">Remove</a-button> + </a-space> + </a-collapse-panel> + </a-collapse> + <a-button v-if="noises" type="primary" @click="addNoise" style="margin-top: 10px">Add Noise</a-button> + </a-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.mux"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.mux"}}</template> + <template #description>{{ i18n "pages.settings.muxDesc"}}</template> + <template #control> + <a-switch v-model="enableMux"></a-switch> + </template> + </a-setting-list-item> + <a-list-item v-if="enableMux" style="padding: 10px 20px;"> + <a-collapse> + <a-collapse-panel header='{{ i18n "pages.settings.muxSett"}}'> + <a-setting-list-item paddings="small"> + <template #title>Concurrency</template> + <template #control> + <a-input-number v-model="muxConcurrency" :min="-1" :max="1024" + style="width: 100%;"></a-input-number> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>xudp Concurrency</template> + <template #control> + <a-input-number v-model="muxXudpConcurrency" :min="-1" :max="1024" + style="width: 100%;"></a-input-number> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>xudp UDP 443</template> + <template #control> + <a-select v-model="muxXudpProxyUDP443" style="width: 100%" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p" :label="p" v-for="p in ['reject', 'allow', 'skip']"> + <span>[[ p ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + </a-collapse-panel> + </a-collapse> + </a-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.direct" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.direct"}}</template> + <template #description>{{ i18n "pages.settings.directDesc"}}</template> + <template #control> + <a-switch v-model="enableDirect"></a-switch> + </template> + </a-setting-list-item> + <a-list-item v-if="enableDirect" style="padding: 10px 20px;"> + <a-collapse> + <a-collapse-panel header='{{ i18n "pages.settings.direct"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.directips" }}</template> + <template #control> + <a-select mode="tags" style="width: 100%" v-model="directIPs" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p.value" :label="p.label" v-for="p in directIPsOptions"> + <span>[[ p.label ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.directdomains" }}</template> + <template #control> + <a-select mode="tags" style="width: 100%" v-model="directDomains" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p.value" :label="p.label" v-for="p in diretDomainsOptions"> + <span>[[ p.label ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + </a-collapse-panel> + </a-collapse> + </a-list-item> + </a-collapse-panel> +</a-collapse> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/panel/telegram.html b/web/html/xui/settings/panel/telegram.html new file mode 100644 index 00000000..b826f17d --- /dev/null +++ b/web/html/xui/settings/panel/telegram.html @@ -0,0 +1,87 @@ +{{define "settings/panel/telegram"}} +<a-collapse> + <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.telegramBotEnable" }}</template> + <template #description>{{ i18n "pages.settings.telegramBotEnableDesc" }}</template> + <template #control> + <a-switch v-model="allSetting.tgBotEnable"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.telegramToken"}}</template> + <template #description>{{ i18n "pages.settings.telegramTokenDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.tgBotToken"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.telegramChatId"}}</template> + <template #description>{{ i18n "pages.settings.telegramChatIdDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.tgBotChatId"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.telegramBotLanguage"}}</template> + <template #control> + <a-select ref="selectBotLang" v-model="allSetting.tgLang" + :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> + <a-select-option :value="l.value" :label="l.value" v-for="l in LanguageManager.supportedLanguages"> + <span role="img" :aria-label="l.name" v-text="l.icon"></span> <span + v-text="l.name"></span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.notifications" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.telegramNotifyTime"}}</template> + <template #description>{{ i18n "pages.settings.telegramNotifyTimeDesc"}}</template> + <template #control> + <a-input type="text" v-model="allSetting.tgRunTime"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.tgNotifyBackup" }}</template> + <template #description>{{ i18n "pages.settings.tgNotifyBackupDesc" }}</template> + <template #control> + <a-switch v-model="allSetting.tgBotBackup"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.tgNotifyLogin" }}</template> + <template #description>{{ i18n "pages.settings.tgNotifyLoginDesc" }}</template> + <template #control> + <a-switch v-model="allSetting.tgBotLoginNotify"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.tgNotifyCpu" }}</template> + <template #description>{{ i18n "pages.settings.tgNotifyCpuDesc" }}</template> + <template #control> + <a-input-number :min="0" :min="100" v-model="allSetting.tgCpu" style="width: 100%;"></a-switch> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.proxyAndServer" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.telegramProxy"}}</template> + <template #description>{{ i18n "pages.settings.telegramProxyDesc"}}</template> + <template #control> + <a-input type="text" placeholder="socks5://user:pass@host:port" + v-model="allSetting.tgBotProxy"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.settings.telegramAPIServer"}}</template> + <template #description>{{ i18n "pages.settings.telegramAPIServerDesc"}}</template> + <template #control> + <a-input type="text" placeholder="https://api.example.com" + v-model="allSetting.tgBotAPIServer"></a-input> + </template> + </a-setting-list-item> + </a-collapse-panel> +</a-collapse> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/xray/advanced.html b/web/html/xui/settings/xray/advanced.html new file mode 100644 index 00000000..6b9cb87b --- /dev/null +++ b/web/html/xui/settings/xray/advanced.html @@ -0,0 +1,14 @@ +{{define "settings/xray/advanced"}} +<a-space direction="vertical" size="small"> + <a-list-item-meta title='{{ i18n "pages.xray.Template"}}' + description='{{ i18n "pages.xray.TemplateDesc"}}'></a-list-item-meta> + <a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" style="margin: 10px 0;" + :size="isMobile ? 'small' : ''"> + <a-radio-button value="xraySetting">{{ i18n "pages.xray.completeTemplate"}}</a-radio-button> + <a-radio-button value="inboundSettings">{{ i18n "pages.xray.Inbounds" }}</a-radio-button> + <a-radio-button value="outboundSettings">{{ i18n "pages.xray.Outbounds" }}</a-radio-button> + <a-radio-button value="routingRuleSettings">{{ i18n "pages.xray.Routings" }}</a-radio-button> + </a-radio-group> + <textarea style="position:absolute; left: -800px;" id="xraySetting"></textarea> +</a-space> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/xray/balancers.html b/web/html/xui/settings/xray/balancers.html new file mode 100644 index 00000000..7e062ec0 --- /dev/null +++ b/web/html/xui/settings/xray/balancers.html @@ -0,0 +1,53 @@ +{{define "settings/xray/balancers"}} +<template v-if="balancersData.length > 0"> + <a-space direction="vertical" size="middle"> + <a-button type="primary" icon="plus" @click="addBalancer()"> + <span>{{ i18n "pages.xray.balancer.addBalancer"}}</span> + </a-button> + <a-table :columns="balancerColumns" bordered :row-key="r => r.key" :data-source="balancersData" + :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"> + <template slot="action" slot-scope="text, balancer, index"> + <span>[[ index+1 ]]</span> + <a-dropdown :trigger="['click']"> + <a-icon @click="e => e.preventDefault()" type="more" + style="font-size: 16px; text-decoration: bold;"></a-icon> + <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> + <a-menu-item @click="editBalancer(index)"> + <a-icon type="edit"></a-icon> + <span>{{ i18n "edit" }}</span> + </a-menu-item> + <a-menu-item @click="deleteBalancer(index)"> + <span style="color: #FF4D4F"> + <a-icon type="delete"></a-icon> + <span>{{ i18n "delete"}}</span> + </span> + </a-menu-item> + </a-menu> + </a-dropdown> + </template> + <template slot="strategy" slot-scope="text, balancer, index"> + <a-tag style="margin:0;" v-if="balancer.strategy=='random'" color="purple">Random</a-tag> + <a-tag style="margin:0;" v-if="balancer.strategy=='roundRobin'" color="green">Round Robin</a-tag> + <a-tag style="margin:0;" v-if="balancer.strategy=='leastLoad'" color="green">Least Load</a-tag> + <a-tag style="margin:0;" v-if="balancer.strategy=='leastPing'" color="green">Least Ping</a-tag> + </template> + <template slot="selector" slot-scope="text, balancer, index"> + <a-tag class="info-large-tag" style="margin:1;" v-for="sel in balancer.selector">[[ sel ]]</a-tag> + </template> + </a-table> + <a-radio-group v-if="observatoryEnable || burstObservatoryEnable" v-model="obsSettings" @change="changeObsCode" + button-style="solid" :size="isMobile ? 'small' : ''"> + <a-radio-button value="observatory" v-if="observatoryEnable">Observatory</a-radio-button> + <a-radio-button value="burstObservatory" v-if="burstObservatoryEnable">Burst Observatory</a-radio-button> + </a-radio-group> + <textarea style="position:absolute; left: -800px;" id="obsSetting"></textarea> + </a-space> +</template> +<template v-else> + <a-empty description='{{ i18n "emptyBalancersDesc" }}' style="margin: 10px;"> + <a-button type="primary" icon="plus" @click="addBalancer()" style="margin-top: 10px;"> + <span>{{ i18n "pages.xray.balancer.addBalancer"}}</span> + </a-button> + </a-empty> +</template> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/xray/basics.html b/web/html/xui/settings/xray/basics.html new file mode 100644 index 00000000..292d8f50 --- /dev/null +++ b/web/html/xui/settings/xray/basics.html @@ -0,0 +1,275 @@ +{{define "settings/xray/basics"}} +<a-collapse> + <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> + <a-row :xs="24" :sm="24" :lg="12"> + <a-alert type="warning" style="text-align: center;"> + <template slot="message"> + <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> + <span>{{ i18n "pages.xray.generalConfigsDesc" }}</span> + </template> + </a-alert> + </a-row> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.FreedomStrategy" }}</template> + <template #description>{{ i18n "pages.xray.FreedomStrategyDesc" }}</template> + <template #control> + <a-select v-model="freedomStrategy" :dropdown-class-name="themeSwitcher.currentTheme" + style="width: 100%"> + <a-select-option v-for="s in OutboundDomainStrategies" :value="s"> + <span>[[ s ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.RoutingStrategy" }}</template> + <template #description>{{ i18n "pages.xray.RoutingStrategyDesc" }}</template> + <template #control> + <a-select v-model="routingStrategy" :dropdown-class-name="themeSwitcher.currentTheme" + style="width: 100%"> + <a-select-option v-for="s in routingDomainStrategies" :value="s"> + <span>[[ s ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.xray.statistics" }}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.statsInboundUplink" }}</template> + <template #description>{{ i18n "pages.xray.statsInboundUplinkDesc" }}</template> + <template #control> + <a-switch v-model="statsInboundUplink"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.statsInboundDownlink" }}</template> + <template #description>{{ i18n "pages.xray.statsInboundDownlinkDesc" }}</template> + <template #control> + <a-switch v-model="statsInboundDownlink"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.statsOutboundUplink" }}</template> + <template #description>{{ i18n "pages.xray.statsOutboundUplinkDesc" }}</template> + <template #control> + <a-switch v-model="statsOutboundUplink"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.statsOutboundDownlink" }}</template> + <template #description>{{ i18n "pages.xray.statsOutboundDownlinkDesc" }}</template> + <template #control> + <a-switch v-model="statsOutboundDownlink"></a-switch> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.xray.logConfigs" }}'> + <a-row :xs="24" :sm="24" :lg="12"> + <a-alert type="warning" style="text-align: center;"> + <template slot="message"> + <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> + <span>{{ i18n "pages.xray.logConfigsDesc" }}</span> + </template> + </a-alert> + </a-row> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.logLevel" }}</template> + <template #description>{{ i18n "pages.xray.logLevelDesc" }}</template> + <template #control> + <a-select v-model="logLevel" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> + <a-select-option v-for="s in log.loglevel" :value="s"> + <span>[[ s ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.accessLog" }}</template> + <template #description>{{ i18n "pages.xray.accessLogDesc" }}</template> + <template #control> + <a-select v-model="accessLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> + <a-select-option value=''> + <span>Empty</span> + </a-select-option> + <a-select-option v-for="s in log.access" :value="s"> + <span>[[ s ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.errorLog" }}</template> + <template #description>{{ i18n "pages.xray.errorLogDesc" }}</template> + <template #control> + <a-select v-model="errorLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> + <a-select-option value=''> + <span>Empty</span> + </a-select-option> + <a-select-option v-for="s in log.error" :value="s"> + <span>[[ s ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.maskAddress" }}</template> + <template #description>{{ i18n "pages.xray.maskAddressDesc" }}</template> + <template #control> + <a-select v-model="maskAddressLog" :dropdown-class-name="themeSwitcher.currentTheme" + style="width: 100%"> + <a-select-option value=''> + <span>Empty</span> + </a-select-option> + <a-select-option v-for="s in log.maskAddress" :value="s"> + <span>[[ s ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.dnsLog"}}</template> + <template #description>{{ i18n "pages.xray.dnsLogDesc"}}</template> + <template #control> + <a-switch v-model="dnslog"></a-switch> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.xray.blockConfigs"}}'> + <a-row :xs="24" :sm="24" :lg="12"> + <a-alert type="warning" style="text-align: center;"> + <template slot="message"> + <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> + <span>{{ i18n "pages.xray.blockConfigsDesc" }}</span> + </template> + </a-alert> + </a-row> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.Torrent"}}</template> + <template #description>{{ i18n "pages.xray.TorrentDesc"}}</template> + <template #control> + <a-switch v-model="torrentSettings"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.Family"}}</template> + <template #description>{{ i18n "pages.xray.FamilyDesc"}}</template> + <template #control> + <a-switch v-model="familyProtectSettings"></a-switch> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.xray.basicRouting"}}'> + <a-row :xs="24" :sm="24" :lg="12"> + <a-alert type="warning" style="text-align: center;"> + <template slot="message"> + <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> + <span>{{ i18n "pages.xray.blockConnectionsConfigsDesc" }}</span> + </template> + </a-alert> + </a-row> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.blockips" }}</template> + <template #control> + <a-select mode="tags" v-model="blockedIPs" style="width: 100%" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.IPsOptions"> + <span>[[ p.label ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.blockdomains" }}</template> + <template #control> + <a-select mode="tags" v-model="blockedDomains" style="width: 100%" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.BlockDomainsOptions"> + <span>[[ p.label ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-row :xs="24" :sm="24" :lg="12"> + <a-alert type="warning" style="text-align: center; margin-top: 20px;"> + <template slot="message"> + <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> + <span>{{ i18n "pages.xray.directConnectionsConfigsDesc" }}</span> + </template> + </a-alert> + </a-row> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.directips" }}</template> + <template #control> + <a-select mode="tags" style="width: 100%" v-model="directIPs" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.IPsOptions"> + <span>[[ p.label ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.directdomains" }}</template> + <template #control> + <a-select mode="tags" style="width: 100%" v-model="directDomains" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.DomainsOptions"> + <span>[[ p.label ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-row :xs="24" :sm="24" :lg="12"> + <a-alert type="warning" style="text-align: center; margin-top: 20px;"> + <template slot="message"> + <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> + <span>{{ i18n "pages.xray.ipv4RoutingDesc" }}</span> + </template> + </a-alert> + </a-row> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.ipv4Routing" }}</template> + <template #control> + <a-select mode="tags" style="width: 100%" v-model="ipv4Domains" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.ServicesOptions"> + <span>[[ p.label ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-row :xs="24" :sm="24" :lg="12"> + <a-alert type="warning" style="text-align: center; margin-top: 20px;"> + <template slot="message"> + <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> + {{ i18n "pages.xray.warpRoutingDesc" }} + </template> + </a-alert> + </a-row> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.warpRouting" }}</template> + <template #control> + <template v-if="WarpExist"> + <a-select mode="tags" style="width: 100%" v-model="warpDomains" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.ServicesOptions"> + <span>[[ p.label ]]</span> + </a-select-option> + </a-select> + </template> + <template v-else> + <a-button type="primary" icon="cloud" @click="showWarp()">WARP</a-button> + </template> + </template> + </a-setting-list-item> + </a-collapse-panel> + <a-collapse-panel header='{{ i18n "pages.settings.resetDefaultConfig"}}'> + <a-space direction="horizontal" style="padding: 0 20px"> + <a-button type="danger" @click="resetXrayConfigToDefault"> + <span>{{ i18n "pages.settings.resetDefaultConfig" }}</span> + </a-button> + </a-space> + </a-collapse-panel> +</a-collapse> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/xray/dns.html b/web/html/xui/settings/xray/dns.html new file mode 100644 index 00000000..65735ff9 --- /dev/null +++ b/web/html/xui/settings/xray/dns.html @@ -0,0 +1,149 @@ +{{define "settings/xray/dns"}} +<a-collapse> + <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.dns.enable" }}</template> + <template #description>{{ i18n "pages.xray.dns.enableDesc" }}</template> + <template #control> + <a-switch v-model="enableDNS"></a-switch> + </template> + </a-setting-list-item> + <template v-if="enableDNS"> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.dns.tag" }}</template> + <template #description>{{ i18n "pages.xray.dns.tagDesc" }}</template> + <template #control> + <a-input type="text" v-model="dnsTag"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.dns.clientIp" }}</template> + <template #description>{{ i18n "pages.xray.dns.clientIpDesc" }}</template> + <template #control> + <a-input type="text" v-model="dnsClientIp"></a-input> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.dns.strategy" }}</template> + <template #description>{{ i18n "pages.xray.dns.strategyDesc" }}</template> + <template #control> + <a-select v-model="dnsStrategy" style="width: 100%" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']"> + <span>[[ l ]]</span> + </a-select-option> + </a-select> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.dns.disableCache" }}</template> + <template #description>{{ i18n "pages.xray.dns.disableCacheDesc" }}</template> + <template #control> + <a-switch v-model="dnsDisableCache"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.dns.disableFallback" }}</template> + <template #description>{{ i18n "pages.xray.dns.disableFallbackDesc" }}</template> + <template #control> + <a-switch v-model="dnsDisableFallback"></a-switch> + </template> + </a-setting-list-item> + <a-setting-list-item paddings="small"> + <template #title>{{ i18n "pages.xray.dns.disableFallbackIfMatch" }}</template> + <template #description>{{ i18n "pages.xray.dns.disableFallbackIfMatchDesc" }}</template> + <template #control> + <a-switch v-model="dnsDisableFallbackIfMatch"></a-switch> + </template> + </a-setting-list-item> + </template> + </a-collapse-panel> + <template v-if="enableDNS"> + <a-collapse-panel header='DNS'> + <template v-if="dnsServers.length > 0"> + <a-space direction="vertical" size="middle"> + <a-button type="primary" icon="plus" @click="addDNSServer()"> + <span>{{ i18n "pages.xray.dns.add" }}</span> + </a-button> + <a-table :columns="dnsColumns" bordered :row-key="r => r.key" :data-source="dnsServers" + :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"> + <template slot="action" slot-scope="text,dns,index"> + <span>[[ index+1 ]]</span> + <a-dropdown :trigger="['click']"> + <a-icon @click="e => e.preventDefault()" type="more" + style="font-size: 16px; text-decoration: bold;"></a-icon> + <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> + <a-menu-item @click="editDNSServer(index)"> + <a-icon type="edit"></a-icon> + <span>{{ i18n "edit" }}</span> + </a-menu-item> + <a-menu-item @click="deleteDNSServer(index)"> + <span style="color: #FF4D4F"> + <a-icon type="delete"></a-icon> + <span>{{ i18n "delete"}}</span> + </span> + </a-menu-item> + </a-menu> + </a-dropdown> + </template> + <template slot="address" slot-scope="dns,index"> + <span v-if="typeof dns == 'object'">[[ dns.address ]]</span> + <span v-else>[[ dns ]]</span> + </template> + <template slot="domain" slot-scope="dns,index"> + <span v-if="typeof dns == 'object'">[[ dns.domains.join(",") ]]</span> + </template> + <template slot="expectIPs" slot-scope="dns,index"> + <span v-if="typeof dns == 'object'">[[ dns.expectIPs.join(",") ]]</span> + </template> + </a-table> + </a-space> + </template> + <template v-else> + <a-empty description='{{ i18n "emptyDnsDesc" }}' style="margin: 10px;"> + <a-button type="primary" icon="plus" @click="addDNSServer()" style="margin-top: 10px;"> + <span>{{ i18n "pages.xray.dns.add" }}</span> + </a-button> + </a-empty> + </template> + </a-collapse-panel> + <a-collapse-panel header='Fake DNS'> + <template v-if="fakeDns && fakeDns.length > 0"> + <a-space direction="vertical" size="middle"> + <a-button type="primary" icon="plus" @click="addFakedns()">{{ i18n "pages.xray.fakedns.add" + }}</a-button> + <a-table :columns="fakednsColumns" bordered :row-key="r => r.key" :data-source="fakeDns" + :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"> + <template slot="action" slot-scope="text,fakedns,index"> + <span>[[ index+1 ]]</span> + <a-dropdown :trigger="['click']"> + <a-icon @click="e => e.preventDefault()" type="more" + style="font-size: 16px; text-decoration: bold;"></a-icon> + <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> + <a-menu-item @click="editFakedns(index)"> + <a-icon type="edit"></a-icon> + <span>{{ i18n "edit" }}</span> + </a-menu-item> + <a-menu-item @click="deleteFakedns(index)"> + <span style="color: #FF4D4F"> + <a-icon type="delete"></a-icon> + <span>{{ i18n "delete"}}</span> + </span> + </a-menu-item> + </a-menu> + </a-dropdown> + </template> + </a-table> + </a-space> + </template> + <template v-else> + <a-empty description='{{ i18n "emptyFakeDnsDesc" }}' style="margin: 20px;"> + <a-button type="primary" icon="plus" @click="addFakedns()" style="margin-top: 10px;"> + <span>{{ i18n "pages.xray.fakedns.add" }}</span> + </a-button> + </a-empty> + </template> + </a-collapse-panel> + </template> +</a-collapse> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/xray/outbounds.html b/web/html/xui/settings/xray/outbounds.html new file mode 100644 index 00000000..45d07c4c --- /dev/null +++ b/web/html/xui/settings/xray/outbounds.html @@ -0,0 +1,72 @@ +{{define "settings/xray/outbounds"}} +<a-space direction="vertical" size="middle"> + <a-row> + <a-col :xs="12" :sm="12" :lg="12"> + <a-space direction="horizontal" size="small"> + <a-button type="primary" icon="plus" @click="addOutbound()"> + {{ i18n "pages.xray.outbound.addOutbound" }} + </a-button> + <a-button type="primary" icon="cloud" @click="showWarp()">WARP</a-button> + </a-space> + </a-col> + <a-col :xs="12" :sm="12" :lg="12" style="text-align: right;"> + <a-icon type="sync" :spin="refreshing" @click="refreshOutboundTraffic()" style="margin: 0 5px;"></a-icon> + <a-popconfirm placement="topRight" @confirm="resetOutboundTraffic(-1)" + title='{{ i18n "pages.inbounds.resetTrafficContent"}}' :overlay-class-name="themeSwitcher.currentTheme" + ok-text='{{ i18n "reset"}}' cancel-text='{{ i18n "cancel"}}'> + <a-icon slot="icon" type="question-circle-o" + :style="themeSwitcher.isDarkTheme ? 'color: #008771' : 'color: #008771'"></a-icon> + <a-icon type="retweet" style="cursor: pointer;"></a-icon> + </a-popconfirm> + </a-col> + </a-row> + <a-table :columns="outboundColumns" bordered :row-key="r => r.key" :data-source="outboundData" + :scroll="isMobile ? {} : { x: 800 }" :pagination="false" :indent-size="0"> + <template slot="action" slot-scope="text, outbound, index"> + <span>[[ index+1 ]]</span> + <a-dropdown :trigger="['click']"> + <a-icon @click="e => e.preventDefault()" type="more" + style="font-size: 16px; text-decoration: bold;"></a-icon> + <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> + <a-menu-item v-if="index>0" @click="setFirstOutbound(index)"> + <a-icon type="vertical-align-top"></a-icon> + <span>{{ i18n "pages.xray.rules.first"}}</span> + </a-menu-item> + <a-menu-item @click="editOutbound(index)"> + <a-icon type="edit"></a-icon> + <span>{{ i18n "edit" }}</span> + </a-menu-item> + <a-menu-item @click="resetOutboundTraffic(index)"> + <span> + <a-icon type="retweet"></a-icon> + <span>{{ i18n "pages.inbounds.resetTraffic"}}</span> + </span> + </a-menu-item> + <a-menu-item @click="deleteOutbound(index)"> + <span style="color: #FF4D4F"> + <a-icon type="delete"></a-icon> + <span>{{ i18n "delete"}}</span> + </span> + </a-menu-item> + </a-menu> + </a-dropdown> + </template> + <template slot="address" slot-scope="text, outbound, index"> + <p style="margin: 0 5px;" v-for="addr in findOutboundAddress(outbound)">[[ addr ]]</p> + </template> + <template slot="protocol" slot-scope="text, outbound, index"> + <a-tag style="margin:0;" color="purple">[[ outbound.protocol ]]</a-tag> + <template + v-if="[Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(outbound.protocol)"> + <a-tag style="margin:0;" color="blue">[[ outbound.streamSettings.network ]]</a-tag> + <a-tag style="margin:0;" v-if="outbound.streamSettings.security=='tls'" color="green">tls</a-tag> + <a-tag style="margin:0;" v-if="outbound.streamSettings.security=='reality'" + color="green">reality</a-tag> + </template> + </template> + <template slot="traffic" slot-scope="text, outbound, index"> + <a-tag color="green">[[ findOutboundTraffic(outbound) ]]</a-tag> + </template> + </a-table> +</a-space> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/xray/reverse.html b/web/html/xui/settings/xray/reverse.html new file mode 100644 index 00000000..a8c93ea9 --- /dev/null +++ b/web/html/xui/settings/xray/reverse.html @@ -0,0 +1,38 @@ +{{define "settings/xray/reverse"}} +<template v-if="reverseData.length > 0"> + <a-space direction="vertical" size="middle"> + <a-button type="primary" icon="plus" @click="addReverse()"> + <span>{{ i18n "pages.xray.outbound.addReverse" }}</span> + </a-button> + <a-table :columns="reverseColumns" bordered :row-key="r => r.key" :data-source="reverseData" + :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"> + <template slot="action" slot-scope="text, reverse, index"> + <span>[[ index+1 ]]</span> + <a-dropdown :trigger="['click']"> + <a-icon @click="e => e.preventDefault()" type="more" + style="font-size: 16px; text-decoration: bold;"></a-icon> + <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> + <a-menu-item @click="editReverse(index)"> + <a-icon type="edit"></a-icon> + <span>{{ i18n "edit" }}</span> + </a-menu-item> + <a-menu-item @click="deleteReverse(index)"> + <span style="color: #FF4D4F"> + <a-icon type="delete"></a-icon> + <span>{{ i18n "delete"}}</span> + </span> + </a-menu-item> + </a-menu> + </a-dropdown> + </template> + </a-table> + </a-space> +</template> +<template v-else> + <a-empty description='{{ i18n "emptyReverseDesc" }}' style="margin: 10px;"> + <a-button type="primary" icon="plus" @click="addReverse()" style="margin-top: 10px;"> + {{ i18n "pages.xray.outbound.addReverse" }} + </a-button> + </a-empty> +</template> +{{end}} \ No newline at end of file diff --git a/web/html/xui/settings/xray/routing.html b/web/html/xui/settings/xray/routing.html new file mode 100644 index 00000000..8c2502de --- /dev/null +++ b/web/html/xui/settings/xray/routing.html @@ -0,0 +1,119 @@ +{{define "settings/xray/routing"}} +<a-space direction="vertical" size="middle"> + <a-button type="primary" icon="plus" @click="addRule">{{ i18n "pages.xray.rules.add" }}</a-button> + <a-table-sortable :columns="isMobile ? rulesMobileColumns : rulesColumns" bordered :row-key="r => r.key" + :data-source="routingRuleData" :scroll="isMobile ? {} : { x: 1000 }" :pagination="false" :indent-size="0" + v-on:onSort="replaceRule"> + <template slot="action" slot-scope="text, rule, index"> + <a-table-sort-trigger :item-index="index"></a-table-sort-trigger> + <span class="ant-table-row-index"> [[ index+1 ]] </span> + <a-dropdown :trigger="['click']"> + <a-icon @click="e => e.preventDefault()" type="more" + style="font-size: 16px; text-decoration: bold;"></a-icon> + <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> + <a-menu-item v-if="index>0" @click="replaceRule(index,0)"> + <a-icon type="vertical-align-top"></a-icon> + {{ i18n "pages.xray.rules.first"}} + </a-menu-item> + <a-menu-item v-if="index>0" @click="replaceRule(index,index-1)"> + <a-icon type="arrow-up"></a-icon> + {{ i18n "pages.xray.rules.up"}} + </a-menu-item> + <a-menu-item v-if="index<routingRuleData.length-1" @click="replaceRule(index,index+1)"> + <a-icon type="arrow-down"></a-icon> + {{ i18n "pages.xray.rules.down"}} + </a-menu-item> + <a-menu-item v-if="index<routingRuleData.length-1" + @click="replaceRule(index,routingRuleData.length-1)"> + <a-icon type="vertical-align-bottom"></a-icon> + {{ i18n "pages.xray.rules.last"}} + </a-menu-item> + <a-menu-item @click="editRule(index)"> + <a-icon type="edit"></a-icon> + {{ i18n "edit" }} + </a-menu-item> + <a-menu-item @click="deleteRule(index)"> + <span style="color: #FF4D4F"> + <a-icon type="delete"></a-icon> {{ i18n "delete"}} + </span> + </a-menu-item> + </a-menu> + </a-dropdown> + </template> + <template slot="inbound" slot-scope="text, rule, index"> + <a-popover :overlay-class-name="themeSwitcher.currentTheme"> + <template slot="content"> + <p v-if="rule.inboundTag">Inbound Tag: [[ rule.inboundTag ]]</p> + <p v-if="rule.user">User email: [[ rule.user ]]</p> + </template> + [[ [rule.inboundTag,rule.user].join('\n') ]] + </a-popover> + </template> + <template slot="outbound" slot-scope="text, rule, index"> + <a-popover :overlay-class-name="themeSwitcher.currentTheme"> + <template slot="content"> + <p v-if="rule.outboundTag">Outbound Tag: [[ rule.outboundTag ]]</p> + </template> + [[ rule.outboundTag ]] + </a-popover> + </template> + <template slot="balancer" slot-scope="text, rule, index"> + <a-popover :overlay-class-name="themeSwitcher.currentTheme"> + <template slot="content"> + <p v-if="rule.balancerTag">Balancer Tag: [[ rule.balancerTag ]]</p> + </template> + [[ rule.balancerTag ]] + </a-popover> + </template> + <template slot="info" slot-scope="text, rule, index"> + <a-popover placement="bottomRight" + v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0" + :overlay-class-name="themeSwitcher.currentTheme" trigger="click"> + <template slot="content"> + <table cellpadding="2" style="max-width: 300px;"> + <tr v-if="rule.source"> + <td>Source</td> + <td><a-tag color="blue" v-for="r in rule.source.split(',')">[[ r ]]</a-tag></td> + </tr> + <tr v-if="rule.sourcePort"> + <td>Source Port</td> + <td><a-tag color="green" v-for="r in rule.sourcePort.split(',')">[[ r ]]</a-tag></td> + </tr> + <tr v-if="rule.network"> + <td>Network</td> + <td><a-tag color="blue" v-for="r in rule.network.split(',')">[[ r ]]</a-tag></td> + </tr> + <tr v-if="rule.protocol"> + <td>Protocol</td> + <td><a-tag color="green" v-for="r in rule.protocol.split(',')">[[ r ]]</a-tag></td> + </tr> + <tr v-if="rule.attrs"> + <td>Attrs</td> + <td><a-tag color="blue" v-for="r in rule.attrs.split(',')">[[ r ]]</a-tag></td> + </tr> + <tr v-if="rule.ip"> + <td>IP</td> + <td><a-tag color="green" v-for="r in rule.ip.split(',')">[[ r ]]</a-tag></td> + </tr> + <tr v-if="rule.domain"> + <td>Domain</td> + <td><a-tag color="blue" v-for="r in rule.domain.split(',')">[[ r ]]</a-tag></td> + </tr> + <tr v-if="rule.port"> + <td>Port</td> + <td><a-tag color="green" v-for="r in rule.port.split(',')">[[ r ]]</a-tag></td> + </tr> + <tr v-if="rule.balancerTag"> + <td>Balancer Tag</td> + <td><a-tag color="blue">[[ rule.balancerTag ]]</a-tag></td> + </tr> + </table> + </template> + <a-button shape="round" size="small" style="font-size: 14px; padding: 0 10px;"> + <a-icon type="info"></a-icon> + </a-button> + </a-popover> + </template> + </a-table-sortable> +</a-space> +{{end}} \ No newline at end of file diff --git a/web/html/xui/xray.html b/web/html/xui/xray.html index 8ba14f7d..1abef018 100644 --- a/web/html/xui/xray.html +++ b/web/html/xui/xray.html @@ -6,7 +6,6 @@ <link rel="stylesheet" href="{{ .base_path }}assets/codemirror/xq.min.css?{{ .cur_ver }}"> <link rel="stylesheet" href="{{ .base_path }}assets/codemirror/lint/lint.css"> -<script src="{{ .base_path }}assets/base64/base64.min.js"></script> <script src="{{ .base_path }}assets/js/model/outbound.js?{{ .cur_ver }}"></script> <script src="{{ .base_path }}assets/codemirror/codemirror.min.js?{{ .cur_ver }}"></script> <script src="{{ .base_path }}assets/codemirror/javascript.js"></script> @@ -40,27 +39,13 @@ .ant-list-item { display: block; } - .collapse-title { - color: inherit; - font-weight: bold; - font-size: 18px; - padding: 10px 20px; - border-bottom: 2px solid; - } - .collapse-title>i { - color: inherit; - font-size: 24px; - } - .ant-collapse-content-box>li { - padding: 12px 0 0 !important; - } .ant-list-item>li { padding: 10px 20px !important; } </style> <body> <a-layout id="app" v-cloak :class="themeSwitcher.currentTheme"> - {{ template "commonSider" . }} + <a-sidebar></a-sidebar> <a-layout id="content-layout"> <a-layout-content> <a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'> @@ -104,682 +89,25 @@ @change="(activeKey) => { this.changePage(activeKey); }" :class="themeSwitcher.currentTheme"> <a-tab-pane key="tpl-basic" tab='{{ i18n "pages.xray.basicTemplate"}}' style="padding-top: 20px;"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> - <a-row :xs="24" :sm="24" :lg="12"> - <a-alert type="warning" style="text-align: center;"> - <template slot="message"> - <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> - {{ i18n "pages.xray.generalConfigsDesc" }} - </template> - </a-alert> - </a-row> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.FreedomStrategy" }}</template> - <template #description>{{ i18n "pages.xray.FreedomStrategyDesc" }}</template> - <template #control> - <a-select v-model="freedomStrategy" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> - <a-select-option v-for="s in OutboundDomainStrategies" :value="s">[[ s ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.RoutingStrategy" }}</template> - <template #description>{{ i18n "pages.xray.RoutingStrategyDesc" }}</template> - <template #control> - <a-select v-model="routingStrategy" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> - <a-select-option v-for="s in routingDomainStrategies" :value="s">[[ s ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.xray.statistics" }}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.statsInboundUplink" }}</template> - <template #description>{{ i18n "pages.xray.statsInboundUplinkDesc" }}</template> - <template #control> - <a-switch v-model="statsInboundUplink"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.statsInboundDownlink" }}</template> - <template #description>{{ i18n "pages.xray.statsInboundDownlinkDesc" }}</template> - <template #control> - <a-switch v-model="statsInboundDownlink"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.statsOutboundUplink" }}</template> - <template #description>{{ i18n "pages.xray.statsOutboundUplinkDesc" }}</template> - <template #control> - <a-switch v-model="statsOutboundUplink"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.statsOutboundDownlink" }}</template> - <template #description>{{ i18n "pages.xray.statsOutboundDownlinkDesc" }}</template> - <template #control> - <a-switch v-model="statsOutboundDownlink"></a-switch> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.xray.logConfigs" }}'> - <a-row :xs="24" :sm="24" :lg="12"> - <a-alert type="warning" style="text-align: center;"> - <template slot="message"> - <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> - {{ i18n "pages.xray.logConfigsDesc" }} - </template> - </a-alert> - </a-row> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.logLevel" }}</template> - <template #description>{{ i18n "pages.xray.logLevelDesc" }}</template> - <template #control> - <a-select v-model="logLevel" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> - <a-select-option v-for="s in log.loglevel" :value="s">[[ s ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.accessLog" }}</template> - <template #description>{{ i18n "pages.xray.accessLogDesc" }}</template> - <template #control> - <a-select v-model="accessLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> - <a-select-option value=''>Empty</a-select-option> - <a-select-option v-for="s in log.access" :value="s">[[ s ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.errorLog" }}</template> - <template #description>{{ i18n "pages.xray.errorLogDesc" }}</template> - <template #control> - <a-select v-model="errorLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> - <a-select-option value=''>Empty</a-select-option> - <a-select-option v-for="s in log.error" :value="s">[[ s ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.maskAddress" }}</template> - <template #description>{{ i18n "pages.xray.maskAddressDesc" }}</template> - <template #control> - <a-select v-model="maskAddressLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%"> - <a-select-option value=''>Empty</a-select-option> - <a-select-option v-for="s in log.maskAddress" :value="s">[[ s ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.dnsLog"}}</template> - <template #description>{{ i18n "pages.xray.dnsLogDesc"}}</template> - <template #control> - <a-switch v-model="dnslog"></a-switch> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.xray.blockConfigs"}}'> - <a-row :xs="24" :sm="24" :lg="12"> - <a-alert type="warning" style="text-align: center;"> - <template slot="message"> - <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> - {{ i18n "pages.xray.blockConfigsDesc" }} - </template> - </a-alert> - </a-row> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.Torrent"}}</template> - <template #description>{{ i18n "pages.xray.TorrentDesc"}}</template> - <template #control> - <a-switch v-model="torrentSettings"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.Family"}}</template> - <template #description>{{ i18n "pages.xray.FamilyDesc"}}</template> - <template #control> - <a-switch v-model="familyProtectSettings"></a-switch> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.xray.basicRouting"}}'> - <a-row :xs="24" :sm="24" :lg="12"> - <a-alert type="warning" style="text-align: center;"> - <template slot="message"> - <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> - {{ i18n "pages.xray.blockConnectionsConfigsDesc" }} - </template> - </a-alert> - </a-row> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.blockips" }}</template> - <template #control> - <a-select mode="tags" v-model="blockedIPs" style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.IPsOptions">[[ p.label ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.blockdomains" }}</template> - <template #control> - <a-select mode="tags" v-model="blockedDomains" style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.BlockDomainsOptions">[[ p.label ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-row :xs="24" :sm="24" :lg="12"> - <a-alert type="warning" style="text-align: center; margin-top: 20px;"> - <template slot="message"> - <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> - {{ i18n "pages.xray.directConnectionsConfigsDesc" }} - </template> - </a-alert> - </a-row> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.directips" }}</template> - <template #control> - <a-select mode="tags" style="width: 100%" v-model="directIPs" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.IPsOptions">[[ p.label ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.directdomains" }}</template> - <template #control> - <a-select mode="tags" style="width: 100%" v-model="directDomains" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.DomainsOptions">[[ p.label ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-row :xs="24" :sm="24" :lg="12"> - <a-alert type="warning" style="text-align: center; margin-top: 20px;"> - <template slot="message"> - <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> - {{ i18n "pages.xray.ipv4RoutingDesc" }} - </template> - </a-alert> - </a-row> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.ipv4Routing" }}</template> - <template #control> - <a-select mode="tags" style="width: 100%" v-model="ipv4Domains" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.ServicesOptions">[[ p.label ]]</a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-row :xs="24" :sm="24" :lg="12"> - <a-alert type="warning" style="text-align: center; margin-top: 20px;"> - <template slot="message"> - <a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon> - {{ i18n "pages.xray.warpRoutingDesc" }} - </template> - </a-alert> - </a-row> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.warpRouting" }}</template> - <template #control> - <template v-if="WarpExist"> - <a-select mode="tags" style="width: 100%" v-model="warpDomains" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.ServicesOptions">[[ p.label ]]</a-select-option> - </a-select> - </template> - <template v-else> - <a-button type="primary" icon="cloud" @click="showWarp()">WARP</a-button> - </template> - </template> - </a-setting-list-item> - </a-collapse-panel> - <a-collapse-panel header='{{ i18n "pages.settings.resetDefaultConfig"}}'> - <a-space direction="horizontal" style="padding: 0 20px"> - <a-button type="danger" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button> - </a-space> - </a-collapse-panel> - </a-collapse> + {{ template "settings/xray/basics" . }} </a-tab-pane> <a-tab-pane key="tpl-routing" tab='{{ i18n "pages.xray.Routings"}}' style="padding-top: 20px;"> - <a-space direction="vertical" size="middle"> - <a-button type="primary" icon="plus" @click="addRule">{{ i18n "pages.xray.rules.add" }}</a-button> - <a-table-sortable :columns="isMobile ? rulesMobileColumns : rulesColumns" bordered - :row-key="r => r.key" - :data-source="routingRuleData" - :scroll="isMobile ? {} : { x: 1000 }" - :pagination="false" - :indent-size="0" - v-on:onSort="replaceRule"> - <template slot="action" slot-scope="text, rule, index"> - <a-table-sort-trigger :item-index="index"></a-table-sort-trigger> - <span class="ant-table-row-index"> [[ index+1 ]] </span> - <a-dropdown :trigger="['click']"> - <a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon> - <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> - <a-menu-item v-if="index>0" @click="replaceRule(index,0)"> - <a-icon type="vertical-align-top"></a-icon> - {{ i18n "pages.xray.rules.first"}} - </a-menu-item> - <a-menu-item v-if="index>0" @click="replaceRule(index,index-1)"> - <a-icon type="arrow-up"></a-icon> - {{ i18n "pages.xray.rules.up"}} - </a-menu-item> - <a-menu-item v-if="index<routingRuleData.length-1" @click="replaceRule(index,index+1)"> - <a-icon type="arrow-down"></a-icon> - {{ i18n "pages.xray.rules.down"}} - </a-menu-item> - <a-menu-item v-if="index<routingRuleData.length-1" @click="replaceRule(index,routingRuleData.length-1)"> - <a-icon type="vertical-align-bottom"></a-icon> - {{ i18n "pages.xray.rules.last"}} - </a-menu-item> - <a-menu-item @click="editRule(index)"> - <a-icon type="edit"></a-icon> - {{ i18n "edit" }} - </a-menu-item> - <a-menu-item @click="deleteRule(index)"> - <span style="color: #FF4D4F"> - <a-icon type="delete"></a-icon> {{ i18n "delete"}} - </span> - </a-menu-item> - </a-menu> - </a-dropdown> - </template> - <template slot="inbound" slot-scope="text, rule, index"> - <a-popover :overlay-class-name="themeSwitcher.currentTheme"> - <template slot="content"> - <p v-if="rule.inboundTag">Inbound Tag: [[ rule.inboundTag ]]</p> - <p v-if="rule.user">User email: [[ rule.user ]]</p> - </template> - [[ [rule.inboundTag,rule.user].join('\n') ]] - </a-popover> - </template> - <template slot="outbound" slot-scope="text, rule, index"> - <a-popover :overlay-class-name="themeSwitcher.currentTheme"> - <template slot="content"> - <p v-if="rule.outboundTag">Outbound Tag: [[ rule.outboundTag ]]</p> - </template> - [[ rule.outboundTag ]] - </a-popover> - </template> - <template slot="balancer" slot-scope="text, rule, index"> - <a-popover :overlay-class-name="themeSwitcher.currentTheme"> - <template slot="content"> - <p v-if="rule.balancerTag">Balancer Tag: [[ rule.balancerTag ]]</p> - </template> - [[ rule.balancerTag ]] - </a-popover> - </template> - <template slot="info" slot-scope="text, rule, index"> - <a-popover placement="bottomRight" - v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0" - :overlay-class-name="themeSwitcher.currentTheme" trigger="click"> - <template slot="content"> - <table cellpadding="2" style="max-width: 300px;"> - <tr v-if="rule.source"> - <td>Source</td> - <td><a-tag color="blue" v-for="r in rule.source.split(',')">[[ r ]]</a-tag></td> - </tr> - <tr v-if="rule.sourcePort"> - <td>Source Port</td> - <td><a-tag color="green" v-for="r in rule.sourcePort.split(',')">[[ r ]]</a-tag></td> - </tr> - <tr v-if="rule.network"> - <td>Network</td> - <td><a-tag color="blue" v-for="r in rule.network.split(',')">[[ r ]]</a-tag></td> - </tr> - <tr v-if="rule.protocol"> - <td>Protocol</td> - <td><a-tag color="green" v-for="r in rule.protocol.split(',')">[[ r ]]</a-tag></td> - </tr> - <tr v-if="rule.attrs"> - <td>Attrs</td> - <td><a-tag color="blue" v-for="r in rule.attrs.split(',')">[[ r ]]</a-tag></td> - </tr> - <tr v-if="rule.ip"> - <td>IP</td> - <td><a-tag color="green" v-for="r in rule.ip.split(',')">[[ r ]]</a-tag></td> - </tr> - <tr v-if="rule.domain"> - <td>Domain</td> - <td><a-tag color="blue" v-for="r in rule.domain.split(',')">[[ r ]]</a-tag></td> - </tr> - <tr v-if="rule.port"> - <td>Port</td> - <td><a-tag color="green" v-for="r in rule.port.split(',')">[[ r ]]</a-tag></td> - </tr> - <tr v-if="rule.balancerTag"> - <td>Balancer Tag</td> - <td><a-tag color="blue">[[ rule.balancerTag ]]</a-tag></td> - </tr> - </table> - </template> - <a-button shape="round" size="small" style="font-size: 14px; padding: 0 10px;"> - <a-icon type="info"></a-icon> - </a-button> - </a-popover> - </template> - </a-table-sortable> - </a-space> + {{ template "settings/xray/routing" . }} </a-tab-pane> <a-tab-pane key="tpl-outbound" tab='{{ i18n "pages.xray.Outbounds"}}' force-render="true"> - <a-space direction="vertical" size="middle"> - <a-row> - <a-col :xs="12" :sm="12" :lg="12"> - <a-space direction="horizontal" size="small"> - <a-button type="primary" icon="plus" @click="addOutbound()"> - {{ i18n "pages.xray.outbound.addOutbound" }} - </a-button> - <a-button type="primary" icon="cloud" @click="showWarp()">WARP</a-button> - </a-space> - </a-col> - <a-col :xs="12" :sm="12" :lg="12" style="text-align: right;"> - <a-icon type="sync" :spin="refreshing" @click="refreshOutboundTraffic()" style="margin: 0 5px;"></a-icon> - <a-popconfirm placement="topRight" @confirm="resetOutboundTraffic(-1)" - title='{{ i18n "pages.inbounds.resetTrafficContent"}}' - :overlay-class-name="themeSwitcher.currentTheme" - ok-text='{{ i18n "reset"}}' - cancel-text='{{ i18n "cancel"}}'> - <a-icon slot="icon" type="question-circle-o" :style="themeSwitcher.isDarkTheme ? 'color: #008771' : 'color: #008771'"></a-icon> - <a-icon type="retweet" style="cursor: pointer;"></a-icon> - </a-popconfirm> - </a-col> - </a-row> - <a-table :columns="outboundColumns" bordered - :row-key="r => r.key" - :data-source="outboundData" - :scroll="isMobile ? {} : { x: 800 }" - :pagination="false" - :indent-size="0"> - <template slot="action" slot-scope="text, outbound, index"> - [[ index+1 ]] - <a-dropdown :trigger="['click']"> - <a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon> - <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> - <a-menu-item v-if="index>0" @click="setFirstOutbound(index)"> - <a-icon type="vertical-align-top"></a-icon> - {{ i18n "pages.xray.rules.first"}} - </a-menu-item> - <a-menu-item @click="editOutbound(index)"> - <a-icon type="edit"></a-icon> - {{ i18n "edit" }} - </a-menu-item> - <a-menu-item @click="resetOutboundTraffic(index)"> - <span> - <a-icon type="retweet"></a-icon> {{ i18n "pages.inbounds.resetTraffic"}} - </span> - </a-menu-item> - <a-menu-item @click="deleteOutbound(index)"> - <span style="color: #FF4D4F"> - <a-icon type="delete"></a-icon> {{ i18n "delete"}} - </span> - </a-menu-item> - </a-menu> - </a-dropdown> - </template> - <template slot="address" slot-scope="text, outbound, index"> - <p style="margin: 0 5px;" v-for="addr in findOutboundAddress(outbound)">[[ addr ]]</p> - </template> - <template slot="protocol" slot-scope="text, outbound, index"> - <a-tag style="margin:0;" color="purple">[[ outbound.protocol ]]</a-tag> - <template v-if="[Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(outbound.protocol)"> - <a-tag style="margin:0;" color="blue">[[ outbound.streamSettings.network ]]</a-tag> - <a-tag style="margin:0;" v-if="outbound.streamSettings.security=='tls'" color="green">tls</a-tag> - <a-tag style="margin:0;" v-if="outbound.streamSettings.security=='reality'" color="green">reality</a-tag> - </template> - </template> - <template slot="traffic" slot-scope="text, outbound, index"> - <a-tag color="green">[[ findOutboundTraffic(outbound) ]]</a-tag> - </template> - </a-table> - </a-space> + {{ template "settings/xray/outbounds" . }} </a-tab-pane> <a-tab-pane key="tpl-reverse" tab='{{ i18n "pages.xray.outbound.reverse"}}' style="padding-top: 20px;" force-render="true"> - <template v-if="reverseData.length > 0"> - <a-space direction="vertical" size="middle"> - <a-button type="primary" icon="plus" @click="addReverse()"> - {{ i18n "pages.xray.outbound.addReverse" }} - </a-button> - <a-table :columns="reverseColumns" bordered - :row-key="r => r.key" - :data-source="reverseData" - :scroll="isMobile ? {} : { x: 200 }" - :pagination="false" - :indent-size="0"> - <template slot="action" slot-scope="text, reverse, index"> - [[ index+1 ]] - <a-dropdown :trigger="['click']"> - <a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon> - <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> - <a-menu-item @click="editReverse(index)"> - <a-icon type="edit"></a-icon> - {{ i18n "edit" }} - </a-menu-item> - <a-menu-item @click="deleteReverse(index)"> - <span style="color: #FF4D4F"> - <a-icon type="delete"></a-icon> {{ i18n "delete"}} - </span> - </a-menu-item> - </a-menu> - </a-dropdown> - </template> - </a-table> - </a-space> - </template> - <template v-else> - <a-empty description='{{ i18n "emptyReverseDesc" }}' style="margin: 10px;"> - <a-button type="primary" icon="plus" @click="addReverse()" style="margin-top: 10px;"> - {{ i18n "pages.xray.outbound.addReverse" }} - </a-button> - </a-empty> - </template> + {{ template "settings/xray/reverse" . }} </a-tab-pane> <a-tab-pane key="tpl-balancer" tab='{{ i18n "pages.xray.Balancers"}}' style="padding-top: 20px;" force-render="true"> - <template v-if="balancersData.length > 0"> - <a-space direction="vertical" size="middle"> - <a-button type="primary" icon="plus" @click="addBalancer()"> - {{ i18n "pages.xray.balancer.addBalancer"}} - </a-button> - <a-table :columns="balancerColumns" bordered - :row-key="r => r.key" - :data-source="balancersData" - :scroll="isMobile ? {} : { x: 200 }" - :pagination="false" - :indent-size="0"> - <template slot="action" slot-scope="text, balancer, index"> - [[ index+1 ]] - <a-dropdown :trigger="['click']"> - <a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon> - <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> - <a-menu-item @click="editBalancer(index)"> - <a-icon type="edit"></a-icon> - {{ i18n "edit" }} - </a-menu-item> - <a-menu-item @click="deleteBalancer(index)"> - <span style="color: #FF4D4F"> - <a-icon type="delete"></a-icon> {{ i18n "delete"}} - </span> - </a-menu-item> - </a-menu> - </a-dropdown> - </template> - <template slot="strategy" slot-scope="text, balancer, index"> - <a-tag style="margin:0;" v-if="balancer.strategy=='random'" color="purple">Random</a-tag> - <a-tag style="margin:0;" v-if="balancer.strategy=='roundRobin'" color="green">Round Robin</a-tag> - <a-tag style="margin:0;" v-if="balancer.strategy=='leastLoad'" color="green">Least Load</a-tag> - <a-tag style="margin:0;" v-if="balancer.strategy=='leastPing'" color="green">Least Ping</a-tag> - </template> - <template slot="selector" slot-scope="text, balancer, index"> - <a-tag class="info-large-tag" style="margin:1;" v-for="sel in balancer.selector">[[ sel ]]</a-tag> - </template> - </a-table> - <a-radio-group - v-if="observatoryEnable || burstObservatoryEnable" - v-model="obsSettings" - @change="changeObsCode" - button-style="solid" - :size="isMobile ? 'small' : ''"> - <a-radio-button value="observatory" v-if="observatoryEnable">Observatory</a-radio-button> - <a-radio-button value="burstObservatory" v-if="burstObservatoryEnable">Burst Observatory</a-radio-button> - </a-radio-group> - <textarea style="position:absolute; left: -800px;" id="obsSetting"></textarea> - </a-space> - </template> - <template v-else> - <a-empty description='{{ i18n "emptyBalancersDesc" }}' style="margin: 10px;"> - <a-button type="primary" icon="plus" @click="addBalancer()" style="margin-top: 10px;"> - {{ i18n "pages.xray.balancer.addBalancer"}} - </a-button> - </a-empty> - </template> + {{ template "settings/xray/balancers" . }} + </a-tab-pane> + <a-tab-pane key="tpl-dns" tab='DNS' style="padding-top: 20px;" force-render="true"> + {{ template "settings/xray/dns" . }} </a-tab-pane> - <a-tab-pane key="tpl-dns" tab='DNS' style="padding-top: 20px;" force-render="true"> - <a-collapse> - <a-collapse-panel header='{{ i18n "pages.xray.generalConfigs"}}'> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.dns.enable" }}</template> - <template #description>{{ i18n "pages.xray.dns.enableDesc" }}</template> - <template #control> - <a-switch v-model="enableDNS"></a-switch> - </template> - </a-setting-list-item> - <template v-if="enableDNS"> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.dns.tag" }}</template> - <template #description>{{ i18n "pages.xray.dns.tagDesc" }}</template> - <template #control> - <a-input type="text" v-model="dnsTag"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.dns.clientIp" }}</template> - <template #description>{{ i18n "pages.xray.dns.clientIpDesc" }}</template> - <template #control> - <a-input type="text" v-model="dnsClientIp"></a-input> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.dns.strategy" }}</template> - <template #description>{{ i18n "pages.xray.dns.strategyDesc" }}</template> - <template #control> - <a-select v-model="dnsStrategy" style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']"> - [[ l ]] - </a-select-option> - </a-select> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.dns.disableCache" }}</template> - <template #description>{{ i18n "pages.xray.dns.disableCacheDesc" }}</template> - <template #control> - <a-switch v-model="dnsDisableCache"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.dns.disableFallback" }}</template> - <template #description>{{ i18n "pages.xray.dns.disableFallbackDesc" }}</template> - <template #control> - <a-switch v-model="dnsDisableFallback"></a-switch> - </template> - </a-setting-list-item> - <a-setting-list-item paddings="small"> - <template #title>{{ i18n "pages.xray.dns.disableFallbackIfMatch" }}</template> - <template #description>{{ i18n "pages.xray.dns.disableFallbackIfMatchDesc" }}</template> - <template #control> - <a-switch v-model="dnsDisableFallbackIfMatch"></a-switch> - </template> - </a-setting-list-item> - </template> - </a-collapse-panel> - <template v-if="enableDNS"> - <a-collapse-panel header='DNS'> - <template v-if="dnsServers.length > 0"> - <a-space direction="vertical" size="middle"> - <a-button type="primary" icon="plus" @click="addDNSServer()">{{ i18n - "pages.xray.dns.add" }}</a-button> - <a-table :columns="dnsColumns" bordered :row-key="r => r.key" - :data-source="dnsServers" :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"> - <template slot="action" slot-scope="text,dns,index"> - [[ index+1 ]] - <a-dropdown :trigger="['click']"> - <a-icon @click="e => e.preventDefault()" type="more" - style="font-size: 16px; text-decoration: bold;"></a-icon> - <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> - <a-menu-item @click="editDNSServer(index)"> - <a-icon type="edit"></a-icon> - {{ i18n "edit" }} - </a-menu-item> - <a-menu-item @click="deleteDNSServer(index)"> - <span style="color: #FF4D4F"> - <a-icon type="delete"></a-icon> {{ i18n "delete"}} - </span> - </a-menu-item> - </a-menu> - </a-dropdown> - </template> - <template slot="address" slot-scope="dns,index"> - <span v-if="typeof dns == 'object'">[[ dns.address ]]</span> - <span v-else>[[ dns ]]</span> - </template> - <template slot="domain" slot-scope="dns,index"> - <span v-if="typeof dns == 'object'">[[ dns.domains.join(",") ]]</span> - </template> - <template slot="expectIPs" slot-scope="dns,index"> - <span v-if="typeof dns == 'object'">[[ dns.expectIPs.join(",") ]]</span> - </template> - </a-table> - </a-space> - </template> - <template v-else> - <a-empty description='{{ i18n "emptyDnsDesc" }}' style="margin: 10px;"> - <a-button type="primary" icon="plus" @click="addDNSServer()" style="margin-top: 10px;">{{ i18n "pages.xray.dns.add" }}</a-button> - </a-empty> - </template> - </a-collapse-panel> - <a-collapse-panel header='Fake DNS'> - <template v-if="fakeDns && fakeDns.length > 0"> - <a-space direction="vertical" size="middle"> - <a-button type="primary" icon="plus" @click="addFakedns()">{{ i18n "pages.xray.fakedns.add" }}</a-button> - <a-table :columns="fakednsColumns" bordered :row-key="r => r.key" - :data-source="fakeDns" :scroll="isMobile ? {} : { x: 200 }" :pagination="false" :indent-size="0"> - <template slot="action" slot-scope="text,fakedns,index"> - [[ index+1 ]] - <a-dropdown :trigger="['click']"> - <a-icon @click="e => e.preventDefault()" type="more" - style="font-size: 16px; text-decoration: bold;"></a-icon> - <a-menu slot="overlay" :theme="themeSwitcher.currentTheme"> - <a-menu-item @click="editFakedns(index)"> - <a-icon type="edit"></a-icon> - {{ i18n "edit" }} - </a-menu-item> - <a-menu-item @click="deleteFakedns(index)"> - <span style="color: #FF4D4F"> - <a-icon type="delete"></a-icon> {{ i18n "delete"}} - </span> - </a-menu-item> - </a-menu> - </a-dropdown> - </template> - </a-table> - </a-space> - </template> - <template v-else> - <a-empty description='{{ i18n "emptyFakeDnsDesc" }}' style="margin: 20px;"> - <a-button type="primary" icon="plus" @click="addFakedns()" style="margin-top: 10px;">{{ i18n "pages.xray.fakedns.add" }}</a-button> - </a-empty> - </template> - </a-collapse-panel> - </template> - </a-collapse> - </a-tab-pane> <a-tab-pane key="tpl-advanced" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;" force-render="true"> - <a-space direction="vertical" size="small"> - <a-list-item-meta title='{{ i18n "pages.xray.Template"}}' description='{{ i18n "pages.xray.TemplateDesc"}}'></a-list-item-meta> - <a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" style="margin: 10px 0;" :size="isMobile ? 'small' : ''"> - <a-radio-button value="xraySetting">{{ i18n "pages.xray.completeTemplate"}}</a-radio-button> - <a-radio-button value="inboundSettings">{{ i18n "pages.xray.Inbounds" }}</a-radio-button> - <a-radio-button value="outboundSettings">{{ i18n "pages.xray.Outbounds" }}</a-radio-button> - <a-radio-button value="routingRuleSettings">{{ i18n "pages.xray.Routings" }}</a-radio-button> - </a-radio-group> - <textarea style="position:absolute; left: -800px;" id="xraySetting"></textarea> - </a-space> + {{ template "settings/xray/advanced" . }} </a-tab-pane> </a-tabs> </a-space> @@ -788,16 +116,17 @@ </a-layout> </a-layout> {{template "js" .}} +{{template "component/aSidebar" .}} {{template "component/aThemeSwitch" .}} {{template "component/aTableSortable" .}} {{template "component/aSettingListItem" .}} -{{template "ruleModal"}} -{{template "outModal"}} -{{template "reverseModal"}} -{{template "balancerModal"}} -{{template "dnsModal"}} -{{template "fakednsModal"}} -{{template "warpModal"}} +{{template "modals/ruleModal"}} +{{template "modals/outModal"}} +{{template "modals/reverseModal"}} +{{template "modals/balancerModal"}} +{{template "modals/dnsModal"}} +{{template "modals/fakednsModal"}} +{{template "modals/warpModal"}} <script> const rulesColumns = [ { title: "#", align: 'center', width: 15, scopedSlots: { customRender: 'action' } }, @@ -865,7 +194,6 @@ delimiters: ['[[', ']]'], el: '#app', data: { - siderDrawer, themeSwitcher, isDarkTheme: themeSwitcher.isDarkTheme, spinning: false, @@ -877,7 +205,7 @@ refreshing: false, restartResult: '', showAlert: false, - isMobile: window.innerWidth <= 768, + isMobile: DeviceUtils.isMobile(), advSettings: 'xraySetting', obsSettings: '', cm: null,