AppLayout.vue 2.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <script setup>
  2. import { ref, computed, onBeforeUpdate } from 'vue'
  3. import AppTopBar from '@/components/AppTopBar.vue'
  4. import AppSidebar from '@/components/AppSidebar.vue'
  5. import AppFooter from '@/components/AppFooter.vue'
  6. import AppMessage from '@/components/AppMessage.vue'
  7. import menu from '@/utils/menu'
  8. const mobileMenuActive = ref(false)
  9. const staticMenuInactive = ref(false)
  10. const menuClick = ref(false)
  11. const isDesktop = () => window.innerWidth >= 992
  12. const addClass = (element, className) => {
  13. if (element.classList) element.classList.add(className)
  14. else element.className += ' ' + className
  15. }
  16. const removeClass = (element, className) => {
  17. if (element.classList) element.classList.remove(className)
  18. else
  19. element.className = element.className.replace(
  20. new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'),
  21. ' '
  22. )
  23. }
  24. onBeforeUpdate(() => {
  25. if (mobileMenuActive.value) {
  26. addClass(document.body, 'body-overflow-hidden')
  27. } else {
  28. removeClass(document.body, 'body-overflow-hidden')
  29. }
  30. })
  31. const containerClass = computed(() => {
  32. return [
  33. 'layout-wrapper',
  34. 'layout-static',
  35. {
  36. 'layout-static-sidebar-inactive': staticMenuInactive.value,
  37. 'layout-mobile-sidebar-active': mobileMenuActive.value,
  38. },
  39. ]
  40. })
  41. const onWrapperClick = () => {
  42. if (!menuClick.value) {
  43. mobileMenuActive.value = false
  44. }
  45. menuClick.value = false
  46. }
  47. const onMenuToggle = (event) => {
  48. menuClick.value = true
  49. if (isDesktop()) {
  50. staticMenuInactive.value = !staticMenuInactive.value
  51. } else {
  52. mobileMenuActive.value = !mobileMenuActive.value
  53. }
  54. event.preventDefault()
  55. }
  56. const onSidebarClick = () => {
  57. menuClick.value = true
  58. }
  59. const onMenuItemClick = (event) => {
  60. if (event.item && !event.item.items) {
  61. mobileMenuActive.value = false
  62. }
  63. }
  64. </script>
  65. <template>
  66. <div :class="containerClass" @click="onWrapperClick">
  67. <AppTopBar @menu-toggle="onMenuToggle" />
  68. <div class="layout-sidebar" @click="onSidebarClick">
  69. <AppSidebar :model="menu[$page.props.auth.user.role_id]" @menuitem-click="onMenuItemClick" />
  70. </div>
  71. <div class="layout-main-container">
  72. <div class="layout-main">
  73. <AppMessage />
  74. <slot />
  75. </div>
  76. <AppFooter />
  77. </div>
  78. <Transition name="layout-mask">
  79. <div class="layout-mask p-component-overlay" v-if="mobileMenuActive"></div>
  80. </Transition>
  81. </div>
  82. </template>