DashboardLayout.vue 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. <div :class="containerClass" @click="onWrapperClick">
  44. <TopBar @menu-toggle="onMenuToggle" />
  45. <nav class="layout-sidebar">
  46. <Sidebar :menu="menu[$page.props.auth.user.role_id]" />
  47. </nav>
  48. <div class="layout-main-container">
  49. <main class="layout-main">
  50. <AppMessage />
  51. <slot />
  52. </main>
  53. <Footer />
  54. </div>
  55. <Transition name="layout-mask">
  56. <div
  57. class="layout-mask p-component-overlay"
  58. v-if="mobileMenuActive"
  59. ></div>
  60. </Transition>
  61. </div>
  62. </template>
  63. <style lang="scss" scoped>
  64. .layout-sidebar {
  65. position: fixed;
  66. width: 300px;
  67. height: calc(100vh - 9rem);
  68. z-index: 996;
  69. overflow-y: auto;
  70. user-select: none;
  71. top: 7rem;
  72. left: 2rem;
  73. transition: transform 0.2s, left 0.2s;
  74. background-color: var(--surface-overlay);
  75. border-radius: 4px;
  76. padding: 1.5rem;
  77. box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.02), 0px 0px 2px rgba(0, 0, 0, 0.05),
  78. 0px 1px 4px rgba(0, 0, 0, 0.08);
  79. }
  80. .layout-main-container {
  81. display: flex;
  82. flex-direction: column;
  83. min-height: 100vh;
  84. justify-content: space-between;
  85. padding: 7rem 2rem 2rem 4rem;
  86. transition: margin-left 0.2s;
  87. }
  88. .layout-main {
  89. flex: 1 1 auto;
  90. }
  91. .layout-footer {
  92. transition: margin-left 0.2s;
  93. display: flex;
  94. align-items: center;
  95. justify-content: center;
  96. padding-top: 1rem;
  97. border-top: 1px solid var(--surface-border);
  98. }
  99. @media (min-width: 992px) {
  100. .layout-wrapper {
  101. .layout-main-container {
  102. margin-left: 300px;
  103. }
  104. &.layout-static-sidebar-inactive {
  105. .layout-sidebar {
  106. transform: translateX(-100%);
  107. left: 0;
  108. }
  109. .layout-main-container {
  110. margin-left: 0;
  111. padding-left: 2rem;
  112. }
  113. }
  114. .layout-mask {
  115. display: none;
  116. }
  117. }
  118. }
  119. @media (max-width: 991px) {
  120. .layout-wrapper {
  121. .layout-main-container {
  122. margin-left: 0;
  123. padding-left: 2rem;
  124. }
  125. .layout-sidebar {
  126. transform: translateX(-100%);
  127. left: 0;
  128. top: 0;
  129. height: 100vh;
  130. border-top-left-radius: 0;
  131. border-bottom-left-radius: 0;
  132. }
  133. .layout-mask {
  134. z-index: 995;
  135. background-color: var(--maskbg);
  136. &.layout-mask-enter-from,
  137. &.layout-mask-leave-to {
  138. background-color: transparent;
  139. }
  140. }
  141. &.layout-mobile-sidebar-active {
  142. .layout-sidebar {
  143. transform: translateX(0);
  144. }
  145. .layout-mask {
  146. display: block;
  147. }
  148. }
  149. }
  150. }
  151. </style>