Remove unused `external` boolean from `navLinks` array in `navbar.tsx`. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: afbd01cd-dc42-460e-8743-7da197043254 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e678fe28-87ab-4437-945b-7a15e872a292/6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805/BWIZrK7 Replit-Helium-Checkpoint-Created: true
137 lines
4.8 KiB
TypeScript
137 lines
4.8 KiB
TypeScript
import { useState } from "react";
|
|
import { motion, useScroll, useMotionValueEvent } from "framer-motion";
|
|
import { Menu, X, ExternalLink } from "lucide-react";
|
|
|
|
export function Navbar() {
|
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
const [mobileOpen, setMobileOpen] = useState(false);
|
|
const { scrollY } = useScroll();
|
|
|
|
useMotionValueEvent(scrollY, "change", (latest) => {
|
|
setIsScrolled(latest > 20);
|
|
});
|
|
|
|
const navLinks = [
|
|
{ name: "Kompetenzen", href: "#competencies" },
|
|
{ name: "Stärken", href: "#strengths" },
|
|
{ name: "Projekte", href: "#projects" },
|
|
{ name: "Über mich", href: "#bio" },
|
|
{ name: "Kontakt", href: "#contact" },
|
|
];
|
|
|
|
const blogLinks = [
|
|
{ name: "Tech-Blog", href: "https://blog.unixweb.de" },
|
|
{ name: "KI-Blog", href: "https://ki-blog.unixweb.de" },
|
|
];
|
|
|
|
return (
|
|
<motion.header
|
|
className={`fixed top-0 w-full z-50 transition-all duration-300 ${
|
|
isScrolled
|
|
? "bg-white/95 backdrop-blur-md border-b border-border shadow-sm py-3"
|
|
: "bg-transparent py-5"
|
|
}`}
|
|
initial={{ y: -100 }}
|
|
animate={{ y: 0 }}
|
|
transition={{ duration: 0.4, ease: "easeOut" }}
|
|
>
|
|
<div className="max-w-6xl mx-auto px-4 md:px-8 flex items-center justify-between">
|
|
<a
|
|
href="#hero"
|
|
className="flex items-center gap-2 text-foreground font-bold text-lg tracking-tight"
|
|
data-testid="link-logo"
|
|
>
|
|
<span className="w-8 h-8 rounded-lg bg-primary flex items-center justify-center text-white text-sm font-bold">
|
|
JH
|
|
</span>
|
|
<span className="hidden sm:block text-foreground">Joachim Hummel</span>
|
|
</a>
|
|
|
|
<nav className="hidden md:flex items-center gap-1">
|
|
{navLinks.map((link) => (
|
|
<a
|
|
key={link.name}
|
|
href={link.href}
|
|
className="px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-secondary rounded-lg transition-all"
|
|
data-testid={`link-nav-${link.name.toLowerCase().replace(/\s/g, '-')}`}
|
|
>
|
|
{link.name}
|
|
</a>
|
|
))}
|
|
<div className="w-px h-4 bg-border mx-1" />
|
|
{blogLinks.map((link) => (
|
|
<a
|
|
key={link.name}
|
|
href={link.href}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="inline-flex items-center gap-1 px-3 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-secondary rounded-lg transition-all"
|
|
data-testid={`link-nav-${link.name.toLowerCase().replace(/\s/g, '-')}`}
|
|
>
|
|
{link.name}
|
|
<ExternalLink className="w-3 h-3 opacity-50" />
|
|
</a>
|
|
))}
|
|
</nav>
|
|
|
|
<div className="hidden md:block">
|
|
<a
|
|
href="#contact"
|
|
className="px-4 py-2 bg-primary text-white text-sm font-semibold rounded-lg hover:bg-primary/90 transition-colors"
|
|
data-testid="button-nav-contact"
|
|
>
|
|
Kontakt
|
|
</a>
|
|
</div>
|
|
|
|
<button
|
|
className="md:hidden p-2 rounded-lg text-muted-foreground hover:bg-secondary transition-colors"
|
|
onClick={() => setMobileOpen(!mobileOpen)}
|
|
data-testid="button-mobile-menu"
|
|
>
|
|
{mobileOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
|
|
</button>
|
|
</div>
|
|
|
|
{mobileOpen && (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: -8 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className="md:hidden bg-white border-t border-border px-4 py-4 flex flex-col gap-1"
|
|
>
|
|
{navLinks.map((link) => (
|
|
<a
|
|
key={link.name}
|
|
href={link.href}
|
|
onClick={() => setMobileOpen(false)}
|
|
className="px-4 py-3 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-secondary rounded-lg transition-all"
|
|
>
|
|
{link.name}
|
|
</a>
|
|
))}
|
|
<div className="border-t border-border my-1" />
|
|
{blogLinks.map((link) => (
|
|
<a
|
|
key={link.name}
|
|
href={link.href}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="inline-flex items-center gap-2 px-4 py-3 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-secondary rounded-lg transition-all"
|
|
>
|
|
{link.name}
|
|
<ExternalLink className="w-3 h-3 opacity-50" />
|
|
</a>
|
|
))}
|
|
<a
|
|
href="#contact"
|
|
onClick={() => setMobileOpen(false)}
|
|
className="mt-2 px-4 py-3 bg-primary text-white text-sm font-semibold rounded-lg text-center"
|
|
>
|
|
Kontakt aufnehmen
|
|
</a>
|
|
</motion.div>
|
|
)}
|
|
</motion.header>
|
|
);
|
|
}
|