authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-22 12:22:20-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-22 12:22:20-07:00
log83bbfa7e87e16a3c21413fe55524c1d05ce88dab
treed4d6fc2ec60a35b3a97f1db47f30676c40585814
parent1c2f933892cce833823fcfbf3099a51813ba67fb
signature Signed by PGP key B5690EEEBB952194

refactor(web): sidebar alerts use the standard variants; one keycap (#13043)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

12 files changed, 52 insertions(+), 71 deletions(-)

apps/web/src/components/CommandPalette.tsx+2-2
......@@ -2874,7 +2874,7 @@ function OpenCommandPaletteDialog(props: {
28742874 }
28752875 >
28762876 <span>{isRemoteProjectPending ? "Working" : remoteProjectButtonLabel}</span>
2877 <KbdGroup className="pointer-events-none -me-0.5 items-center gap-1">
2877 <KbdGroup className="pointer-events-none -me-0.5">
28782878 <Kbd>Enter</Kbd>
28792879 </KbdGroup>
28802880 </TooltipTrigger>
......@@ -2917,7 +2917,7 @@ function OpenCommandPaletteDialog(props: {
29172917 <span>
29182918 {isCloneDestinationStep && isRemoteProjectPending ? "Cloning" : submitActionLabel}
29192919 </span>
2920 <KbdGroup className="pointer-events-none -me-0.5 items-center gap-1">
2920 <KbdGroup className="pointer-events-none -me-0.5">
29212921 <Kbd>{hasHighlightedBrowseItem ? `${submitModifierLabel} Enter` : "Enter"}</Kbd>
29222922 </KbdGroup>
29232923 </TooltipTrigger>
apps/web/src/components/CommandPaletteContent.tsx+4-4
......@@ -52,7 +52,7 @@ export function CommandPaletteContent({
5252 <CommandPanel className={panelClassName}>{children}</CommandPanel>
5353 <CommandFooter className="gap-3 max-sm:flex-col max-sm:items-start">
5454 <div className="flex items-center gap-3">
55 <KbdGroup className="items-center gap-1.5">
55 <KbdGroup>
5656 <Kbd>
5757 <ArrowUpIcon />
5858 </Kbd>
......@@ -62,18 +62,18 @@ export function CommandPaletteContent({
6262 <span>Navigate</span>
6363 </KbdGroup>
6464 {footerActionLabel !== undefined ? (
65 <KbdGroup className="items-center gap-1.5">
65 <KbdGroup>
6666 <Kbd>Enter</Kbd>
6767 <span>{footerActionLabel}</span>
6868 </KbdGroup>
6969 ) : null}
7070 {showBackHint ? (
71 <KbdGroup className="items-center gap-1.5">
71 <KbdGroup>
7272 <Kbd>Backspace</Kbd>
7373 <span>Back</span>
7474 </KbdGroup>
7575 ) : null}
76 <KbdGroup className="items-center gap-1.5">
76 <KbdGroup>
7777 <Kbd>Esc</Kbd>
7878 <span>{escapeLabel}</span>
7979 </KbdGroup>
apps/web/src/components/LegacySidebar.tsx+5-14
......@@ -2673,18 +2673,13 @@ function LocalSecondaryStatus() {
26732673 return (
26742674 <SidebarGroup>
26752675 {connecting.length > 0 ? (
2676 <Alert
2677 variant="default"
2678 className="rounded-2xl border-border/40 bg-accent/40 text-muted-foreground"
2679 >
2676 <Alert variant="sidebar">
26802677 <Spinner />
2681 <AlertTitle className="text-xs font-medium text-foreground">
2682 Connecting {connecting.join(", ")}
2683 </AlertTitle>
2678 <AlertTitle>Connecting {connecting.join(", ")}</AlertTitle>
26842679 </Alert>
26852680 ) : null}
26862681 {failed.length > 0 ? (
2687 <Alert variant="warning" className="rounded-2xl border-warning/40 bg-warning/8">
2682 <Alert variant="warning">
26882683 <TriangleAlertIcon />
26892684 <AlertTitle>Couldn't connect {failed.map((entry) => entry.label).join(", ")}</AlertTitle>
26902685 <AlertDescription>
......@@ -2980,11 +2975,7 @@ const SidebarProjectsContent = memo(function SidebarProjectsContent(
29802975 >
29812976 <SearchIcon />
29822977 <span className="flex-1 truncate">Search</span>
2983 {commandPaletteShortcutLabel ? (
2984 <Kbd className="h-4 min-w-0 rounded-sm px-1.5 text-[10px]">
2985 {commandPaletteShortcutLabel}
2986 </Kbd>
2987 ) : null}
2978 {commandPaletteShortcutLabel ? <Kbd>{commandPaletteShortcutLabel}</Kbd> : null}
29882979 </CommandDialogTrigger>
29892980 </SidebarMenuItem>
29902981 </SidebarMenu>
......@@ -2993,7 +2984,7 @@ const SidebarProjectsContent = memo(function SidebarProjectsContent(
29932984 >
29942985 {showArm64IntelBuildWarning && arm64IntelBuildWarningDescription ? (
29952986 <SidebarGroup>
2996 <Alert variant="warning" className="rounded-2xl border-warning/40 bg-warning/8">
2987 <Alert variant="warning">
29972988 <TriangleAlertIcon />
29982989 <AlertTitle>Intel build on Apple Silicon</AlertTitle>
29992990 <AlertDescription>{arm64IntelBuildWarningDescription}</AlertDescription>
apps/web/src/components/chat/ModelListRow.tsx+1-3
......@@ -98,9 +98,7 @@ export const ModelListRow = memo(function ModelListRow(props: {
9898 {props.showSelection && props.isSelected ? (
9999 <CheckIcon className="size-3.5" aria-hidden="true" />
100100 ) : null}
101 {props.jumpLabel ? (
102 <Kbd className="h-4 min-w-0 rounded-sm px-1.5 text-[10px]">{props.jumpLabel}</Kbd>
103 ) : null}
101 {props.jumpLabel ? <Kbd>{props.jumpLabel}</Kbd> : null}
104102 <Tooltip>
105103 <TooltipTrigger
106104 render={
apps/web/src/components/chat/ProviderStatusBanner.tsx+24-35
......@@ -1,8 +1,8 @@
11import { type ProviderInstanceId, type ServerProvider } from "@t3tools/contracts";
22import { memo } from "react";
33import { InfoIcon, XIcon } from "lucide-react";
4import { cn } from "~/lib/utils";
5import { Button } from "../ui/button";
4import { Alert, AlertAction, AlertDescription, AlertTitle } from "../ui/alert";
5import { Button, InlineButton } from "../ui/button";
66import { formatProviderDriverKindLabel } from "../../providerModels";
77import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
88
......@@ -83,48 +83,37 @@ export const ProviderStatusBanner = memo(function ProviderStatusBanner({
8383
8484 return (
8585 <div className="pointer-events-auto mx-auto w-fit max-w-[calc(100%-2rem)] pt-3">
86 <div
87 className={cn(
88 "alert-glass relative inline-flex items-center gap-3 rounded-xl border py-3 ps-3.5 pe-10 text-card-foreground text-sm",
89 status.status === "warning"
90 ? "border-warning/32 [&_svg]:text-warning"
91 : "border-destructive/32 text-destructive-foreground [&_svg]:text-destructive",
92 )}
93 data-variant={status.status === "warning" ? "warning" : "error"}
94 role="alert"
86 <Alert
87 variant={status.status === "warning" ? "warning" : "error"}
88 surface="glass"
89 controlAlignment="first-line"
9590 >
96 <InfoIcon className="size-4 shrink-0" aria-hidden />
97 <div className="flex min-w-0 flex-col gap-1">
98 <div className="font-medium">{title}</div>
91 <InfoIcon />
92 <AlertTitle>{title}</AlertTitle>
93 <AlertDescription>
9994 <Tooltip>
100 <TooltipTrigger
101 render={<div className="line-clamp-3 text-muted-foreground">{message}</div>}
102 />
95 <TooltipTrigger render={<div className="line-clamp-3" />}>{message}</TooltipTrigger>
10396 <TooltipPopup side="top" className="whitespace-pre-wrap">
10497 {message}
10598 </TooltipPopup>
10699 </Tooltip>
107100 {onOpenProviderSetup && hasProviderSetup(status) ? (
108 <Button
109 className="self-start px-0 text-foreground"
110 onClick={() => onOpenProviderSetup(status.instanceId)}
111 size="xs"
112 variant="link"
113 >
101 <InlineButton onClick={() => onOpenProviderSetup(status.instanceId)}>
114102 Open provider setup
115 </Button>
103 </InlineButton>
116104 ) : null}
117 </div>
118 <Button
119 aria-label={`Dismiss ${providerName} provider ${status.status}`}
120 className="absolute top-2 right-2 size-6"
121 onClick={onDismiss}
122 size="icon-xs"
123 variant="ghost-muted"
124 >
125 <XIcon aria-hidden className="size-3.5" />
126 </Button>
127 </div>
105 </AlertDescription>
106 <AlertAction>
107 <Button
108 aria-label={`Dismiss ${providerName} provider ${status.status}`}
109 onClick={onDismiss}
110 size="icon-xs"
111 variant="ghost-muted"
112 >
113 <XIcon />
114 </Button>
115 </AlertAction>
116 </Alert>
128117 </div>
129118 );
130119});
apps/web/src/components/chat/ThreadErrorBanner.tsx+1-6
......@@ -43,12 +43,7 @@ export const ThreadErrorBanner = memo(function ThreadErrorBanner({
4343 if (!error) return null;
4444 return (
4545 <div className="pointer-events-auto mx-auto w-fit max-w-[min(48rem,calc(100%-2rem))] pt-3">
46 <Alert
47 variant="error"
48 controlAlignment="first-line"
49 className="alert-glass"
50 data-variant="error"
51 >
46 <Alert variant="error" surface="glass" controlAlignment="first-line">
5247 <CircleAlertIcon />
5348 <AlertDescription>
5449 <Tooltip>
apps/web/src/components/desktop/SnapShotShortcutKeys.tsx+1-1
......@@ -16,7 +16,7 @@ export function SnapShotShortcutKeys({
1616 const seen = seenLabels.get(label) ?? 0;
1717 seenLabels.set(label, seen + 1);
1818 return (
19 <Kbd aria-hidden className="min-w-6 justify-center px-1.5" key={`${label}-${seen}`}>
19 <Kbd aria-hidden key={`${label}-${seen}`}>
2020 {label}
2121 </Kbd>
2222 );
apps/web/src/components/settings/KeybindingsSettings.tsx+2-2
......@@ -79,9 +79,9 @@ function KeybindingPill({ value }: { value: string }) {
7979 return { part, key: seen === 0 ? part : `${part}-${seen}` };
8080 });
8181 return (
82 <KbdGroup className="bg-transparent p-0 shadow-none">
82 <KbdGroup>
8383 {parts.map(({ part, key }) => (
84 <Kbd key={key} className="min-w-6 justify-center px-1.5">
84 <Kbd key={key}>
8585 {part === "mod"
8686 ? navigator.platform.toLowerCase().includes("mac")
8787 ? "⌘"
apps/web/src/components/settings/SettingsSidebarNav.tsx+1-1
......@@ -275,7 +275,7 @@ export function SettingsSidebarNav({ pathname }: { pathname: string }) {
275275 <XIcon className="size-3" />
276276 </Button>
277277 ) : (
278 <Kbd className="h-4 min-w-0 rounded-sm px-1.5 text-[10px]">/</Kbd>
278 <Kbd>/</Kbd>
279279 )}
280280 </div>
281281 {isSearching && results.length === 0 ? (
apps/web/src/components/sidebar/SidebarUpdatePill.tsx+1-1
......@@ -100,7 +100,7 @@ function SidebarUpdateArchitectureWarningContent() {
100100 if (!visible || !description) return null;
101101
102102 return (
103 <Alert variant="warning" className="rounded-2xl border-warning/40 bg-warning/8 text-xs">
103 <Alert variant="warning">
104104 <TriangleAlertIcon />
105105 <AlertTitle>Intel build on Apple Silicon</AlertTitle>
106106 <AlertDescription>{description}</AlertDescription>
apps/web/src/components/ui/alert.tsx+9-1
......@@ -6,9 +6,15 @@ import { cn } from "~/lib/utils";
66
77const alertVariants = cva("relative rounded-xl border px-3.5 py-3 text-card-foreground text-sm", {
88 defaultVariants: {
9 surface: "default",
910 variant: "default",
1011 },
1112 variants: {
13 // "glass" floats the alert over content; alert-glass tints from data-variant.
14 surface: {
15 default: "",
16 glass: "alert-glass",
17 },
1218 variant: {
1319 default: "bg-transparent dark:bg-input/32 [&_svg]:text-muted-foreground",
1420 sidebar:
......@@ -45,6 +51,7 @@ function alertChildSlot(child: React.ReactElement): string | undefined {
4551function Alert({
4652 className,
4753 variant,
54 surface,
4855 controlAlignment = "center",
4956 children,
5057 ...props
......@@ -73,8 +80,9 @@ function Alert({
7380
7481 return (
7582 <div
76 className={cn(alertVariants({ variant }), className)}
83 className={cn(alertVariants({ surface, variant }), className)}
7784 data-slot="alert"
85 data-variant={variant ?? "default"}
7886 role="alert"
7987 {...props}
8088 >
scripts/lint-restyle-ceiling.ts+1-1
......@@ -8,7 +8,7 @@ import * as NodeURL from "node:url";
88// components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the
99// count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you
1010// migrate a file, and delete this script when the rule becomes an error.
11export const RESTYLE_CEILING = 668;
11export const RESTYLE_CEILING = 628;
1212
1313const RULE = "shadcn(no-restyle)";
1414