Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTara Rostami <132676256+TaraRostami@users.noreply.github.com>2024-04-20 21:45:36 +0300
committerGitHub <noreply@github.com>2024-04-20 21:45:36 +0300
commitdb24d216210e0038f92e634de1ab8a46fbce4632 (patch)
tree3648326a1e359543febd865747822bc6f8f72781 /web/html/xui
parent3d5c06bf08f0ede7206e0ef39966d6be2106a225 (diff)
UI Improvements (#2228)
* UI Improvements Better Table Update QR Code Modal Better Info Modal Compression HTML files Better Dropdown Menu Better Calendar and more .. Remove files Minor Fixes
Diffstat (limited to 'web/html/xui')
-rw-r--r--web/html/xui/common_sider.html86
-rw-r--r--web/html/xui/component/sortableTable.html418
-rw-r--r--web/html/xui/component/themeSwitch.html57
-rw-r--r--web/html/xui/dns_modal.html163
-rw-r--r--web/html/xui/form/outbound.html660
-rw-r--r--web/html/xui/form/protocol/http.html36
-rw-r--r--web/html/xui/form/protocol/socks.html59
-rw-r--r--web/html/xui/form/protocol/trojan.html88
-rw-r--r--web/html/xui/form/protocol/vless.html92
-rw-r--r--web/html/xui/form/protocol/wireguard.html136
-rw-r--r--web/html/xui/form/stream/external_proxy.html47
-rw-r--r--web/html/xui/form/stream/stream_http.html28
-rw-r--r--web/html/xui/form/stream/stream_httpupgrade.html44
-rw-r--r--web/html/xui/form/stream/stream_tcp.html138
-rw-r--r--web/html/xui/form/stream/stream_ws.html44
-rw-r--r--web/html/xui/form/tls_settings.html337
-rw-r--r--web/html/xui/inbound_client_table.html471
-rw-r--r--web/html/xui/inbound_info_modal.html892
-rw-r--r--web/html/xui/inbounds.html95
-rw-r--r--web/html/xui/index.html25
-rw-r--r--web/html/xui/xray.html78
-rw-r--r--web/html/xui/xray_rule_modal.html493
22 files changed, 2292 insertions, 2195 deletions
diff --git a/web/html/xui/common_sider.html b/web/html/xui/common_sider.html
index bc8f4608..df659489 100644
--- a/web/html/xui/common_sider.html
+++ b/web/html/xui/common_sider.html
@@ -1,61 +1,65 @@
{{define "menuItems"}}
<a-menu-item key="{{ .base_path }}panel/">
- <a-icon type="dashboard"></a-icon>
- <span><b>{{ i18n "menu.dashboard"}}</b></span>
+ <a-icon type="dashboard"></a-icon>
+ <span>
+ <b>{{ i18n "menu.dashboard"}}</b>
+ </span>
</a-menu-item>
<a-menu-item key="{{ .base_path }}panel/inbounds">
- <a-icon type="user"></a-icon>
- <span><b>{{ i18n "menu.inbounds"}}</b></span>
+ <a-icon type="user"></a-icon>
+ <span>
+ <b>{{ i18n "menu.inbounds"}}</b>
+ </span>
</a-menu-item>
<a-menu-item key="{{ .base_path }}panel/settings">
- <a-icon type="setting"></a-icon>
- <span><b>{{ i18n "menu.settings"}}</b></span>
+ <a-icon type="setting"></a-icon>
+ <span>
+ <b>{{ i18n "menu.settings"}}</b>
+ </span>
</a-menu-item>
<a-menu-item key="{{ .base_path }}panel/xray">
- <a-icon type="tool"></a-icon>
- <span><b>{{ i18n "menu.xray"}}</b></span>
+ <a-icon type="tool"></a-icon>
+ <span>
+ <b>{{ i18n "menu.xray"}}</b>
+ </span>
</a-menu-item>
<a-menu-item key="{{ .base_path }}logout">
- <a-icon type="logout"></a-icon>
- <span><b>{{ i18n "menu.logout"}}</b></span>
+ <a-icon type="logout"></a-icon>
+ <span>
+ <b>{{ i18n "menu.logout"}}</b>
+ </span>
</a-menu-item>
{{end}}
{{define "commonSider"}}
-<a-layout-sider :theme="themeSwitcher.currentTheme" id="sider" collapsible breakpoint="md" collapsed-width="0">
- <theme-switch></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 :theme="themeSwitcher.currentTheme" id="sider" collapsible breakpoint="md">
+ <theme-switch></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>
- <theme-switch></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 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>
+ <theme-switch></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;
- },
- };
+ 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/component/sortableTable.html b/web/html/xui/component/sortableTable.html
index 5eb2e1cc..f62eba44 100644
--- a/web/html/xui/component/sortableTable.html
+++ b/web/html/xui/component/sortableTable.html
@@ -1,236 +1,216 @@
{{define "component/sortableTableTrigger"}}
- <a-icon type="drag"
- class="sortable-icon"
- style="cursor: move;"
- @mouseup="mouseUpHandler"
- @mousedown="mouseDownHandler"
- @click="clickHandler" />
+<a-icon type="drag"
+ class="sortable-icon"
+ style="cursor: move;"
+ @mouseup="mouseUpHandler"
+ @mousedown="mouseDownHandler"
+ @click="clickHandler" />
{{end}}
{{define "component/sortableTable"}}
<script>
- const DRAGGABLE_ROW_CLASS = 'draggable-row';
-
- const findParentRowElement = (el) => {
- if (!el || !el.tagName) {
- return null;
- } else if (el.classList.contains(DRAGGABLE_ROW_CLASS)) {
- return el;
- } else if (el.parentNode) {
- return findParentRowElement(el.parentNode);
- } else {
- return null;
- }
+ const DRAGGABLE_ROW_CLASS = 'draggable-row';
+ const findParentRowElement = (el) => {
+ if (!el || !el.tagName) {
+ return null;
+ } else if (el.classList.contains(DRAGGABLE_ROW_CLASS)) {
+ return el;
+ } else if (el.parentNode) {
+ return findParentRowElement(el.parentNode);
+ } else {
+ return null;
}
-
- Vue.component('a-table-sortable', {
- data() {
- return {
- sortingElementIndex: null,
- newElementIndex: null,
- };
- },
- props: ['data-source', 'customRow'],
- inheritAttrs: false,
- provide() {
- const sortable = {}
-
- Object.defineProperty(sortable, "setSortableIndex", {
- enumerable: true,
- get: () => this.setCurrentSortableIndex,
- });
-
- Object.defineProperty(sortable, "resetSortableIndex", {
- enumerable: true,
- get: () => this.resetSortableIndex,
- });
-
- return {
- sortable,
- }
+ }
+ Vue.component('a-table-sortable', {
+ data() {
+ return {
+ sortingElementIndex: null,
+ newElementIndex: null,
+ };
+ },
+ props: ['data-source', 'customRow'],
+ inheritAttrs: false,
+ provide() {
+ const sortable = {}
+ Object.defineProperty(sortable, "setSortableIndex", {
+ enumerable: true,
+ get: () => this.setCurrentSortableIndex,
+ });
+ Object.defineProperty(sortable, "resetSortableIndex", {
+ enumerable: true,
+ get: () => this.resetSortableIndex,
+ });
+ return {
+ sortable,
+ }
+ },
+ render: function(createElement) {
+ return createElement('a-table', {
+ class: {
+ 'ant-table-is-sorting': this.isDragging(),
},
- render: function (createElement) {
- return createElement('a-table', {
- class: {
- 'ant-table-is-sorting': this.isDragging(),
- },
- props: {
- ...this.$attrs,
- 'data-source': this.records,
- customRow: (record, index) => this.customRowRender(record, index),
- },
- on: this.$listeners,
- nativeOn: {
- drop: (e) => this.dropHandler(e),
- },
- scopedSlots: this.$scopedSlots,
- }, this.$slots.default, )
+ props: {
+ ...this.$attrs,
+ 'data-source': this.records,
+ customRow: (record, index) => this.customRowRender(record, index),
},
- created() {
- this.$memoSort = {};
+ on: this.$listeners,
+ nativeOn: {
+ drop: (e) => this.dropHandler(e),
},
- methods: {
- isDragging() {
- const currentIndex = this.sortingElementIndex;
- return currentIndex !== null && currentIndex !== undefined;
- },
- resetSortableIndex(e, index) {
- this.sortingElementIndex = null;
- this.newElementIndex = null;
- this.$memoSort = {};
- },
- setCurrentSortableIndex(e, index) {
- this.sortingElementIndex = index;
- },
- dragStartHandler(e, index) {
- if (!this.isDragging()) {
- e.preventDefault();
- return;
- }
- const hideDragImage = this.$el.cloneNode(true);
- hideDragImage.id = "hideDragImage-hide";
- hideDragImage.style.opacity = 0;
- e.dataTransfer.setDragImage(hideDragImage, 0, 0);
- },
- dragStopHandler(e, index) {
- const hideDragImage = document.getElementById('hideDragImage-hide');
- if (hideDragImage) hideDragImage.remove();
- this.resetSortableIndex(e, index);
- },
- dragOverHandler(e, index) {
- if (!this.isDragging()) {
- return;
- }
-
- e.preventDefault();
-
- const currentIndex = this.sortingElementIndex;
- if (index === currentIndex) {
- this.newElementIndex = null;
- return;
- }
-
- const row = findParentRowElement(e.target);
- if (!row) {
- return;
- }
-
- const rect = row.getBoundingClientRect();
- const offsetTop = e.pageY - rect.top;
-
- if (offsetTop < rect.height / 2) {
- this.newElementIndex = Math.max(index - 1, 0);
- } else {
- this.newElementIndex = index;
- }
- },
- dropHandler(e) {
- if (this.isDragging()) {
- this.$emit('onsort', this.sortingElementIndex, this.newElementIndex);
- }
- },
- customRowRender(record, index) {
- const parentMethodResult = this.customRow?.(record, index) || {};
- const newIndex = this.newElementIndex;
- const currentIndex = this.sortingElementIndex;
-
- return {
- ...parentMethodResult,
- attrs: {
- ...(parentMethodResult?.attrs || {}),
- draggable: true,
- },
- on: {
- ...(parentMethodResult?.on || {}),
- dragstart: (e) => this.dragStartHandler(e, index),
- dragend: (e) => this.dragStopHandler(e, index),
- dragover: (e) => this.dragOverHandler(e, index),
- },
- class: {
- ...(parentMethodResult?.class || {}),
- [DRAGGABLE_ROW_CLASS]: true,
- ['dragging']: this.isDragging()
- ? (newIndex === null ? index === currentIndex : index === newIndex)
- : false,
- },
- };
- }
- },
- computed: {
- records() {
- const newIndex = this.newElementIndex;
- const currentIndex = this.sortingElementIndex;
-
- if (!this.isDragging() || newIndex === null || currentIndex === newIndex) {
- return this.dataSource;
- }
-
- if (this.$memoSort.newIndex === newIndex) {
- return this.$memoSort.list;
- }
-
- let list = [...this.dataSource];
- list.splice(newIndex, 0, list.splice(currentIndex, 1)[0]);
-
- this.$memoSort = {
- newIndex,
- list,
- };
-
- return list;
- }
+ scopedSlots: this.$scopedSlots,
+ }, this.$slots.default, )
+ },
+ created() {
+ this.$memoSort = {};
+ },
+ methods: {
+ isDragging() {
+ const currentIndex = this.sortingElementIndex;
+ return currentIndex !== null && currentIndex !== undefined;
+ },
+ resetSortableIndex(e, index) {
+ this.sortingElementIndex = null;
+ this.newElementIndex = null;
+ this.$memoSort = {};
+ },
+ setCurrentSortableIndex(e, index) {
+ this.sortingElementIndex = index;
+ },
+ dragStartHandler(e, index) {
+ if (!this.isDragging()) {
+ e.preventDefault();
+ return;
}
- });
-
- Vue.component('table-sort-trigger', {
- template: `{{template "component/sortableTableTrigger"}}`,
- props: ['item-index'],
- inject: ['sortable'],
- methods: {
- mouseDownHandler(e) {
- if (this.sortable) {
- this.sortable.setSortableIndex(e, this.itemIndex);
- }
- },
- mouseUpHandler(e) {
- if (this.sortable) {
- this.sortable.resetSortableIndex(e, this.itemIndex);
- }
- },
- clickHandler(e) {
- e.preventDefault();
- },
+ const hideDragImage = this.$el.cloneNode(true);
+ hideDragImage.id = "hideDragImage-hide";
+ hideDragImage.style.opacity = 0;
+ e.dataTransfer.setDragImage(hideDragImage, 0, 0);
+ },
+ dragStopHandler(e, index) {
+ const hideDragImage = document.getElementById('hideDragImage-hide');
+ if (hideDragImage) hideDragImage.remove();
+ this.resetSortableIndex(e, index);
+ },
+ dragOverHandler(e, index) {
+ if (!this.isDragging()) {
+ return;
}
- })
-</script>
-
-<style>
- @media only screen and (max-width: 767px) {
- .sortable-icon {
- display: none;
+ e.preventDefault();
+ const currentIndex = this.sortingElementIndex;
+ if (index === currentIndex) {
+ this.newElementIndex = null;
+ return;
}
+ const row = findParentRowElement(e.target);
+ if (!row) {
+ return;
+ }
+ const rect = row.getBoundingClientRect();
+ const offsetTop = e.pageY - rect.top;
+ if (offsetTop < rect.height / 2) {
+ this.newElementIndex = Math.max(index - 1, 0);
+ } else {
+ this.newElementIndex = index;
+ }
+ },
+ dropHandler(e) {
+ if (this.isDragging()) {
+ this.$emit('onsort', this.sortingElementIndex, this.newElementIndex);
+ }
+ },
+ customRowRender(record, index) {
+ const parentMethodResult = this.customRow?.(record, index) || {};
+ const newIndex = this.newElementIndex;
+ const currentIndex = this.sortingElementIndex;
+ return {
+ ...parentMethodResult,
+ attrs: {
+ ...(parentMethodResult?.attrs || {}),
+ draggable: true,
+ },
+ on: {
+ ...(parentMethodResult?.on || {}),
+ dragstart: (e) => this.dragStartHandler(e, index),
+ dragend: (e) => this.dragStopHandler(e, index),
+ dragover: (e) => this.dragOverHandler(e, index),
+ },
+ class: {
+ ...(parentMethodResult?.class || {}),
+ [DRAGGABLE_ROW_CLASS]: true,
+ ['dragging']: this.isDragging() ? (newIndex === null ? index === currentIndex : index === newIndex) : false,
+ },
+ };
+ }
+ },
+ computed: {
+ records() {
+ const newIndex = this.newElementIndex;
+ const currentIndex = this.sortingElementIndex;
+ if (!this.isDragging() || newIndex === null || currentIndex === newIndex) {
+ return this.dataSource;
+ }
+ if (this.$memoSort.newIndex === newIndex) {
+ return this.$memoSort.list;
+ }
+ let list = [...this.dataSource];
+ list.splice(newIndex, 0, list.splice(currentIndex, 1)[0]);
+ this.$memoSort = {
+ newIndex,
+ list,
+ };
+ return list;
+ }
}
- .ant-table-is-sorting .draggable-row td {
- background-color: #ffffff !important;
- }
- .dark .ant-table-is-sorting .draggable-row td {
- background-color: var(--dark-color-surface-100) !important;
- }
- .ant-table-is-sorting .dragging td {
- background-color: rgb(232 244 242) !important;
- color: rgba(0, 0, 0, 0.3);
- }
- .dark .ant-table-is-sorting .dragging td {
- background-color: var(--dark-color-table-hover) !important;
- color: rgba(255, 255, 255, 0.3);
- }
- .ant-table-is-sorting .dragging {
- opacity: 1;
- box-shadow: 1px -2px 2px #008771;
- transition: all 0.2s;
+ });
+ Vue.component('table-sort-trigger', {
+ template: `{{template "component/sortableTableTrigger"}}`,
+ props: ['item-index'],
+ inject: ['sortable'],
+ methods: {
+ mouseDownHandler(e) {
+ if (this.sortable) {
+ this.sortable.setSortableIndex(e, this.itemIndex);
+ }
+ },
+ mouseUpHandler(e) {
+ if (this.sortable) {
+ this.sortable.resetSortableIndex(e, this.itemIndex);
+ }
+ },
+ clickHandler(e) {
+ e.preventDefault();
+ },
}
- .ant-table-is-sorting .dragging .ant-table-row-index {
- opacity: 0.3;
+ })
+</script>
+<style>
+ @media only screen and (max-width: 767px) {
+ .sortable-icon {
+ display: none;
}
+ }
+ .ant-table-is-sorting .draggable-row td {
+ background-color: #ffffff !important;
+ }
+ .dark .ant-table-is-sorting .draggable-row td {
+ background-color: var(--dark-color-surface-100) !important;
+ }
+ .ant-table-is-sorting .dragging td {
+ background-color: rgb(232 244 242) !important;
+ color: rgba(0, 0, 0, 0.3);
+ }
+ .dark .ant-table-is-sorting .dragging td {
+ background-color: var(--dark-color-table-hover) !important;
+ color: rgba(255, 255, 255, 0.3);
+ }
+ .ant-table-is-sorting .dragging {
+ opacity: 1;
+ box-shadow: 1px -2px 2px #008771;
+ transition: all 0.2s;
+ }
+ .ant-table-is-sorting .dragging .ant-table-row-index {
+ opacity: 0.3;
+ }
</style>
{{end}}
diff --git a/web/html/xui/component/themeSwitch.html b/web/html/xui/component/themeSwitch.html
index 28fe3e11..0de64a84 100644
--- a/web/html/xui/component/themeSwitch.html
+++ b/web/html/xui/component/themeSwitch.html
@@ -1,6 +1,23 @@
{{define "component/themeSwitchTemplate"}}
<template>
- <a-menu class="change-theme" :theme="themeSwitcher.currentTheme" mode="inline" selected-keys="">
+ <a-menu :theme="themeSwitcher.currentTheme" mode="inline" selected-keys="">
+ <a-sub-menu>
+ <span slot="title">
+ <a-icon type="bulb" :theme="themeSwitcher.isDarkTheme ? 'filled' : 'outlined'"></a-icon>
+ <span>Theme</span>
+ </span>
+ <a-menu-item id="change-theme" class="ant-menu-theme-switch" @mousedown="themeSwitcher.animationsOff()"> Dark <a-switch style="margin-left: 2px;" size="small" :default-checked="themeSwitcher.isDarkTheme" @change="themeSwitcher.toggleTheme()"></a-switch>
+ </a-menu-item>
+ <a-menu-item id="change-theme-ultra" v-if="themeSwitcher.isDarkTheme" class="ant-menu-theme-switch" @mousedown="themeSwitcher.animationsOffUltra()"> Ultra <a-checkbox style="margin-left: 2px;" :checked="themeSwitcher.isUltra" @click="themeSwitcher.toggleUltra()"></a-checkbox>
+ </a-menu-item>
+ </a-sub-menu>
+ </a-menu>
+</template>
+{{end}}
+
+{{define "component/themeSwitchTemplateLogin"}}
+<template>
+ <a-menu @mousedown="themeSwitcher.animationsOff()" id="change-theme" :theme="themeSwitcher.currentTheme" mode="inline" selected-keys="">
<a-menu-item mode="inline" class="ant-menu-theme-switch">
<a-icon type="bulb" :theme="themeSwitcher.isDarkTheme ? 'filled' : 'outlined'"></a-icon>
<a-switch size="small" :default-checked="themeSwitcher.isDarkTheme" @change="themeSwitcher.toggleTheme()"></a-switch>
@@ -23,6 +40,26 @@
const theme = isDarkTheme ? 'dark' : 'light';
document.querySelector('body').setAttribute('class', theme);
return {
+ animationsOff() {
+ document.documentElement.setAttribute('data-theme-animations', 'off');
+ const themeAnimations = document.querySelector('#change-theme');
+ themeAnimations.addEventListener('mouseleave', () => {
+ document.documentElement.removeAttribute('data-theme-animations');
+ });
+ themeAnimations.addEventListener('touchend', () => {
+ document.documentElement.removeAttribute('data-theme-animations');
+ });
+ },
+ animationsOffUltra() {
+ document.documentElement.setAttribute('data-theme-animations', 'off');
+ const themeAnimationsUltra = document.querySelector('#change-theme-ultra');
+ themeAnimationsUltra.addEventListener('mouseleave', () => {
+ document.documentElement.removeAttribute('data-theme-animations');
+ });
+ themeAnimationsUltra.addEventListener('touchend', () => {
+ document.documentElement.removeAttribute('data-theme-animations');
+ });
+ },
isDarkTheme,
isUltra,
get currentTheme() {
@@ -57,13 +94,19 @@
getContainer: () => document.getElementById('message')
});
document.getElementById('message').className = themeSwitcher.currentTheme;
- const themeAnimations = document.querySelector('.change-theme');
- themeAnimations.addEventListener('mousedown', () => {
- document.documentElement.setAttribute('data-theme-animations', 'off');
- });
- themeAnimations.addEventListener('mouseleave', () => {
- document.documentElement.removeAttribute('data-theme-animations');
+ }
+ });
+ Vue.component('theme-switch-login', {
+ props: [],
+ template: `{{template "component/themeSwitchTemplateLogin"}}`,
+ data: () => ({
+ themeSwitcher
+ }),
+ mounted() {
+ this.$message.config({
+ getContainer: () => document.getElementById('message')
});
+ document.getElementById('message').className = themeSwitcher.currentTheme;
}
});
</script>
diff --git a/web/html/xui/dns_modal.html b/web/html/xui/dns_modal.html
index 4c85e7f3..0abde2f3 100644
--- a/web/html/xui/dns_modal.html
+++ b/web/html/xui/dns_modal.html
@@ -1,90 +1,89 @@
{{define "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">
- <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
- <a-form-item label='{{ i18n "pages.xray.outbound.address" }}'>
- <a-input v-model.trim="dnsModal.dnsServer.address"></a-input>
- </a-form-item>
- <a-form-item label='{{ i18n "pages.xray.dns.domains" }}'>
- <a-button size="small" type="primary" @click="dnsModal.dnsServer.domains.push('')">+</a-button>
- <template v-for="(domain, index) in dnsModal.dnsServer.domains">
- <a-input v-model.trim="dnsModal.dnsServer.domains[index]">
- <a-button size="small" slot="addonAfter" @click="dnsModal.dnsServer.domains.splice(index,1)">-</a-button>
- </a-input>
- </template>
- </a-form-item>
- <a-form-item label='{{ i18n "pages.xray.dns.strategy" }}' v-if="isAdvanced">
- <a-select
- v-model="dnsModal.dnsServer.queryStrategy"
- 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>
- </a-form-item>
- </a-form>
+<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">
+ <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
+ <a-form-item label='{{ i18n "pages.xray.outbound.address" }}'>
+ <a-input v-model.trim="dnsModal.dnsServer.address"></a-input>
+ </a-form-item>
+ <a-form-item label='{{ i18n "pages.xray.dns.domains" }}'>
+ <a-button icon="plus" size="small" type="primary" @click="dnsModal.dnsServer.domains.push('')"></a-button>
+ <template v-for="(domain, index) in dnsModal.dnsServer.domains">
+ <a-input v-model.trim="dnsModal.dnsServer.domains[index]">
+ <a-button icon="minus" size="small" slot="addonAfter" @click="dnsModal.dnsServer.domains.splice(index,1)"></a-button>
+ </a-input>
+ </template>
+ </a-form-item>
+ <a-form-item label='{{ i18n "pages.xray.dns.strategy" }}' v-if="isAdvanced">
+ <a-select v-model="dnsModal.dnsServer.queryStrategy" 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>
+ </a-form-item>
+ </a-form>
</a-modal>
<script>
- const dnsModal = {
- title: '',
- visible: false,
- okText: '{{ i18n "confirm" }}',
- isEdit: false,
- confirm: null,
- dnsServer: {
+ const dnsModal = {
+ title: '',
+ visible: false,
+ okText: '{{ i18n "confirm" }}',
+ isEdit: false,
+ confirm: null,
+ dnsServer: {
+ address: "localhost",
+ domains: [],
+ queryStrategy: 'UseIP',
+ },
+ ok() {
+ domains = dnsModal.dnsServer.domains.filter(d => d.length > 0);
+ dnsModal.dnsServer.domains = domains;
+ newDnsServer = domains.length > 0 ? dnsModal.dnsServer : dnsModal.dnsServer.address;
+ ObjectUtil.execute(dnsModal.confirm, newDnsServer);
+ },
+ show({
+ title = '',
+ okText = '{{ i18n "confirm" }}',
+ dnsServer,
+ confirm = (dnsServer) => {},
+ isEdit = false
+ }) {
+ this.title = title;
+ this.okText = okText;
+ this.confirm = confirm;
+ this.visible = true;
+ if (isEdit) {
+ if (typeof dnsServer == 'object') {
+ this.dnsServer = dnsServer;
+ } else {
+ this.dnsServer = {
+ address: dnsServer ?? "",
+ domains: [],
+ queryStrategy: 'UseIP',
+ }
+ }
+ } else {
+ this.dnsServer = {
address: "localhost",
domains: [],
queryStrategy: 'UseIP',
- },
- ok() {
- domains = dnsModal.dnsServer.domains.filter(d => d.length>0);
- dnsModal.dnsServer.domains = domains;
- newDnsServer = domains.length > 0 ? dnsModal.dnsServer : dnsModal.dnsServer.address;
- ObjectUtil.execute(dnsModal.confirm, newDnsServer);
- },
- show({ title='', okText='{{ i18n "confirm" }}', dnsServer, confirm=(dnsServer)=>{}, isEdit=false }) {
- this.title = title;
- this.okText = okText;
- this.confirm = confirm;
- this.visible = true;
- if(isEdit) {
- if (typeof dnsServer == 'object'){
- this.dnsServer = dnsServer;
- } else {
- this.dnsServer = {
- address: dnsServer ?? "",
- domains: [],
- queryStrategy: 'UseIP',
- }
- }
- } else {
- this.dnsServer = {
- address: "localhost",
- domains: [],
- queryStrategy: 'UseIP',
- }
- }
- this.isEdit = isEdit;
- },
- close() {
- dnsModal.visible = false;
- },
- };
-
- new Vue({
- delimiters: ['[[', ']]'],
- el: '#dns-modal',
- data: {
- dnsModal: dnsModal,
- },
- computed: {
- isAdvanced: {
- get: function () { return dnsModal.dnsServer.domains.length>0 }
- }
}
- });
-
+ }
+ this.isEdit = isEdit;
+ },
+ close() {
+ dnsModal.visible = false;
+ },
+ };
+ new Vue({
+ delimiters: ['[[', ']]'],
+ el: '#dns-modal',
+ data: {
+ dnsModal: dnsModal,
+ },
+ computed: {
+ isAdvanced: {