www_indaba/src/components/navbar.tsx
2025-06-12 14:23:09 +02:00

102 lines
3.0 KiB
TypeScript

'use client'
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
} from '@headlessui/react'
import { Bars2Icon } from '@heroicons/react/24/solid'
import { motion } from 'framer-motion'
import { Link } from './link'
import { Logo } from './logo'
import { PlusGrid, PlusGridItem, PlusGridRow } from './plus-grid'
const links = [
{ href: '/company', label: 'About' },
{ href: '/projects', label: 'Projects' },
{ href: '/participate', label: 'Get Involved' },
]
function DesktopNav({ color = "white" }: { color?: "white" | "black" }) {
return (
<nav className="relative hidden lg:flex">
{links.map(({ href, label }) => (
<PlusGridItem key={href} className="relative flex">
<Link
href={href}
className={`flex items-center px-4 py-3 text-base font-medium text-${color} bg-blend-multiply data-hover:bg-black/2.5`}
>
{label}
</Link>
</PlusGridItem>
))}
</nav>
)
}
function MobileNavButton() {
return (
<DisclosureButton
className="flex size-12 items-center justify-center self-center rounded-lg data-hover:bg-black/5 lg:hidden"
aria-label="Open main menu"
>
<Bars2Icon className="size-6" />
</DisclosureButton>
)
}
function MobileNav({ color = "white" }: { color?: "white" | "black" }) {
return (
<DisclosurePanel className="lg:hidden">
<div className="flex flex-col gap-6 py-4">
{links.map(({ href, label }, linkIndex) => (
<motion.div
initial={{ opacity: 0, rotateX: -90 }}
animate={{ opacity: 1, rotateX: 0 }}
transition={{
duration: 0.15,
ease: 'easeInOut',
rotateX: { duration: 0.3, delay: linkIndex * 0.1 },
}}
key={href}
>
<Link href={href} className={`text-base font-medium text-${color}`}>
{label}
</Link>
</motion.div>
))}
</div>
<div className="absolute left-1/2 w-screen -translate-x-1/2">
<div className="absolute inset-x-0 top-0 border-t border-black/5" />
<div className="absolute inset-x-0 top-2 border-t border-black/5" />
</div>
</DisclosurePanel>
)
}
export function Navbar({ banner, color = "white" }: { banner?: React.ReactNode, color?: "white" | "black" }) {
return (
<Disclosure as="header" className="pt-12 sm:pt-16">
<PlusGrid>
<PlusGridRow className="relative flex justify-between">
<div className="relative flex gap-6">
<PlusGridItem className="py-3">
<Link href="/" title="Home">
<Logo className="h-9" color={color} />
</Link>
</PlusGridItem>
{banner && (
<div className="relative hidden items-center py-3 lg:flex">
{banner}
</div>
)}
</div>
<DesktopNav color={color} />
<MobileNavButton />
</PlusGridRow>
</PlusGrid>
<MobileNav color={color} />
</Disclosure>
)
}