import { useTranslation } from 'react-i18next'; import { NavLink } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; import { useConversationsContext } from '../context/ConversationsContext'; import { useFriendshipsContext } from '../context/FriendshipsContext'; import { ChatBubbleIcon, GearIcon, LogoMark, ShieldIcon, SignOutIcon, SparklesIcon, UsersIcon, } from './icons'; interface NavItem { to: string; labelKey: string; icon: React.ComponentType>; badge?: 'friends' | 'chats'; } const PRIMARY_NAV: NavItem[] = [ { to: '/chats', labelKey: 'app:nav.chats', icon: ChatBubbleIcon, badge: 'chats' }, { to: '/friends', labelKey: 'app:nav.friends', icon: UsersIcon, badge: 'friends' }, ]; const ADMIN_NAV: NavItem = { to: '/admin', labelKey: 'app:nav.admin', icon: ShieldIcon, }; // Clean-Rail 72px icon rail. Brand logo top → primary tabs → spacer → // settings + theme toggle + sign-out at bottom. Active tab shows a pill // indicator anchored to the left edge of the rail. export function Sidebar() { const { t } = useTranslation(['app']); const { signOut, profile } = useAuth(); const { incomingCount } = useFriendshipsContext(); const { totalUnread } = useConversationsContext(); const navItems: NavItem[] = profile?.isAdmin ? [...PRIMARY_NAV, ADMIN_NAV] : PRIMARY_NAV; return ( ); } interface RailNavLinkProps { to: string; label: string; icon: React.ComponentType>; badge?: number; } function RailNavLink({ to, label, icon: Icon, badge = 0 }: RailNavLinkProps) { const ariaLabel = badge > 0 ? `${label} (${badge})` : label; return ( [ 'group relative flex h-11 w-11 cursor-pointer items-center justify-center rounded-xl transition', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/50', isActive ? 'bg-accent text-accent-fg shadow-[0_8px_22px_rgba(88,101,242,0.34)]' : 'text-fg-muted hover:rounded-2xl hover:bg-surface-3/80 hover:text-fg dark:hover:bg-[#313338]', ].join(' ') } > {({ isActive }) => ( <> {isActive && ( ); } interface RailIconButtonProps { label: string; onClick: () => void; icon: React.ComponentType>; tone?: 'default' | 'danger'; } function RailIconButton({ label, onClick, icon: Icon, tone = 'default' }: RailIconButtonProps) { const toneClass = tone === 'danger' ? 'text-fg-muted hover:rounded-2xl hover:bg-rose-500/10 hover:text-rose-400 focus-visible:ring-rose-400/40' : 'text-fg-muted hover:rounded-2xl hover:bg-surface-3/80 hover:text-fg focus-visible:ring-accent/50 dark:hover:bg-[#313338]'; return ( ); } function RailBadge({ count }: { count: number }) { const display = count > 99 ? '99+' : String(count); return ( ); }