training_data/apps/web/src/components/presentation/NavBar.tsx

59 lines
1.5 KiB
TypeScript

// components/NavBar.tsx
import { motion } from "framer-motion";
import React, { useState } from "react";
interface NavItem {
id: string;
icon?: React.ReactNode;
label: string;
}
interface NavBarProps {
items: NavItem[];
defaultSelected?: string;
onSelect?: (id: string) => void;
}
export const NavBar = ({ items, defaultSelected, onSelect }: NavBarProps) => {
const [selected, setSelected] = useState(defaultSelected || items[0]?.id);
const handleSelect = (id: string) => {
setSelected(id);
onSelect?.(id);
};
return (
<nav className="bg-white px-4 py-2 shadow-sm">
<div className="max-w-6xl mx-auto">
<ul className="flex items-center space-x-8">
{items.map((item) => (
<li key={item.id} className="relative">
<button
onClick={() => handleSelect(item.id)}
className={`flex items-center space-x-2 px-2 py-4 text-sm font-medium transition-colors
${selected === item.id ? "text-black" : "text-gray-500 hover:text-gray-800"}`}>
{item.icon && (
<span className="w-4 h-4">{item.icon}</span>
)}
<span>{item.label}</span>
</button>
{selected === item.id && (
<motion.div
className="absolute bottom-0 left-0 right-0 h-0.5 bg-black"
layoutId="underline"
initial={false}
transition={{
type: "spring",
stiffness: 500,
damping: 30,
}}
/>
)}
</li>
))}
</ul>
</div>
</nav>
);
};