| 1 |
1 |
"use client"; |
| 2 |
2 |
|
| 3 |
3 |
import { useEffect, useId, useRef, useState } from "react"; |
|
4 |
+import { createPortal } from "react-dom"; |
| 4 |
5 |
import { Button } from "@/components/ui/Button"; |
| 5 |
6 |
import { NavLinks } from "./NavLinks"; |
| 6 |
7 |
|
| 37 |
38 |
}; |
| 38 |
39 |
}, [open]); |
| 39 |
40 |
|
|
41 |
+ // Le panneau est rendu dans <body> par un portail : l’en-tête utilise |
|
42 |
+ // backdrop-filter, qui ferait de lui le bloc conteneur d’un élément `fixed`. |
| 40 |
43 |
return ( |
| 41 |
44 |
<div className="lg:hidden"> |
| 42 |
45 |
<button |
| 61 |
64 |
</svg> |
| 62 |
65 |
</button> |
| 63 |
66 |
|
| 64 |
|
− {open ? ( |
| 65 |
|
− <div |
| 66 |
|
− id={panelId} |
| 67 |
|
− role="dialog" |
| 68 |
|
− aria-modal="true" |
| 69 |
|
− aria-label={`Menu ${brandName}`} |
| 70 |
|
− className="bg-ivory-100 fixed inset-0 z-50 flex flex-col motion-safe:animate-[fade-in_var(--duration-base)_var(--ease-out)]" |
| 71 |
|
− > |
| 72 |
|
− <div className="container-site flex items-center justify-between py-4"> |
| 73 |
|
− <span className="text-navy-900 font-serif text-xl">{brandName}</span> |
| 74 |
|
− <button |
| 75 |
|
− ref={closeRef} |
| 76 |
|
− type="button" |
| 77 |
|
− className="text-navy-900 hover:bg-navy-900/5 inline-flex h-11 w-11 items-center justify-center rounded-md" |
| 78 |
|
− aria-label="Fermer le menu" |
| 79 |
|
− onClick={() => setOpen(false)} |
|
67 |
+ {open |
|
68 |
+ ? createPortal( |
|
69 |
+ <div |
|
70 |
+ id={panelId} |
|
71 |
+ role="dialog" |
|
72 |
+ aria-modal="true" |
|
73 |
+ aria-label={`Menu ${brandName}`} |
|
74 |
+ className="bg-ivory-100 fixed inset-0 z-50 flex flex-col motion-safe:animate-[fade-in_var(--duration-base)_var(--ease-out)]" |
| 80 |
75 |
> |
| 81 |
|
− <svg |
| 82 |
|
− viewBox="0 0 24 24" |
| 83 |
|
− className="h-6 w-6" |
| 84 |
|
− fill="none" |
| 85 |
|
− stroke="currentColor" |
| 86 |
|
− strokeWidth="1.6" |
| 87 |
|
− strokeLinecap="round" |
| 88 |
|
− aria-hidden="true" |
|
76 |
+ <div className="container-site flex items-center justify-between py-4"> |
|
77 |
+ <span className="text-navy-900 font-serif text-xl">{brandName}</span> |
|
78 |
+ <button |
|
79 |
+ ref={closeRef} |
|
80 |
+ type="button" |
|
81 |
+ className="text-navy-900 hover:bg-navy-900/5 inline-flex h-11 w-11 items-center justify-center rounded-md" |
|
82 |
+ aria-label="Fermer le menu" |
|
83 |
+ onClick={() => setOpen(false)} |
|
84 |
+ > |
|
85 |
+ <svg |
|
86 |
+ viewBox="0 0 24 24" |
|
87 |
+ className="h-6 w-6" |
|
88 |
+ fill="none" |
|
89 |
+ stroke="currentColor" |
|
90 |
+ strokeWidth="1.6" |
|
91 |
+ strokeLinecap="round" |
|
92 |
+ aria-hidden="true" |
|
93 |
+ > |
|
94 |
+ <path d="m6 6 12 12M18 6 6 18" /> |
|
95 |
+ </svg> |
|
96 |
+ </button> |
|
97 |
+ </div> |
|
98 |
+ <nav |
|
99 |
+ aria-label="Navigation mobile" |
|
100 |
+ className="container-site flex-1 overflow-y-auto py-6" |
| 89 |
101 |
> |
| 90 |
|
− <path d="m6 6 12 12M18 6 6 18" /> |
| 91 |
|
− </svg> |
| 92 |
|
− </button> |
| 93 |
|
− </div> |
| 94 |
|
− <nav |
| 95 |
|
− aria-label="Navigation mobile" |
| 96 |
|
− className="container-site flex-1 overflow-y-auto py-6" |
| 97 |
|
− > |
| 98 |
|
− <NavLinks |
| 99 |
|
− items={items} |
| 100 |
|
− vertical |
| 101 |
|
− className="flex flex-col gap-1" |
| 102 |
|
− onNavigate={() => setOpen(false)} |
| 103 |
|
− /> |
| 104 |
|
− </nav> |
| 105 |
|
− <div className="container-site pb-10"> |
| 106 |
|
− <Button href={cta.href} size="lg" className="w-full" onClick={() => setOpen(false)}> |
| 107 |
|
− {cta.label} |
| 108 |
|
− </Button> |
| 109 |
|
− </div> |
| 110 |
|
− </div> |
| 111 |
|
− ) : null} |
|
102 |
+ <NavLinks |
|
103 |
+ items={items} |
|
104 |
+ vertical |
|
105 |
+ className="flex flex-col gap-1" |
|
106 |
+ onNavigate={() => setOpen(false)} |
|
107 |
+ /> |
|
108 |
+ </nav> |
|
109 |
+ <div className="container-site pb-10"> |
|
110 |
+ <Button href={cta.href} size="lg" className="w-full" onClick={() => setOpen(false)}> |
|
111 |
+ {cta.label} |
|
112 |
+ </Button> |
|
113 |
+ </div> |
|
114 |
+ </div>, |
|
115 |
+ document.body, |
|
116 |
+ ) |
|
117 |
+ : null} |
| 112 |
118 |
</div> |
| 113 |
119 |
); |
| 114 |
120 |
} |