Navigation.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <!--
  2. Menu Navigation
  3. -->
  4. <template>
  5. <!-- Navigation (écran large) -->
  6. <div v-if="mdAndUp">
  7. <LayoutNavigationTopbar />
  8. <v-row class="navigation-lg" style="margin-top: 0 !important;">
  9. <!-- Logo Opentalent -->
  10. <v-col cols="3">
  11. <nuxt-link to="/">
  12. <v-img class="logo" src="/images/logo/navigation-logo.png" />
  13. </nuxt-link>
  14. </v-col>
  15. <!-- Menu principal -->
  16. <v-col cols="9">
  17. <v-menu
  18. v-for="item in menu"
  19. :key="item.label"
  20. open-on-hover
  21. >
  22. <template v-slot:activator="{ props }">
  23. <nuxt-link
  24. v-bind="props"
  25. class="menuItem first-level"
  26. :to="item.to"
  27. >
  28. {{ item.label }}
  29. </nuxt-link>
  30. </template>
  31. <v-list
  32. v-if="item.children?.length > 0"
  33. class="menu-list"
  34. >
  35. <v-list-item
  36. v-for="child in item.children"
  37. :key="child.label"
  38. :to="child.to"
  39. class="menuItem"
  40. >
  41. <v-list-item-title>{{ child.label }}</v-list-item-title>
  42. </v-list-item>
  43. </v-list>
  44. </v-menu>
  45. </v-col>
  46. </v-row>
  47. </div>
  48. <!-- Navigation (petit écran) -->
  49. <v-app
  50. v-else
  51. class="navigation-sm"
  52. >
  53. <!-- Top bar -->
  54. <v-app-bar app>
  55. <v-app-bar-nav-icon
  56. @click="toggleMenu"
  57. />
  58. <nuxt-link to="/">
  59. <v-img class="logo-md" src="/images/logo/navigation-logo.png" />
  60. </nuxt-link>
  61. <nuxt-link
  62. to="https://admin.opentalent.fr/#/login/"
  63. style="text-decoration: none"
  64. >
  65. <v-btn text>
  66. <v-icon left class="fas fa-user icon"></v-icon>
  67. </v-btn>
  68. </nuxt-link>
  69. <v-btn text>
  70. <v-icon left class="fas fa-phone icon"></v-icon>
  71. </v-btn>
  72. <nuxt-link to="/agenda-culturel" style="text-decoration: none">
  73. <v-btn text>
  74. <v-icon left class="fas fa-calendar icon"></v-icon>
  75. </v-btn>
  76. </nuxt-link>
  77. </v-app-bar>
  78. <!-- Tiroir de navigation principal -->
  79. <v-navigation-drawer
  80. v-model="isMenuOpen"
  81. app
  82. temporary
  83. >
  84. <v-list nav dense>
  85. <v-list-item
  86. v-if="isSubMenu"
  87. class="menuItem back-item"
  88. @click="onBackItemClick"
  89. >
  90. <v-list-item-title>
  91. <v-icon icon="fas fa-caret-left" class="mr-1"/> Retour
  92. </v-list-item-title>
  93. </v-list-item>
  94. <v-list-item
  95. v-for="(item, index) in activeMenu"
  96. :key="item.label"
  97. :to="item.to"
  98. class="menuItem"
  99. @click="onMenuItemClick(index, item)"
  100. >
  101. <v-list-item-title>
  102. {{ item.label }}
  103. </v-list-item-title>
  104. </v-list-item>
  105. </v-list>
  106. </v-navigation-drawer>
  107. </v-app>
  108. </template>
  109. <script setup lang="ts">
  110. import { useDisplay } from "vuetify";
  111. import type { MainMenuItem } from "~/types/interface";
  112. const { mdAndUp } = useDisplay();
  113. const menu: Array<MainMenuItem> = [
  114. {
  115. label: "Nos logiciels",
  116. children: [
  117. { label: "Opentalent Artist", to: "/opentalent_artist" },
  118. { label: "Opentalent School", to: "/opentalent_school" },
  119. { label: "Opentalent Manager", to: "/opentalent_manager" },
  120. ]
  121. },
  122. {
  123. label: "Nos services",
  124. children: [
  125. { label: "Formations", to: "/formations" },
  126. { label: "Webinaires", to: "/webinaires" },
  127. ]
  128. },
  129. {
  130. label: "À propos",
  131. children: [
  132. { label: "Qui sommes-nous", to: "/qui-sommes-nous" },
  133. { label: "Nous rejoindre", to: "/nous-rejoindre" },
  134. ]
  135. },
  136. { label: "Actualités", to: "/actualites" },
  137. { label: "Contact", to: "/nous-contacter" },
  138. ]
  139. // Menu dépliant (petit écran)
  140. const isMenuOpen: Ref<boolean> = ref(false);
  141. const toggleMenu = () => {
  142. isMenuOpen.value = !isMenuOpen.value;
  143. };
  144. const activeMenuIndex: Ref<number | null> = ref(null)
  145. const activeMenu = computed(() =>
  146. activeMenuIndex.value !== null ? menu[activeMenuIndex.value].children : menu
  147. )
  148. /**
  149. * Determines if the is active menu is a sub-menu .
  150. *
  151. * @function isSubMenu
  152. * @returns {boolean} - True if a sub-menu is active, otherwise false.
  153. */
  154. const isSubMenu = computed(() => activeMenuIndex.value !== null)
  155. /**
  156. * Handles the click event on a menu item.
  157. *
  158. * @param {number} index - The index of the clicked menu item.
  159. * @param {MainMenuItem} item - The clicked menu item.
  160. * @returns {void}
  161. */
  162. const onMenuItemClick = (index: number, item: MainMenuItem): void => {
  163. if (!item.children) {
  164. return
  165. }
  166. withAnimation(() => activeMenuIndex.value = index)
  167. }
  168. /**
  169. * Function to handle back button click event.
  170. */
  171. const onBackItemClick = (): void => {
  172. withAnimation(() => activeMenuIndex.value = null)
  173. }
  174. /**
  175. * Déclenche une animation de changement de menu en fermant et rouvrant le drawer
  176. * @param callback
  177. */
  178. const withAnimation = (callback: () => void) => {
  179. isMenuOpen.value = false
  180. callback()
  181. setTimeout(() => {isMenuOpen.value = true}, 85)
  182. }
  183. </script>
  184. <style scoped>
  185. .logo {
  186. height: 8rem;
  187. }
  188. .logo-md {
  189. width: 150px;
  190. height: 300px;
  191. }
  192. .icon {
  193. color: #000000;
  194. }
  195. .menuItem, .menuItem .v-list-item-title {
  196. font-family: "Barlow", serif;
  197. font-style: normal;
  198. font-weight: 500;
  199. font-size: 0.9rem;
  200. letter-spacing: 0.1em;
  201. text-transform: uppercase;
  202. color: #0e2d32;
  203. cursor: pointer;
  204. text-decoration: none !important;
  205. }
  206. /**
  207. Navigation grands écrans
  208. */
  209. .navigation-lg {
  210. display: flex;
  211. align-items: center;
  212. background-color: #ffffff;
  213. .menuItem {
  214. padding: 18px;
  215. }
  216. .menuItem.first-level {
  217. font-size: 1rem;
  218. margin-right: 1rem;
  219. font-weight: 700;
  220. letter-spacing: 0.05em;
  221. }
  222. }
  223. /**
  224. Navigation petits écrans
  225. */
  226. .navigation-sm {
  227. background-color: #ffffff;
  228. position: fixed;
  229. top: 0;
  230. }
  231. .back-item {
  232. border-bottom: solid 1px darkgray;
  233. border-radius: 0;
  234. .v-list-item-title {
  235. display: flex;
  236. align-items: center;
  237. }
  238. }
  239. </style>