Redesign: Modernes SaaS-Design für Joachim Hummel Portfolio
Task #4 — vollständiges Redesign von dunkler Terminal-Ästhetik zu modernem SaaS-Look. Änderungen: - index.css: Komplette Neudefinition der CSS-Variablen. Helles Farbschema (weißer Hintergrund), Primärfarbe Indigo/Blau (hsl 234 89% 60%), neutrale Grautöne, Google Font Inter eingebunden. Utility-Klassen .section-number, .hero-gradient, .dot-pattern, .card-hover hinzugefügt. Terminal-spezifische Klassen (.glow-text, .glow-box, .bg-grid-pattern) entfernt. - navbar.tsx: Sticky Nav mit transparentem Start → weißem Hintergrund + Schatten beim Scrollen. Logo "JH" als gefülltes Indigo-Badge + "Joachim Hummel" Text. Pill-Style Navigation Links. Primär-CTA Button. Vollständiges Mobile-Menü mit Hamburger/X Toggle. - hero.tsx: Zentriertes Layout, großer Display-Headline mit Indigo-Akzent auf Nachname. "Verfügbar für neue Projekte" Badge mit grünem Puls. Skill-Badges (30+ Jahre, ITIL, etc.). Zwei CTAs: gefüllter Primärbutton + Outline-Button. Subtiler Radial-Gradient + Dot-Pattern. - competencies.tsx: Sechs weiße Karten im Grid mit farbigen Icon-Badges (blau, sky, grün, orange, violett, rose). Tech-Icon-Leiste (Linux, Ubuntu, Docker, Grafana, Nginx, Ansible, Prometheus) mit Hover-Farbeffekt und Labels. - strengths.tsx: Drei weiße Karten auf hellgrauem Hintergrund. Nummerierung (01/02/03) als dekoratives Element. Highlight-Badge je Karte. Kein Glow, kein Neon. - projects.tsx: Sechs Projektkarten mit farbigen Icon-Badges je Projektkategorie. Externe Links für SafeDocs Portal (safedocsportal.com) und zensend.email als ArrowUpRight-Icon-Buttons. Pill-Badges für Tags. - bio.tsx: Zweispaltiges Layout. Links: Fließtext + Kunden-Badges. Rechts: Weißes Highlights-Panel mit CheckCircle-Icons (7 Punkte inkl. ITIL, BSI, Tech-Blogger). - contact.tsx: Primärfarbige E-Mail-Karte + drei kompakte Link-Cards (Tech-Blog, KI-Blog, Website). Footer-Zeile mit Name und Standort. - home.tsx: Vereinfacht — kein Fixed-Background, kein Grid-Pattern, kein Ambient-Glow. max-w-6xl Container für alle Sektionen.
This commit is contained in:
@@ -1,56 +1,104 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { motion, useScroll, useMotionValueEvent } from "framer-motion";
|
||||
import { Menu, X } 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 > 50);
|
||||
setIsScrolled(latest > 20);
|
||||
});
|
||||
|
||||
const navLinks = [
|
||||
{ name: "Kompetenzen", href: "#competencies" },
|
||||
{ name: "3 Welten", href: "#strengths" },
|
||||
{ name: "Stärken", href: "#strengths" },
|
||||
{ name: "Projekte", href: "#projects" },
|
||||
{ name: "Über mich", href: "#bio" },
|
||||
{ name: "Kontakt", href: "#contact" },
|
||||
];
|
||||
|
||||
return (
|
||||
<motion.header
|
||||
className={`fixed top-0 w-full z-50 transition-all duration-300 ${
|
||||
isScrolled
|
||||
? "bg-background/80 backdrop-blur-md border-b border-border/50 py-4"
|
||||
: "bg-transparent py-6"
|
||||
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.5 }}
|
||||
transition={{ duration: 0.4, ease: "easeOut" }}
|
||||
>
|
||||
<div className="container mx-auto px-4 md:px-8 flex items-center justify-between">
|
||||
<a href="#hero" className="text-xl font-bold font-mono text-primary glow-text">
|
||||
JH<span className="text-muted-foreground">.</span>
|
||||
<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 gap-8">
|
||||
|
||||
<nav className="hidden md:flex items-center gap-1">
|
||||
{navLinks.map((link) => (
|
||||
<a
|
||||
key={link.name}
|
||||
<a
|
||||
key={link.name}
|
||||
href={link.href}
|
||||
className="text-sm font-mono text-muted-foreground hover:text-primary transition-colors"
|
||||
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>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<a
|
||||
href="#contact"
|
||||
className="md:hidden px-4 py-2 border border-border rounded text-sm font-mono text-foreground hover:border-primary transition-colors"
|
||||
<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"
|
||||
>
|
||||
Kontakt
|
||||
</a>
|
||||
{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>
|
||||
))}
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user