Navigation
MobileMenu
Blend-mode mobile header with an animated burger and a full-screen link overlay.
npx bezel-add add mobile-menupackages/ui/src/navigation/MobileMenu.tsx · 79 lines
"use client";
import { useState } from "react";
type NavLink = { label: string; href: string };
type Props = {
logo?: string;
logoHref?: string;
links?: NavLink[];
};
export function MobileMenu({ logo = "YASH", logoHref = "/", links = [] }: Props) {
const [open, setOpen] = useState(false);
return (
<>
<style>{`
.yui-mnav {
display: flex; align-items: center; justify-content: space-between;
position: fixed; top: 0; left: 0; width: 100%;
padding: 2rem; z-index: 2000;
mix-blend-mode: difference;
}
.yui-mnav-logo { font-size: 2.5rem; font-weight: 500; color: #fff; text-decoration: none; }
.yui-burger {
width: 2.4rem; height: 1.8rem;
display: flex; flex-direction: column; justify-content: space-between;
background: none; border: none; cursor: pointer; padding: 0;
}
.yui-burger span {
width: 100%; height: 0.2rem; background: #fff; border-radius: 999px;
transition: transform 0.4s cubic-bezier(0.25,1,0.5,1), opacity 0.3s;
transform-origin: center;
}
.yui-burger:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.yui-burger.open span:nth-child(1) { transform: translateY(0.8rem) rotate(45deg); }
.yui-burger.open span:nth-child(2) { opacity: 0; }
.yui-burger.open span:nth-child(3) { transform: translateY(-0.8rem) rotate(-45deg); }
.yui-moverlay {
position: fixed; inset: 0; z-index: 1999;
background: #000;
display: flex; align-items: center; justify-content: center;
opacity: 0; visibility: hidden;
transition: opacity 0.5s, visibility 0.5s;
}
.yui-moverlay.open { opacity: 1; visibility: visible; }
.yui-moverlay ul { display: flex; flex-direction: column; gap: 2.5rem; list-style: none; margin: 0; padding: 0; text-align: center; }
.yui-moverlay li a {
display: inline-block;
font-size: 3rem; font-weight: 500; color: #fff;
text-decoration: none; text-transform: uppercase; letter-spacing: -0.05em;
padding: 0.3rem 1.5rem; border: 1px solid rgba(255,255,255,0.2); border-radius: 999px;
transition: background 0.3s, color 0.3s;
}
.yui-moverlay li a:hover { background: #fff; color: #000; }
.yui-moverlay li a:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
`}</style>
<nav className="yui-mnav">
<a href={logoHref} className="yui-mnav-logo">{logo}</a>
<button
className={`yui-burger${open ? " open" : ""}`}
onClick={() => setOpen((o) => !o)}
aria-label={open ? "Close menu" : "Open menu"}
>
<span /><span /><span />
</button>
</nav>
<div className={`yui-moverlay${open ? " open" : ""}`} onClick={() => setOpen(false)}>
<ul onClick={(e) => e.stopPropagation()}>
{links.map((link) => (
<li key={link.href}>
<a href={link.href} onClick={() => setOpen(false)}>{link.label}</a>
</li>
))}
</ul>
</div>
</>
);
}