Md.vue 4.2 KB

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