Olivier Massot 1 год назад
Родитель
Сommit
2273cc7986

+ 106 - 89
components/Common/StickyMenu.vue

@@ -1,29 +1,36 @@
+<!--
+Menu d'actions rapides (appel, contact, ...), qui reste accroché au bord droit
+de l'écran (ou au bas de l'écran sur les petits écrans)
+-->
+
 <template>
-  <div class="sticky-menu">
-    <div class="container-square" v-if="lgAndUp">
-      <v-row
-        v-for="(action, index) in actionsOrDefault"
-        :key="index"
-        :class="['square', action.bgColor]"
-        @click="() => onActionClick(action)"
-      >
-        <NuxtLink :to="action.url" class="link">
-          <div>
-            <v-icon :class="action.iconClass" />
-            <p class="text-square mt-2">{{ action.text }}</p>
-          </div>
-        </NuxtLink>
-      </v-row>
-    </div>
-
-    <div class="band" v-else-if="!layoutStore.isFooterVisible">
-      <v-btn color="#9edbdd">
-        Nous contacter
-      </v-btn>
-      <v-btn color="#0e2d32" style="color: white;">
-        Nous appeler
-      </v-btn>
-    </div>
+  <!-- Écrans larges : menu lateral -->
+  <div class="sticky-menu lateral" v-if="lgAndUp">
+    <v-row
+      v-for="(action, index) in actionsOrDefault"
+      :key="index"
+      :class="['square', action.bgColor]"
+      @click="() => onActionClick(action)"
+    >
+      <NuxtLink :to="action.url" class="link">
+        <div>
+          <v-icon :class="action.iconClass" />
+          <p class="text-square mt-2">{{ action.text }}</p>
+        </div>
+      </NuxtLink>
+    </v-row>
+  </div>
+
+  <!-- Petits : menu sous forme de bandeau en pied de page (sauf si le footer du site est visible) -->
+  <div class="sticky-menu band" v-else-if="!layoutStore.isFooterVisible">
+    <v-btn
+      v-for="(action, index) in actionsOrDefault"
+      :key="index"
+      :class="[action.bgColor]"
+      @click="() => onActionClick(action)"
+    >
+      {{ action.text }}
+    </v-btn>
   </div>
 </template>
 
@@ -38,9 +45,12 @@ import { StickyMenuAction } from "~/types/interface";
 const { mdAndDown, lgAndUp } = useDisplay();
 const router = useRouter();
 const layoutStore = useLayoutStore()
+const { isMobileDevice } = useClientDevice()
 
+// TODO: passer en conf?
 const telephoneNumber = "09 72 12 60 17";
 
