phase 16: React dashboard with full platform control and analytics

This commit is contained in:
Celes Renata
2026-04-11 16:19:46 -07:00
parent 25e0e386b7
commit faccb0b8db
53 changed files with 7924 additions and 13 deletions
+105
View File
@@ -0,0 +1,105 @@
import type { ReactNode } from 'react';
import { Link, useRouterState } from '@tanstack/react-router';
import {
Home,
Building2,
FileText,
TrendingUp,
Lightbulb,
ShoppingCart,
Wallet,
ShieldCheck,
Activity,
Download,
Cpu,
Radar,
Terminal,
LayoutDashboard,
List,
} from 'lucide-react';
interface NavItem {
to: string;
label: string;
icon: ReactNode;
group?: string;
}
const navItems: NavItem[] = [
{ to: '/', label: 'Home', icon: <Home size={18} /> },
{ to: '/companies', label: 'Companies', icon: <Building2 size={18} />, group: 'Data' },
{ to: '/watchlists', label: 'Watchlists', icon: <List size={18} />, group: 'Data' },
{ to: '/documents', label: 'Documents', icon: <FileText size={18} />, group: 'Data' },
{ to: '/trends', label: 'Trends', icon: <TrendingUp size={18} />, group: 'Intelligence' },
{ to: '/recommendations', label: 'Recommendations', icon: <Lightbulb size={18} />, group: 'Intelligence' },
{ to: '/orders', label: 'Orders', icon: <ShoppingCart size={18} />, group: 'Trading' },
{ to: '/positions', label: 'Positions', icon: <Wallet size={18} />, group: 'Trading' },
{ to: '/trading', label: 'Trading Controls', icon: <ShieldCheck size={18} />, group: 'Trading' },
{ to: '/ops/pipeline', label: 'Pipeline', icon: <Activity size={18} />, group: 'Ops' },
{ to: '/ops/ingestion', label: 'Ingestion', icon: <Download size={18} />, group: 'Ops' },
{ to: '/ops/model', label: 'Model Perf', icon: <Cpu size={18} />, group: 'Ops' },
{ to: '/ops/coverage', label: 'Coverage', icon: <Radar size={18} />, group: 'Ops' },
{ to: '/analytics/query', label: 'SQL Explorer', icon: <Terminal size={18} />, group: 'Analytics' },
{ to: '/analytics/dashboards', label: 'Dashboards', icon: <LayoutDashboard size={18} />, group: 'Analytics' },
];
export function AppLayout({ children }: { children: ReactNode }) {
const routerState = useRouterState();
const currentPath = routerState.location.pathname;
let lastGroup: string | undefined;
return (
<div className="flex h-screen overflow-hidden">
{/* Sidebar */}
<nav
className="w-56 shrink-0 bg-surface-900 border-r border-surface-700 flex flex-col"
aria-label="Main navigation"
>
<div className="px-4 py-4 border-b border-surface-700">
<span className="text-lg font-bold tracking-tight text-brand-400">
Stonks Oracle
</span>
</div>
<div className="flex-1 overflow-y-auto py-2 px-2 space-y-0.5">
{navItems.map((item) => {
const showGroup = item.group && item.group !== lastGroup;
lastGroup = item.group;
const active =
item.to === '/'
? currentPath === '/'
: currentPath.startsWith(item.to);
return (
<div key={item.to}>
{showGroup && (
<div className="px-2 pt-4 pb-1 text-[11px] font-semibold uppercase tracking-wider text-gray-500">
{item.group}
</div>
)}
<Link
to={item.to}
className={`flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-sm transition-colors ${
active
? 'bg-brand-600/20 text-brand-300'
: 'text-gray-400 hover:bg-surface-800 hover:text-gray-200'
}`}
aria-current={active ? 'page' : undefined}
>
{item.icon}
{item.label}
</Link>
</div>
);
})}
</div>
</nav>
{/* Main content */}
<main className="flex-1 overflow-y-auto bg-surface-950 p-6">
{children}
</main>
</div>
);
}