feat: refresh workbench visual layout

This commit is contained in:
2026-07-27 11:50:29 +08:00
parent b9bc9c3d39
commit f0485ca86e
33 changed files with 1624 additions and 353 deletions
@@ -9,9 +9,7 @@ import {
FlaskConical,
type LucideIcon
} from "lucide-react";
import {
MAP_ICON_CELL_RADIUS_CLASS_NAME
} from "@/features/map/core";
import { MAP_ICON_CELL_RADIUS_CLASS_NAME } from "@/features/map/core";
import { cn } from "@/shared/ui/cn";
import type { WorkbenchAlert, WorkbenchScenario, WorkbenchUser } from "../types";
import { AlertMenu, ScenarioMenu, UserMenu } from "./workbench-top-bar-menus";
@@ -77,7 +75,8 @@ export function WorkbenchTopBar({
onExportConfig
}: WorkbenchTopBarProps) {
const [openMenu, setOpenMenu] = useState<HeaderMenuId | null>(null);
const activeScenario = scenarios.find((scenario) => scenario.id === activeScenarioId) ?? scenarios[0];
const activeScenario =
scenarios.find((scenario) => scenario.id === activeScenarioId) ?? scenarios[0];
const createMenuOpenChange = (menuId: HeaderMenuId) => (open: boolean) => {
setOpenMenu(open ? menuId : null);
};
@@ -85,11 +84,18 @@ export function WorkbenchTopBar({
return (
<header className="acrylic-navigation pointer-events-auto absolute left-0 right-0 top-0 z-30 flex h-14 select-none items-center justify-between border-b px-3 sm:px-4 md:px-5">
<div className="flex min-w-0 items-center gap-2.5">
<div className={cn("grid h-8 w-8 shrink-0 place-items-center bg-blue-600 text-white shadow-lg shadow-blue-600/20", MAP_ICON_CELL_RADIUS_CLASS_NAME)}>
<div
className={cn(
"grid h-8 w-8 shrink-0 place-items-center bg-blue-600 text-white shadow-lg shadow-blue-600/20",
MAP_ICON_CELL_RADIUS_CLASS_NAME
)}
>
<Droplets size={18} aria-hidden="true" />
</div>
<div className="min-w-0">
<h1 className="truncate text-sm font-semibold leading-5 text-slate-950"></h1>
<h1 className="truncate text-sm font-semibold leading-5 text-slate-950">
</h1>
<p className="hidden truncate text-xs leading-4 text-slate-500 sm:block"></p>
</div>
</div>
@@ -133,18 +139,31 @@ export function WorkbenchTopBar({
</div>
<div className="flex shrink-0 items-center gap-1.5">
{devPanelEnabled ? <div className="hidden lg:block">
<button
type="button"
aria-label="切换地图 Dev Panel"
aria-pressed={devPanelOpen}
onClick={onToggleDevPanel}
className={cn("group px-2 active:scale-95", headerControlButtonClassName, devPanelOpen && "bg-blue-50/80 text-blue-700")}
>
<span className={cn(headerControlIconClassName, devPanelOpen && "bg-blue-600/10 text-blue-700")}><FlaskConical size={14} aria-hidden="true" /></span>
<span className={compactHeaderTextClassName}>Dev</span>
</button>
</div> : null}
{devPanelEnabled ? (
<div className="hidden lg:block">
<button
type="button"
aria-label="切换地图 Dev Panel"
aria-pressed={devPanelOpen}
onClick={onToggleDevPanel}
className={cn(
"group px-2 active:scale-95",
headerControlButtonClassName,
devPanelOpen && "bg-blue-50/80 text-blue-700"
)}
>
<span
className={cn(
headerControlIconClassName,
devPanelOpen && "bg-blue-600/10 text-blue-700"
)}
>
<FlaskConical size={14} aria-hidden="true" />
</span>
<span className={compactHeaderTextClassName}>Dev</span>
</button>
</div>
) : null}
<div className="lg:hidden">
<AlertMenu
compact
@@ -199,12 +218,7 @@ function TaskTickerToggle({
visible && "bg-blue-50/80 text-blue-700"
)}
>
<span
className={cn(
headerControlIconClassName,
visible && "bg-blue-600/10 text-blue-700"
)}
>
<span className={cn(headerControlIconClassName, visible && "bg-blue-600/10 text-blue-700")}>
<Icon size={14} aria-hidden="true" />
</span>
<span className={compactHeaderTextClassName}></span>
@@ -212,17 +226,13 @@ function TaskTickerToggle({
);
}
function ConditionFeedToggle({
visible,
onToggle
}: {
visible: boolean;
onToggle: () => void;
}) {
function ConditionFeedToggle({ visible, onToggle }: { visible: boolean; onToggle: () => void }) {
return (
<button
type="button"
aria-label="工况任务"
aria-pressed={visible}
title="工况任务"
onClick={onToggle}
className={cn(
"group px-2",
@@ -230,12 +240,7 @@ function ConditionFeedToggle({
visible && "bg-blue-50/80 text-blue-700"
)}
>
<span
className={cn(
headerControlIconClassName,
visible && "bg-blue-600/10 text-blue-700"
)}
>
<span className={cn(headerControlIconClassName, visible && "bg-blue-600/10 text-blue-700")}>
<CalendarClock size={14} aria-hidden="true" />
</span>
<span className={compactHeaderTextClassName}></span>
@@ -243,12 +248,22 @@ function ConditionFeedToggle({
);
}
function HeaderReadout({ icon: Icon, label, value }: { icon?: LucideIcon; label: string; value: string }) {
function HeaderReadout({
icon: Icon,
label,
value
}: {
icon?: LucideIcon;
label: string;
value: string;
}) {
return (
<div className="flex min-w-0 items-center gap-1.5 whitespace-nowrap">
<div className="flex shrink-0 items-center gap-1.5 whitespace-nowrap">
{Icon ? <Icon size={14} className="shrink-0 text-blue-700" aria-hidden="true" /> : null}
<span className="hidden text-xs font-medium text-slate-500 2xl:inline">{label}</span>
<span className="max-w-16 truncate text-sm font-semibold text-slate-800 2xl:max-w-28">{value}</span>
<span className="max-w-40 shrink-0 truncate text-sm font-semibold text-slate-800">
{value}
</span>
</div>
);
}