DashboardLayout.vue 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <script setup>
  2. import { ref, computed } from 'vue'
  3. import AppTopBar from '@/components/AppTopBar.vue'
  4. import AppSidebar from '@/components/AppSidebar.vue'
  5. import AppMessage from '@/components/AppMessage.vue'
  6. import menu from '@/utils/menu'
  7. const mobileMenuActive = ref(false)
  8. const staticMenuInactive = ref(false)
  9. const menuClick = ref(false)
  10. const isDesktop = () => window.innerWidth >= 992
  11. const containerClass = computed(() => {
  12. return [
  13. 'layout-wrapper',
  14. {
  15. 'layout-static-sidebar-inactive': staticMenuInactive.value,
  16. 'layout-mobile-sidebar-active': mobileMenuActive.value,
  17. },
  18. ]
  19. })
  20. const onWrapperClick = () => {
  21. if (!menuClick.value) {
  22. mobileMenuActive.value = false
  23. }
  24. menuClick.value = false
  25. }
  26. const onMenuToggle = (event) => {
  27. menuClick.value = true
  28. if (isDesktop()) {
  29. staticMenuInactive.value = !staticMenuInactive.value
  30. } else {
  31. mobileMenuActive.value = !mobileMenuActive.value
  32. }
  33. event.preventDefault()
  34. }
  35. </script>
  36. <template>
  37. <div :class="containerClass" @click="onWrapperClick">
  38. <AppTopBar @menu-toggle="onMenuToggle" />
  39. <div class="layout-sidebar">
  40. <AppSidebar :menu="menu[$page.props.auth.user.role_id]" />
  41. </div>
  42. <div class="layout-main-container">
  43. <div class="layout-main">
  44. <AppMessage />
  45. <slot />
  46. </div>
  47. <div class="layout-footer">
  48. Developed by
  49. <a
  50. href="https://dijitalcode.com"
  51. target="_blank"
  52. class="font-medium ml-2"
  53. >DijitalCODE</a
  54. >
  55. </div>
  56. </div>
  57. <Transition name="layout-mask">
  58. <div
  59. class="layout-mask p-component-overlay"
  60. v-if="mobileMenuActive"
  61. ></div>
  62. </Transition>
  63. </div>
  64. </template>
  65. <style lang="scss" scoped>
  66. .layout-sidebar {
  67. position: fixed;
  68. width: 300px;
  69. height: calc(100vh - 9rem);
  70. z-index: 996;
  71. overflow-y: auto;
  72. user-select: none;
  73. top: 7rem;
  74. left: 2rem;
  75. transition: transform 0.2s, left 0.2s;
  76. background-color: var(--surface-overlay);
  77. border-radius: 4px;
  78. padding: 1.5rem;
  79. box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.02), 0px 0px 2px rgba(0, 0, 0, 0.05),
  80. 0px 1px 4px rgba(0, 0, 0, 0.08);
  81. }
  82. .layout-main-container {
  83. display: flex;
  84. flex-direction: column;
  85. min-height: 100vh;
  86. justify-content: space-between;
  87. padding: 7rem 2rem 2rem 4rem;
  88. transition: margin-left 0.2s;
  89. }
  90. .layout-main {
  91. flex: 1 1 auto;
  92. }
  93. .layout-footer {
  94. transition: margin-left 0.2s;
  95. display: flex;
  96. align-items: center;
  97. justify-content: center;
  98. padding-top: 1rem;
  99. border-top: 1px solid var(--surface-border);
  100. }
  101. @media (min-width: 992px) {
  102. .layout-wrapper {
  103. .layout-main-container {
  104. margin-left: 300px;
  105. }
  106. &.layout-static-sidebar-inactive {
  107. .layout-sidebar {
  108. transform: translateX(-100%);
  109. left: 0;
  110. }
  111. .layout-main-container {
  112. margin-left: 0;
  113. padding-left: 2rem;
  114. }
  115. }
  116. .layout-mask {
  117. display: none;
  118. }
  119. }
  120. }
  121. @media (max-width: 991px) {
  122. .layout-wrapper {
  123. .layout-main-container {
  124. margin-left: 0;
  125. padding-left: 2rem;
  126. }
  127. .layout-sidebar {
  128. transform: translateX(-100%);
  129. left: 0;
  130. top: 0;
  131. height: 100vh;
  132. border-top-left-radius: 0;
  133. border-bottom-left-radius: 0;
  134. }
  135. .layout-mask {
  136. z-index: 995;
  137. background-color: var(--maskbg);
  138. &.layout-mask-enter-from,
  139. &.layout-mask-leave-to {
  140. background-color: transparent;
  141. }
  142. }
  143. &.layout-mobile-sidebar-active {
  144. .layout-sidebar {
  145. transform: translateX(0);
  146. }
  147. .layout-mask {
  148. display: block;
  149. }
  150. }
  151. }
  152. }
  153. </style>