From bcc360892c276efd91a9c5bd2b01c84b77f5ace0 Mon Sep 17 00:00:00 2001 From: Mikkel Georgsen Date: Fri, 10 Apr 2026 07:39:56 +0000 Subject: [PATCH] feat(06-03): add AdvisorPage, /advisor route, and TopBar link - AdvisorPage: two-panel layout (sidebar + chat), streaming SSE tokens - Sidebar: conversation list with refetchInterval 5s, New Chat button - Chat: optimistic user messages, streaming cursor, model dropdown - router.tsx: lazy AdvisorPage import + advisorRoute at /advisor - TopBar.tsx: MessageSquare icon + Advisor link between Test and Scan - AppShell.tsx: noPadding prop for full-height layouts --- web/src/components/layout/AppShell.tsx | 10 +- web/src/components/layout/TopBar.tsx | 8 +- web/src/pages/AdvisorPage.tsx | 288 +++++++++++++++++++++++++ web/src/router.tsx | 13 +- 4 files changed, 315 insertions(+), 4 deletions(-) create mode 100644 web/src/pages/AdvisorPage.tsx diff --git a/web/src/components/layout/AppShell.tsx b/web/src/components/layout/AppShell.tsx index 75da8ae..a2d7bad 100644 --- a/web/src/components/layout/AppShell.tsx +++ b/web/src/components/layout/AppShell.tsx @@ -1,11 +1,17 @@ import * as React from 'react' import { TopBar } from './TopBar' -export function AppShell({ children }: { children: React.ReactNode }) { +interface AppShellProps { + children: React.ReactNode + /** When true, removes default padding/max-width from the main content area */ + noPadding?: boolean +} + +export function AppShell({ children, noPadding = false }: AppShellProps) { return (
-
+
{children}
diff --git a/web/src/components/layout/TopBar.tsx b/web/src/components/layout/TopBar.tsx index e7eeac4..c4ff960 100644 --- a/web/src/components/layout/TopBar.tsx +++ b/web/src/components/layout/TopBar.tsx @@ -1,4 +1,4 @@ -import { Plus, QrCode, Cable } from 'lucide-react' +import { Plus, QrCode, Cable, MessageSquare } from 'lucide-react' import { Link } from '@tanstack/react-router' import { Button } from '@/components/ui/button' @@ -9,6 +9,12 @@ export function TopBar() { HWLab
+ +
+ +
+ {conversationsQuery.isLoading && ( +

Loading...

+ )} + {conversationsQuery.data?.length === 0 && ( +

+ No conversations yet +

+ )} + {conversationsQuery.data?.map((conv) => ( + + ))} +
+ + + {/* Main chat panel */} +
+ {/* Messages area */} +
+ {allMessages.length === 0 && !streamingContent && ( +
+ +

Ask anything about your homelab

+
+ )} + + {allMessages.map((msg) => ( +
+
+ {msg.content} +
+
+ ))} + + {/* Streaming assistant message */} + {streamingContent && ( +
+
+ {streamingContent} + +
+
+ )} + +
+
+ + {/* Input row */} +
+ + +