From 046f464378dadcf509e52048053bbbbfda1c0f9a Mon Sep 17 00:00:00 2001 From: Matthieu Date: Mon, 9 Feb 2026 11:20:04 +0100 Subject: [PATCH] refactor(layout): extract AppNavbar component and rewrite app.vue (F7.3) Extract 680-line navbar into LayoutAppNavbar component with useNavDropdown composable. app.vue reduced from 698 to 22 LOC. Co-Authored-By: Claude Opus 4.6 --- app/app.vue | 857 +--------------------------- app/components/layout/AppNavbar.vue | 368 ++++++++++++ app/composables/useNavDropdown.ts | 65 +++ 3 files changed, 456 insertions(+), 834 deletions(-) create mode 100644 app/components/layout/AppNavbar.vue create mode 100644 app/composables/useNavDropdown.ts diff --git a/app/app.vue b/app/app.vue index f616b54..e775de4 100644 --- a/app/app.vue +++ b/app/app.vue @@ -1,698 +1,22 @@ - - - diff --git a/app/components/layout/AppNavbar.vue b/app/components/layout/AppNavbar.vue new file mode 100644 index 0000000..50eacb5 --- /dev/null +++ b/app/components/layout/AppNavbar.vue @@ -0,0 +1,368 @@ + + + + + diff --git a/app/composables/useNavDropdown.ts b/app/composables/useNavDropdown.ts new file mode 100644 index 0000000..be15873 --- /dev/null +++ b/app/composables/useNavDropdown.ts @@ -0,0 +1,65 @@ +import { ref, watch, onUnmounted } from 'vue' +import { useRoute } from '#imports' + +export function useNavDropdown() { + const openDropdown = ref(null) + let dropdownCloseTimer: ReturnType | null = null + const route = useRoute() + + const setDropdown = (name: string) => { + if (dropdownCloseTimer) { + clearTimeout(dropdownCloseTimer) + dropdownCloseTimer = null + } + if (openDropdown.value !== name) { + openDropdown.value = name + } + } + + const scheduleDropdownClose = (name: string) => { + if (dropdownCloseTimer) { + clearTimeout(dropdownCloseTimer) + } + dropdownCloseTimer = setTimeout(() => { + if (openDropdown.value === name) { + openDropdown.value = null + } + dropdownCloseTimer = null + }, 200) + } + + const closeDropdownNow = () => { + if (dropdownCloseTimer) { + clearTimeout(dropdownCloseTimer) + dropdownCloseTimer = null + } + openDropdown.value = null + } + + const toggleDropdown = (name: string) => { + if (openDropdown.value === name) { + closeDropdownNow() + return + } + setDropdown(name) + } + + watch(() => route.fullPath, () => { + closeDropdownNow() + }) + + onUnmounted(() => { + if (dropdownCloseTimer) { + clearTimeout(dropdownCloseTimer) + dropdownCloseTimer = null + } + }) + + return { + openDropdown, + setDropdown, + scheduleDropdownClose, + closeDropdownNow, + toggleDropdown, + } +}