"use client" /** * AskLeoSidebar — app-wide right rail for the AI assistant. * Mirrors the left sidebar behavior: slides in/out with a toggle button. * Lives in the (app) layout so it persists across all pages. * * The conversation itself is `AskLeoThreadBody`, shared with the floating * window (`components/ask-leo-window.tsx`); this file owns only the docked * shell and its header. */ import * as React from "react" import { useLocation } from "react-router" import { useProduct } from "@/contexts/product-context" import { productSlug } from "@/stores/app-store" import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip" import { useSidebar } from "@/components/ui/sidebar" import { ASK_LEO_PANEL_WIDTH_DEFAULT, ASK_LEO_PANEL_WIDTH_KEY, NestedSecondaryPanelShell, } from "@/components/templates/nested-secondary-panel-shell" import { useSidebarReflowZoom } from "@/hooks/use-sidebar-reflow-zoom" import { AskLeoShortcutKbds, useAskLeo } from "@/components/ask-leo-context" import { AskLeoIdentity, AskLeoNewChatButton, AskLeoThreadBody, } from "@/components/ask-leo-thread-body" import { AskLeoViewToggle } from "@/components/ask-leo-view-toggle" import { useLeoAmbience } from "@/components/leo-ambience-context" import { LeoIcon } from "@/components/ui/leo-icon" import { focusAskLeoLauncher } from "@/lib/ask-leo-focus" function isLeoLandingPath(pathname: string, leoHref: string) { return pathname === leoHref || pathname.startsWith(`${leoHref}/`) } /** * Right-rail Ask Leo — same shell as {@link NestedSecondaryPanelShell} / library secondary nav. * Sits beside `SidebarInset` in the app row (not inside the main inset card). */ export function AskLeoSidebar() { const { open, setOpen } = useAskLeo() const { setSettingsOpen } = useLeoAmbience() const { isMobile } = useSidebar() const reflowZoom = useSidebarReflowZoom() const navFlyout = isMobile || reflowZoom const { pathname } = useLocation() const { product } = useProduct() const leoHref = `/${productSlug(product)}/leo` const isOnLeoLanding = isLeoLandingPath(pathname, leoHref) // Closing takes the focused button off the page with it, which drops focus to // the document root. Hand it back to the toggle that reopens the panel. const closePanel = React.useCallback(() => { setOpen(false) focusAskLeoLauncher() }, [setOpen]) // Primary-nav collapse lives in `AskLeoShell` so switching panel → window // restores the hub width (window must not leave the sidebar collapsed). if (isOnLeoLanding) { return null } return ( <> {navFlyout && open ? (