203 lines
8.9 KiB
TypeScript
203 lines
8.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Link from "next/link";
|
|
import { LanguageSwitcher } from "@/components/sections/lang/language-switcher";
|
|
import { ThemeToggle } from "@/components/sections/theme/theme-toggle";
|
|
import { Dictionary } from "@/lib/IDict";
|
|
import { CyberButton } from "../ui/cyber-button";
|
|
import { MenuSquare, X, Terminal, FolderOpen, ArrowRight } from "lucide-react";
|
|
import { motion, AnimatePresence } from "framer-motion";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export function Header({
|
|
dict,
|
|
lang,
|
|
}: {
|
|
dict: Dictionary["nav"];
|
|
lang: string;
|
|
}) {
|
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
|
|
// Ссылки для мобильного меню (расширенный список, как в футере)
|
|
const mobileLinks = [
|
|
{ name: dict.features, href: `/${lang}#features`, icon: Terminal },
|
|
{ name: dict.pricing, href: `/${lang}#pricing`, icon: FolderOpen },
|
|
{ name: dict.faq, href: `/${lang}#faq`, icon: FolderOpen },
|
|
{ name: dict.blog, href: `/${lang}/blog`, icon: FolderOpen },
|
|
];
|
|
|
|
return (
|
|
<>
|
|
<header className="fixed top-4 md:top-6 left-1/2 -translate-x-1/2 w-[95%] max-w-5xl z-50 bg-card/30 dark:bg-card/20 backdrop-blur-xl border border-border/50 rounded-full shadow-lg transition-all duration-500 hover:bg-card/50 dark:hover:bg-card/40">
|
|
<div className="px-4 md:px-8 h-14 md:h-16 flex items-center justify-between">
|
|
{/* ЛЕВЫЙ БЛОК: Адаптивный Логотип */}
|
|
<Link
|
|
href={`/${lang}`}
|
|
className="flex items-center gap-2 md:gap-3 group hover:scale-105 transition-transform duration-300 w-fit relative z-50"
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
<div className="text-lg sm:text-2xl md:text-3xl tracking-wide md:tracking-widest flex items-center select-none font-bold uppercase">
|
|
<span
|
|
className="text-transparent animate-neon-flicker transition-all duration-300"
|
|
style={{
|
|
WebkitTextStroke: "1px #00E5F2",
|
|
filter: "drop-shadow(0 0 5px rgba(0,229,242,0.6))",
|
|
}}
|
|
>
|
|
Net
|
|
</span>
|
|
<span
|
|
className="text-transparent transition-all duration-300"
|
|
style={{
|
|
WebkitTextStroke: "1px #00E5F2",
|
|
filter: "drop-shadow(0 0 5px rgba(0,229,242,0.6))",
|
|
}}
|
|
>
|
|
runner
|
|
</span>
|
|
<span
|
|
className="ml-1.5 md:ml-2 text-transparent opacity-90 group-hover:opacity-100 transition-all duration-300"
|
|
style={{
|
|
WebkitTextStroke: "1px #8B3DFF",
|
|
filter: "drop-shadow(0 0 5px rgba(139,61,255,0.6))",
|
|
}}
|
|
>
|
|
VPN
|
|
</span>
|
|
</div>
|
|
</Link>
|
|
|
|
{/* ЦЕНТРАЛЬНЫЙ БЛОК: Навигация (скрыта на мобилках) */}
|
|
<nav className="hidden md:flex items-center gap-8 text-sm font-bold text-muted-foreground">
|
|
<Link
|
|
href={`/${lang}#features`}
|
|
className="hover:text-primary transition-colors duration-200"
|
|
>
|
|
{dict.features}
|
|
</Link>
|
|
<Link
|
|
href={`/${lang}#pricing`}
|
|
className="hover:text-primary transition-colors duration-200"
|
|
>
|
|
{dict.pricing}
|
|
</Link>
|
|
<Link
|
|
href={`/${lang}#faq`}
|
|
className="hover:text-primary transition-colors duration-200"
|
|
>
|
|
{dict.faq}
|
|
</Link>
|
|
</nav>
|
|
|
|
{/* ПРАВЫЙ БЛОК: Контролы */}
|
|
<div className="flex items-center gap-1.5 md:gap-4 relative z-50">
|
|
<div className="flex items-center gap-1 md:gap-2">
|
|
<LanguageSwitcher />
|
|
<ThemeToggle />
|
|
</div>
|
|
|
|
<CyberButton
|
|
href={`/${lang}/download`}
|
|
variant="primary"
|
|
className="hidden sm:block scale-75 md:scale-90 origin-right"
|
|
>
|
|
{dict.cta}
|
|
</CyberButton>
|
|
|
|
{/* КНОПКА МОБИЛЬНОГО МЕНЮ */}
|
|
<button
|
|
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
|
className="sm:hidden p-2 rounded-xl bg-background/50 border border-border text-foreground hover:bg-muted transition-colors"
|
|
aria-label="Toggle System Menu"
|
|
>
|
|
{isMenuOpen ? (
|
|
<X className="size-5" />
|
|
) : (
|
|
<MenuSquare className="size-5" />
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{/* ВСПЛЫВАЮЩЕЕ ОКНО (Мобильное меню в стиле ретро-ОС) */}
|
|
<AnimatePresence>
|
|
{isMenuOpen && (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: -20, scale: 0.95 }}
|
|
animate={{ opacity: 1, y: 0, scale: 1 }}
|
|
exit={{ opacity: 0, y: -20, scale: 0.95 }}
|
|
transition={{ type: "spring", stiffness: 300, damping: 25 }}
|
|
className="fixed top-24 left-4 right-4 z-40 sm:hidden origin-top"
|
|
>
|
|
{/* Окно-папка */}
|
|
<div className="bg-[#E5E5E5] dark:bg-[#1E1E1E] border-2 border-t-white border-l-white border-b-gray-500 border-r-gray-500 dark:border-t-gray-600 dark:border-l-gray-600 dark:border-b-black dark:border-r-black p-1 shadow-[4px_4px_0_0_rgba(0,0,0,0.5)]">
|
|
{/* Заголовок окна (Title bar) */}
|
|
<div className="bg-blue-800 text-white px-2 py-1 flex items-center justify-between mb-2 font-mono text-xs font-bold tracking-wider">
|
|
<span className="flex items-center gap-2">
|
|
<Terminal className="size-3" /> C:\NETRUNNER\MENU.EXE
|
|
</span>
|
|
</div>
|
|
|
|
{/* Содержимое папки (Ссылки) */}
|
|
<div className="bg-white dark:bg-black border-2 border-inset border-t-gray-500 border-l-gray-500 border-b-white border-r-white dark:border-t-black dark:border-l-black dark:border-b-gray-700 dark:border-r-gray-700 p-2 font-mono flex flex-col gap-1 max-h-[70vh] overflow-y-auto custom-scrollbar-retro">
|
|
{mobileLinks.map((link) => (
|
|
<Link
|
|
key={link.name}
|
|
href={link.href}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
className="flex items-center gap-3 p-3 hover:bg-blue-800 hover:text-white dark:hover:bg-primary/20 dark:hover:text-primary transition-colors group cursor-pointer text-sm text-black dark:text-white shrink-0"
|
|
>
|
|
<link.icon className="size-5 text-gray-500 group-hover:text-white dark:group-hover:text-primary transition-colors fill-yellow-200 dark:fill-transparent" />
|
|
<span className="flex-1">{link.name}</span>
|
|
<span className="opacity-0 group-hover:opacity-100 transition-opacity">
|
|
_
|
|
</span>
|
|
</Link>
|
|
))}
|
|
|
|
{/* Разделитель */}
|
|
<div className="my-2 border-t border-dashed border-gray-400 dark:border-gray-700 shrink-0" />
|
|
|
|
{/* Доп ссылки из футера */}
|
|
<Link
|
|
href={`/${lang}/docs`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
className="flex items-center gap-3 p-3 hover:bg-blue-800 hover:text-white dark:hover:bg-primary/20 dark:hover:text-primary transition-colors group cursor-pointer text-xs text-gray-600 dark:text-gray-400 shrink-0"
|
|
>
|
|
<Terminal className="size-4" />
|
|
<span className="flex-1 uppercase tracking-widest">
|
|
Documentation
|
|
</span>
|
|
</Link>
|
|
|
|
{/* Кнопка теперь идет СРАЗУ за списком, а не прибита к низу h-[60vh] */}
|
|
<div className="pt-4 pb-2 px-2 shrink-0">
|
|
<CyberButton
|
|
href={`/${lang}/download`}
|
|
variant="primary"
|
|
className="w-full text-xs"
|
|
>
|
|
<span className="flex items-center justify-center gap-2">
|
|
{dict.cta} <ArrowRight className="size-3" />
|
|
</span>
|
|
</CyberButton>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
|
|
{/* Оверлей для закрытия меню по клику вне его */}
|
|
{isMenuOpen && (
|
|
<div
|
|
className="fixed inset-0 z-30 sm:hidden bg-black/20 backdrop-blur-sm"
|
|
onClick={() => setIsMenuOpen(false)}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|