DashboardLayout.vue 3.5KB

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