From 70210a228332fd08288de2ff624ad5cf3f97cb3e Mon Sep 17 00:00:00 2001 From: Cyrus Gray <144336577+graycyrus@users.noreply.github.com> Date: Thu, 11 Jun 2026 18:10:10 +0530 Subject: [PATCH] feat(nav): make Assistant the center FAB, move Brain into the tab row (#3593) --- app/src/components/BottomTabBar.tsx | 60 ++++++++++--------- .../__tests__/BottomTabBar.test.tsx | 43 ++++++------- app/src/config/__tests__/navConfig.test.ts | 47 ++++++++------- app/src/config/navConfig.ts | 32 +++++----- app/src/index.css | 6 -- 5 files changed, 96 insertions(+), 92 deletions(-) diff --git a/app/src/components/BottomTabBar.tsx b/app/src/components/BottomTabBar.tsx index 27cb67299..3ef3202c2 100644 --- a/app/src/components/BottomTabBar.tsx +++ b/app/src/components/BottomTabBar.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; -import { AVATAR_MENU_ITEMS, BRAIN_TAB, NAV_TABS } from '../config/navConfig'; +import { AVATAR_MENU_ITEMS, CENTER_TAB, NAV_TABS } from '../config/navConfig'; import { useT } from '../lib/i18n/I18nContext'; import { useCoreState } from '../providers/CoreStateProvider'; import { trackEvent } from '../services/analytics'; @@ -16,11 +16,14 @@ import { resolveUserName } from '../utils/userName'; // ── SVG icons, keyed by tab id ──────────────────────────────────────────────── -function TabIcon({ id }: { id: string }) { +function TabIcon({ id, large = false }: { id: string; large?: boolean }) { + // Regular pill tabs render small (w-4); the raised center FAB renders large + // (w-6) so its glyph reads as the centerpiece. + const cls = large ? 'w-6 h-6' : 'w-4 h-4'; switch (id) { case 'home': return ( - + + + + + + + { ); }; - // The Brain — a raised circular button rising out of the center of the bar. - // The bg-colored ring fakes a notch cut into the pill's top edge. `brain-fab` - // is targeted by the reduced-motion gate in index.css to silence the glow. + // The Assistant — a raised circular button rising out of the center of the + // bar. The bg-colored ring fakes a notch cut into the pill's top edge. + // `center-fab` marks the button (test/identification hook); it renders a + // static glow when active — no pulse. // // `-my-3` collapses the button's 48px (h-12) layout footprint so it no longer // forces the nav row taller than the ~32px pill tabs — the bar height is - // driven by the tabs, while `-translate-y-5` still lifts the circle above the + // driven by the tabs, while `-translate-y-4` still lifts the circle above the // top edge. Without it the lower half of the raised circle left a dead band // of empty bar height beneath the tabs. - const renderBrainButton = () => { - const active = isActive(BRAIN_TAB.path); - const brainTab = { ...BRAIN_TAB, label: t(BRAIN_TAB.labelKey) }; + const renderCenterButton = () => { + const active = isActive(CENTER_TAB.path); + const centerTab = { ...CENTER_TAB, label: t(CENTER_TAB.labelKey) }; return ( ); }; // Home is a normal pill tab now (no longer pinned/icon-only). The regular - // tabs split evenly around the centered Brain button; only the avatar stays - // pinned to the far-right behind a divider: - // | home · human · assistant ( 🧠 ) connections · activity · settings | [ avatar ] + // tabs split evenly around the centered Assistant button; only the avatar + // stays pinned to the far-right behind a divider: + // | home · human · brain ( 💬 ) connections · activity · settings | [ avatar ] const leftTabs = tabs.slice(0, 3); const rightTabs = tabs.slice(3); @@ -341,7 +345,7 @@ const BottomTabBar = () => { }}>
{ agentProfilesApiMock.select.mockResolvedValue(testProfiles); }); - it('renders exactly 6 regular tab buttons (Brain is rendered separately)', async () => { + it('renders exactly 6 regular tab buttons (Assistant is rendered separately)', async () => { await renderBottomTabBar('/home'); // Query only the regular pill tabs inside