LayoutPage.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <!-- Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import {
  4. type MaybeElementRef,
  5. useCurrentElement,
  6. type VueInstance,
  7. } from '@vueuse/core'
  8. import { storeToRefs } from 'pinia'
  9. import { ref, useTemplateRef, watch } from 'vue'
  10. import { useTrapTab } from '#shared/composables/useTrapTab.ts'
  11. import { useApplicationStore } from '#shared/stores/application.ts'
  12. import { useSessionStore } from '#shared/stores/session.ts'
  13. import LeftSidebarFooterMenu from '#desktop/components/layout/LayoutSidebar/LeftSidebar/LeftSidebarFooterMenu.vue'
  14. import LeftSidebarHeader from '#desktop/components/layout/LayoutSidebar/LeftSidebar/LeftSidebarHeader.vue'
  15. import LayoutSidebar from '#desktop/components/layout/LayoutSidebar.vue'
  16. import { numberOfPermanentItems } from '#desktop/components/PageNavigation/firstLevelRoutes.ts'
  17. import PageNavigation from '#desktop/components/PageNavigation/PageNavigation.vue'
  18. import QuickSearch from '#desktop/components/QuickSearch/QuickSearch.vue'
  19. import UserTaskbarTabs from '#desktop/components/UserTaskbarTabs/UserTaskbarTabs.vue'
  20. import { useResizeGridColumns } from '#desktop/composables/useResizeGridColumns.ts'
  21. const { config } = storeToRefs(useApplicationStore())
  22. const noTransition = ref(false)
  23. const layoutSidebarInstance = useTemplateRef('layout-sidebar')
  24. const isQuickSearchActive = ref(false)
  25. const quickSearchValue = ref('')
  26. const { deactivateTabTrap, activateTabTrap } = useTrapTab(
  27. useCurrentElement(
  28. layoutSidebarInstance as MaybeElementRef<VueInstance> | undefined,
  29. ),
  30. true,
  31. )
  32. watch(isQuickSearchActive, (isActive) =>
  33. isActive ? activateTabTrap() : deactivateTabTrap(),
  34. )
  35. const { userId } = useSessionStore()
  36. const storageKeyId = `${userId}-left`
  37. const {
  38. currentSidebarWidth,
  39. maxSidebarWidth,
  40. minSidebarWidth,
  41. gridColumns,
  42. collapseSidebar,
  43. resizeSidebar,
  44. expandSidebar,
  45. resetSidebarWidth,
  46. } = useResizeGridColumns(storageKeyId)
  47. </script>
  48. <template>
  49. <div
  50. class="grid h-full max-h-full overflow-y-clip duration-100"
  51. :class="{ 'transition-none': noTransition }"
  52. :style="gridColumns"
  53. >
  54. <LayoutSidebar
  55. id="main-sidebar"
  56. ref="layout-sidebar"
  57. :name="storageKeyId"
  58. :aria-label="$t('Main sidebar')"
  59. :current-width="currentSidebarWidth"
  60. :max-width="maxSidebarWidth"
  61. :min-width="minSidebarWidth"
  62. :classes="{
  63. collapseButton: 'z-60',
  64. resizeLine: 'z-60',
  65. }"
  66. :collapsible="!isQuickSearchActive"
  67. resizable
  68. no-scroll
  69. :no-padding="isQuickSearchActive"
  70. remember-collapse
  71. @collapse="collapseSidebar"
  72. @expand="expandSidebar"
  73. @resize-horizontal="resizeSidebar"
  74. @resize-horizontal-start="noTransition = true"
  75. @resize-horizontal-end="noTransition = false"
  76. @reset-width="resetSidebarWidth"
  77. >
  78. <template #default="{ isCollapsed }">
  79. <!-- TODO: Switch to `scheme-dark` utility once we upgrade to TW 4. -->
  80. <div
  81. class="flex h-full flex-col"
  82. data-theme="dark"
  83. style="color-scheme: dark"
  84. >
  85. <LeftSidebarHeader
  86. v-model:search="quickSearchValue"
  87. v-model:search-active="isQuickSearchActive"
  88. class="mb-2"
  89. :class="{ 'px-3 pt-2.5': isQuickSearchActive }"
  90. :collapsed="isCollapsed"
  91. />
  92. <QuickSearch
  93. v-show="isQuickSearchActive"
  94. :search="quickSearchValue"
  95. :collapsed="isCollapsed"
  96. />
  97. <PageNavigation
  98. v-show="!isQuickSearchActive"
  99. :collapsed="isCollapsed"
  100. />
  101. <UserTaskbarTabs
  102. v-show="!isQuickSearchActive"
  103. :collapsed="isCollapsed"
  104. />
  105. <LeftSidebarFooterMenu
  106. v-show="!isQuickSearchActive"
  107. :collapsed="isCollapsed"
  108. class="mt-auto"
  109. />
  110. </div>
  111. </template>
  112. </LayoutSidebar>
  113. <div id="main-content" class="relative">
  114. <RouterView #default="{ Component, route: currentRoute }">
  115. <KeepAlive
  116. :exclude="['ErrorTab']"
  117. :max="config.ui_task_mananger_max_task_count"
  118. >
  119. <component
  120. :is="Component"
  121. v-if="!currentRoute.meta.permanentItem"
  122. :key="currentRoute.path"
  123. />
  124. </KeepAlive>
  125. <KeepAlive :max="numberOfPermanentItems">
  126. <component
  127. :is="Component"
  128. v-if="currentRoute.meta.permanentItem"
  129. :key="currentRoute.meta.pageKey || currentRoute.path"
  130. />
  131. </KeepAlive>
  132. </RouterView>
  133. </div>
  134. </div>
  135. </template>