feat: refine workbench visuals and map controls
Unify the Agent history extension with the header acrylic surface, preserve the full conversation body, and consolidate shared control and status styling. Restore map flow and SCADA controller behavior, remove obsolete rendering paths, and extend regression coverage. Button press coverage now releases outside the target so state assertions cannot accidentally toggle the control.
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
import { AlertTriangle, CheckCircle2, Info, Loader2, X, XCircle } from "lucide-react";
|
||||
import type { ReactNode } from "react";
|
||||
import { cn } from "@/shared/ui/cn";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import {
|
||||
StatusIcon as SemanticStatusIcon,
|
||||
type StatusTone
|
||||
} from "@/shared/ui/status";
|
||||
import {
|
||||
MAP_COMPACT_RADIUS_CLASS_NAME,
|
||||
MAP_ICON_CELL_RADIUS_CLASS_NAME,
|
||||
@@ -8,37 +13,13 @@ import {
|
||||
} from "./map-control-styles";
|
||||
import type { MapNoticeOptions, MapNoticeTone } from "./notice-types";
|
||||
|
||||
const toneClassNames: Record<MapNoticeTone, string> = {
|
||||
info: "glass-transient text-slate-900",
|
||||
success: "glass-transient text-slate-900",
|
||||
warning: "glass-transient text-slate-900",
|
||||
error: "glass-transient text-slate-900",
|
||||
loading: "glass-transient text-slate-900"
|
||||
};
|
||||
|
||||
const iconClassNames: Record<MapNoticeTone, string> = {
|
||||
info: "text-blue-600",
|
||||
success: "text-green-600",
|
||||
warning: "text-orange-500",
|
||||
error: "text-red-500",
|
||||
loading: "text-blue-600"
|
||||
};
|
||||
|
||||
const noticeAccentClassNames: Record<MapNoticeTone, string> = {
|
||||
info: "bg-blue-600",
|
||||
success: "bg-green-500",
|
||||
warning: "bg-orange-500",
|
||||
error: "bg-red-500",
|
||||
loading: "bg-blue-600"
|
||||
};
|
||||
|
||||
const noticeIconSurfaceClassNames: Record<MapNoticeTone, string> = {
|
||||
info: "border-blue-100 bg-blue-50",
|
||||
success: "border-green-100 bg-green-50",
|
||||
warning: "border-orange-100 bg-orange-50",
|
||||
error: "border-red-100 bg-red-50",
|
||||
loading: "border-blue-100 bg-blue-50"
|
||||
};
|
||||
const noticeTones = {
|
||||
info: "info",
|
||||
success: "success",
|
||||
warning: "warning",
|
||||
error: "danger",
|
||||
loading: "info"
|
||||
} satisfies Record<MapNoticeTone, StatusTone>;
|
||||
|
||||
export function MapNoticeContent({
|
||||
title,
|
||||
@@ -79,15 +60,10 @@ function MapNoticeFrame({ tone, children }: { tone: MapNoticeTone; children: Rea
|
||||
<div
|
||||
role={tone === "error" || tone === "warning" ? "alert" : "status"}
|
||||
className={cn(
|
||||
"relative flex w-full items-start gap-2.5 overflow-hidden border py-2.5 pl-3 pr-10 text-sm",
|
||||
"glass-transient relative flex w-full items-start gap-2.5 overflow-hidden border py-2.5 pl-3 pr-10 text-sm text-slate-900",
|
||||
MAP_READABLE_RADIUS_CLASS_NAME,
|
||||
toneClassNames[tone]
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn("absolute bottom-0 left-0 top-0 w-1", noticeAccentClassNames[tone])}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -101,20 +77,14 @@ function MapNoticeIcon({
|
||||
icon: ReturnType<typeof getNoticeIcon>;
|
||||
}) {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"mt-0.5 grid h-7 w-7 shrink-0 place-items-center border",
|
||||
MAP_ICON_CELL_RADIUS_CLASS_NAME,
|
||||
iconClassNames[tone],
|
||||
noticeIconSurfaceClassNames[tone]
|
||||
)}
|
||||
<SemanticStatusIcon
|
||||
tone={noticeTones[tone]}
|
||||
activity={tone === "loading" ? "loading" : "static"}
|
||||
size="md"
|
||||
className={cn("mt-0.5", MAP_ICON_CELL_RADIUS_CLASS_NAME)}
|
||||
>
|
||||
<Icon
|
||||
size={17}
|
||||
aria-hidden="true"
|
||||
className={tone === "loading" ? "animate-spin" : undefined}
|
||||
/>
|
||||
</span>
|
||||
<Icon size={17} />
|
||||
</SemanticStatusIcon>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -142,16 +112,15 @@ function MapNoticeBody({
|
||||
|
||||
function MapNoticeAction({ label, onClick }: { label: string; onClick: () => void }) {
|
||||
return (
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className={cn(
|
||||
"mt-2 inline-flex h-7 items-center justify-center border border-blue-100 bg-blue-50 px-2.5 text-xs font-semibold text-blue-700 transition hover:bg-blue-100",
|
||||
MAP_COMPACT_RADIUS_CLASS_NAME
|
||||
)}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className={cn("mt-2 border-blue-100 bg-blue-50 text-blue-700", MAP_COMPACT_RADIUS_CLASS_NAME)}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user