GRV-Summit-Site/components/layout/MobileNavSheet.tsx
“kirukib” 3693495dd0
Some checks are pending
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Waiting to run
Add site-wide topography patterns and refine section styling.
Use mainwhite.svg on white sections with curvy green transitions into flat green bands, improve text and button contrast, and deploy via OpenNext on Cloudflare Workers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 20:34:36 +03:00

172 lines
5.6 KiB
TypeScript

"use client";
import Link from "next/link";
import { Menu, X } from "lucide-react";
import { useEffect } from "react";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { programDays } from "@/content/program";
import { site } from "@/content/site";
import { TicketsMarqueeCta } from "@/components/layout/NavTicketsCta";
import { cn } from "@/lib/utils";
const navLinks = [
{ href: "/speakers", label: "Lineup" },
{ href: "/pitch-competition", label: "Pitch", badge: "Grants" },
{ href: "/partners", label: "Partners" },
{ href: "/exhibit", label: "Exhibit" },
] as const;
type TriggerProps = {
open: boolean;
onToggle: () => void;
};
export function MobileNavTrigger({ open, onToggle }: TriggerProps) {
return (
<button
type="button"
onClick={onToggle}
className={cn(
"inline-flex items-center gap-2 rounded-full px-4 py-2.5 text-sm font-semibold transition-colors lg:hidden",
open
? "bg-[#141414] text-white"
: "bg-[#141414] text-white hover:bg-[#1f1f1f]"
)}
aria-expanded={open}
aria-controls="mobile-nav-panel"
aria-label={open ? "Close menu" : "Open menu"}
>
{open ? "Close" : "Menu"}
{open ? <X className="size-4" strokeWidth={2} /> : <Menu className="size-4" strokeWidth={2} />}
</button>
);
}
type DropdownProps = {
open: boolean;
onClose: () => void;
};
export function MobileNavDropdown({ open, onClose }: DropdownProps) {
useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
document.body.style.overflow = "hidden";
window.addEventListener("keydown", onKey);
return () => {
document.body.style.overflow = "";
window.removeEventListener("keydown", onKey);
};
}, [open, onClose]);
if (!open) return null;
return (
<>
<button
type="button"
className="fixed inset-0 top-16 z-40 bg-black/30 lg:hidden"
aria-label="Close menu"
onClick={onClose}
/>
<nav
id="mobile-nav-panel"
className={cn(
"absolute left-0 right-0 top-[calc(100%+0.5rem)] z-50 overflow-hidden rounded-[1.75rem]",
"bg-[#141414] text-white shadow-2xl shadow-black/40",
"animate-in fade-in slide-in-from-top-3 duration-200"
)}
aria-label="Mobile navigation"
>
<div className="divide-y divide-white/10">
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="program" className="border-0">
<AccordionTrigger
className={cn(
"px-5 py-5 text-lg font-medium text-white hover:no-underline",
"[&[data-state=open]>svg]:rotate-180",
"[&>svg]:size-5 [&>svg]:text-white/50"
)}
>
Program
</AccordionTrigger>
<AccordionContent className="px-5 pb-4 pt-0">
<ul className="space-y-1 border-t border-white/10 pt-3">
{programDays.map((day) => (
<li key={day.id}>
<Link
href="/program"
onClick={onClose}
className="block rounded-xl px-3 py-3 transition-colors hover:bg-white/5"
>
<span className="text-[10px] font-semibold uppercase tracking-wider text-white/45">
{day.date}
</span>
<span className="mt-0.5 block text-sm font-medium text-white/90">
{day.title}
</span>
</Link>
</li>
))}
<li>
<Link
href="/program"
onClick={onClose}
className="mt-1 block rounded-xl px-3 py-2.5 text-sm font-semibold text-[#ffb300] hover:bg-white/5"
>
View full program
</Link>
</li>
</ul>
</AccordionContent>
</AccordionItem>
</Accordion>
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
onClick={onClose}
className="flex items-center justify-between px-5 py-5 text-lg font-medium transition-colors hover:bg-white/5"
>
<span>{link.label}</span>
{"badge" in link && link.badge && (
<span className="rounded-md bg-[#ffb300] px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-[#0f0404]">
{link.badge}
</span>
)}
</Link>
))}
</div>
<div className="flex items-center gap-3 border-t border-white/10 p-4">
<Link
href={site.links.pitchApplyUrl}
onClick={onClose}
className={cn(
"flex h-12 min-w-0 flex-1 items-center justify-center rounded-full",
"bg-white px-4 text-sm font-bold text-[#0f0404] transition-transform active:scale-[0.98]"
)}
>
Apply to pitch
</Link>
<TicketsMarqueeCta
onNavigate={onClose}
className={cn(
"h-12 min-w-[8.5rem] max-w-[9.5rem] shrink-0",
"focus-visible:ring-offset-[#141414]"
)}
/>
</div>
</nav>
</>
);
}