import { useRef } from 'react'; import { motion, useMotionValue, useSpring, useTransform } from 'framer-motion'; import { useNavigate, useLocation } from '@tanstack/react-router'; import { LayoutDashboard, Bot, FileText, Database, Terminal, Settings, Users, type LucideIcon, } from 'lucide-react'; import { cn } from '@/lib/utils'; import { useAppStore } from '@/store/app-store'; export function FloatingDock() { const mouseX = useMotionValue(Infinity); const navigate = useNavigate(); const location = useLocation(); const { currentProject } = useAppStore(); const navItems = [ { id: 'board', icon: LayoutDashboard, label: 'Board', path: '/board' }, { id: 'agent', icon: Bot, label: 'Agent', path: '/agent' }, { id: 'spec', icon: FileText, label: 'Spec', path: '/spec' }, { id: 'context', icon: Database, label: 'Context', path: '/context' }, { id: 'profiles', icon: Users, label: 'Profiles', path: '/profiles' }, { id: 'terminal', icon: Terminal, label: 'Terminal', path: '/terminal' }, { id: 'settings', icon: Settings, label: 'Settings', path: '/settings' }, ]; if (!currentProject) return null; return (
mouseX.set(e.pageX)} onMouseLeave={() => mouseX.set(Infinity)} className={cn( 'flex h-16 items-end gap-4 rounded-2xl px-4 pb-3', 'bg-white/5 backdrop-blur-2xl border border-white/10 shadow-2xl' )} > {navItems.map((item) => ( navigate({ to: item.path })} /> ))}
); } function DockIcon({ mouseX, icon: Icon, path, label, isActive, onClick, }: { mouseX: any; icon: LucideIcon; path: string; label: string; isActive: boolean; onClick: () => void; }) { const ref = useRef(null); const distance = useTransform(mouseX, (val: number) => { const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 }; return val - bounds.x - bounds.width / 2; }); const widthSync = useTransform(distance, [-150, 0, 150], [40, 80, 40]); const width = useSpring(widthSync, { mass: 0.1, stiffness: 150, damping: 12 }); return ( {/* Tooltip */}
{label}
{/* Active Dot */} {isActive && ( )} ); }