develop #3

Merged
kbe merged 227 commits from develop into main 2025-09-16 14:35:23 +00:00
3 changed files with 87 additions and 12 deletions
Showing only changes of commit 9404f10c93 - Show all commits

View File

@@ -0,0 +1,73 @@
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")
}
}
}
}

View File

@@ -2,10 +2,8 @@
// Run that command whenever you add a new controller or create them with
// ./bin/rails generate stimulus controllerName
// Import the main Stimulus application
import { application } from "./application"
// Import all controllers
import LogoutController from "./logout_controller";
application.register("logout", LogoutController);
@@ -18,6 +16,9 @@ application.register("flash-message", FlashMessageController);
import TicketSelectionController from "./ticket_selection_controller"
application.register("ticket-selection", TicketSelectionController);
import HeaderController from "./header_controller"
application.register("header", HeaderController);

View File

@@ -1,5 +1,5 @@
<header class="bg-neutral-800 border-b border-neutral-700">
<nav x-data="{ open: false }" class="container mx-auto px-4 sm:px-6 lg:px-8">
<nav data-controller="header" class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<!-- Logo & Navigation -->
<div class="flex items-center space-x-8">
@@ -17,8 +17,8 @@
<!-- Authentication -->
<div class="flex items-center space-x-4">
<% if user_signed_in? %>
<div class="relative" x-data="{ open: false }" @click.outside="open = false">
<button @click="open = !open"
<div class="relative" data-header-target="userMenuButton">
<button data-action="click->header#toggleUserMenu"
class="bg-purple-700 text-white border border-purple-800 font-medium py-2 px-4 rounded-lg hover:bg-purple-800 transition-colors duration-200 flex items-center space-x-2">
<span><%= current_user.email.length > 20 ? current_user.email[0,20] + "..." : current_user.email %></span>
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
@@ -26,8 +26,7 @@
</svg>
</button>
<div x-show="open" x-transition
class="absolute right-0 mt-2 w-48 rounded-md shadow-lg z-50">
<div data-header-target="userMenu" class="absolute right-0 mt-2 w-48 rounded-md shadow-lg z-50 hidden">
<%= link_to t("header.profile"), edit_user_registration_path,
class: "block px-4 py-2 text-sm bg-black text-gray-100 hover:bg-purple-700 first:rounded-t-md" %>
<%= link_to t("header.reservations"), "#",
@@ -47,17 +46,19 @@
</div>
<% end %>
<!-- Mobile Menu Button -->
<button @click="open = !open" class="sm:hidden p-2 rounded-md text-neutral-300 hover:text-white hover:bg-purple-700">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path :class="{ "hidden": open }" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
<path :class="{ "hidden": !open }" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
<button data-action="click->header#toggleMobileMenu" data-header-target="mobileMenuButton" class="sm:hidden p-2 rounded-md text-neutral-300 hover:text-white hover:bg-purple-700">
<svg data-menu-icon="open" class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg data-menu-icon="close" class="h-6 w-6 hidden" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<!-- Mobile Menu -->
<div :class="{ "block": open, "hidden": !open }" class="hidden sm:hidden">
<div data-header-target="mobileMenu" class="hidden sm:hidden">
<div class="px-2 pt-2 pb-3 space-y-1">
<%= link_to t("header.parties"), events_path,
class: "block px-3 py-2 rounded-md text-base font-medium bg-black text-gray-100 hover:text-purple-200 hover:bg-purple-700" %>