Removed aggressive background text in footer. Implemented intelligent back button for projects. Redesigned project archive page. Stabilized idle quote logic in activity feed.
107 lines
4.4 KiB
TypeScript
107 lines
4.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { motion, AnimatePresence } from "framer-motion";
|
|
import { Menu, X } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { useLocale, useTranslations } from "next-intl";
|
|
import { usePathname } from "next/navigation";
|
|
import { ThemeToggle } from "./ThemeToggle";
|
|
|
|
const Header = () => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const locale = useLocale();
|
|
const pathname = usePathname();
|
|
const t = useTranslations("nav");
|
|
|
|
const isHome = pathname === `/${locale}` || pathname === `/${locale}/`;
|
|
|
|
const navItems = [
|
|
{ name: t("home"), href: `/${locale}` },
|
|
{ name: t("about"), href: isHome ? "#about" : `/${locale}#about` },
|
|
{ name: t("projects"), href: isHome ? "#projects" : `/${locale}/projects` },
|
|
{ name: t("contact"), href: isHome ? "#contact" : `/${locale}#contact` },
|
|
];
|
|
|
|
return (
|
|
<>
|
|
<div className="fixed top-8 left-0 right-0 z-50 flex justify-center px-6 pointer-events-none">
|
|
<motion.nav
|
|
initial={{ y: -100, opacity: 0 }}
|
|
animate={{ y: 0, opacity: 1 }}
|
|
className="pointer-events-auto bg-white/70 dark:bg-stone-900/70 backdrop-blur-2xl border border-white/40 dark:border-white/5 shadow-[0_8px_32px_rgba(0,0,0,0.05)] rounded-full px-3 py-2 flex items-center gap-1 md:gap-4"
|
|
>
|
|
{/* Logo Pill */}
|
|
<Link
|
|
href={`/${locale}`}
|
|
className="w-10 h-10 flex items-center justify-center rounded-full bg-stone-900 dark:bg-stone-50 text-white dark:text-stone-900 transition-transform hover:scale-105 active:scale-95 shadow-lg"
|
|
>
|
|
<span className="font-black text-xs tracking-tighter">dk</span>
|
|
</Link>
|
|
|
|
{/* Desktop Menu */}
|
|
<div className="hidden md:flex items-center gap-1">
|
|
{navItems.map((item) => (
|
|
<Link
|
|
key={item.name}
|
|
href={item.href}
|
|
className="px-5 py-2 text-[10px] font-black uppercase tracking-[0.2em] text-stone-500 hover:text-stone-900 dark:hover:text-stone-100 rounded-full transition-all"
|
|
>
|
|
{item.name}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
|
|
<div className="w-px h-4 bg-stone-200 dark:bg-white/10 mx-1 hidden md:block"></div>
|
|
|
|
{/* Actions Pill */}
|
|
<div className="flex items-center gap-1 bg-stone-100/50 dark:bg-white/5 rounded-full p-1">
|
|
<Link
|
|
href={locale === "en" ? pathname.replace(/^\/en/, "/de") : pathname.replace(/^\/de/, "/en")}
|
|
className="w-8 h-8 flex items-center justify-center text-[10px] font-black text-stone-500 hover:text-stone-900 dark:hover:text-stone-100 rounded-full transition-colors"
|
|
>
|
|
{locale === "en" ? "DE" : "EN"}
|
|
</Link>
|
|
<ThemeToggle />
|
|
|
|
{/* Mobile Menu Toggle */}
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="w-8 h-8 flex md:hidden items-center justify-center text-stone-600 dark:text-stone-400 hover:bg-white dark:hover:bg-stone-800 rounded-full transition-colors shadow-sm"
|
|
>
|
|
{isOpen ? <X size={14} /> : <Menu size={14} />}
|
|
</button>
|
|
</div>
|
|
</motion.nav>
|
|
</div>
|
|
|
|
{/* Mobile Menu Overlay */}
|
|
<AnimatePresence>
|
|
{isOpen && (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 10, scale: 0.98 }}
|
|
animate={{ opacity: 1, y: 0, scale: 1 }}
|
|
exit={{ opacity: 0, y: 10, scale: 0.98 }}
|
|
className="fixed top-24 left-6 right-6 z-40 bg-white/90 dark:bg-stone-900/95 backdrop-blur-3xl border border-white/40 dark:border-white/10 rounded-[2.5rem] shadow-2xl p-6 md:hidden overflow-hidden"
|
|
>
|
|
<div className="flex flex-col gap-3">
|
|
{navItems.map((item) => (
|
|
<Link
|
|
key={item.name}
|
|
href={item.href}
|
|
onClick={() => setIsOpen(false)}
|
|
className="px-6 py-4 text-sm font-black uppercase tracking-[0.2em] text-stone-900 dark:text-stone-100 bg-stone-50 dark:bg-white/5 rounded-2xl transition-colors hover:bg-liquid-mint/10"
|
|
>
|
|
{item.name}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Header;
|