diff --git a/crates/agent-gateway/web/src/components/hub/HubChrome.tsx b/crates/agent-gateway/web/src/components/hub/HubChrome.tsx index ad295d273..b49340216 100644 --- a/crates/agent-gateway/web/src/components/hub/HubChrome.tsx +++ b/crates/agent-gateway/web/src/components/hub/HubChrome.tsx @@ -1,4 +1,4 @@ -import type { ReactNode } from "react"; +import type { ButtonHTMLAttributes, ReactNode } from "react"; import { useLocale } from "../../i18n"; import { cn } from "../../lib/shared/utils"; import { PanelLeft } from "../icons"; @@ -6,15 +6,14 @@ import { Button } from "../ui/button"; export function HubBackdrop(props: { tone?: "amber" | "violet" | "neutral" }) { const { tone = "neutral" } = props; - // macOS frosted-glass: subtle monochrome wash; tone provides only the faintest temperature shift. - // Dark: the canvas drops below --background (--hub-canvas) so background-tinted glass reads - // elevated, and the halos stay a whisper above the canvas instead of a gray fog. + // Cool monochrome wash; tone only shifts temperature slightly. + // Dark canvas sits below --background so glass panels read elevated. const haloClass = tone === "amber" - ? "bg-[radial-gradient(circle_at_top_left,hsl(0_0%_100%/0.85),transparent_60%)] dark:bg-[radial-gradient(circle_at_top_left,hsl(222_18%_14%/0.55),transparent_60%)]" + ? "bg-[radial-gradient(circle_at_top_left,hsl(40_30%_98%/0.9),transparent_58%)] dark:bg-[radial-gradient(circle_at_top_left,hsl(36_18%_14%/0.45),transparent_58%)]" : tone === "violet" - ? "bg-[radial-gradient(circle_at_top_left,hsl(220_18%_98%/0.85),transparent_60%)] dark:bg-[radial-gradient(circle_at_top_left,hsl(224_20%_14%/0.55),transparent_60%)]" - : "bg-[radial-gradient(circle_at_top_left,hsl(0_0%_100%/0.8),transparent_60%)] dark:bg-[radial-gradient(circle_at_top_left,hsl(224_18%_14%/0.5),transparent_60%)]"; + ? "bg-[radial-gradient(circle_at_top_left,hsl(250_28%_98%/0.9),transparent_58%)] dark:bg-[radial-gradient(circle_at_top_left,hsl(250_18%_14%/0.45),transparent_58%)]" + : "bg-[radial-gradient(circle_at_top_left,hsl(240_12%_98%/0.88),transparent_58%)] dark:bg-[radial-gradient(circle_at_top_left,hsl(240_12%_14%/0.4),transparent_58%)]"; return ( <>
@@ -26,7 +25,7 @@ export function HubBackdrop(props: { tone?: "amber" | "violet" | "neutral" }) { />
@@ -45,9 +44,10 @@ export function HubHeader(props: { }) { const { icon, title, subtitle, actions, sidebarOpen, onOpenSidebar } = props; const { t } = useLocale(); + // Web has no macOS title-bar overlay; always show the open-sidebar control when closed. const showSidebarButton = !sidebarOpen; return ( -
+
{showSidebarButton ? ( ) : null}
-
+
{icon}
-

+

{title}

{subtitle ? ( -

+

{subtitle}

) : null} @@ -92,31 +95,61 @@ export function GlassPanel(props: { className?: string; }) { const { children, tone = "default", active = false, className } = props; - const toneClass = (() => { - switch (tone) { - case "muted": - return "border-border/40 bg-muted/40"; - case "error": - return "border-destructive/30 bg-destructive/5"; - case "amber": - case "violet": - case "neutral": - return active - ? "border-border/55 bg-background/80 shadow-[0_1px_0_rgba(255,255,255,0.6)_inset,0_6px_22px_-14px_rgba(15,23,42,0.18)] dark:border-white/[0.09] dark:bg-white/[0.06] dark:shadow-[0_1px_0_rgba(255,255,255,0.06)_inset,0_6px_22px_-14px_rgba(0,0,0,0.55)]" - : "border-border/40 bg-background/60"; - default: - return "border-border/40 bg-background/60"; - } - })(); return (
{children}
); } + +/** Status strip under HubHeader (Skills enabled / MCP ready). */ +export function HubStatusBanner(props: { + ready?: boolean; + children: ReactNode; + className?: string; +}) { + const { ready = false, children, className } = props; + return ( +
+ {children} +
+ ); +} + +/** Segmented tab track (Installed / Store / Import). */ +export function HubSegmentedTrack(props: { children: ReactNode; className?: string }) { + return
{props.children}
; +} + +export function HubSegmentButton( + props: ButtonHTMLAttributes & { + active?: boolean; + icon?: ReactNode; + count?: number | null; + }, +) { + const { active, icon, count, className, children, type = "button", ...rest } = props; + return ( + + ); +} diff --git a/crates/agent-gateway/web/src/components/project-tools/RightDockLauncher.tsx b/crates/agent-gateway/web/src/components/project-tools/RightDockLauncher.tsx index f2b9520e1..2bd23ebaa 100644 --- a/crates/agent-gateway/web/src/components/project-tools/RightDockLauncher.tsx +++ b/crates/agent-gateway/web/src/components/project-tools/RightDockLauncher.tsx @@ -190,7 +190,7 @@ export function RightDockChooser(props: RightDockChooserProps) { onClick={tool.onClick} disabled={tool.disabled} title={tool.titleAttr} - className="group flex items-center gap-3 rounded-lg border border-border/60 bg-background px-3.5 py-3 text-left text-sm text-foreground transition-all hover:border-border hover:bg-muted/60 hover:shadow-sm disabled:pointer-events-none disabled:opacity-50" + className="group flex items-center gap-3 rounded-2xl border border-border/50 bg-background/70 px-3.5 py-3 text-left text-sm text-foreground shadow-[0_1px_0_rgba(255,255,255,0.45)_inset] backdrop-blur-md transition-[background-color,border-color,transform,box-shadow] duration-150 ease-[cubic-bezier(0.23,1,0.32,1)] hover:border-border hover:bg-background/90 hover:shadow-sm active:scale-[0.98] disabled:pointer-events-none disabled:opacity-50 motion-reduce:active:scale-100 dark:border-white/[0.08] dark:bg-white/[0.04] dark:shadow-[0_1px_0_rgba(255,255,255,0.06)_inset]" >
{tool.icon} diff --git a/crates/agent-gateway/web/src/components/project-tools/RightDockPanel.tsx b/crates/agent-gateway/web/src/components/project-tools/RightDockPanel.tsx index 1d8fbecc2..b58a42ad2 100644 --- a/crates/agent-gateway/web/src/components/project-tools/RightDockPanel.tsx +++ b/crates/agent-gateway/web/src/components/project-tools/RightDockPanel.tsx @@ -742,22 +742,18 @@ export const RightDockPanel = memo(function RightDockPanel(props: RightDockPanel data-state={isOpen ? "open" : "closed"} data-project-tools-resizing={isResizing ? "true" : undefined} className={cn( - "project-tools-panel zone-font-scale fixed inset-x-0 bottom-0 z-40 flex h-[min(72vh,34rem)] min-h-0 w-full shrink-0 flex-col overflow-hidden bg-background shadow-2xl transition-[opacity,transform] duration-200 ease-out motion-reduce:transition-none md:relative md:inset-auto md:z-10 md:h-full md:overflow-visible md:shadow-none", + // Desktop: single drawer (track width + panel slide). Do NOT fade + // opacity first then collapse width — that reads as a double close. + // Mobile: bottom sheet via translate-y only. + "project-tools-panel zone-font-scale fixed inset-x-0 bottom-0 z-40 h-[min(72vh,34rem)] min-h-0 w-full shrink-0 overflow-hidden border-t shadow-[0_-12px_40px_-18px_rgba(15,23,42,0.28)] motion-reduce:transition-none md:relative md:inset-auto md:z-10 md:h-full md:border-l md:border-t-0 md:shadow-none", isOpen - ? "pointer-events-auto translate-y-0 border-t border-border opacity-100 md:w-[var(--project-tools-panel-width)] md:translate-x-0 md:border-l md:border-t-0" - : "pointer-events-none translate-y-full border-t border-transparent opacity-0 md:translate-x-3 md:translate-y-0 md:border-l-0 md:border-t-0", + ? "pointer-events-auto translate-y-0 md:translate-y-0" + : "pointer-events-none translate-y-full border-transparent md:translate-y-0", effectiveWidthCollapsed ? "md:w-0" : "md:w-[var(--project-tools-panel-width)]", )} style={{ ...panelStyle, "--zone-font-scale": fontScale } as CSSProperties} > -
+
{effectiveShouldRenderContent ? ( <>