59 lines
1.5 KiB
TypeScript
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>
|
|
);
|
|
};
|