taghirsado / components /BottomNav.tsx
Opera10's picture
Upload 10 files
a8df197 verified
Raw
History Blame Contribute Delete
4.32 kB
import React from 'react';
type TabType = 'home' | 'custom' | 'history';
interface BottomNavProps {
activeTab: TabType;
onChange: (tab: TabType) => void;
badgeCount?: number;
historyRef?: React.RefObject<HTMLButtonElement | null>;
}
const BottomNav: React.FC<BottomNavProps> = ({ activeTab, onChange, badgeCount, historyRef }) => {
const tabs: { id: TabType; icon: string; label: string; ref?: React.RefObject<HTMLButtonElement | null> }[] = [
{ id: 'home', icon: 'fa-house', label: 'خانه' },
{ id: 'custom', icon: 'fa-microphone-lines', label: 'ساخت صدا' },
{ id: 'history', icon: 'fa-clock-rotate-left', label: 'سوابق', ref: historyRef },
];
return (
<div className="fixed bottom-6 left-0 right-0 z-50 px-6 pointer-events-none">
<div className="max-w-[360px] mx-auto pointer-events-auto relative">
{/* Animated Rotating Border Container */}
<div className="absolute -inset-[2px] rounded-full overflow-hidden">
{/* Spinning Gradient - Very Slow and Subtle Dark Tone */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[200%] h-[1000%] bg-[conic-gradient(from_0deg_at_50%_50%,transparent_0%,rgba(30,41,59,0.15)_50%,transparent_100%)] animate-[spin_10s_linear_infinite]"></div>
</div>
{/* Main Nav Content */}
<div className="relative bg-white/95 backdrop-blur-xl shadow-[0_10px_40px_-10px_rgba(0,0,0,0.1)] border border-white/50 rounded-full h-[70px] flex items-center justify-between px-2">
{tabs.map((tab) => {
const isActive = activeTab === tab.id;
return (
<button
key={tab.id}
ref={tab.ref}
onClick={() => onChange(tab.id)}
className="relative flex-1 h-full flex flex-col items-center justify-center group rounded-full overflow-hidden"
>
{/* Active Indicator Background */}
<div
className={`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full h-full rounded-full transition-all duration-500 ease-out -z-10
${isActive ? 'bg-gradient-to-t from-gray-50 to-transparent opacity-100' : 'opacity-0'}`}
></div>
{/* Badge for History */}
{tab.id === 'history' && badgeCount && badgeCount > 0 ? (
<span className="absolute top-3 right-[28%] flex h-2 w-2 z-20">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-red-500 border border-white"></span>
</span>
) : null}
{/* Icon Container */}
<div className={`relative w-12 h-8 flex items-center justify-center mb-0.5 transition-all duration-300
${isActive ? '-translate-y-1' : 'translate-y-0'}`}>
{/* Active Glow behind icon */}
{isActive && (
<div className="absolute inset-0 bg-blue-500/10 blur-xl rounded-full"></div>
)}
<i className={`fas ${tab.icon} text-xl transition-all duration-300 z-10
${isActive
? 'text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-purple-600 scale-110 drop-shadow-sm'
: 'text-gray-400 group-hover:text-gray-600'}`}>
</i>
</div>
{/* Label - Always Visible */}
<span className={`text-[10px] font-bold transition-all duration-300 absolute bottom-3
${isActive ? 'text-gray-800' : 'text-gray-400'}`}>
{tab.label}
</span>
{/* Bottom Active Dot */}
<div className={`absolute bottom-1 w-1 h-1 rounded-full bg-gradient-to-r from-blue-600 to-purple-600 transition-all duration-300
${isActive ? 'opacity-100 scale-100' : 'opacity-0 scale-0'}`}></div>
</button>
);
})}
</div>
</div>
</div>
);
};
export default BottomNav;