diff options
Diffstat (limited to 'apps/web/src/components/header.tsx')
| -rw-r--r-- | apps/web/src/components/header.tsx | 180 |
1 files changed, 135 insertions, 45 deletions
diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index f8877330..95f08304 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -1,57 +1,147 @@ "use client"; +import { useState } from "react"; import Link from "next/link"; +import { motion } from "motion/react"; import { Button } from "./ui/button"; import { ArrowRight } from "lucide-react"; -import { HeaderBase } from "./header-base"; import Image from "next/image"; import { ThemeToggle } from "./theme-toggle"; +import { GithubIcon, Menu02Icon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { cn } from "@/utils/ui"; +import { DEFAULT_LOGO_URL, SOCIAL_LINKS } from "@/constants/site-constants"; export function Header() { - const leftContent = ( - <Link href="/" className="flex items-center gap-3"> - <Image - src="/logo.svg" - alt="OpenCut Logo" - className="invert dark:invert-0" - width={32} - height={32} - /> - <span className="text-xl font-medium hidden md:block">OpenCut</span> - </Link> - ); + const [isMenuOpen, setIsMenuOpen] = useState(false); + const closeMenu = () => setIsMenuOpen(false); - const rightContent = ( - <nav className="flex items-center gap-2"> - <div className="flex items-center gap-4"> - <Link href="/blog"> - <Button variant="text" className="text-sm p-0"> - Blog - </Button> - </Link> - <Link href="/contributors"> - <Button variant="text" className="text-sm p-0"> - Contributors - </Button> - </Link> - </div> - <Link href="/projects"> - <Button size="sm" className="text-sm ml-2"> - Projects - <ArrowRight className="h-4 w-4" /> - </Button> - </Link> - <ThemeToggle className="mr-2" /> - </nav> - ); + const links = [ + { + label: "Contributors", + href: "/contributors", + }, + { + label: "Sponsors", + href: "/sponsors", + }, + { + label: "Blog", + href: "/blog", + }, + ]; - return ( - <div className="sticky top-4 z-50 mx-4 md:mx-0"> - <HeaderBase - className="bg-background border rounded-2xl max-w-3xl mx-auto mt-4 pl-4 pr-[11px]" - leftContent={leftContent} - rightContent={rightContent} - /> - </div> - ); + return ( + <header className="bg-background shadow-background/85 sticky top-0 z-10 shadow-[0_30px_35px_15px_rgba(0,0,0,1)]"> + <div className="relative flex w-full items-center justify-between px-6 pt-4"> + <div className="relative z-10 flex items-center gap-6"> + <Link href="/" className="flex items-center gap-3"> + <Image + src={DEFAULT_LOGO_URL} + alt="OpenCut Logo" + className="invert dark:invert-0" + width={32} + height={32} + /> + </Link> + <nav className="hidden items-center gap-4 md:flex"> + {links.map((link) => ( + <Link key={link.href} href={link.href}> + <Button variant="text" className="p-0 text-sm"> + {link.label} + </Button> + </Link> + ))} + </nav> + </div> + + <div className="relative z-10"> + <div className="flex items-center gap-3 md:hidden"> + <Button + variant="text" + size="icon" + className="flex items-center justify-center p-0" + onClick={() => setIsMenuOpen(!isMenuOpen)} + > + <HugeiconsIcon icon={Menu02Icon} size={30} /> + </Button> + </div> + <div className="hidden items-center gap-3 md:flex"> + <Link href={SOCIAL_LINKS.github}> + <Button className="bg-background text-sm" variant="outline"> + <HugeiconsIcon icon={GithubIcon} className="size-4" /> + 40k+ + </Button> + </Link> + <Link href="/projects"> + <Button variant="foreground" className="text-sm"> + Projects + <ArrowRight className="size-4" /> + </Button> + </Link> + <ThemeToggle /> + </div> + </div> + <div + className={cn( + "bg-background/20 pointer-events-none fixed inset-0 opacity-0 backdrop-blur-3xl", + "transition-opacity duration-150", + isMenuOpen && "pointer-events-auto opacity-100", + )} + > + <div className="relative h-full"> + <button + type="button" + aria-label="Close menu" + className="absolute inset-0" + onClick={closeMenu} + onKeyDown={(event) => { + if ( + event.key === "Enter" || + event.key === " " || + event.key === "Escape" + ) { + event.preventDefault(); + closeMenu(); + } + }} + /> + <nav className="flex flex-col gap-3 px-6 pt-[5rem]"> + {links.map((link, index) => ( + <motion.div + key={link.href} + initial={{ scale: 0.98, opacity: 0 }} + animate={{ + scale: isMenuOpen ? 1 : 0.98, + opacity: isMenuOpen ? 1 : 0, + }} + transition={{ + duration: 0.4, + delay: isMenuOpen ? index * 0.1 : 0, + ease: [0.25, 0.46, 0.45, 0.94], + }} + > + <Link + href={link.href} + className="text-2xl font-semibold" + onClick={() => setIsMenuOpen(false)} + > + {link.label} + </Link> + </motion.div> + ))} + </nav> + <ThemeToggle + className="absolute right-8 bottom-8 size-10" + iconClassName="!size-[1.2rem]" + onToggle={(e) => { + e.preventDefault(); + e.stopPropagation(); + }} + /> + </div> + </div> + </div> + </header> + ); } |
