Browse Source

Code refactoring (#2785)

* chore: pretty theme menu in sidebar

* refactor: renaming component templates

* refactor: create custom `a-statistic` component

* fix: display button text only on large screens

* chore: remove loading background in overview page

* fix: show `Version` text when xray version is unknown
Shishkevich D. 2 weeks ago
parent
commit
db62a07fb8

+ 2 - 2
web/html/login.html

@@ -473,8 +473,8 @@
     </transition>
   </a-layout>
 {{template "js" .}}
-{{template "component/themeSwitcher" .}}
-{{template "component/password" .}}
+{{template "component/aThemeSwitch" .}}
+{{template "component/aPasswordInput" .}}
 <script>
   class User {
     constructor() {

+ 5 - 15
web/html/xui/common_sider.html

@@ -1,33 +1,23 @@
 {{define "menuItems"}}
 <a-menu-item key="{{ .base_path }}panel/">
   <a-icon type="dashboard"></a-icon>
-  <span>
-    <b>{{ i18n "menu.dashboard"}}</b>
-  </span>
+  <span>{{ i18n "menu.dashboard"}}</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>
+  <span>{{ i18n "menu.inbounds"}}</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>
+  <span>{{ i18n "menu.settings"}}</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>
+  <span>{{ i18n "menu.xray"}}</span>
 </a-menu-item>
 <a-menu-item key="{{ .base_path }}logout">
   <a-icon type="logout"></a-icon>
-  <span>
-    <b>{{ i18n "menu.logout"}}</b>
-  </span>
+  <span>{{ i18n "menu.logout"}}</span>
 </a-menu-item>
 {{end}}
 

+ 55 - 0
web/html/xui/component/aCustomStatistic.html

@@ -0,0 +1,55 @@
+{{define "component/customStatistic"}}
+<template>
+    <a-statistic :title="title" :value="value">
+        <template #prefix>
+            <slot name="prefix"></slot>
+        </template>
+        <template #suffix>
+            <slot name="suffix"></slot>
+        </template>
+    </a-statistic>
+</template>
+{{end}}
+
+{{define "component/aCustomStatistic"}}
+<style>
+    .dark .ant-statistic-title,
+    .dark .ant-statistic-content {
+        color: var(--dark-color-text-primary) !important
+    }
+
+    .dark .ant-statistic-title {
+        user-select: none;
+        opacity: 0.55;
+    }
+    
+    .ant-statistic-title {
+        margin-bottom: 0 !important;
+    }
+
+    .ant-statistic-content-prefix {
+        margin-right: 6px !important;
+    }
+
+    .ant-statistic-content-prefix,
+    .ant-statistic-content-value {
+        font-size: 1.05rem;
+    }
+</style>
+
+<script>
+  Vue.component('a-custom-statistic', {
+    props: {
+      'title': {
+        type: String,
+        required: false,
+      },
+      'value': {
+        type: String,
+        required: false
+      }
+    },
+    template: `{{template "component/customStatistic"}}`,
+  });
+</script>
+{{end}}

+ 1 - 1
web/html/xui/component/password.html → web/html/xui/component/aPasswordInput.html

@@ -12,7 +12,7 @@
 </template>
 {{end}}
 
-{{define "component/password"}}
+{{define "component/aPasswordInput"}}
 <script>
   Vue.component('a-password-input', {
     props: {

+ 1 - 1
web/html/xui/component/persianDatepicker.html → web/html/xui/component/aPersianDatepicker.html

@@ -12,7 +12,7 @@
 </template>
 {{end}}
 
-{{define "component/persianDatepicker"}}
+{{define "component/aPersianDatepicker"}}
 <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>

+ 1 - 9
web/html/xui/component/setting.html → web/html/xui/component/aSettingListItem.html

@@ -18,18 +18,10 @@
 </a-list-item>
 {{end}}
 
-{{define "component/setting"}}
+{{define "component/aSettingListItem"}}
 <script>
     Vue.component('a-setting-list-item', {
         props: {
-            'title': {
-                type: String,
-                required: true,
-            },
-            'description': {
-                type: String,
-                required: false,
-            },
             'paddings': {
                 type: String,
                 required: false,

+ 1 - 1
web/html/xui/component/sortableTable.html → web/html/xui/component/aTableSortable.html

@@ -3,7 +3,7 @@
   @click="clickHandler" />
 {{end}}
 
-{{define "component/sortableTable"}}
+{{define "component/aTableSortable"}}
 <script>
   const DRAGGABLE_ROW_CLASS = 'draggable-row';
   const findParentRowElement = (el) => {

+ 8 - 8
web/html/xui/component/themeSwitch.html → web/html/xui/component/aThemeSwitch.html

@@ -4,15 +4,15 @@
     <a-sub-menu>
       <span slot="title">
         <a-icon type="bulb" :theme="themeSwitcher.isDarkTheme ? 'filled' : 'outlined'"></a-icon>
-        <span>Theme</span>
+        <span>{{ i18n "menu.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()"> 
+        <span>{{ i18n "menu.dark" }}</span>
+        <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()"> 
+        <span>{{ i18n "menu.ultraDark" }}</span>
+        <a-checkbox style="margin-left: 2px;" :checked="themeSwitcher.isUltra" @click="themeSwitcher.toggleUltra()"></a-checkbox>
       </a-menu-item>
     </a-sub-menu>
   </a-menu>
@@ -36,7 +36,7 @@
 </template>
 {{end}}
 
-{{define "component/themeSwitcher"}}
+{{define "component/aThemeSwitch"}}
 <script>
   function createThemeSwitcher() {
     const isDarkTheme = localStorage.getItem('dark-mode') === 'true';

+ 2 - 2
web/html/xui/inbounds.html

@@ -548,8 +548,8 @@
 <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/themeSwitcher" .}}
-{{template "component/persianDatepicker" .}}
+{{template "component/aThemeSwitch" .}}
+{{template "component/aPersianDatepicker" .}}
 <script>
     const columns = [{
         title: "ID",

+ 37 - 34
web/html/xui/index.html

@@ -27,8 +27,6 @@
   .dark .ant-backup-list-item svg,
   .dark .ant-card-actions>li>*,
   .dark .ant-badge-status-text,
-  .dark .ant-statistic-title,
-  .dark .ant-statistic-content,
   .dark .ant-card-extra {
     color: var(--dark-color-text-primary) !important;
   }
@@ -44,12 +42,6 @@
   .ant-card-actions {
     background: transparent !important;
   }
-  .ant-statistic-content-prefix {
-    font-size: 20px;
-  }
-  .ant-statistic-content-value {
-    font-size: 18px;
-  }
   .ip-hidden {
     filter: blur(10px);
   }
@@ -123,14 +115,22 @@
           </transition>
           <transition name="list" appear>
             <template v-if="!status.isLoaded">
-              <a-card hoverable style="text-align: center; padding: 30px 0; margin-top: 10px;">
+              <div style="text-align: center; padding: 30px 0; margin-top: 10px;">
                 <a-spin size="large"></a-spin>
-              </a-card>
+              </div>
             </template>
             <template v-else>
               <a-row>
                 <a-col :sm="24" :lg="12">
-                  <a-card title='{{ i18n "pages.index.xrayStatus" }}' hoverable>
+                  <a-card hoverable>
+                    <template #title>
+                      <a-space direction="horizontal">
+                        <span>{{ i18n "pages.index.xrayStatus" }}</span>
+                        <a-tag v-if="isMobile && status.xray.version != 'Unknown'" color="green">
+                          v[[ status.xray.version ]]
+                        </a-tag>
+                      </a-space>
+                    </template>
                     <template #extra>
                       <template v-if="status.xray.state != State.Error">
                         <a-badge :text="status.xray.state" :color="status.xray.color" style="text-transform: capitalize;"/>
@@ -150,15 +150,17 @@
                     <template #actions>
                       <a-space direction="horizontal" @click="stopXrayService" style="justify-content: center;">
                         <a-icon type="poweroff"></a-icon>
-                        <span>{{ i18n "pages.index.stopXray" }}</span>
+                        <span v-if="!isMobile">{{ i18n "pages.index.stopXray" }}</span>
                       </a-space>
                       <a-space direction="horizontal" @click="restartXrayService" style="justify-content: center;">
                         <a-icon type="reload"></a-icon>
-                        <span>{{ i18n "pages.index.restartXray" }}</span>
+                        <span v-if="!isMobile">{{ i18n "pages.index.restartXray" }}</span>
                       </a-space>
                       <a-space direction="horizontal" @click="openSelectV2rayVersion" style="justify-content: center;">
                         <a-icon type="tool"></a-icon>
-                        <span>v[[ status.xray.version ]]</span>
+                        <span v-if="!isMobile">
+                          [[ status.xray.version != 'Unknown' ? `v${status.xray.version}` : '{{ i18n "pages.index.xraySwitch" }}' ]]
+                        </span>
                       </a-space>
                     </template>
                   </a-card>
@@ -168,15 +170,15 @@
                     <template #actions>
                       <a-space direction="horizontal" @click="openLogs()" style="justify-content: center;">
                         <a-icon type="bars"></a-icon>
-                        <span>{{ i18n "pages.index.logs" }}</span>
+                        <span v-if="!isMobile">{{ i18n "pages.index.logs" }}</span>
                       </a-space>
                       <a-space direction="horizontal" @click="openConfig" style="justify-content: center;">
                         <a-icon type="control"></a-icon>
-                        <span>{{ i18n "pages.index.config" }}</span>
+                        <span v-if="!isMobile">{{ i18n "pages.index.config" }}</span>
                       </a-space>
                       <a-space direction="horizontal" @click="openBackup" style="justify-content: center;">
                         <a-icon type="cloud-server"></a-icon>
-                        <span>{{ i18n "pages.index.backup" }}</span>
+                        <span v-if="!isMobile">{{ i18n "pages.index.backup" }}</span>
                       </a-space>
                     </template>
                   </a-card>
@@ -223,18 +225,18 @@
                     </template>
                     <a-row :class="showIp ? 'ip-visible' : 'ip-hidden'">
                       <a-col :lg="12" :sm="24" :style="{ marginTop: isMobile ? '10px' : 0 }">
-                        <a-statistic title="IPv4" :value="status.publicIP.ipv4">
+                        <a-custom-statistic title="IPv4" :value="status.publicIP.ipv4">
                           <template #prefix>
                             <a-icon type="global" />
                           </template>
-                        </a-statistic>
+                        </a-custom-statistic>
                       </a-col>
                       <a-col :lg="12" :sm="24" :style="{ marginTop: isMobile ? '10px' : 0 }">
-                        <a-statistic title="IPv6" :value="status.publicIP.ipv6">
+                        <a-custom-statistic title="IPv6" :value="status.publicIP.ipv6">
                           <template #prefix>
                             <a-icon type="global" />
                           </template>
-                        </a-statistic>
+                        </a-custom-statistic>
                       </a-col>
                     </a-row>
                   </a-card>
@@ -243,18 +245,18 @@
                   <a-card title='{{ i18n "pages.index.connectionCount" }}' hoverable>
                     <a-row>
                       <a-col :lg="12" :sm="24" :style="{ marginTop: isMobile ? '10px' : 0 }">
-                        <a-statistic title="TCP" :value="status.tcpCount">
+                        <a-custom-statistic title="TCP" :value="status.tcpCount">
                           <template #prefix>
                             <a-icon type="swap" />
                           </template>
-                        </a-statistic>
+                        </a-custom-statistic>
                       </a-col>
                       <a-col :lg="12" :sm="24" :style="{ marginTop: isMobile ? '10px' : 0 }">
-                        <a-statistic title="UDP" :value="status.udpCount">
+                        <a-custom-statistic title="UDP" :value="status.udpCount">
                           <template #prefix>
                             <a-icon type="swap" />
                           </template>
-                        </a-statistic>
+                        </a-custom-statistic>
                       </a-col>
                     </a-row>
                   </a-card>
@@ -263,24 +265,24 @@
                   <a-card title='{{ i18n "pages.index.overallSpeed" }}' hoverable>
                     <a-row>
                       <a-col :lg="12" :sm="24" :style="{ marginTop: isMobile ? '10px' : 0 }">
-                        <a-statistic title='{{ i18n "pages.index.upload" }}' :value="SizeFormatter.sizeFormat(status.netIO.up)">
+                        <a-custom-statistic title='{{ i18n "pages.index.upload" }}' :value="SizeFormatter.sizeFormat(status.netIO.up)">
                           <template #prefix>
                             <a-icon type="arrow-up" />
                           </template>
                           <template #suffix>
                             /s
                           </template>
-                        </a-statistic>
+                        </a-custom-statistic>
                       </a-col>
                       <a-col :lg="12" :sm="24" :style="{ marginTop: isMobile ? '10px' : 0 }">
-                        <a-statistic title='{{ i18n "pages.index.download" }}' :value="SizeFormatter.sizeFormat(status.netIO.down)">
+                        <a-custom-statistic title='{{ i18n "pages.index.download" }}' :value="SizeFormatter.sizeFormat(status.netIO.down)">
                           <template #prefix>
                             <a-icon type="arrow-down" />
                           </template>
                           <template #suffix>
                             /s
                           </template>
-                        </a-statistic>
+                        </a-custom-statistic>
                       </a-col>
                     </a-row>
                   </a-card>
@@ -289,18 +291,18 @@
                   <a-card title='{{ i18n "pages.index.totalData" }}' hoverable>
                     <a-row>
                       <a-col :lg="12" :sm="24" :style="{ marginTop: isMobile ? '10px' : 0 }">
-                        <a-statistic title='{{ i18n "pages.index.sent" }}' :value="SizeFormatter.sizeFormat(status.netTraffic.sent)">
+                        <a-custom-statistic title='{{ i18n "pages.index.sent" }}' :value="SizeFormatter.sizeFormat(status.netTraffic.sent)">
                           <template #prefix>
                             <a-icon type="cloud-upload" />
                           </template>
-                        </a-statistic>
+                        </a-custom-statistic>
                       </a-col>
                       <a-col :lg="12" :sm="24" :style="{ marginTop: isMobile ? '10px' : 0 }">
-                        <a-statistic title='{{ i18n "pages.index.received" }}' :value="SizeFormatter.sizeFormat(status.netTraffic.recv)">
+                        <a-custom-statistic title='{{ i18n "pages.index.received" }}' :value="SizeFormatter.sizeFormat(status.netTraffic.recv)">
                           <template #prefix>
                             <a-icon type="cloud-download" />
                           </template>
-                        </a-statistic>
+                        </a-custom-statistic>
                       </a-col>
                     </a-row>
                   </a-card>
@@ -397,7 +399,8 @@
     </a-modal>
   </a-layout>
 {{template "js" .}}
-{{template "component/themeSwitcher" .}}
+{{template "component/aThemeSwitch" .}}
+{{template "component/aCustomStatistic" .}}
 {{template "textModal"}}
 <script>
     const State = {

+ 3 - 3
web/html/xui/settings.html

@@ -663,9 +663,9 @@
   </a-layout>
 {{template "js" .}}
 <script src="{{ .base_path }}assets/js/model/setting.js?{{ .cur_ver }}"></script>
-{{template "component/themeSwitcher" .}}
-{{template "component/password" .}}
-{{template "component/setting"}}
+{{template "component/aThemeSwitch" .}}
+{{template "component/aPasswordInput" .}}
+{{template "component/aSettingListItem" .}}
 <script>
   const app = new Vue({
     delimiters: ['[[', ']]'],

+ 3 - 3
web/html/xui/xray.html

@@ -788,9 +788,9 @@
     </a-layout>
   </a-layout>
 {{template "js" .}}
-{{template "component/themeSwitcher" .}}
-{{template "component/sortableTable" .}}
-{{template "component/setting"}}
+{{template "component/aThemeSwitch" .}}
+{{template "component/aTableSortable" .}}
+{{template "component/aSettingListItem" .}}
 {{template "ruleModal"}}
 {{template "outModal"}}
 {{template "reverseModal"}}

+ 3 - 0
web/translation/translate.en_US.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "No added reverse proxies."
 
 [menu]
+"theme" = "Theme"
+"dark" = "Dark"
+"ultraDark" = "Ultra Dark"
 "dashboard" = "Overview"
 "inbounds" = "Inbounds"
 "settings" = "Panel Settings"

+ 3 - 0
web/translation/translate.es_ES.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "No hay proxies inversos añadidos."
 
 [menu]
+"theme" = "Tema"
+"dark" = "Oscuro"
+"ultraDark" = "Ultra Oscuro"
 "dashboard" = "Estado del Sistema"
 "inbounds" = "Entradas"
 "settings" = "Configuraciones"

+ 3 - 0
web/translation/translate.fa_IR.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "هیچ پروکسی معکوس اضافه نشده است."
 
 [menu]
+"theme" = "تم"
+"dark" = "تیره"
+"ultraDark" = "فوق تیره"
 "dashboard" = "نمای کلی"
 "inbounds" = "ورودی‌ها"
 "settings" = "تنظیمات پنل"

+ 3 - 0
web/translation/translate.id_ID.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "Tidak ada proxy terbalik yang ditambahkan."
 
 [menu]
+"theme" = "Tema"
+"dark" = "Gelap"
+"ultraDark" = "Sangat Gelap"
 "dashboard" = "Ikhtisar"
 "inbounds" = "Masuk"
 "settings" = "Pengaturan Panel"

+ 3 - 0
web/translation/translate.ja_JP.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "追加されたリバースプロキシはありません。"
 
 [menu]
+"theme" = "テーマ"
+"dark" = "ダーク"
+"ultraDark" = "ウルトラダーク"
 "dashboard" = "ダッシュボード"
 "inbounds" = "インバウンド一覧"
 "settings" = "パネル設定"

+ 3 - 0
web/translation/translate.pt_BR.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "Nenhum proxy reverso adicionado."
 
 [menu]
+"theme" = "Tema"
+"dark" = "Escuro"
+"ultraDark" = "Ultra Escuro"
 "dashboard" = "Visão Geral"
 "inbounds" = "Inbounds"
 "settings" = "Panel Settings"

+ 3 - 0
web/translation/translate.ru_RU.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "Нет добавленных обратных прокси."
 
 [menu]
+"theme" = "Тема"
+"dark" = "Темная"
+"ultraDark" = "Ультра темная"
 "dashboard" = "Статус системы"
 "inbounds" = "Подключения"
 "settings" = "Настройки панели"

+ 3 - 0
web/translation/translate.tr_TR.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "Eklenmiş ters proxy yok."
 
 [menu]
+"theme" = "Tema"
+"dark" = "Koyu"
+"ultraDark" = "Ultra Koyu"
 "dashboard" = "Genel Bakış"
 "inbounds" = "Gelenler"
 "settings" = "Panel Ayarları"

+ 3 - 0
web/translation/translate.uk_UA.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "Немає доданих зворотних проксі."
 
 [menu]
+"theme" = "Тема"
+"dark" = "Темна"
+"ultraDark" = "Ультра темна"
 "dashboard" = "Огляд"
 "inbounds" = "Вхідні"
 "settings" = "Параметри панелі"

+ 3 - 0
web/translation/translate.vi_VN.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "Không có proxy ngược nào được thêm."
 
 [menu]
+"theme" = "Chủ đề"
+"dark" = "Tối"
+"ultraDark" = "Siêu tối"
 "dashboard" = "Trạng thái hệ thống"
 "inbounds" = "Đầu vào khách hàng"
 "settings" = "Cài đặt bảng điều khiển"

+ 3 - 0
web/translation/translate.zh_CN.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "未添加反向代理。"
 
 [menu]
+"theme" = "主题"
+"dark" = "暗色"
+"ultraDark" = "超暗色"
 "dashboard" = "系统状态"
 "inbounds" = "入站列表"
 "settings" = "面板设置"

+ 3 - 0
web/translation/translate.zh_TW.toml

@@ -67,6 +67,9 @@
 "emptyReverseDesc" = "未添加反向代理。"
 
 [menu]
+"theme" = "主題"
+"dark" = "深色"
+"ultraDark" = "超深色"
 "dashboard" = "系統狀態"
 "inbounds" = "入站列表"
 "settings" = "面板設定"