From 6cc5efde0ccefabbbb520422b1c394dd92300d39 Mon Sep 17 00:00:00 2001 From: Gavin Kline Date: Sat, 25 Jul 2026 12:32:16 -0400 Subject: [PATCH 1/3] fix: make composer banners more opaque --- .../components/chat/ComposerBannerStack.tsx | 6 +-- .../chat/ProviderStatusBanner.test.tsx | 10 +++- .../components/chat/ProviderStatusBanner.tsx | 50 +++++++++---------- apps/web/src/components/ui/alert.tsx | 3 ++ 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/apps/web/src/components/chat/ComposerBannerStack.tsx b/apps/web/src/components/chat/ComposerBannerStack.tsx index 3f8f56f041a..b60f1533da3 100644 --- a/apps/web/src/components/chat/ComposerBannerStack.tsx +++ b/apps/web/src/components/chat/ComposerBannerStack.tsx @@ -172,11 +172,7 @@ function ComposerBannerStackAlert({ const dismissOnly = item.onDismiss && !item.actions; return ( - + {item.icon} {item.title} {item.description ? {item.description} : null} diff --git a/apps/web/src/components/chat/ProviderStatusBanner.test.tsx b/apps/web/src/components/chat/ProviderStatusBanner.test.tsx index 2a5bfe9ed3a..3d8a33360eb 100644 --- a/apps/web/src/components/chat/ProviderStatusBanner.test.tsx +++ b/apps/web/src/components/chat/ProviderStatusBanner.test.tsx @@ -41,7 +41,15 @@ describe("ProviderStatusBanner", () => { expect(markup).toContain('role="alert"'); expect(markup).toContain('aria-label="Dismiss Codex provider warning"'); - expect(markup).toContain("absolute top-2 right-2"); + }); + + it("renders an opaque surface so the timeline behind it cannot read through", () => { + const markup = renderToStaticMarkup( + {}} />, + ); + + expect(markup).toContain("alert-glass"); + expect(markup).toContain('data-variant="warning"'); }); it("labels error dismiss controls with the correct severity", () => { diff --git a/apps/web/src/components/chat/ProviderStatusBanner.tsx b/apps/web/src/components/chat/ProviderStatusBanner.tsx index a64a94bc1c3..aa4d8370a3e 100644 --- a/apps/web/src/components/chat/ProviderStatusBanner.tsx +++ b/apps/web/src/components/chat/ProviderStatusBanner.tsx @@ -1,8 +1,9 @@ import { type ServerProvider } from "@t3tools/contracts"; import { memo } from "react"; import { InfoIcon, XIcon } from "lucide-react"; -import { cn } from "~/lib/utils"; import { formatProviderDriverKindLabel } from "../../providerModels"; +import { Alert, AlertAction, AlertDescription, AlertTitle } from "../ui/alert"; +import { Button } from "../ui/button"; import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; export function getProviderStatusBannerKey(status: ServerProvider | null): string | null { @@ -44,36 +45,33 @@ export const ProviderStatusBanner = memo(function ProviderStatusBanner({ return (
-
- -
-
{title}
+ {/* + * This banner is an overlay painted on top of the message timeline, so it + * needs `alert-glass` — the alert variants alone are a 4% tint with no + * surface behind them, which lets the transcript read through the copy. + */} + + + {title} + - {message}
} - /> + {message}
} /> {message} -
- - + + + + +
); }); diff --git a/apps/web/src/components/ui/alert.tsx b/apps/web/src/components/ui/alert.tsx index 20be44dd3e5..ee65e800bb3 100644 --- a/apps/web/src/components/ui/alert.tsx +++ b/apps/web/src/components/ui/alert.tsx @@ -68,6 +68,9 @@ function Alert({
From e2778ea37ad23b9d469bfc440accdba63ee9884c Mon Sep 17 00:00:00 2001 From: Gavin Kline Date: Sat, 25 Jul 2026 14:13:51 -0400 Subject: [PATCH 2/3] fix(web): tint the provider banner dismiss icon with its alert variant The ghost Button variant forces `svg:not([class*='text-'])` to muted-foreground, which out-specifies the alert's `[&_svg]` tint and left the dismiss X grey where it used to be destructive-coloured. Colour the icon at the call site, the same way ThreadErrorBanner does. Also drops two explanatory comments flagged in review. Co-Authored-By: Claude Opus 5 (1M context) --- .../components/chat/ProviderStatusBanner.tsx | 19 ++++++++++++------- apps/web/src/components/ui/alert.tsx | 2 -- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/web/src/components/chat/ProviderStatusBanner.tsx b/apps/web/src/components/chat/ProviderStatusBanner.tsx index aa4d8370a3e..70bcb3e917c 100644 --- a/apps/web/src/components/chat/ProviderStatusBanner.tsx +++ b/apps/web/src/components/chat/ProviderStatusBanner.tsx @@ -1,6 +1,7 @@ import { type ServerProvider } from "@t3tools/contracts"; import { memo } from "react"; import { InfoIcon, XIcon } from "lucide-react"; +import { cn } from "~/lib/utils"; import { formatProviderDriverKindLabel } from "../../providerModels"; import { Alert, AlertAction, AlertDescription, AlertTitle } from "../ui/alert"; import { Button } from "../ui/button"; @@ -32,6 +33,7 @@ export const ProviderStatusBanner = memo(function ProviderStatusBanner({ } const providerName = status.displayName?.trim() || formatProviderDriverKindLabel(status.driver); + const variant = status.status === "warning" ? "warning" : "error"; const isUnauthenticated = status.status === "error" && status.auth.status === "unauthenticated"; const title = isUnauthenticated ? `${providerName} is unauthenticated` @@ -45,12 +47,7 @@ export const ProviderStatusBanner = memo(function ProviderStatusBanner({ return (
- {/* - * This banner is an overlay painted on top of the message timeline, so it - * needs `alert-glass` — the alert variants alone are a 4% tint with no - * surface behind them, which lets the transcript read through the copy. - */} - + {title} @@ -68,7 +65,15 @@ export const ProviderStatusBanner = memo(function ProviderStatusBanner({ aria-label={`Dismiss ${providerName} provider ${status.status}`} onClick={onDismiss} > - + {/* Ghost buttons force svgs to muted-foreground unless the icon + sets its own text colour, which would drop the alert's tint. */} + diff --git a/apps/web/src/components/ui/alert.tsx b/apps/web/src/components/ui/alert.tsx index ee65e800bb3..c2b8c5ea0d7 100644 --- a/apps/web/src/components/ui/alert.tsx +++ b/apps/web/src/components/ui/alert.tsx @@ -68,8 +68,6 @@ function Alert({
Date: Sat, 25 Jul 2026 14:15:03 -0400 Subject: [PATCH 3/3] chore(web): drop explanatory comment on the dismiss icon Co-Authored-By: Claude Opus 5 (1M context) --- apps/web/src/components/chat/ProviderStatusBanner.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/web/src/components/chat/ProviderStatusBanner.tsx b/apps/web/src/components/chat/ProviderStatusBanner.tsx index 70bcb3e917c..957fe8c9049 100644 --- a/apps/web/src/components/chat/ProviderStatusBanner.tsx +++ b/apps/web/src/components/chat/ProviderStatusBanner.tsx @@ -65,8 +65,6 @@ export const ProviderStatusBanner = memo(function ProviderStatusBanner({ aria-label={`Dismiss ${providerName} provider ${status.status}`} onClick={onDismiss} > - {/* Ghost buttons force svgs to muted-foreground unless the icon - sets its own text colour, which would drop the alert's tint. */}