GRV-Summit-Site/components/layout/MobileNavSheet.tsx
kirukib cb404ec079
Some checks failed
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Has been cancelled
Align site colors with GRV brand book palette.
Centralize primary, secondary, tertiary, and neutral tokens and apply them across theme variables and UI components.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 14:45:22 +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-[#b9d8c9] 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-[#37a47a] px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-[#ffffff]">
{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-[#ffffff] 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>
</>
);
}