All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 39s
Build & Deploy / 🧪 QA (push) Successful in 1m44s
Build & Deploy / 🏗️ Build (push) Successful in 3m23s
Build & Deploy / 🚀 Deploy (push) Successful in 47s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m2s
Build & Deploy / 🔔 Notify (push) Successful in 2s
102 lines
3.9 KiB
TypeScript
102 lines
3.9 KiB
TypeScript
'use client';
|
|
|
|
import * as React from 'react';
|
|
import { usePathname } from 'next/navigation';
|
|
import { TransitionLink } from '@/components/ui/TransitionLink';
|
|
import { Home, Briefcase, Users, Mail } from 'lucide-react';
|
|
import { motion } from 'framer-motion';
|
|
|
|
export interface NavLink {
|
|
label: string;
|
|
url: string;
|
|
}
|
|
|
|
interface MobileBottomNavProps {
|
|
navLinks: NavLink[];
|
|
currentLocale: string;
|
|
}
|
|
|
|
export function MobileBottomNav({ navLinks, currentLocale }: MobileBottomNavProps) {
|
|
const pathname = usePathname() || '/';
|
|
|
|
// Construct our bottom nav items based on the passed links
|
|
const items = React.useMemo(() => {
|
|
const homeUrl = `/${currentLocale}`;
|
|
|
|
// Find the specific links from the provided navLinks (which might be translated)
|
|
// We do a simple match based on index or keywords if needed, but since we know the order:
|
|
// 0: Kompetenzen, 1: Über uns, 2: Karriere, 3: Messen
|
|
const competenciesUrl = navLinks[0]?.url || `/${currentLocale}/kompetenzen`;
|
|
const aboutUrl = navLinks[1]?.url || `/${currentLocale}/ueber-uns`;
|
|
const contactUrl = `/${currentLocale}/${currentLocale === 'de' ? 'kontakt' : 'contact'}`;
|
|
|
|
return [
|
|
{
|
|
label: currentLocale === 'de' ? 'Start' : 'Home',
|
|
url: homeUrl,
|
|
icon: <Home className="w-6 h-6 mb-1" strokeWidth={2} />,
|
|
exactMatch: true
|
|
},
|
|
{
|
|
label: navLinks[0]?.label || (currentLocale === 'de' ? 'Kompetenzen' : 'Competencies'),
|
|
url: competenciesUrl,
|
|
icon: <Briefcase className="w-6 h-6 mb-1" strokeWidth={2} />
|
|
},
|
|
{
|
|
label: navLinks[1]?.label || (currentLocale === 'de' ? 'Über uns' : 'About Us'),
|
|
url: aboutUrl,
|
|
icon: <Users className="w-6 h-6 mb-1" strokeWidth={2} />
|
|
},
|
|
{
|
|
label: currentLocale === 'de' ? 'Kontakt' : 'Contact',
|
|
url: contactUrl,
|
|
icon: <Mail className="w-6 h-6 mb-1" strokeWidth={2} />
|
|
}
|
|
];
|
|
}, [currentLocale, navLinks]);
|
|
|
|
return (
|
|
<div className="md:hidden fixed bottom-0 left-0 right-0 z-50 px-2 pb-6 pt-2 bg-gradient-to-t from-white via-white to-white/90 backdrop-blur-xl border-t border-neutral-200/50 shadow-[0_-8px_32px_rgba(0,0,0,0.05)] safe-area-bottom">
|
|
<nav className="flex justify-around items-center max-w-md mx-auto">
|
|
{items.map((item) => {
|
|
// Determine if active
|
|
const mappedUrl = item.url.startsWith('/') && !item.url.match(/^\/(en|de)/)
|
|
? `/${currentLocale}${item.url}`
|
|
: item.url;
|
|
|
|
const isActive = item.exactMatch
|
|
? pathname === mappedUrl
|
|
: (pathname === mappedUrl || (mappedUrl !== `/${currentLocale}` && pathname?.startsWith(`${mappedUrl}/`)));
|
|
|
|
return (
|
|
<TransitionLink
|
|
key={item.label}
|
|
href={mappedUrl}
|
|
className={`relative flex flex-col items-center justify-center w-full min-h-[44px] py-1 transition-colors duration-300 select-none ${
|
|
isActive ? 'text-primary' : 'text-neutral-500 hover:text-neutral-900'
|
|
}`}
|
|
>
|
|
<div className="relative flex flex-col items-center justify-center">
|
|
{/* Active Icon Background */}
|
|
{isActive && (
|
|
<motion.div
|
|
layoutId="mobile-nav-active-bg"
|
|
className="absolute inset-0 bg-primary/10 rounded-full scale-150"
|
|
transition={{ type: 'spring', stiffness: 500, damping: 30 }}
|
|
/>
|
|
)}
|
|
|
|
{/* Icon wrapper to ensure it sits above the background */}
|
|
<div className="relative z-10 transition-transform duration-300 active:scale-90">
|
|
{item.icon}
|
|
</div>
|
|
</div>
|
|
<span className="text-[10px] font-semibold mt-0.5 tracking-wide z-10">{item.label}</span>
|
|
</TransitionLink>
|
|
);
|
|
})}
|
|
</nav>
|
|
</div>
|
|
);
|
|
}
|