# Phase 10: Frontend Shell — shadcn/ui ## Setup shadcn/ui ```bash cd frontend npx shadcn@latest init # Responder: Vite, Zinc, CSS variables, YES to tailwind ``` ## Layout principal ``` ┌────────────────────────────────────────────────┐ │ TopBar: [☰] [ABE logo] ···· [⌘K Search] [🌙] [👤]│ ├────────┬───────────────────────────────────────┤ │ │ │ │ Side- │ Content Area │ │ bar │ (React Router Outlet) │ │ │ │ │ 📊 Dashboard │ │ 🔍 Explorations │ │ 🐛 Findings │ │ 📄 Reports │ │ ───────── │ │ ⚙️ Settings │ │ │ │ └────────┴───────────────────────────────────────┘ ``` ## Dark mode (DEFAULT) - Usar estrategia class-based: `` - CSS variables de shadcn ya soportan dark mode - Toggle en TopBar: sol/luna - Persistir en localStorage key 'abe-theme' ## Auth flow en frontend ``` App monta → GET /api/auth/setup-required → si required: mostrar /setup → si no: GET /api/auth/me → si 401: redirect /login → si ok: render AppLayout con user data ``` ## API client (lib/api.ts) ```typescript const API_URL = import.meta.env.VITE_API_URL || ''; export async function apiFetch(path: string, init?: RequestInit): Promise { const res = await fetch(`${API_URL}${path}`, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers }, }); if (res.status === 401) { window.location.href = '/login'; throw new Error('Unauthorized'); } if (!res.ok) { const body = await res.json().catch(() => ({})); throw new Error(body.message || `HTTP ${res.status}`); } return res.json(); } ``` ## Routing ```typescript } /> } /> }> } /> } /> } /> } /> } /> } /> } /> } /> ``` ## Command Palette (⌘K) Powered by shadcn Command (cmdk): - Buscar por: sessions, findings, settings sections - Acciones: "New Exploration", "Generate Report" - Keyboard: ⌘K abre, Esc cierra ## File structure ``` frontend/src/ ├── components/ │ ├── ui/ # shadcn generados (NO tocar) │ ├── layout/ │ │ ├── AppLayout.tsx │ │ ├── AppSidebar.tsx │ │ ├── TopBar.tsx │ │ ├── CommandPalette.tsx │ │ ├── ProtectedRoute.tsx │ │ └── ThemeProvider.tsx │ └── common/ │ └── SeverityBadge.tsx ├── hooks/ │ ├── useAuth.ts │ └── useSocket.ts ├── lib/ │ ├── api.ts │ ├── queryClient.ts │ └── utils.ts # cn() de shadcn ├── stores/ │ └── uiStore.ts ├── pages/ │ ├── Dashboard.tsx (placeholder "Coming in Phase 11") │ ├── Login.tsx │ └── Setup.tsx ├── App.tsx └── main.tsx ``` ## IMPORTANTE - El Dashboard en esta fase puede ser un placeholder que diga "Dashboard — Coming soon" - Lo importante es que el shell funcione: login → sidebar → routing → theme - NO intentar hacer todo el dashboard aquí — eso es Phase 11