main
vue 124 lines 2.7 KB
Raw
1 <template>
2 <aside
3 id="app-sidebar"
4 class="sidebar flex flex-col"
5 :class="{ collapsed: sidebarCollapsed, opened: !sidebarCollapsed }"
6 >
7 <div ref="sidebar" class="sidebar-wrap flex grow flex-col">
8 <div :class="{ 'px-7': !sidebarClosed, 'px-2': sidebarClosed }" class="transition-all">
9 <SidebarHeader :logo-small="sidebarClosed" />
10 </div>
11 <n-scrollbar>
12 <div :class="{ 'px-2': !sidebarClosed }" class="transition-all">
13 <Navbar :collapsed="sidebarClosed" />
14 </div>
15 </n-scrollbar>
16 <div class="p-2">
17 <SidebarFooter :collapsed="sidebarClosed" />
18 </div>
19 </div>
20 </aside>
21 </template>
22
23 <script lang="ts" setup>
24 import { onClickOutside, useElementHover } from "@vueuse/core"
25 import { NScrollbar } from "naive-ui"
26 import { computed, onMounted, ref, watch } from "vue"
27 import Navbar from "@/app-layouts/common/Navbar"
28 import { useThemeStore } from "@/stores/theme"
29 import { isMobile } from "@/utils"
30 import SidebarFooter from "./SidebarFooter.vue"
31 import SidebarHeader from "./SidebarHeader.vue"
32
33 const themeStore = useThemeStore()
34 const sidebar = ref(null)
35 const sidebarHovered = useElementHover(sidebar)
36 const sidebarCollapsed = computed<boolean>(() => themeStore.sidebar.collapsed)
37 const sidebarClosed = computed<boolean>(() => !sidebarHovered.value && sidebarCollapsed.value)
38
39 function clickListener() {
40 if (sidebar.value) {
41 onClickOutside(sidebar, e => {
42 if (!sidebarCollapsed.value) {
43 e.stopPropagation()
44 themeStore.closeSidebar()
45 }
46 })
47 }
48 }
49 onMounted(() => {
50 watch(
51 sidebarCollapsed,
52 val => {
53 if (val) {
54 if (isMobile()) {
55 sidebarHovered.value = false
56 }
57 }
58 },
59 {
60 immediate: true
61 }
62 )
63
64 if (window.innerWidth <= 700) {
65 clickListener()
66 }
67 })
68 </script>
69
70 <style lang="scss" scoped>
71 @import "./variables";
72
73 .sidebar {
74 position: fixed;
75 z-index: 5;
76 top: 0;
77 left: 0;
78 width: var(--sidebar-open-width);
79 height: 100vh;
80 height: 100svh;
81 overflow-x: hidden;
82 overflow-y: auto;
83 background-color: var(--bg-sidebar-color);
84 transition:
85 width var(--sidebar-anim-ease) var(--sidebar-anim-duration),
86 box-shadow var(--sidebar-anim-ease) var(--sidebar-anim-duration),
87 color 0.3s var(--bezier-ease) 0s,
88 background-color 0.3s var(--bezier-ease) 0s;
89 z-index: -1;
90 transition: all 0.3s var(--bezier-ease) 0s;
91 transform: translateX(-100%);
92
93 .sidebar-wrap {
94 overflow: hidden;
95 }
96
97 @media (max-width: $sidebar-bp) {
98 &.opened {
99 z-index: 2100;
100 transform: translateX(0);
101 box-shadow: 0px 0px 80px 0px rgba(0, 0, 0, 0.2);
102 }
103 }
104
105 :deep(.n-scrollbar-rail) {
106 opacity: 0.15;
107 }
108 }
109
110 .direction-rtl {
111 .sidebar {
112 left: unset;
113 right: 0;
114
115 @media (max-width: $sidebar-bp) {
116 transform: translateX(100%);
117
118 &.opened {
119 transform: translateX(0%);
120 }
121 }
122 }
123 }
124 </style>