+// Actions par défaut du menu, peut-être surchargé via la propriété `actions`
 const defaultActions: Array<StickyMenuAction> = [
   {
     type: StickyMenuActionType.FOLLOW_LINK,
@@ -58,6 +68,9 @@ const defaultActions: Array<StickyMenuAction> = [
 ];
 
 const props = defineProps({
+  /**
+   * Actions accessibles via le menu (par défaut: "Nous contacter", "Nous appeller")
+   */
   actions: {
     type: Array<StickyMenuAction>,
     required: false,
@@ -69,45 +82,57 @@ const actionsOrDefault: ComputedRef<Array<StickyMenuAction>> = computed(() => {
   return props.actions.length > 0 ? props.actions : defaultActions
 })
 
-const onActionClick = (action: StickyMenuAction) => {
-  if (action.type === StickyMenuActionType.ASK_FOR_A_DEMO) {
-    router.push({ path: action.url, query: { request: "demo" } });
-  } else if (action.type === StickyMenuActionType.CALL_US) {
-    if (isMobileDevice()) {
-      window.location.href = `tel:${telephoneNumber}`;
-    } else {
-      alert(`Notre numéro de téléphone : ${telephoneNumber}`);
-    }
-  } else if (action.url) {
-    router.push({ path: action.url });
+const callUs = () => {
+  if (isMobileDevice()) {
+    window.location.href = `tel:${telephoneNumber}`;
   } else {
-    throw Error('Unrecognized action')
+    alert(`Notre numéro de téléphone : ${telephoneNumber}`);
   }
-};
+}
 
-const isMobileDevice = () => {
-  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
-    navigator.userAgent
-  );
+/**
+ * On a cliqué sur une des actions du menu
+ * @param action
+ */
+const onActionClick = (action: StickyMenuAction) => {
+  switch (action.type) {
+    case StickyMenuActionType.ASK_FOR_A_DEMO:
+      router.push({ path: action.url, query: { request: "demo" } });
+      break;
+
+    case StickyMenuActionType.CALL_US:
+      callUs()
+      break;
+
+    case StickyMenuActionType.FOLLOW_LINK:
+      if (!action.url) {
+        throw Error('Missing prop : url')
+      }
+      router.push({ path: action.url });
+      break
+
+    default:
+      throw Error('Unrecognized action')
+  }
 };
+
+
 </script>
 
 <style scoped lang="scss">
-.square {
-  transition: transform 0.3s ease-in-out;
-}
 
-.square:hover {
-  transform: translateX(-10px);
+.sticky-menu {
+  z-index: 100;
 }
 
-.link {
-  text-decoration: none;
-  color: white;
-}
+// Menu format lateral (pour affichage écrans larges)
+.sticky-menu.lateral {
+  position: sticky;
+  right: 0;
+  top: 50%;
+  transform: translateY(-50%);
+  float: right;
 
-.container-square {
-  text-align: center !important;
   display: flex;
   flex-direction: column;
   color: white;
@@ -119,16 +144,38 @@ const isMobileDevice = () => {
   text-transform: uppercase;
 }
 
-.red-square,
-.yellow-square,
-.blue-square,
-.darkblue-square,
-.green-square {
+// Menu format ruban (pour affichage petits écrans)
+.sticky-menu.band {
+  position: fixed;
+  height: 46px;
+  bottom: 0;
+  width: 100%;
+  display: flex;
+  justify-content: center;
+  background-color: white;
+
+  .v-btn {
+    margin: 4px 6px;
+  }
+}
+
+.square {
   position: relative;
-  font-family: "Barlow";
+  font-family: "Barlow", serif;
   width: 7rem;
   padding: 1rem;
   cursor: pointer;
+
+  transition: transform 0.3s ease-in-out;
+}
+
+.square:hover {
+  transform: translateX(-10px);
+}
+
+.link {
+  text-decoration: none;
+  color: white;
 }
 
 .yellow-square {
@@ -151,34 +198,4 @@ const isMobileDevice = () => {
 .darkblue-square {
   background: #0e2d32;
 }
-
-.text-square {
-}
-
-@media (min-width: 1280px) {
-  .sticky-menu {
-    position: sticky;
-    //right: 0;
-    top: 50%;
-    transform: translateY(-50%);
-    z-index: 1;
-    float: right;
-  }
-}
-
-// Menu format ruban (pour affichage petits écrans)
-.sticky-menu .band {
-  position: fixed;
-  height: 46px;
-  bottom: 0;
-  width: 100%;
-  display: flex;
-  justify-content: center;
-  background-color: white;
-  z-index: 100;
-
-  .v-btn {
-    margin: 4px 6px;
-  }
-}
 </style>

+ 14 - 0
composables/useClientDevice.ts

@@ -0,0 +1,14 @@
+import { NitroFetchRequest } from "nitropack";
+
+
+export function useClientDevice() {
+  const isMobileDevice = () => {
+    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
+      navigator.userAgent
+    );
+  }
+
+  return {
+    isMobileDevice
+  }
+}

+ 10 - 3
pages/formations.vue

@@ -2,24 +2,31 @@
   <LayoutNavigation />
 
   <FormationBanner />
+
   <CommonMenuScroll :menus="menus" class="mb-6" />
 
   <CommonStickyMenu />
 
   <FormationPresentation />
+
   <FormationCatalogue />
+
   <FormationOPCA />
+
   <FormationCertification />
+
   <FormationParticipation />
+
   <FormationReviews />
+
   <LayoutFAQ />
+
   <LayoutFooterSolutionsFooter id="layout-footer" />
+
   <LayoutFooter id="layout-footer" />
 </template>
 
-<script setup>
-import { ref, onMounted } from "vue";
-
+<script setup lang="ts">
 const menus = ref([
   { id: "Presentation", label: "Présentation", element: null },
   { id: "Catalogue", label: "Catalogue", element: null },

+ 20 - 45
pages/opentalent_artist.vue

@@ -3,26 +3,34 @@
   <LogicielsArtistBanner />
   <CommonMenuScroll :menus="menus" class="mb-6" />
 
-  <div v-if="shouldShowStickyMenu" id="sticky-menu">
-    <CommonStickyMenu
-      :shouldShowStickyMenu="shouldShowStickyMenu"
-      :squaresData="squaresData"
-    />
-  </div>
+  <CommonStickyMenu :actions="stickyMenuActions" />
+
   <LogicielsArtistPresentation />
+
   <LogicielsArtistAvantages />
+
   <LogicielsArtistFonctionnalites />
+
   <LogicielsArtistComparatif />
+
   <LogicielsArtistAbonnement />
+
   <LogicielsArtistFormations />
+
   <LogicielsArtistReviews />
+
   <LayoutFAQ />
+
   <LayoutFooterPrefooter />
-  <LayoutFooter id="layout-footer" />
+
+  <LayoutFooter />
 </template>
 
-<script setup>
-import { ref, onMounted } from "vue";
+<script setup lang="ts">
+import { ref } from "vue";
+import { StickyMenuActionType } from "~/types/enum/layout";
+import { StickyMenuAction } from "~/types/interface";
+
 const menus = ref([
   { id: "Presentation", label: "Présentation", element: null },
   { id: "Avantages", label: "Avantages", element: null },
@@ -33,56 +41,23 @@ const menus = ref([
   { id: "Temoignages", label: "Témoignages", element: null },
 ]).value;
 
-const shouldShowStickyMenu = ref(true);
-
-const squaresData = [
+const stickyMenuActions: Array<StickyMenuAction> = [
   {
-    id: 1,
+    type: StickyMenuActionType.FOLLOW_LINK,
     bgColor: "yellow-square",
     iconClass: "fa-regular fa-comments icon",
     text: "Nous contacter",
     url: "/nous-contacter",
   },
   {
-    id: 2,
+    type: StickyMenuActionType.FOLLOW_LINK,
     bgColor: "yellow-square",
     iconClass: "fa-solid fa-circle-info icon",
     text: "Brochure",
     url: "https://www.opentalent.fr/fileadmin/stockage/commercial/plaquettes_commerciales/Depliant_Opentalent_Artist_23.pdf ",
   }
 ];
-
-onMounted(() => {
-  const stickyMenu = document.getElementById("sticky-menu");
-  const footer = document.getElementById("layout-footer");
-
-  const observer = new IntersectionObserver(
-    ([entry]) => {
-      shouldShowStickyMenu.value = !entry.isIntersecting;
-    },
-    {
-      root: null,
-      threshold: 0,
-    }
-  );
-
-  observer.observe(footer);
-});
 </script>
 
 <style scoped>
-#sticky-menu {
-  position: sticky;
-  top: 25rem;
-  z-index: 10;
-  margin-bottom: -35rem;
-  float: right;
-}
-
-@media (max-width: 1800px) {
-  #sticky-menu {
-    top: 16rem;
-    margin-bottom: -28rem;
-  }
-}
 </style>

+ 23 - 46
pages/opentalent_manager.vue

@@ -1,27 +1,36 @@
 <template>
   <LayoutNavigation />
+
   <LogicielsManagerBanner />
+
   <CommonMenuScroll :menus="menus" class="mb-6" />
 
-  <div v-if="shouldShowStickyMenu" id="sticky-menu">
-    <CommonStickyMenu
-      :shouldShowStickyMenu="shouldShowStickyMenu"
-      :squaresData="squaresData"
-    />
-  </div>
+  <CommonStickyMenu :actions="stickyMenuActions" />
+
   <LogicielsManagerPresentation />
+
   <LogicielsManagerAvantages />
+
   <LogicielsManagerFonctionnalites />
+
   <LogicielsManagerPyramide />
+
   <LogicielsManagerFormation />
+
   <LogicielsManagerReviews />
+
   <LayoutFAQ />
-  <LayoutFooterSolutionsFooter/>
-  <LayoutFooter id="layout-footer" />
+
+  <LayoutFooterSolutionsFooter />
+
+  <LayoutFooter />
+
 </template>
 
-<script setup>
-import { ref, onMounted } from "vue";
+<script setup lang="ts">
+import { StickyMenuAction } from "~/types/interface";
+import { StickyMenuActionType } from "~/types/enum/layout";
+
 const menus = ref([
   { id: "Presentation", label: "Présentation", element: null },
   { id: "Avantages", label: "Avantages", element: null },
@@ -29,63 +38,31 @@ const menus = ref([
   { id: "Formations", label: "Formations", element: null },
   { id: "Temoignages", label: "Témoignages", element: null },
 ]).value;
-const shouldShowStickyMenu = ref(true);
 
-const squaresData = [
+const stickyMenuActions: Array<StickyMenuAction> = [
   {
-    id: 1,
+    type: StickyMenuActionType.FOLLOW_LINK,
     bgColor: "red-square",
     iconClass: "fa-regular fa-comments icon",
     text: "Nous contacter",
     url: "/nous-contacter",
   },
   {
-    id: 2,
+    type: StickyMenuActionType.FOLLOW_LINK,
     bgColor: "red-square",
     iconClass: "fa-brands fa-readme icon",
     text: "Brochure",
     url: "https://www.opentalent.fr/fileadmin/user_upload/Manager.pdf",
   },
   {
-    id: 4,
+    type: StickyMenuActionType.CALL_US,
     bgColor: "darkblue-square",
     iconClass: "fa-solid fa-phone icon",
     text: "Nous appeler",
   },
 ];
-
-onMounted(() => {
-  const stickyMenu = document.getElementById("sticky-menu");
-  const footer = document.getElementById("layout-footer");
-
-  const observer = new IntersectionObserver(
-    ([entry]) => {
-      shouldShowStickyMenu.value = !entry.isIntersecting;
-    },
-    {
-      root: null,
-      threshold: 0,
-    }
-  );
-
-  observer.observe(footer);
-});
 </script>
 
 
 <style scoped>
-#sticky-menu {
-  position: sticky;
-  top: 25rem;
-  z-index: 10;
-  margin-bottom: -35rem;
-  float: right;
-}
-
-@media (max-width: 1800px) {
-  #sticky-menu {
-    top: 16rem;
-    margin-bottom: -28rem;
-  }
-}
 </style>

+ 24 - 28
pages/opentalent_school.vue

@@ -1,30 +1,38 @@
 <template>
   <LayoutNavigation />
+
   <LogicielsSchoolBanner />
+
   <CommonMenuScroll :menus="menus" class="mb-6" />
 
-  <div v-if="shouldShowStickyMenu" id="sticky-menu" class="mt-6">
-    <CommonStickyMenu
-      :shouldShowStickyMenu="shouldShowStickyMenu"
-      :squaresData="squaresData"
-    />
-  </div>
+  <CommonStickyMenu :actions="stickyMenuActions" />
+
   <LogicielsSchoolPresentation />
+
   <LogicielsSchoolAvantages />
+
   <LogicielsSchoolFonctionnalites />
+
   <LogicielsSchoolComparatif />
+
   <LogicielsSchoolProjet />
+
   <LogicielsSchoolFormations />
+
   <LogicielsSchoolReviews />
+
   <LayoutFAQ  />
+
   <LayoutFooterSolutionsFooter />
-  <LayoutFooter id="layout-footer" />
+
+  <LayoutFooter />
 </template>
 
-<script setup>
+<script setup lang="ts">
 import { ref } from "vue";
+import { StickyMenuAction } from "~/types/interface";
+import { StickyMenuActionType } from "~/types/enum/layout";
 
-const shouldShowStickyMenu = ref(true);
 const menus = ref([
   { id: "Presentation", label: "Présentation", element: null },
   { id: "Avantages", label: "Avantages", element: null },
@@ -34,30 +42,32 @@ const menus = ref([
   { id: "Formations", label: "Formations", element: null },
   { id: "Temoignages", label: "Temoignages", element: null },
 ]).value;
-const squaresData = [
+
+
+const stickyMenuActions: Array<StickyMenuAction> = [
   {
-    id: 1,
+    type: StickyMenuActionType.FOLLOW_LINK,
     bgColor: "blue-square",
     iconClass: "fa-regular fa-comments icon",
     text: "Nous contacter",
     url: "/nous-contacter",
   },
   {
-    id: 2,
+    type: StickyMenuActionType.FOLLOW_LINK,
     bgColor: "blue-square",
     iconClass: "fa-solid fa-circle-info icon",
     text: "Demander une demo",
     url: "/nous-contacter",
   },
   {
-    id: 3,
+    type: StickyMenuActionType.FOLLOW_LINK,
     bgColor: "blue-square",
     iconClass: "fa-brands fa-readme icon",
     text: "Brochure",
     url: "https://www.opentalent.fr/fileadmin/stockage/commercial/plaquettes_commerciales/De%CC%81pliant-school_23.pdf",
   },
   {
-    id: 4,
+    type: StickyMenuActionType.CALL_US,
     bgColor: "darkblue-square",
     iconClass: "fa-solid fa-phone icon",
     text: "Nous Appeler",
@@ -67,18 +77,4 @@ const squaresData = [
 </script>
 
 <style scoped>
-#sticky-menu {
-  position: sticky;
-  top: 25rem;
-  z-index: 10;
-  margin-bottom: -35rem;
-  float: right;
-}
-
-@media (max-width: 1800px) {
-  #sticky-menu {
-    top: 16rem;
-    margin-bottom: -28rem;
-  }
-}
 </style>

+ 11 - 4
pages/qui-sommes-nous.vue

@@ -2,24 +2,31 @@
   <LayoutNavigation />
 
   <AboutBanner />
+
   <CommonMenuScroll :menus="menus" class="mb-6" />
 
   <CommonStickyMenu />
 
   <AboutHistoire />
+
   <AboutValeurs />
+
   <AboutLogiciels />
+
   <AboutAgenda />
+
   <AboutChronologie />
+
   <AboutEquipe />
+
   <AboutFAQ />
+
   <LayoutFooterPrefooter />
-  <LayoutFooter id="layout-footer" />
-</template>
 
-<script setup>
-import { ref } from "vue";
+  <LayoutFooter />
+</template>
 
+<script setup lang="ts">
 const menus = ref([
   { id: "Qui-sommes-nous", label: "Qui sommes-nous", element: null },
   { id: "valeurs", label: "Nos valeurs", element: null },

+ 5 - 4
pages/webinaires.vue

@@ -4,16 +4,17 @@
   <CommonStickyMenu />
 
   <WebinaireBanner />
+
   <WebinaireCatalogue />
+
   <WebinaireFAQ />
+
   <LayoutPrefooter />
-  <LayoutFooter id="layout-footer" />
+
+  <LayoutFooter />
 </template>
 
 <script setup>
-import { useRouter } from 'vue-router';
-
-const router = useRouter();
 </script>
 
 <style scoped>