Spaces:
Running
Running
| 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; | |