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