// Unified tab system — identical appearance across every page. // // TabGroup → primary nav row (supports lucide icons, used in Reports + Management + Settings) // TabBar → secondary sub-tab row (pill style, used below TabGroup in Reports) // TabRow → alias for TabGroup without icons — exact same markup and spacing // TabCard → white rounded-xl card shell that wraps tab chrome + content // Use this on any page that has tabs so it sits in the p-6 grey area correctly. // // Rule: ALL tab bars use px-6 pt-2 pb-0, border-b border-slate-200, transparent bg (inherits page bg). // The sky-500 underline indicator is the ONLY active state difference. const TAB_BTN_BASE = 'relative flex items-center gap-2 px-4 py-3 text-[13.5px] font-medium transition-colors whitespace-nowrap' const TAB_BTN_ACTIVE = 'text-slate-900' const TAB_BTN_INACTIVE = 'text-slate-500 hover:text-slate-700' // ─── Primary tab row (with optional icons) ─────────────────────────────────── export function TabGroup({ tabs, active, onChange }) { return (
{tabs.map((tab) => { const isActive = tab.id === active const Icon = tab.icon ?? tab.Icon return ( ) })}
) } // ─── Secondary sub-tab row (pill style) ────────────────────────────────────── export function TabBar({ tabs, active, onChange }) { return (
{tabs.map((tab) => { const isActive = tab.id === active return ( ) })}
) } // ─── TabRow: identical to TabGroup, kept as named alias ────────────────────── export function TabRow({ tabs, active, onChange }) { return } // ─── TabCard: the white card shell for any tabbed page ─────────────────────── // Renders a rounded-xl bordered white card that fills the available space. // Place TabGroup/TabBar as direct children, then a flex-1 overflow content area. // // Usage: // // // {/* optional */} //
...
//
export function TabCard({ children, className = '' }) { return (
{children}
) }