Polish MCP widget UI

This commit is contained in:
Ishaan Gupta 2026-07-03 16:27:37 +05:30
parent f0023bb414
commit 649d985d48
4 changed files with 38 additions and 35 deletions

View file

@ -6,7 +6,7 @@ export function PermissionBadge({ permission }: Props) {
const isWrite = permission === "write"
return (
<span
className="ml-auto mt-2 inline-flex h-8 min-w-[94px] shrink-0 items-center justify-center gap-1.5 rounded-full bg-[#0D121A] px-3 text-[12px] font-medium text-[#FAFAFA] shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.7)] sm:h-9 sm:min-w-[116px] sm:px-5 sm:text-[14px]"
className="text-[#8B8B8B]"
style={{ fontFamily: "var(--font-brand)" }}
>
{isWrite ? "Read/write" : "Read only"}

View file

@ -24,15 +24,20 @@ export function WorkspaceCard({
onClick={() => onClick(containerTag.containerTag)}
variant={active ? "active" : "interactive"}
>
<div className="absolute right-4 top-4 text-[11px] font-medium leading-none">
{access ? <PermissionBadge permission={access.permission} /> : null}
</div>
{active ? (
<Check className="absolute bottom-4 right-4 size-3.5 shrink-0 text-accent" />
) : null}
<Stack className="h-full" gap="xs">
<Stack align="center" direction="row" gap="sm" justify="between">
<span
className="min-w-0 truncate text-sm font-medium text-white"
className="min-w-0 max-w-[calc(100%-96px)] truncate text-sm font-medium text-white"
style={{ fontFamily: "var(--font-brand)" }}
>
{name}
</span>
{active ? <Check className="size-4 shrink-0 text-accent" /> : null}
</Stack>
<div className="truncate text-xs leading-relaxed text-[#8B8B8B]">
{containerTag.containerTag}
@ -51,7 +56,6 @@ export function WorkspaceCard({
</div>
)}
<div className="flex-1" />
{access ? <PermissionBadge permission={access.permission} /> : null}
</Stack>
</Card>
)

View file

@ -204,28 +204,24 @@
align-items: center;
gap: var(--space-2);
margin: var(--space-4) var(--page-header-px) 0;
padding: 7px 10px 7px 8px;
border: 1px solid #263348;
border-radius: var(--radius-lg);
background: rgba(8, 11, 15, 0.92);
backdrop-filter: blur(18px);
box-shadow: var(--shadow-sm);
padding: 0;
border: 0;
background: transparent;
box-shadow: none;
opacity: 0.86;
}
.mcp-widget-brand-mark {
display: grid;
width: 26px;
height: 26px;
width: 20px;
height: 20px;
place-items: center;
color: var(--accent);
border-radius: var(--radius-md);
background: #080b0f;
box-shadow: inset 1.5px 1.5px 4.5px rgba(0, 0, 0, 0.7);
}
.mcp-widget-brand-mark svg {
width: 17px;
height: 14px;
width: 16px;
height: 13px;
}
.mcp-widget-brand-copy {
@ -238,7 +234,7 @@
.mcp-widget-brand-name {
color: var(--text-primary);
font-size: 12px;
font-weight: 700;
font-weight: 650;
line-height: 1;
}
@ -249,6 +245,12 @@
line-height: 1.15;
}
.shadow-inside-out {
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.3),
inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
.mcp-widget-content {
position: relative;
z-index: 1;

View file

@ -3,44 +3,41 @@ import { type ButtonHTMLAttributes, forwardRef, type ReactNode } from "react"
import { Loader2 } from "../../lib/icons"
import { cn } from "../lib/cn"
// Mirrors console-v2's button: uppercase + tracked, brand-font by default,
// CVA primary/secondary/ghost/danger × sm/icon. We skip `asChild` because the
// widget has no router links and dropping it saves a @radix-ui/react-slot dep.
// Mirrors apps/web's pill-shaped inside-out controls while keeping the widget
// variants small and dependency-free for MCP iframes.
const buttonVariants = cva(
[
"inline-flex items-center justify-center gap-2",
"font-semibold",
"rounded-[var(--radius-md)]",
"rounded-full",
"transition-all cursor-pointer",
"disabled:pointer-events-none disabled:opacity-50",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)]/20 focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-primary)]",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)]/35 focus-visible:ring-offset-0",
"[&_svg:not([class*='size-'])]:size-4 shrink-0",
].join(" "),
{
variants: {
variant: {
primary: [
"bg-[var(--accent)] text-[var(--accent-foreground)]",
"shadow-[0_10px_28px_rgba(75,160,250,0.24)]",
"hover:bg-[var(--accent-hover)] hover:shadow-[0_12px_32px_rgba(75,160,250,0.32)]",
"bg-[#0D121A] text-[#FAFAFA] shadow-inside-out",
"hover:bg-[#121820] active:bg-[#080B0F]",
].join(" "),
secondary: [
"bg-[var(--bg-control)] text-[var(--text-primary)]",
"border border-[var(--border-control)]",
"hover:bg-[var(--bg-control-hover)] hover:border-[#3A4455]",
"bg-[#0D121A] text-[#FAFAFA] shadow-inside-out",
"hover:bg-[#121820]",
].join(" "),
ghost: [
"text-[var(--text-primary)]",
"hover:bg-[var(--bg-muted)]",
"text-[#737373]",
"hover:bg-white/5 hover:text-[#FAFAFA]",
].join(" "),
danger: [
"bg-[var(--danger)] text-[var(--text-inverse)]",
"hover:bg-[var(--danger)]/90",
"bg-[#EF4444]/15 text-[#EF4444]",
"hover:bg-[#EF4444]/25",
].join(" "),
},
size: {
sm: "h-[var(--height-md)] px-[var(--space-4)] text-[length:var(--text-sm)]",
icon: "size-[var(--height-sm)] p-0",
sm: "h-9 px-4 text-[13px]",
icon: "size-8 p-0",
},
},
defaultVariants: {