Md.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <template>
  2. <div class="app-container">
  3. <v-app class="navigation-sm">
  4. <!-- Top bar -->
  5. <v-app-bar>
  6. <template #prepend>
  7. <v-app-bar-nav-icon @click="toggleMenu" />
  8. </template>
  9. <v-app-bar-title>
  10. <nuxt-link to="/">
  11. <v-img
  12. class="logo-md"
  13. src="/images/logos/opentalent/Logo_Opentalent-gris.png"
  14. />
  15. </nuxt-link>
  16. </v-app-bar-title>
  17. <template #append>
  18. <v-btn
  19. href="https://admin.opentalent.fr/#/login/"
  20. icon="fas fa-user"
  21. class="icon"
  22. />
  23. <v-btn to="/nous-contacter" icon="fas fa-phone" class="icon" />
  24. <AgendaLink href="/agenda-culturel">
  25. <v-btn icon="fas fa-calendar" class="icon" />
  26. </AgendaLink>
  27. </template>
  28. </v-app-bar>
  29. <!-- Tiroir de navigation principal -->
  30. <v-navigation-drawer v-model="isMenuOpen" app temporary>
  31. <v-list nav dense>
  32. <v-list-item
  33. v-if="isSubMenu"
  34. class="menuItem back-item"
  35. @click="onBackItemClick"
  36. >
  37. <v-list-item-title>
  38. <v-icon icon="fas fa-caret-left" class="mr-1" /> Retour
  39. </v-list-item-title>
  40. </v-list-item>
  41. <v-list-item
  42. v-for="(item, index) in activeMenu"
  43. :key="item.label"
  44. :to="item.to"
  45. class="menuItem"
  46. @click="onMenuItemClick(index, item)"
  47. >
  48. <v-list-item-title class="d-flex flex-row w-100">
  49. <span class="flex-grow-1">
  50. {{ item.label }}
  51. </span>
  52. <span v-if="item.children?.length! > 0">
  53. <v-icon icon="fa fa-angle-right" />
  54. </span>
  55. </v-list-item-title>
  56. </v-list-item>
  57. </v-list>
  58. </v-navigation-drawer>
  59. </v-app>
  60. </div>
  61. </template>
  62. <script setup lang="ts">
  63. import type { PropType, Ref } from 'vue'
  64. import { useDisplay } from 'vuetify'
  65. import AgendaLink from '~/components/Common/AgendaLink.vue'
  66. import type { MainMenuItem } from '~/types/interface'
  67. const { smAndUp } = useDisplay()
  68. const props = defineProps({
  69. menu: {
  70. type: Array as PropType<Array<MainMenuItem>>,
  71. required: true,
  72. },
  73. })
  74. const isMenuOpen: Ref<boolean> = ref(false)
  75. const toggleMenu = () => {
  76. isMenuOpen.value = !isMenuOpen.value
  77. }
  78. const activeMenuIndex: Ref<number | null> = ref(null)
  79. const activeMenu = computed(() =>
  80. activeMenuIndex.value !== null
  81. ? props.menu![activeMenuIndex.value].children
  82. : props.menu
  83. )
  84. /**
  85. * Determines if the is active menu is a sub-menu .
  86. *
  87. * @function isSubMenu
  88. * @returns {boolean} - True if a sub-menu is active, otherwise false.
  89. */
  90. const isSubMenu = computed(() => activeMenuIndex.value !== null)
  91. /**
  92. * Handles the click event on a menu item.
  93. *
  94. * @param {number} index - The index of the clicked menu item.
  95. * @param {MainMenuItem} item - The clicked menu item.
  96. * @returns {void}
  97. */
  98. const onMenuItemClick = (index: number, item: MainMenuItem): void => {
  99. if (!item.children) {
  100. return
  101. }
  102. withAnimation(() => (activeMenuIndex.value = index))
  103. }
  104. /**
  105. * Function to handle back button click event.
  106. */
  107. const onBackItemClick = (): void => {
  108. withAnimation(() => (activeMenuIndex.value = null))
  109. }
  110. /**
  111. * Déclenche une animation de changement de menu en fermant et rouvrant le drawer
  112. * @param callback
  113. */
  114. const withAnimation = (callback: () => void) => {
  115. isMenuOpen.value = false
  116. callback()
  117. setTimeout(() => {
  118. isMenuOpen.value = true
  119. }, 85)
  120. }
  121. </script>
  122. <style scoped lang="scss">
  123. .app-container {
  124. height: 54px;
  125. }
  126. .v-app-bar {
  127. max-width: 100vw;
  128. }
  129. .navigation-sm {
  130. background-color: var(--neutral-color);
  131. position: fixed;
  132. top: 0;
  133. z-index: 1000;
  134. }
  135. .logo-md {
  136. width: 150px;
  137. height: 50px;
  138. }
  139. .back-item {
  140. border-bottom: solid 1px var(--on-neutral-color-light);
  141. border-radius: 0;
  142. .v-list-item-title {
  143. display: flex;
  144. align-items: center;
  145. }
  146. }
  147. .icon {
  148. color: var(--on-neutral-color-light);
  149. }
  150. </style>