TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1"use client";2import * as React from "react";3import Link from "next/link";4import { usePathname } from "next/navigation";5import { AnimatePresence, motion, useReducedMotion } from "motion/react";6import { ArrowRight, Menu, X } from "lucide-react";7import { Logo } from "@/components/brand/logo";8import { Button } from "@/components/ui/button";9import { ThemeToggle } from "./theme-toggle";10import { cn } from "@/lib/utils";1112const NAV = [13 { label: "Features", href: "/#features" },14 { label: "Demo", href: "/#demo" },15 { label: "Models", href: "/models" },16 { label: "Security", href: "/security" },17 { label: "FAQ", href: "/#faq" },18];1920export function MarketingHeader() {21 const [open, setOpen] = React.useState(false);22 const pathname = usePathname();23 const reduce = useReducedMotion();2425 // Close the mobile menu when navigating (state adjusted during render, not in an effect).26 const [seenPath, setSeenPath] = React.useState(pathname);27 if (seenPath !== pathname) {28 setSeenPath(pathname);29 setOpen(false);30 }3132 React.useEffect(() => {33 if (!open) return;34 const onKey = (e: KeyboardEvent) => {35 if (e.key === "Escape") setOpen(false);36 };37 window.addEventListener("keydown", onKey);38 return () => window.removeEventListener("keydown", onKey);39 }, [open]);4041 return (42 <header className="glass sticky top-0 z-50 border-b border-border/80">43 <div className="mx-auto flex h-14 w-full max-w-6xl items-center justify-between gap-4 px-5 sm:px-8">44 <Link href="/" className="tap rounded-md py-1" aria-label="PolyLLM home">45 <Logo size={24} />46 </Link>4748 <nav className="hidden items-center gap-1 md:flex" aria-label="Primary">49 {NAV.map((item) => (50 <Link key={item.href} href={item.href} className="rounded-md px-3 py-1.5 text-sm text-fg-muted transition-colors hover:bg-bg-muted hover:text-fg">51 {item.label}52 </Link>53 ))}54 </nav>5556 <div className="hidden items-center gap-1.5 md:flex">57 <ThemeToggle />58 <Button asChild variant="ghost" size="sm">59 <Link href="/login">Sign in</Link>60 </Button>61 <Button asChild size="sm">62 <Link href="/signup">63 Start using PolyLLM64 <ArrowRight />65 </Link>66 </Button>67 </div>6869 <div className="flex items-center gap-1 md:hidden">70 <ThemeToggle />71 <button72 type="button"73 className="tap inline-flex size-8 items-center justify-center rounded-md text-fg-muted hover:bg-bg-muted hover:text-fg"74 aria-expanded={open}75 aria-controls="mobile-nav"76 aria-label={open ? "Close menu" : "Open menu"}77 onClick={() => setOpen((v) => !v)}78 >79 {open ? <X className="size-4.5" /> : <Menu className="size-4.5" />}80 </button>81 </div>82 </div>8384 <AnimatePresence initial={false}>85 {open ? (86 <motion.div87 id="mobile-nav"88 key="mobile-nav"89 className="overflow-hidden border-t border-border md:hidden"90 initial={reduce ? false : { height: 0, opacity: 0 }}91 animate={{ height: "auto", opacity: 1 }}92 exit={reduce ? undefined : { height: 0, opacity: 0 }}93 transition={{ duration: 0.22, ease: [0.16, 1, 0.3, 1] }}94 >95 <nav className="flex flex-col gap-1 px-4 py-3" aria-label="Mobile">96 {NAV.map((item) => (97 <Link98 key={item.href}99 href={item.href}100 onClick={() => setOpen(false)}101 className={cn("rounded-md px-3 py-2 text-[15px] text-fg-muted hover:bg-bg-muted hover:text-fg")}102 >103 {item.label}104 </Link>105 ))}106 <div className="mt-2 grid grid-cols-2 gap-2 border-t border-border pt-3">107 <Button asChild variant="outline" size="lg" className="h-10 text-sm">108 <Link href="/login" onClick={() => setOpen(false)}>109 Sign in110 </Link>111 </Button>112 <Button asChild size="lg" className="h-10 text-sm">113 <Link href="/signup" onClick={() => setOpen(false)}>114 Get started115 </Link>116 </Button>117 </div>118 </nav>119 </motion.div>120 ) : null}121 </AnimatePresence>122 </header>123 );124}125