feat(ui): redesign header to premium floating pill with framer-motion active indicators and dynamic CTA

Former-commit-id: 4586ca5af936d5f81485e92af70353ccfcfb767a
This commit is contained in:
2026-05-07 14:25:45 +02:00
parent c2d0279755
commit f47c07c98e
127 changed files with 247 additions and 229 deletions

View File

@@ -69,50 +69,71 @@ export function Header({ navLinks }: HeaderProps) {
return (
<>
<header
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ease-in-out ${
isSolidMode
? 'bg-neutral-light/90 backdrop-blur-md shadow-sm py-4'
: 'bg-transparent py-6'
className={`fixed top-0 left-0 right-0 z-50 flex justify-center transition-all duration-700 ease-[cubic-bezier(0.16,1,0.3,1)] ${
isSolidMode ? 'pt-4 px-4' : 'pt-0 px-0'
}`}
>
<div className="container flex items-center justify-between">
<Link href={`/${currentLocale}`} className="relative flex items-center h-12 w-48 z-50">
<div
className={`w-full transition-all duration-700 ease-[cubic-bezier(0.16,1,0.3,1)] flex items-center justify-between ${
isSolidMode
? 'max-w-7xl rounded-full bg-white/85 backdrop-blur-2xl shadow-[0_8px_32px_rgba(0,0,0,0.08)] border border-white/60 py-2.5 px-6 md:px-8'
: 'bg-transparent py-6 container'
}`}
>
<Link href={`/${currentLocale}`} className={`relative flex items-center transition-all duration-500 ease-out z-50 group ${isSolidMode ? 'h-9 w-36' : 'h-12 w-48'}`}>
<Image
src={(isSolidMode || isMobileMenuOpen) ? "/assets/logo.png" : "/assets/logo-white.png"}
alt="E-TIB Gruppe"
fill
className="object-contain object-left"
className="object-contain object-left group-hover:scale-105 transition-transform duration-500 origin-left"
priority
sizes="192px"
/>
</Link>
<nav className="hidden md:flex items-center gap-10">
<nav className="hidden md:flex items-center gap-8 lg:gap-10">
{navLinks && navLinks.length > 0 && navLinks.map((link) => {
const mappedUrl = link.url.startsWith('/') && !link.url.match(/^\/(en|de)/)
? `/${currentLocale}${link.url}`
: link.url;
const isActive = pathname === mappedUrl || (mappedUrl !== `/${currentLocale}` && pathname?.startsWith(`${mappedUrl}/`));
return (
<Link
key={link.url}
href={mappedUrl}
className={`font-semibold text-sm uppercase tracking-widest transition-all duration-300 ${
className={`relative font-bold text-xs lg:text-sm uppercase tracking-widest transition-colors duration-300 group py-2 ${
isSolidMode
? 'text-text-primary hover:text-primary'
: 'text-neutral-light hover:text-primary-light'
? (isActive ? 'text-primary' : 'text-text-primary hover:text-primary')
: (isActive ? 'text-white' : 'text-white/80 hover:text-white')
}`}
>
{link.label}
{/* Framer Motion Active Indicator */}
{isActive && (
<motion.div
layoutId="header-active-indicator"
className={`absolute -bottom-1 left-0 right-0 h-0.5 rounded-full ${isSolidMode ? 'bg-primary' : 'bg-white'}`}
transition={{ type: 'spring', stiffness: 400, damping: 30 }}
/>
)}
{/* Subtle hover underline */}
<span className={`absolute -bottom-1 left-1/2 w-0 h-0.5 -translate-x-1/2 rounded-full transition-all duration-300 ease-out group-hover:w-full ${isSolidMode ? 'bg-primary/30' : 'bg-white/30'} ${isActive ? 'opacity-0' : 'opacity-100'}`} />
</Link>
);
})}
<div className={`h-4 w-px mx-2 transition-colors duration-300 ${isSolidMode ? 'bg-neutral-300' : 'bg-white/20'}`} />
<div className={`h-5 w-px transition-colors duration-300 ${isSolidMode ? 'bg-neutral-200' : 'bg-white/20'}`} />
<LanguageSwitcher isSolidMode={isSolidMode} />
<Button
href={`/${currentLocale}/${currentLocale === 'de' ? 'kontakt' : 'contact'}`}
variant="primary"
className="px-8"
variant={isSolidMode ? "primary" : "outline"}
className={`px-7 py-2.5 ml-2 transition-all duration-500 ${!isSolidMode ? 'border-white/30 hover:border-white text-white hover:bg-white hover:text-neutral-dark' : ''}`}
>
{currentLocale === 'de' ? 'Kontakt' : 'Contact'}
</Button>
@@ -120,21 +141,22 @@ export function Header({ navLinks }: HeaderProps) {
{/* Mobile Nav Button */}
<button
className="md:hidden z-50 text-primary p-2"
className="md:hidden z-50 p-2 relative group"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label="Toggle menu"
>
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke={(isSolidMode || isMobileMenuOpen) ? "currentColor" : "white"} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<div className={`absolute inset-0 rounded-full transition-all duration-300 ${isSolidMode ? 'bg-neutral-100 group-hover:bg-neutral-200' : 'bg-white/10 group-hover:bg-white/20'}`} />
<svg className="relative z-10 transition-transform duration-300 group-hover:scale-110" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke={(isSolidMode || isMobileMenuOpen) ? "currentColor" : "white"} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
{isMobileMenuOpen ? (
<>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
<line x1="18" y1="6" x2="6" y2="18" className="origin-center animate-in fade-in zoom-in duration-300" />
<line x1="6" y1="6" x2="18" y2="18" className="origin-center animate-in fade-in zoom-in duration-300" />
</>
) : (
<>
<line x1="3" x2="21" y1="6" y2="6"/>
<line x1="3" x2="21" y1="12" y2="12"/>
<line x1="3" x2="21" y1="18" y2="18"/>
<line x1="3" x2="21" y1="6" y2="6" className="transition-all duration-300 group-hover:translate-x-1" />
<line x1="3" x2="21" y1="12" y2="12" />
<line x1="3" x2="21" y1="18" y2="18" className="transition-all duration-300 group-hover:-translate-x-1" />
</>
)}
</svg>