- Create header_controller.js to handle mobile menu and user dropdown - Replace Alpine.js directives with Stimulus data attributes in header component - Add proper event handling for click outside to close menus - Maintain all existing functionality with improved code consistency
73 lines
2.5 KiB
JavaScript
73 lines
2.5 KiB
JavaScript
import { Controller } from "@hotwired/stimulus"
|
|
|
|
// Controller for handling the header navigation
|
|
// Manages mobile menu toggle and user dropdown menu
|
|
export default class extends Controller {
|
|
static targets = ["mobileMenu", "mobileMenuButton", "userMenu", "userMenuButton"]
|
|
|
|
connect() {
|
|
// Initialize menu states
|
|
this.mobileMenuOpen = false
|
|
this.userMenuOpen = false
|
|
|
|
// Add click outside listener for user menu
|
|
this.clickOutsideHandler = this.handleClickOutside.bind(this)
|
|
document.addEventListener("click", this.clickOutsideHandler)
|
|
}
|
|
|
|
disconnect() {
|
|
// Clean up event listener
|
|
document.removeEventListener("click", this.clickOutsideHandler)
|
|
}
|
|
|
|
// Toggle mobile menu visibility
|
|
toggleMobileMenu() {
|
|
this.mobileMenuOpen = !this.mobileMenuOpen
|
|
this.mobileMenuTarget.classList.toggle("hidden", !this.mobileMenuOpen)
|
|
|
|
// Update button icon based on state
|
|
const iconOpen = this.mobileMenuButtonTarget.querySelector('[data-menu-icon="open"]')
|
|
const iconClose = this.mobileMenuButtonTarget.querySelector('[data-menu-icon="close"]')
|
|
|
|
if (iconOpen && iconClose) {
|
|
iconOpen.classList.toggle("hidden", this.mobileMenuOpen)
|
|
iconClose.classList.toggle("hidden", !this.mobileMenuOpen)
|
|
}
|
|
}
|
|
|
|
// Toggle user dropdown menu visibility
|
|
toggleUserMenu() {
|
|
this.userMenuOpen = !this.userMenuOpen
|
|
if (this.hasUserMenuTarget) {
|
|
this.userMenuTarget.classList.toggle("hidden", !this.userMenuOpen)
|
|
}
|
|
}
|
|
|
|
// Close menus when clicking outside
|
|
handleClickOutside(event) {
|
|
// Close user menu if clicked outside
|
|
if (this.userMenuOpen && this.hasUserMenuTarget &&
|
|
!this.userMenuTarget.contains(event.target) &&
|
|
!this.userMenuButtonTarget.contains(event.target)) {
|
|
this.userMenuOpen = false
|
|
this.userMenuTarget.classList.add("hidden")
|
|
}
|
|
|
|
// Close mobile menu if clicked outside
|
|
if (this.mobileMenuOpen &&
|
|
!this.mobileMenuTarget.contains(event.target) &&
|
|
!this.mobileMenuButtonTarget.contains(event.target)) {
|
|
this.mobileMenuOpen = false
|
|
this.mobileMenuTarget.classList.add("hidden")
|
|
|
|
// Update button icon
|
|
const iconOpen = this.mobileMenuButtonTarget.querySelector('[data-menu-icon="open"]')
|
|
const iconClose = this.mobileMenuButtonTarget.querySelector('[data-menu-icon="close"]')
|
|
|
|
if (iconOpen && iconClose) {
|
|
iconOpen.classList.remove("hidden")
|
|
iconClose.classList.add("hidden")
|
|
}
|
|
}
|
|
}
|
|
} |