mirror of
				https://github.com/MHSanaei/3x-ui.git
				synced 2025-11-04 06:12:52 +00:00 
			
		
		
		
	chore: transforming a common sidebar into a separate component
- also added saving collapsed state
This commit is contained in:
		
							parent
							
								
									40ebf2902e
								
							
						
					
					
						commit
						3ea05d30c1
					
				
					 6 changed files with 109 additions and 63 deletions
				
			
		| 
						 | 
				
			
			@ -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}}
 | 
			
		||||
							
								
								
									
										101
									
								
								web/html/xui/component/aSidebar.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								web/html/xui/component/aSidebar.html
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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}}
 | 
			
		||||
| 
						 | 
				
			
			@ -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"}}'>
 | 
			
		||||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,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,6 +417,7 @@
 | 
			
		|||
    </a-modal>
 | 
			
		||||
  </a-layout>
 | 
			
		||||
{{template "js" .}}
 | 
			
		||||
{{template "component/aSidebar" .}}
 | 
			
		||||
{{template "component/aThemeSwitch" .}}
 | 
			
		||||
{{template "component/aCustomStatistic" .}}
 | 
			
		||||
{{template "modals/textModal"}}
 | 
			
		||||
| 
						 | 
				
			
			@ -591,7 +592,6 @@
 | 
			
		|||
        delimiters: ['[[', ']]'],
 | 
			
		||||
        el: '#app',
 | 
			
		||||
        data: {
 | 
			
		||||
            siderDrawer,
 | 
			
		||||
            themeSwitcher,
 | 
			
		||||
            status: new Status(),
 | 
			
		||||
            versionModal,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@
 | 
			
		|||
</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"}}'>
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +131,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" .}}
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +140,6 @@
 | 
			
		|||
    delimiters: ['[[', ']]'],
 | 
			
		||||
    el: '#app',
 | 
			
		||||
    data: {
 | 
			
		||||
      siderDrawer,
 | 
			
		||||
      themeSwitcher,
 | 
			
		||||
      spinning: false,
 | 
			
		||||
      changeSecret: false,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,7 +59,7 @@
 | 
			
		|||
</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"}}'>
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +130,7 @@
 | 
			
		|||
    </a-layout>
 | 
			
		||||
  </a-layout>
 | 
			
		||||
{{template "js" .}}
 | 
			
		||||
{{template "component/aSidebar" .}}
 | 
			
		||||
{{template "component/aThemeSwitch" .}}
 | 
			
		||||
{{template "component/aTableSortable" .}}
 | 
			
		||||
{{template "component/aSettingListItem" .}}
 | 
			
		||||
| 
						 | 
				
			
			@ -207,7 +208,6 @@
 | 
			
		|||
        delimiters: ['[[', ']]'],
 | 
			
		||||
        el: '#app',
 | 
			
		||||
        data: {
 | 
			
		||||
            siderDrawer,
 | 
			
		||||
            themeSwitcher,
 | 
			
		||||
            isDarkTheme: themeSwitcher.isDarkTheme,
 | 
			
		||||
            spinning: false,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue