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 <noreply@anthropic.com>
66 lines
1.4 KiB
TypeScript
66 lines
1.4 KiB
TypeScript
import { ref, watch, onUnmounted } from 'vue'
|
|
import { useRoute } from '#imports'
|
|
|
|
export function useNavDropdown() {
|
|
const openDropdown = ref<string | null>(null)
|
|
let dropdownCloseTimer: ReturnType<typeof setTimeout> | 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,
|
|
}
|
|
}
|