Md.vue 4.2 KB

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