Files
PrivyDrop/frontend/components/web/Header.tsx
T
2026-03-27 14:15:45 +08:00

146 lines
4.8 KiB
TypeScript

"use client";
import { useState } from "react";
import { useLocale, useTranslations } from "next-intl";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import Image from "next/image";
import { Menu, X, Github } from "lucide-react";
import LanguageSwitcher from "@/components/LanguageSwitcher";
import ThemeToggle from "@/components/web/ThemeToggle";
/**
* Header component providing navigation, language switching, and GitHub link
* Features responsive design with mobile menu support
*/
const Header = () => {
const t = useTranslations("text.Header");
const lang = useLocale();
const pathname = usePathname();
const [isOpen, setIsOpen] = useState(false);
// Configuration for navigation items
const navItems = [
{ href: `/${lang}`, label: t("homeLabel") },
{ href: `/${lang}/features`, label: t("featuresLabel") },
{ href: `/${lang}/blog`, label: t("blogLabel") },
{ href: `/${lang}/about`, label: t("aboutLabel") },
{ href: `/${lang}/help`, label: t("helpLabel") },
{ href: `/${lang}/faq`, label: t("faqLabel") },
{ href: `/${lang}/terms`, label: t("termsLabel") },
{ href: `/${lang}/privacy`, label: t("privacyLabel") },
];
// GitHub repository URL
const githubUrl = "https://github.com/david-bai00/PrivyDrop";
return (
<header className="bg-background border-b sticky top-0 z-50">
<div className="container mx-auto px-4 py-4">
<div className="flex justify-between items-center">
{/* Logo and site name */}
<Link href={`/${lang}`} className="flex items-center space-x-2">
<Image
src="/logo.png"
alt="PrivyDrop Logo"
width={40}
height={40}
priority
/>
<span className="font-bold text-xl hidden sm:inline">
PrivyDrop
</span>
</Link>
{/* Desktop navigation and controls */}
<div className="hidden md:flex items-center space-x-4">
<nav>
<ul className="flex space-x-2">
{navItems.map((item) => (
<li key={item.href}>
<Button
asChild
variant="ghost"
size="sm"
className={cn(
"hover:bg-muted",
pathname === item.href && "bg-muted"
)}
>
<Link href={item.href}>{item.label}</Link>
</Button>
</li>
))}
</ul>
</nav>
{/* Desktop GitHub link and language switcher */}
<div className="flex items-center space-x-2">
<Button asChild variant="ghost" size="icon">
<Link
href={githubUrl}
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub Repository"
>
<Github className="h-5 w-5" />
</Link>
</Button>
<ThemeToggle />
<LanguageSwitcher />
</div>
</div>
{/* Mobile menu controls */}
<div className="md:hidden flex items-center space-x-2">
<LanguageSwitcher />
<ThemeToggle />
<Button asChild variant="ghost" size="icon">
<Link
href={githubUrl}
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub Repository"
>
<Github className="h-5 w-5" />
</Link>
</Button>
<button
className="p-2"
onClick={() => setIsOpen(!isOpen)}
aria-label="Toggle menu"
>
{isOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
</div>
{/* Mobile navigation menu */}
{isOpen && (
<nav className="md:hidden mt-4">
<ul className="flex flex-col space-y-2">
{navItems.map((item) => (
<li key={item.href}>
<Button
asChild
variant="ghost"
className={cn(
"w-full justify-start",
pathname === item.href && "bg-muted"
)}
onClick={() => setIsOpen(false)}
>
<Link href={item.href}>{item.label}</Link>
</Button>
</li>
))}
</ul>
</nav>
)}
</div>
</header>
);
};
export default Header;