ソースを参照

handle hydratation better

Olivier Massot 1 年間 前
コミット
3c6140b501
3 ファイル変更56 行追加41 行削除
  1. 1 0
      .eslintrc.cjs
  2. 48 40
      components/Common/ActionMenu.vue
  3. 7 1
      components/Layout/Navigation.vue

+ 1 - 0
.eslintrc.cjs

@@ -47,5 +47,6 @@ module.exports = {
     useLayoutStore: 'readonly',
     useClientDevice: 'readonly',
     useSeoMeta: 'readonly',
+    onNuxtReady: 'readonly',
   },
 }

+ 48 - 40
components/Common/ActionMenu.vue

@@ -3,46 +3,51 @@ 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>
-  <!-- Écrans larges : menu lateral, accroché au bord droit de l'écran -->
-  <div v-if="lgAndUp && isVisible" class="sticky-menu lateral">
-    <v-row
-      v-for="(action, index) in actionsOrDefault"
-      :key="index"
-      :class="['square', action.color]"
-      @click="() => onActionClick(action)"
+  <div v-show="showMenu">
+    <!-- Écrans larges : menu lateral, accroché au bord droit de l'écran -->
+    <div
+      v-if="lgAndUp && isVisible"
+      class="sticky-menu lateral"
     >
-      <NuxtLink class="link">
-        <div>
-          <v-icon :class="action.icon" />
-
-          <p class="text-square mt-2">
-            {{ action.text }}
-          </p>
-        </div>
-      </NuxtLink>
-    </v-row>
-  </div>
+      <v-row
+        v-for="(action, index) in actionsOrDefault"
+        :key="index"
+        :class="['square', action.color]"
+        @click="() => onActionClick(action)"
+      >
+        <NuxtLink class="link">
+          <div>
+            <v-icon :class="action.icon" />
+
+            <p class="text-square mt-2">
+              {{ action.text }}
+            </p>
+          </div>
+        </NuxtLink>
+      </v-row>
+    </div>
+
+    <!-- Petits écrans : menu sous forme de bandeau en pied de page (sauf si le footer du site est visible) -->
+    <div v-else-if="isVisible" class="sticky-menu band">
+      <v-btn
+        v-for="(action, index) in actionsOrDefault"
+        :key="index"
+        :class="[action.color]"
+        @click="() => onActionClick(action)"
+      >
+        <span v-if="mdAndUp">{{ action.text }}</span>
+        <v-icon v-else>{{ action.icon }}</v-icon>
+      </v-btn>
+    </div>
 
-  <!-- Petits écrans : menu sous forme de bandeau en pied de page (sauf si le footer du site est visible) -->
-  <div v-else-if="isVisible" class="sticky-menu band">
     <v-btn
-      v-for="(action, index) in actionsOrDefault"
-      :key="index"
-      :class="[action.color]"
-      @click="() => onActionClick(action)"
+      v-if="isVisible"
+      :to="{ path: '', hash: '#top' }"
+      class="back-to-the-top secondary"
     >
-      <span v-if="mdAndUp">{{ action.text }}</span>
-      <v-icon v-else>{{ action.icon }}</v-icon>
+      <v-icon>fas fa-arrow-up</v-icon>
     </v-btn>
   </div>
-
-  <v-btn
-    v-if="isVisible"
-    :to="{ path: '', hash: '#top' }"
-    class="back-to-the-top secondary"
-  >
-    <v-icon>fas fa-arrow-up</v-icon>
-  </v-btn>
 </template>
 
 <script setup lang="ts">
@@ -67,6 +72,12 @@ const isVisible: ComputedRef<boolean> = computed(
     !layoutStore.isFooterVisible
 )
 
+// Attend l'hydratation avant d'afficher
+const showMenu = ref(false)
+onNuxtReady(() => {
+  showMenu.value = true
+})
+
 // Actions par défaut du menu, peut-être surchargé via la propriété `actions`
 const defaultActions: Array<ActionMenuItem> = [
   {
@@ -125,12 +136,9 @@ const onActionClick = (action: ActionMenuItem) => {
       if (!action.url) {
         throw new Error('Missing prop : url')
       }
-      navigateTo(
-        action.url,
-        {
-          open: { target: '_blank' }
-        }
-      )
+      navigateTo(action.url, {
+        open: { target: '_blank' },
+      })
       break
 
     default:

+ 7 - 1
components/Layout/Navigation.vue

@@ -4,7 +4,7 @@ Menu Navigation
 <template>
   <div v-intersect="onIntersect">
     <!-- Navigation (écran large) -->
-    <div v-if="lgAndUp">
+    <div v-if="lgAndUp || !nuxtReady">
       <LayoutNavigationLg :menu="menu" />
     </div>
 
@@ -22,6 +22,12 @@ import { useLayoutStore } from '~/stores/layoutStore'
 
 const { lgAndUp } = useDisplay()
 
+// On force la version écran large au build côté serveur
+const nuxtReady = ref(false)
+onNuxtReady(() => {
+  nuxtReady.value = true
+})
+
 const menu: Array<MainMenuItem> = [
   {
     label: 'Nos logiciels',