"use client"; import { useAtomValue, useSetAtom } from "jotai"; import { Plus, X } from "lucide-react"; import { useCallback, useEffect, useRef } from "react"; import { activeTabIdAtom, closeTabAtom, switchTabAtom, type Tab, tabsAtom, } from "@/atoms/tabs/tabs.atom"; import { cn } from "@/lib/utils"; interface TabBarProps { onTabSwitch?: (tab: Tab) => void; onNewChat?: () => void; rightActions?: React.ReactNode; className?: string; } export function TabBar({ onTabSwitch, onNewChat, rightActions, className }: TabBarProps) { const tabs = useAtomValue(tabsAtom); const activeTabId = useAtomValue(activeTabIdAtom); const switchTab = useSetAtom(switchTabAtom); const closeTab = useSetAtom(closeTabAtom); const scrollRef = useRef(null); const handleTabClick = useCallback( (tab: Tab) => { if (tab.id === activeTabId) return; switchTab(tab.id); onTabSwitch?.(tab); }, [activeTabId, switchTab, onTabSwitch] ); const handleTabClose = useCallback( (e: React.MouseEvent, tabId: string) => { e.stopPropagation(); const fallback = closeTab(tabId); if (fallback) { onTabSwitch?.(fallback); } }, [closeTab, onTabSwitch] ); // Keep active tab visible with minimal scroll shift. useEffect(() => { if (!scrollRef.current || !activeTabId) return; const scroller = scrollRef.current; const activeEl = scroller.querySelector(`[data-tab-id="${activeTabId}"]`); if (!activeEl) return; const viewLeft = scroller.scrollLeft; const viewRight = viewLeft + scroller.clientWidth; const tabLeft = activeEl.offsetLeft; const tabRight = tabLeft + activeEl.offsetWidth; if (tabLeft < viewLeft) { scroller.scrollTo({ left: tabLeft, behavior: "smooth" }); return; } if (tabRight > viewRight) { scroller.scrollTo({ left: tabRight - scroller.clientWidth, behavior: "smooth" }); } }, [activeTabId]); // Only show tab bar when there's more than one tab if (tabs.length <= 1) return null; return (
{tabs.map((tab) => { const isActive = tab.id === activeTabId; return ( ); })}
{onNewChat && ( )} {rightActions}
); }