From 62cae68d05cb0e61594f22611f7d73f13ecd2704 Mon Sep 17 00:00:00 2001 From: Offending Commit Date: Fri, 15 May 2026 14:21:40 -0500 Subject: [PATCH] feat(web): add workspace contextual sub-nav to sidebar Detect active workspace via fuzzy matchRoute against /workspaces/$workspaceId and reveal an animated sub-nav with links to Peers, Sessions, Conclusions, and Webhooks for that workspace. Sub-nav collapses smoothly when leaving the workspace context. --- .../web/src/components/layout/Sidebar.tsx | 93 ++++++++++++++++++- 1 file changed, 89 insertions(+), 4 deletions(-) diff --git a/packages/web/src/components/layout/Sidebar.tsx b/packages/web/src/components/layout/Sidebar.tsx index 5f9a7b3..8c4ddf1 100644 --- a/packages/web/src/components/layout/Sidebar.tsx +++ b/packages/web/src/components/layout/Sidebar.tsx @@ -1,5 +1,5 @@ import { Link, useMatchRoute } from "@tanstack/react-router"; -import { motion } from "framer-motion"; +import { AnimatePresence, motion } from "framer-motion"; import { Boxes, Check, @@ -8,9 +8,13 @@ import { Eye, EyeOff, LayoutDashboard, + Lightbulb, + MessageSquare, Moon, Settings, Sun, + Users, + Webhook, } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { HealthDot } from "@/components/shared/HealthDot"; @@ -20,12 +24,19 @@ import { useInstances } from "@/hooks/useInstances"; import { useTheme } from "@/hooks/useTheme"; import { COLOR } from "@/lib/constants"; -const navItems = [ +const TOP_NAV = [ { to: "/" as const, label: "Dashboard", icon: LayoutDashboard, exact: true }, { to: "/workspaces" as const, label: "Workspaces", icon: Boxes, exact: false }, { to: "/settings" as const, label: "Settings", icon: Settings, exact: false }, ]; +const WORKSPACE_SECTIONS = [ + { label: "Peers", icon: Users, section: "peers" }, + { label: "Sessions", icon: MessageSquare, section: "sessions" }, + { label: "Conclusions", icon: Lightbulb, section: "conclusions" }, + { label: "Webhooks", icon: Webhook, section: "webhooks" }, +] as const; + export function Sidebar() { const matchRoute = useMatchRoute(); const { instances, active, activate } = useInstances(); @@ -46,6 +57,13 @@ export function Sidebar() { return () => window.removeEventListener("mousedown", onClick); }, [switcherOpen]); + // Detect workspace context — matchRoute returns params or false + const wsMatch = matchRoute({ + to: "/workspaces/$workspaceId" as never, + fuzzy: true, + }) as { workspaceId: string } | false; + const activeWorkspaceId = wsMatch ? wsMatch.workspaceId : null; + return ( {/* Nav */} -