StickyMenu.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. <!--
  2. Menu d'actions rapides (appel, contact, ...), qui reste accroché au bord droit
  3. de l'écran (ou au bas de l'écran sur les petits écrans)
  4. -->
  5. <!-- TODO: implémenter le theming ici -->
  6. <template>
  7. <!-- Écrans larges : menu lateral -->
  8. <div class="sticky-menu lateral" v-if="lgAndUp">
  9. <v-row
  10. v-for="(action, index) in actionsOrDefault"
  11. :key="index"
  12. :class="['square', action.bgColor]"
  13. @click="() => onActionClick(action)"
  14. >
  15. <NuxtLink :to="action.url" class="link">
  16. <div>
  17. <v-icon :class="action.iconClass" />
  18. <p class="text-square mt-2">{{ action.text }}</p>
  19. </div>
  20. </NuxtLink>
  21. </v-row>
  22. </div>
  23. <!-- Petits : menu sous forme de bandeau en pied de page (sauf si le footer du site est visible) -->
  24. <div class="sticky-menu band" v-else-if="!layoutStore.isFooterVisible">
  25. <v-btn
  26. v-for="(action, index) in actionsOrDefault"
  27. :key="index"
  28. :class="[action.bgColor]"
  29. @click="() => onActionClick(action)"
  30. >
  31. {{ action.text }}
  32. </v-btn>
  33. </div>
  34. </template>
  35. <script setup lang="ts">
  36. import { useRouter } from "vue-router";
  37. import { useDisplay } from "vuetify";
  38. import { useLayoutStore } from "~/stores/layoutStore";
  39. import { StickyMenuActionType } from "~/types/enum/layout";
  40. import type { StickyMenuAction } from "~/types/interface";
  41. const { mdAndDown, lgAndUp } = useDisplay();
  42. const router = useRouter();
  43. const layoutStore = useLayoutStore()
  44. const { isMobileDevice } = useClientDevice()
  45. // TODO: passer en conf?
  46. const telephoneNumber = "09 72 12 60 17";
  47. // Actions par défaut du menu, peut-être surchargé via la propriété `actions`
  48. const defaultActions: Array<StickyMenuAction> = [
  49. {
  50. type: StickyMenuActionType.FOLLOW_LINK,
  51. bgColor: "green-square",
  52. iconClass: "fa-regular fa-comments icon",
  53. text: "Nous contacter",
  54. url: "/nous-contacter",
  55. },
  56. {
  57. type: StickyMenuActionType.CALL_US,
  58. bgColor: "darkblue-square",
  59. iconClass: "fa-solid fa-phone icon",
  60. text: "Nous Appeler",
  61. },
  62. ];
  63. const props = defineProps({
  64. /**
  65. * Actions accessibles via le menu (par défaut: "Nous contacter", "Nous appeller")
  66. */
  67. actions: {
  68. type: Array<StickyMenuAction>,
  69. required: false,
  70. default: []
  71. }
  72. })
  73. const actionsOrDefault: ComputedRef<Array<StickyMenuAction>> = computed(() => {
  74. return props.actions.length > 0 ? props.actions : defaultActions
  75. })
  76. const callUs = () => {
  77. if (isMobileDevice()) {
  78. window.location.href = `tel:${telephoneNumber}`;
  79. } else {
  80. alert(`Notre numéro de téléphone : ${telephoneNumber}`);
  81. }
  82. }
  83. /**
  84. * On a cliqué sur une des actions du menu
  85. * @param action
  86. */
  87. const onActionClick = (action: StickyMenuAction) => {
  88. switch (action.type) {
  89. case StickyMenuActionType.ASK_FOR_A_DEMO:
  90. router.push({ path: action.url, query: { request: "demo" } });
  91. break;
  92. case StickyMenuActionType.CALL_US:
  93. callUs()
  94. break;
  95. case StickyMenuActionType.FOLLOW_LINK:
  96. if (!action.url) {
  97. throw Error('Missing prop : url')
  98. }
  99. router.push({ path: action.url });
  100. break
  101. default:
  102. throw Error('Unrecognized action')
  103. }
  104. };
  105. </script>
  106. <style scoped lang="scss">
  107. .sticky-menu {
  108. z-index: 100;
  109. }
  110. // Menu format lateral (pour affichage écrans larges)
  111. .sticky-menu.lateral {
  112. position: sticky;
  113. right: 0;
  114. top: 60%;
  115. transform: translateY(-50%);
  116. float: right;
  117. display: flex;
  118. flex-direction: column;
  119. color: white;
  120. font-weight: 500;
  121. font-size: 0.7rem;
  122. line-height: 15px;
  123. text-align: center;
  124. letter-spacing: 0.2em;
  125. text-transform: uppercase;
  126. }
  127. // Menu format ruban (pour affichage petits écrans)
  128. .sticky-menu.band {
  129. position: fixed;
  130. height: 46px;
  131. bottom: 0;
  132. width: 100%;
  133. display: flex;
  134. justify-content: center;
  135. background-color: white;
  136. .v-btn {
  137. margin: 4px 6px;
  138. }
  139. }
  140. .square {
  141. position: relative;
  142. font-family: "Barlow", serif;
  143. width: 7rem;
  144. padding: 1rem;
  145. cursor: pointer;
  146. transition: transform 0.3s ease-in-out;
  147. }
  148. .square:hover {
  149. transform: translateX(-10px);
  150. }
  151. .link {
  152. text-decoration: none;
  153. color: white;
  154. }
  155. .yellow-square {
  156. background: rgb(250, 194, 10);
  157. color: #0e2d32;
  158. }
  159. .green-square {
  160. background: #9edbdd;
  161. }
  162. .red-square {
  163. background: #d8050b;
  164. }
  165. .blue-square {
  166. background: #2093be;
  167. }
  168. .logo-square {
  169. background: var(--Bleu-School-60, rgba(32, 147, 190));
  170. }
  171. .darkblue-square {
  172. background: #0e2d32;
  173. }
  174. </style>