Files
me-joachimhummel-de/artifacts/joachim-portfolio/src/components/navbar.tsx
joachimhummel 7b88a63798 Update navigation links to remove unused external flag
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
2026-05-15 15:44:43 +00:00

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>
);
}