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:
authorShishkevich D. <135337715+shishkevichd@users.noreply.github.com>2025-03-08 18:41:27 +0300
committerGitHub <noreply@github.com>2025-03-08 18:41:27 +0300
commit697cd5e6d9d8cdacb1cf36fb485667e2409eba62 (patch)
treef0fb34bc3daeb022e0bd0040128fb6e61fa153cd /web/html/xui
parentc6d27a446355e7278fedd98334a314994bb70153 (diff)
Code refactoring (#2739)
* refactor: switching to the use of typed props * refactor: `password-input` -> `a-password-input` * fix: qr modal copy error
Diffstat (limited to 'web/html/xui')
-rw-r--r--web/html/xui/client_bulk_modal.html4
-rw-r--r--web/html/xui/common_sider.html4
-rw-r--r--web/html/xui/component/password.html52
-rw-r--r--web/html/xui/component/persianDatepicker.html28
-rw-r--r--web/html/xui/component/setting.html21
-rw-r--r--web/html/xui/component/sortableTable.html38
-rw-r--r--web/html/xui/component/themeSwitch.html25
-rw-r--r--web/html/xui/form/client.html4
-rw-r--r--web/html/xui/form/inbound.html4
-rw-r--r--web/html/xui/settings.html4
-rw-r--r--web/html/xui/xray.html2
11 files changed, 128 insertions, 58 deletions
diff --git a/web/html/xui/client_bulk_modal.html b/web/html/xui/client_bulk_modal.html
index 74e49225..82e68c74 100644
--- a/web/html/xui/client_bulk_modal.html
+++ b/web/html/xui/client_bulk_modal.html
@@ -106,9 +106,9 @@
<a-date-picker v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }"
format="YYYY-MM-DD HH:mm:ss" :dropdown-class-name="themeSwitcher.currentTheme"
v-model="clientsBulkModal.expiryTime"></a-date-picker>
- <persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
+ <a-persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
value="clientsBulkModal.expiryTime" v-model="clientsBulkModal.expiryTime">
- </persian-datepicker>
+ </a-persian-datepicker>
</a-form-item>
<a-form-item v-if="clientsBulkModal.expiryTime != 0">
<template slot="label">
diff --git a/web/html/xui/common_sider.html b/web/html/xui/common_sider.html
index df659489..1d5fe075 100644
--- a/web/html/xui/common_sider.html
+++ b/web/html/xui/common_sider.html
@@ -34,7 +34,7 @@
{{define "commonSider"}}
<a-layout-sider :theme="themeSwitcher.currentTheme" id="sider" collapsible breakpoint="md">
- <theme-switch></theme-switch>
+ <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>
@@ -43,7 +43,7 @@
<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-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>
diff --git a/web/html/xui/component/password.html b/web/html/xui/component/password.html
index 37e4c793..0fea1430 100644
--- a/web/html/xui/component/password.html
+++ b/web/html/xui/component/password.html
@@ -1,26 +1,46 @@
{{define "component/passwordInput"}}
<template>
- <a-input :value="value" :type="showPassword ? 'text' : 'password'"
- :placeholder="placeholder"
- :autocomplete="autocomplete"
- :name="name"
- @input="$emit('input', $event.target.value)">
- <template v-if="icon" #prefix>
- <a-icon :type="icon" style="font-size: 16px;" />
- </template>
- <template #addonAfter>
- <a-icon :type="showPassword ? 'eye-invisible' : 'eye'"
- @click="toggleShowPassword"
- style="font-size: 16px;" />
- </template>
- </a-input>
+ <a-input :value="value" :type="showPassword ? 'text' : 'password'" :placeholder="placeholder"
+ :autocomplete="autocomplete" :name="name" @input="$emit('input', $event.target.value)">
+ <template v-if="icon" #prefix>
+ <a-icon :type="icon" style="font-size: 16px;" />
+ </template>
+ <template #addonAfter>
+ <a-icon :type="showPassword ? 'eye-invisible' : 'eye'" @click="toggleShowPassword" style="font-size: 16px;" />
+ </template>
+ </a-input>
</template>
{{end}}
{{define "component/password"}}
<script>
- Vue.component('password-input', {
- props: ["title", "value", "placeholder", "icon", "autocomplete", "name"],
+ Vue.component('a-password-input', {
+ props: {
+ 'title': {
+ type: String,
+ required: false,
+ },
+ 'value': {
+ type: String,
+ required: false,
+ },
+ 'placeholder': {
+ type: String,
+ required: false,
+ },
+ 'autocomplete': {
+ type: String,
+ required: false,
+ },
+ 'name': {
+ type: String,
+ required: false,
+ },
+ 'icon': {
+ type: undefined,
+ required: false
+ }
+ },
template: `{{template "component/passwordInput"}}`,
data() {
return {
diff --git a/web/html/xui/component/persianDatepicker.html b/web/html/xui/component/persianDatepicker.html
index df47c4f3..2df79a06 100644
--- a/web/html/xui/component/persianDatepicker.html
+++ b/web/html/xui/component/persianDatepicker.html
@@ -2,10 +2,10 @@
<template>
<div>
<a-input :value="value" type="text" v-model="date" data-jdp class="persian-datepicker"
- @input="$emit('input', convertToGregorian($event.target.value)); jalaliDatepicker.hide();"
- :placeholder="placeholder">
+ @input="$emit('input', convertToGregorian($event.target.value)); jalaliDatepicker.hide();"
+ :placeholder="placeholder">
<template #addonAfter>
- <a-icon type="calendar" style="font-size: 14px; opacity: 0.5;"/>
+ <a-icon type="calendar" style="font-size: 14px; opacity: 0.5;" />
</template>
</a-input>
</div>
@@ -13,15 +13,27 @@
{{end}}
{{define "component/persianDatepicker"}}
-<link rel="stylesheet" href="{{ .base_path }}assets/persian-datepicker/persian-datepicker.min.css?{{ .cur_ver }}"/>
+<link rel="stylesheet" href="{{ .base_path }}assets/persian-datepicker/persian-datepicker.min.css?{{ .cur_ver }}" />
<script src="{{ .base_path }}assets/moment/moment-jalali.min.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/persian-datepicker/persian-datepicker.min.js?{{ .cur_ver }}"></script>
<script>
-
const persianDatepicker = {};
- Vue.component('persian-datepicker', {
- props: ['placeholder', 'format', 'value'],
+ Vue.component('a-persian-datepicker', {
+ props: {
+ 'format': {
+ type: undefined,
+ required: false,
+ },
+ 'value': {
+ type: String,
+ required: false,
+ },
+ 'placeholder': {
+ type: String,
+ required: false,
+ },
+ },
template: `{{template "component/persianDatepickerTemplate"}}`,
data() {
return {
@@ -57,4 +69,4 @@
}
});
</script>
-{{end}}
+{{end}} \ No newline at end of file
diff --git a/web/html/xui/component/setting.html b/web/html/xui/component/setting.html
index bc2c6e42..85220d25 100644
--- a/web/html/xui/component/setting.html
+++ b/web/html/xui/component/setting.html
@@ -21,7 +21,24 @@
{{define "component/setting"}}
<script>
Vue.component('a-setting-list-item', {
- props: ["title", "description", "paddings"],
+ props: {
+ 'title': {
+ type: String,
+ required: true,
+ },
+ 'description': {
+ type: String,
+ required: false,
+ },
+ 'paddings': {
+ type: String,
+ required: false,
+ defaultValue: "default",
+ validator: function (value) {
+ return ['small', 'default'].includes(value)
+ }
+ }
+ },
template: `{{ template "component/settingListItem" }}`,
computed: {
padding() {
@@ -29,7 +46,7 @@
case "small":
return "10px 20px !important"
break;
- default:
+ case "default":
return "20px !important"
break;
}
diff --git a/web/html/xui/component/sortableTable.html b/web/html/xui/component/sortableTable.html
index f62eba44..67bbcee2 100644
--- a/web/html/xui/component/sortableTable.html
+++ b/web/html/xui/component/sortableTable.html
@@ -1,9 +1,5 @@
{{define "component/sortableTableTrigger"}}
-<a-icon type="drag"
- class="sortable-icon"
- style="cursor: move;"
- @mouseup="mouseUpHandler"
- @mousedown="mouseDownHandler"
+<a-icon type="drag" class="sortable-icon" style="cursor: move;" @mouseup="mouseUpHandler" @mousedown="mouseDownHandler"
@click="clickHandler" />
{{end}}
@@ -28,7 +24,16 @@
newElementIndex: null,
};
},
- props: ['data-source', 'customRow'],
+ props: {
+ 'data-source': {
+ type: undefined,
+ required: false,
+ },
+ 'customRow': {
+ type: undefined,
+ required: false,
+ }
+ },
inheritAttrs: false,
provide() {
const sortable = {}
@@ -44,7 +49,7 @@
sortable,
}
},
- render: function(createElement) {
+ render: function (createElement) {
return createElement('a-table', {
class: {
'ant-table-is-sorting': this.isDragging(),
@@ -59,7 +64,7 @@
drop: (e) => this.dropHandler(e),
},
scopedSlots: this.$scopedSlots,
- }, this.$slots.default, )
+ }, this.$slots.default,)
},
created() {
this.$memoSort = {};
@@ -163,9 +168,14 @@
}
}
});
- Vue.component('table-sort-trigger', {
+ Vue.component('a-table-sort-trigger', {
template: `{{template "component/sortableTableTrigger"}}`,
- props: ['item-index'],
+ props: {
+ 'item-index': {
+ type: undefined,
+ required: false
+ }
+ },
inject: ['sortable'],
methods: {
mouseDownHandler(e) {
@@ -190,27 +200,33 @@
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}}
+{{end}} \ No newline at end of file
diff --git a/web/html/xui/component/themeSwitch.html b/web/html/xui/component/themeSwitch.html
index 0de64a84..28cb79b1 100644
--- a/web/html/xui/component/themeSwitch.html
+++ b/web/html/xui/component/themeSwitch.html
@@ -6,9 +6,13 @@
<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 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 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>
@@ -17,12 +21,15 @@
{{define "component/themeSwitchTemplateLogin"}}
<template>
- <a-menu @mousedown="themeSwitcher.animationsOff()" id="change-theme" :theme="themeSwitcher.currentTheme" mode="inline" selected-keys="">
+ <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>
+ <a-switch size="small" :default-checked="themeSwitcher.isDarkTheme"
+ @change="themeSwitcher.toggleTheme()"></a-switch>
<template v-if="themeSwitcher.isDarkTheme">
- <a-checkbox style="margin-left: 1rem; vertical-align: middle;" :checked="themeSwitcher.isUltra" @click="themeSwitcher.toggleUltra()">Ultra</a-checkbox>
+ <a-checkbox style="margin-left: 1rem; vertical-align: middle;" :checked="themeSwitcher.isUltra"
+ @click="themeSwitcher.toggleUltra()">Ultra</a-checkbox>
</template>
</a-menu-item>
</a-menu>
@@ -83,8 +90,7 @@
};
}
const themeSwitcher = createThemeSwitcher();
- Vue.component('theme-switch', {
- props: [],
+ Vue.component('a-theme-switch', {
template: `{{template "component/themeSwitchTemplate"}}`,
data: () => ({
themeSwitcher
@@ -96,8 +102,7 @@
document.getElementById('message').className = themeSwitcher.currentTheme;
}
});
- Vue.component('theme-switch-login', {
- props: [],
+ Vue.component('a-theme-switch-login', {
template: `{{template "component/themeSwitchTemplateLogin"}}`,
data: () => ({
themeSwitcher
@@ -110,4 +115,4 @@
}
});
</script>
-{{end}}
+{{end}} \ No newline at end of file
diff --git a/web/html/xui/form/client.html b/web/html/xui/form/client.html
index c2bcace1..3aff67e0 100644
--- a/web/html/xui/form/client.html
+++ b/web/html/xui/form/client.html
@@ -154,8 +154,8 @@
</template>
<a-date-picker v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
:dropdown-class-name="themeSwitcher.currentTheme" v-model="client._expiryTime"></a-date-picker>
- <persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
- value="client._expiryTime" v-model="client._expiryTime"></persian-datepicker>
+ <a-persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
+ value="client._expiryTime" v-model="client._expiryTime"></a-persian-datepicker>
<a-tag color="red" v-if="isEdit && isExpiry">Expired</a-tag>
</a-form-item>
<a-form-item v-if="client.expiryTime != 0">
diff --git a/web/html/xui/form/inbound.html b/web/html/xui/form/inbound.html
index 091393ff..e0521c69 100644
--- a/web/html/xui/form/inbound.html
+++ b/web/html/xui/form/inbound.html
@@ -57,9 +57,9 @@
<a-date-picker style="width: 100%;" v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }"
format="YYYY-MM-DD HH:mm:ss" :dropdown-class-name="themeSwitcher.currentTheme"
v-model="dbInbound._expiryTime"></a-date-picker>
- <persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
+ <a-persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'
value="dbInbound._expiryTime" v-model="dbInbound._expiryTime">
- </persian-datepicker>
+ </a-persian-datepicker>
</a-form-item>
</a-form>
diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html
index e8fa7e11..3bfb32a9 100644
--- a/web/html/xui/settings.html
+++ b/web/html/xui/settings.html
@@ -271,7 +271,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.currentPassword"}}</template>
<template #control>
- <password-input autocomplete="current-password" v-model="user.oldPassword"></password-input>
+ <a-password-input autocomplete="current-password" v-model="user.oldPassword"></a-password-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
@@ -283,7 +283,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.newPassword"}}</template>
<template #control>
- <password-input autocomplete="new-password" v-model="user.newPassword"></password-input>
+ <a-password-input autocomplete="new-password" v-model="user.newPassword"></a-password-input>
</template>
</a-setting-list-item>
<a-list-item>
diff --git a/web/html/xui/xray.html b/web/html/xui/xray.html
index d101bdcd..41bbd214 100644
--- a/web/html/xui/xray.html
+++ b/web/html/xui/xray.html
@@ -348,7 +348,7 @@
:indent-size="0"
v-on:onSort="replaceRule">
<template slot="action" slot-scope="text, rule, index">
- <table-sort-trigger :item-index="index"></table-sort-trigger>
+ <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>