Skip to content

Commit f7d8ff5

Browse files
committed
fix
1 parent ceea7b3 commit f7d8ff5

File tree

1 file changed

+104
-67
lines changed

1 file changed

+104
-67
lines changed

src/components/layout/MobileMenu.tsx

Lines changed: 104 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { useState } from "react";
3+
import { useState, useEffect, useCallback } from "react";
44
import Link from "next/link";
55
import { NavItem, isDropdown } from "@/types/navigation";
66
import { trackEvent } from "@/lib/tracking";
@@ -13,10 +13,26 @@ export default function MobileMenu({ items }: MobileMenuProps) {
1313
const [open, setOpen] = useState(false);
1414
const [expandedIndex, setExpandedIndex] = useState<number | null>(null);
1515

16+
const closeMenu = useCallback(() => {
17+
setOpen(false);
18+
setExpandedIndex(null);
19+
}, []);
20+
1621
const toggleDropdown = (index: number) => {
1722
setExpandedIndex(expandedIndex === index ? null : index);
1823
};
1924

25+
useEffect(() => {
26+
if (!open) return;
27+
const handleKeyDown = (e: KeyboardEvent) => {
28+
if (e.key === "Escape") {
29+
closeMenu();
30+
}
31+
};
32+
document.addEventListener("keydown", handleKeyDown);
33+
return () => document.removeEventListener("keydown", handleKeyDown);
34+
}, [open, closeMenu]);
35+
2036
return (
2137
<div className="lg:hidden">
2238
<button
@@ -38,73 +54,94 @@ export default function MobileMenu({ items }: MobileMenuProps) {
3854
</button>
3955

4056
{open && (
41-
<nav className="absolute left-0 right-0 top-full z-50 border-t border-border bg-white shadow-lg">
42-
<ul className="divide-y divide-border">
43-
{items.map((item, index) =>
44-
isDropdown(item) ? (
45-
<li key={item.label}>
46-
<button
47-
type="button"
48-
className="flex w-full items-center justify-between px-4 py-3 font-medium text-dark"
49-
onClick={() => toggleDropdown(index)}
50-
>
51-
{item.label}
52-
<span
53-
className={`text-xs transition-transform duration-200 ${
54-
expandedIndex === index ? "rotate-180" : ""
55-
}`}
57+
<>
58+
<div
59+
className="fixed inset-0 z-40"
60+
aria-hidden="true"
61+
onClick={closeMenu}
62+
/>
63+
<nav
64+
aria-label="Menu de navigation"
65+
className="absolute left-0 right-0 top-full z-50 border-t border-border bg-white shadow-lg"
66+
>
67+
<ul className="divide-y divide-border">
68+
{items.map((item, index) =>
69+
isDropdown(item) ? (
70+
<li key={item.label}>
71+
<button
72+
type="button"
73+
className="flex w-full items-center justify-between px-4 py-3 font-medium text-dark"
74+
onClick={() => toggleDropdown(index)}
75+
>
76+
{item.label}
77+
<span
78+
className={`text-xs transition-transform duration-200 ${
79+
expandedIndex === index ? "rotate-180" : ""
80+
}`}
81+
>
82+
83+
</span>
84+
</button>
85+
{expandedIndex === index && (
86+
<ul className="bg-light-gray pb-2">
87+
{item.items.map((link) => (
88+
<li key={link.href}>
89+
<Link
90+
href={link.href}
91+
className="block px-8 py-3 text-sm text-dark hover:text-primary"
92+
onClick={closeMenu}
93+
>
94+
{link.label}
95+
</Link>
96+
</li>
97+
))}
98+
{item.highlight && (
99+
<li key={item.highlight.href}>
100+
<Link
101+
href={item.highlight.href}
102+
className="block px-8 py-3 text-sm font-semibold text-primary hover:text-primary-dark"
103+
onClick={closeMenu}
104+
>
105+
{item.highlight.label}
106+
</Link>
107+
</li>
108+
)}
109+
</ul>
110+
)}
111+
</li>
112+
) : (
113+
<li key={item.href}>
114+
<Link
115+
href={item.href}
116+
className="block px-4 py-3 font-medium text-dark hover:text-primary"
117+
onClick={closeMenu}
56118
>
57-
58-
</span>
59-
</button>
60-
{expandedIndex === index && (
61-
<ul className="bg-light-gray pb-2">
62-
{item.items.map((link) => (
63-
<li key={link.href}>
64-
<Link
65-
href={link.href}
66-
className="block px-8 py-3 text-sm text-dark hover:text-primary"
67-
onClick={() => setOpen(false)}
68-
>
69-
{link.label}
70-
</Link>
71-
</li>
72-
))}
73-
</ul>
74-
)}
75-
</li>
76-
) : (
77-
<li key={item.href}>
78-
<Link
79-
href={item.href}
80-
className="block px-4 py-3 font-medium text-dark hover:text-primary"
81-
onClick={() => setOpen(false)}
82-
>
83-
{item.label}
84-
</Link>
85-
</li>
86-
),
87-
)}
88-
<li>
89-
<Link
90-
href="/audit-symfony-gratuit"
91-
className="block px-4 py-3 font-semibold text-primary"
92-
onClick={() => { trackEvent("cta_click", { cta_location: "header_mobile", cta_text: "Audit Symfony gratuit" }); setOpen(false); }}
93-
>
94-
Audit Symfony gratuit
95-
</Link>
96-
</li>
97-
<li>
98-
<Link
99-
href="/contact"
100-
className="block px-4 py-3 font-semibold text-primary"
101-
onClick={() => { trackEvent("cta_click", { cta_location: "header_mobile", cta_text: "Contact" }); setOpen(false); }}
102-
>
103-
Contact
104-
</Link>
105-
</li>
106-
</ul>
107-
</nav>
119+
{item.label}
120+
</Link>
121+
</li>
122+
),
123+
)}
124+
<li>
125+
<Link
126+
href="/audit-symfony-gratuit"
127+
className="block px-4 py-3 font-semibold text-primary"
128+
onClick={() => { trackEvent("cta_click", { cta_location: "header_mobile", cta_text: "Audit Symfony gratuit" }); closeMenu(); }}
129+
>
130+
Audit Symfony gratuit
131+
</Link>
132+
</li>
133+
<li>
134+
<Link
135+
href="/contact"
136+
className="block px-4 py-3 font-semibold text-primary"
137+
onClick={() => { trackEvent("cta_click", { cta_location: "header_mobile", cta_text: "Contact" }); closeMenu(); }}
138+
>
139+
Contact
140+
</Link>
141+
</li>
142+
</ul>
143+
</nav>
144+
</>
108145
)}
109146
</div>
110147
);

0 commit comments

Comments
 (0)