fix: mobil menü drawer'ı body'ye portal et — header transform'u fixed konumu bozuyordu

Header scroll efekti #floating-header-wrap'e transform uyguladığı için
içindeki position:fixed overlay viewport yerine header'a göre konumlanıyordu.
Drawer + overlay artık createPortal ile document.body'ye render ediliyor:
sağ drawer, beyaz panel, tam ekran koyu overlay (z-100).
This commit is contained in:
egecankomur
2026-06-02 18:39:34 +03:00
parent 2e001680bf
commit a321ac5c9b
+30 -21
View File
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { Menu, X, ChevronDown, Phone, ArrowRight } from "lucide-react";
@@ -8,7 +9,6 @@ import { Menu, X, ChevronDown, Phone, ArrowRight } from "lucide-react";
type NavService = { slug: string; title: string };
const LINKS = [
{ href: "/", label: "Anasayfa" },
{ href: "/cozumler", label: "Çözümler" },
{ href: "/projeler", label: "Projeler" },
{ href: "/blog", label: "Blog" },
@@ -25,10 +25,13 @@ export function MobileMenu({
phone: string;
phoneRaw: string;
}) {
const [mounted, setMounted] = useState(false);
const [open, setOpen] = useState(false);
const [servicesOpen, setServicesOpen] = useState(false);
const pathname = usePathname();
useEffect(() => setMounted(true), []);
// Rota değişince menüyü kapat
useEffect(() => {
setOpen(false);
@@ -42,36 +45,27 @@ export function MobileMenu({
};
}, [open]);
return (
<div className="lg:hidden">
<button
type="button"
onClick={() => setOpen(true)}
aria-label="Menüyü aç"
aria-expanded={open}
className="inline-flex size-9 items-center justify-center rounded-lg text-gray-700 transition-colors hover:bg-gray-100 hover:text-[var(--navy)]"
>
<Menu className="size-5" />
</button>
{/* Overlay + drawer */}
// Drawer + overlay — header transform bağlamından kaçmak için body'ye portal
const overlay = (
<div
className={`fixed inset-0 z-[60] lg:hidden ${
className={`fixed inset-0 z-[100] lg:hidden ${
open ? "" : "pointer-events-none"
}`}
aria-hidden={!open}
>
{/* Backdrop */}
{/* Koyu overlay */}
<div
onClick={() => setOpen(false)}
className={`absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity duration-300 ${
className={`absolute inset-0 bg-black/50 transition-opacity duration-300 ${
open ? "opacity-100" : "opacity-0"
}`}
/>
{/* Panel */}
{/* Sağ drawer — beyaz panel */}
<div
className={`absolute right-0 top-0 flex h-full w-[86%] max-w-sm flex-col bg-white shadow-2xl transition-transform duration-300 ease-out ${
role="dialog"
aria-modal="true"
className={`absolute right-0 top-0 flex h-full w-[82%] max-w-[340px] flex-col bg-white shadow-2xl transition-transform duration-300 ease-out ${
open ? "translate-x-0" : "translate-x-full"
}`}
>
@@ -84,7 +78,7 @@ export function MobileMenu({
type="button"
onClick={() => setOpen(false)}
aria-label="Menüyü kapat"
className="inline-flex size-9 items-center justify-center rounded-lg text-gray-600 transition-colors hover:bg-gray-100 hover:text-[var(--navy)]"
className="-mr-2 inline-flex size-9 items-center justify-center rounded-lg text-gray-600 transition-colors hover:bg-gray-100 hover:text-[var(--navy)]"
>
<X className="size-5" />
</button>
@@ -133,7 +127,7 @@ export function MobileMenu({
</div>
)}
{LINKS.filter((l) => l.href !== "/").map((l) => (
{LINKS.map((l) => (
<Link
key={l.href}
href={l.href}
@@ -163,6 +157,21 @@ export function MobileMenu({
</div>
</div>
</div>
);
return (
<div className="lg:hidden">
<button
type="button"
onClick={() => setOpen(true)}
aria-label="Menüyü aç"
aria-expanded={open}
className="inline-flex size-9 items-center justify-center rounded-lg text-gray-700 transition-colors hover:bg-gray-100 hover:text-[var(--navy)]"
>
<Menu className="size-5" />
</button>
{mounted && createPortal(overlay, document.body)}
</div>
);
}