fix: refine mobile workbench sheets

This commit is contained in:
2026-07-27 12:56:03 +08:00
parent f0485ca86e
commit f8c79a2af3
12 changed files with 114 additions and 82 deletions
@@ -2,7 +2,6 @@ import {
Activity, Activity,
CheckCircle2, CheckCircle2,
ChevronsUpDown, ChevronsUpDown,
ChevronDown,
ChevronLeft, ChevronLeft,
DatabaseZap, DatabaseZap,
History, History,
@@ -16,7 +15,8 @@ import {
Shield, Shield,
ShieldCheck, ShieldCheck,
Square, Square,
Volume2 Volume2,
X
} from "lucide-react"; } from "lucide-react";
import { AnimatePresence, MotionConfig, motion, useReducedMotion } from "motion/react"; import { AnimatePresence, MotionConfig, motion, useReducedMotion } from "motion/react";
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react"; import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
@@ -292,19 +292,29 @@ export function AgentCommandPanel({
> >
<History size={17} aria-hidden="true" /> <History size={17} aria-hidden="true" />
</button> </button>
<button {presentation === "mobile-sheet" ? (
type="button" <button
aria-label={presentation === "mobile-sheet" ? "关闭 Agent 面板" : "折叠 Agent 面板"} type="button"
title={presentation === "mobile-sheet" ? "关闭 Agent 面板" : "折叠 Agent 面板"} aria-label="关闭 Agent 面板"
onClick={onCollapse} title="关闭 Agent 面板"
className="agent-panel-icon-button grid h-9 w-9 shrink-0 place-items-center rounded-xl text-slate-600 transition" onClick={onCollapse}
> className="group grid h-10 w-10 shrink-0 place-items-center rounded-full text-slate-500"
{presentation === "mobile-sheet" ? ( >
<ChevronDown size={17} aria-hidden="true" /> <span className="surface-control grid h-9 w-9 place-items-center rounded-full shadow-[inset_0_0_0_1px_rgba(148,163,184,0.26),0_4px_12px_rgba(15,33,55,0.10)] transition-[color,background-color,scale] group-active:scale-95 [@media(hover:hover)]:group-hover:bg-blue-50 [@media(hover:hover)]:group-hover:text-blue-700">
) : ( <X size={17} strokeWidth={2.25} aria-hidden="true" />
</span>
</button>
) : (
<button
type="button"
aria-label="折叠 Agent 面板"
title="折叠 Agent 面板"
onClick={onCollapse}
className="agent-panel-icon-button grid h-9 w-9 shrink-0 place-items-center rounded-xl text-slate-600 transition"
>
<ChevronLeft size={17} aria-hidden="true" /> <ChevronLeft size={17} aria-hidden="true" />
)} </button>
</button> )}
</div> </div>
<AnimatePresence initial={false}> <AnimatePresence initial={false}>
{historyOpen ? ( {historyOpen ? (
@@ -1,21 +1,17 @@
import { WORKBENCH_LAYOUT } from "../layout/workbench-layout"; import { WORKBENCH_LAYOUT } from "../layout/workbench-layout";
export type MobileWorkbenchSheetSnap = "peek" | "half" | "full"; export type MobileWorkbenchSheetSnap = "half" | "full";
export function getMobileWorkbenchSheetHeight( export function getMobileWorkbenchSheetHeight(
snap: MobileWorkbenchSheetSnap, snap: MobileWorkbenchSheetSnap,
viewportHeight: number viewportHeight: number
) { ) {
if (snap === "peek") {
return WORKBENCH_LAYOUT.mobileSheet.peekHeight;
}
if (snap === "half") { if (snap === "half") {
return Math.round(viewportHeight * WORKBENCH_LAYOUT.mobileSheet.halfViewportRatio); return Math.round(viewportHeight * WORKBENCH_LAYOUT.mobileSheet.halfViewportRatio);
} }
return Math.max( return Math.max(
WORKBENCH_LAYOUT.mobileSheet.peekHeight, Math.round(viewportHeight * WORKBENCH_LAYOUT.mobileSheet.halfViewportRatio),
viewportHeight - WORKBENCH_LAYOUT.mobileSheet.fullTopGap viewportHeight - WORKBENCH_LAYOUT.mobileSheet.fullTopGap
); );
} }
@@ -2,8 +2,7 @@ import { describe, expect, it } from "vitest";
import { getMobileWorkbenchSheetHeight } from "./mobile-workbench-sheet-layout"; import { getMobileWorkbenchSheetHeight } from "./mobile-workbench-sheet-layout";
describe("mobile workbench sheet heights", () => { describe("mobile workbench sheet heights", () => {
it("keeps the three deterministic snap heights", () => { it("keeps the two deterministic snap heights", () => {
expect(getMobileWorkbenchSheetHeight("peek", 844)).toBe(96);
expect(getMobileWorkbenchSheetHeight("half", 844)).toBe(439); expect(getMobileWorkbenchSheetHeight("half", 844)).toBe(439);
expect(getMobileWorkbenchSheetHeight("full", 844)).toBe(776); expect(getMobileWorkbenchSheetHeight("full", 844)).toBe(776);
}); });
@@ -6,7 +6,6 @@ import {
type PointerEvent, type PointerEvent,
type ReactNode type ReactNode
} from "react"; } from "react";
import { X } from "lucide-react";
import { cn } from "@/shared/ui/cn"; import { cn } from "@/shared/ui/cn";
import { import {
getMobileWorkbenchSheetHeight, getMobileWorkbenchSheetHeight,
@@ -22,11 +21,9 @@ type MobileWorkbenchSheetProps = {
onClose: () => void; onClose: () => void;
children: ReactNode; children: ReactNode;
className?: string; className?: string;
closing?: boolean;
onCloseComplete?: () => void;
}; };
const SNAP_ORDER: MobileWorkbenchSheetSnap[] = ["peek", "half", "full"]; const SNAP_ORDER: MobileWorkbenchSheetSnap[] = ["half", "full"];
export function MobileWorkbenchSheet({ export function MobileWorkbenchSheet({
label, label,
@@ -34,9 +31,7 @@ export function MobileWorkbenchSheet({
onSnapChange, onSnapChange,
onClose, onClose,
children, children,
className, className
closing = false,
onCloseComplete
}: MobileWorkbenchSheetProps) { }: MobileWorkbenchSheetProps) {
const pointerStartRef = useRef<{ y: number; height: number } | null>(null); const pointerStartRef = useRef<{ y: number; height: number } | null>(null);
const draggedRef = useRef(false); const draggedRef = useRef(false);
@@ -87,7 +82,7 @@ export function MobileWorkbenchSheet({
draggedRef.current = true; draggedRef.current = true;
} }
const minHeight = getMobileWorkbenchSheetHeight("peek", window.innerHeight); const minHeight = getMobileWorkbenchSheetHeight("half", window.innerHeight);
const maxHeight = getMobileWorkbenchSheetHeight("full", window.innerHeight); const maxHeight = getMobileWorkbenchSheetHeight("full", window.innerHeight);
setDragHeight(Math.min(maxHeight, Math.max(minHeight, start.height + delta))); setDragHeight(Math.min(maxHeight, Math.max(minHeight, start.height + delta)));
} }
@@ -134,7 +129,7 @@ export function MobileWorkbenchSheet({
if (event.key === "Home") { if (event.key === "Home") {
event.preventDefault(); event.preventDefault();
onSnapChange("peek"); onSnapChange("half");
return; return;
} }
@@ -150,17 +145,11 @@ export function MobileWorkbenchSheet({
data-snap={snap} data-snap={snap}
className={cn( className={cn(
"mobile-workbench-sheet acrylic-panel pointer-events-auto absolute bottom-0 left-0 right-0 z-40 flex min-h-0 flex-col overflow-hidden rounded-t-[20px] border-x border-t transition-[height] duration-200 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none lg:hidden", "mobile-workbench-sheet acrylic-panel pointer-events-auto absolute bottom-0 left-0 right-0 z-40 flex min-h-0 flex-col overflow-hidden rounded-t-[20px] border-x border-t transition-[height] duration-200 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none lg:hidden",
closing && "pointer-events-none",
className className
)} )}
style={{ height: closing ? 0 : (dragHeight ?? restingHeight) }} style={{ height: dragHeight ?? restingHeight }}
onTransitionEnd={(event) => {
if (closing && event.propertyName === "height" && event.target === event.currentTarget) {
onCloseComplete?.();
}
}}
> >
<div className="relative flex h-7 shrink-0 items-center"> <div className="flex h-7 shrink-0 items-center">
<button <button
type="button" type="button"
aria-label={`${label}高度,当前${getSnapLabel(snap)}`} aria-label={`${label}高度,当前${getSnapLabel(snap)}`}
@@ -173,14 +162,6 @@ export function MobileWorkbenchSheet({
> >
<span className="h-1 w-10 rounded-full bg-slate-400/70 transition-[width,background-color] group-focus-visible:w-12 group-focus-visible:bg-blue-600" /> <span className="h-1 w-10 rounded-full bg-slate-400/70 transition-[width,background-color] group-focus-visible:w-12 group-focus-visible:bg-blue-600" />
</button> </button>
<button
type="button"
aria-label={`关闭${label}`}
className="absolute right-2 grid h-7 w-7 place-items-center rounded-lg text-slate-500 transition hover:bg-blue-50 hover:text-blue-700"
onClick={onClose}
>
<X size={15} aria-hidden="true" />
</button>
</div> </div>
<div className="min-h-0 flex-1 overscroll-contain">{children}</div> <div className="min-h-0 flex-1 overscroll-contain">{children}</div>
</section> </section>
@@ -205,14 +186,10 @@ function getClosestSnap(height: number, viewportHeight: number): MobileWorkbench
getMobileWorkbenchSheetHeight(closest, viewportHeight) - height getMobileWorkbenchSheetHeight(closest, viewportHeight) - height
); );
return candidateDistance < closestDistance ? candidate : closest; return candidateDistance < closestDistance ? candidate : closest;
}, "peek"); }, "half");
} }
function getSnapLabel(snap: MobileWorkbenchSheetSnap) { function getSnapLabel(snap: MobileWorkbenchSheetSnap) {
if (snap === "peek") {
return "预览档";
}
if (snap === "half") { if (snap === "half") {
return "半屏档"; return "半屏档";
} }
@@ -4,6 +4,7 @@ import {
ChevronRight, ChevronRight,
ClipboardList, ClipboardList,
History, History,
X,
XCircle XCircle
} from "lucide-react"; } from "lucide-react";
import { AnimatePresence, motion } from "motion/react"; import { AnimatePresence, motion } from "motion/react";
@@ -58,6 +59,7 @@ type ScheduledConditionFeedProps = {
onFocusRequestHandled?: (requestId: number) => void; onFocusRequestHandled?: (requestId: number) => void;
onSelectedConditionChange?: (conditionId: string | null) => void; onSelectedConditionChange?: (conditionId: string | null) => void;
onExpandAgent: () => void; onExpandAgent: () => void;
onClose?: () => void;
onLoadHistorySession: (sessionId: string) => void | Promise<void>; onLoadHistorySession: (sessionId: string) => void | Promise<void>;
onSubmitPrompt: (prompt: string) => void | Promise<void>; onSubmitPrompt: (prompt: string) => void | Promise<void>;
}; };
@@ -79,6 +81,7 @@ export function ScheduledConditionFeed({
onFocusRequestHandled, onFocusRequestHandled,
onSelectedConditionChange, onSelectedConditionChange,
onExpandAgent, onExpandAgent,
onClose,
onLoadHistorySession, onLoadHistorySession,
onSubmitPrompt onSubmitPrompt
}: ScheduledConditionFeedProps) { }: ScheduledConditionFeedProps) {
@@ -325,6 +328,19 @@ export function ScheduledConditionFeed({
/> />
<span className="sr-only">{expanded ? "收起工况任务" : "展开工况任务"}</span> <span className="sr-only">{expanded ? "收起工况任务" : "展开工况任务"}</span>
</button> </button>
{mobileSheet && onClose ? (
<button
type="button"
aria-label="关闭工况任务"
title="关闭工况任务"
onClick={onClose}
className="group grid h-10 w-10 shrink-0 place-items-center rounded-full text-slate-500"
>
<span className="surface-control grid h-9 w-9 place-items-center rounded-full shadow-[inset_0_0_0_1px_rgba(148,163,184,0.26),0_4px_12px_rgba(15,33,55,0.10)] transition-[color,background-color,scale] group-active:scale-95 [@media(hover:hover)]:group-hover:bg-blue-50 [@media(hover:hover)]:group-hover:text-blue-700">
<X size={17} strokeWidth={2.25} aria-hidden="true" />
</span>
</button>
) : null}
</header> </header>
<div <div
@@ -21,7 +21,6 @@ export const WORKBENCH_LAYOUT = {
tickerWidth: 460 tickerWidth: 460
}, },
mobileSheet: { mobileSheet: {
peekHeight: 96,
halfViewportRatio: 0.52, halfViewportRatio: 0.52,
fullTopGap: 68 fullTopGap: 68
} }
+9 -22
View File
@@ -107,7 +107,6 @@ export function MapWorkbenchPage() {
const [conditionFeedExpanded, setConditionFeedExpanded] = useState(false); const [conditionFeedExpanded, setConditionFeedExpanded] = useState(false);
const [mobileSheet, setMobileSheet] = useState<"agent" | "condition" | null>(null); const [mobileSheet, setMobileSheet] = useState<"agent" | "condition" | null>(null);
const [mobileSheetSnap, setMobileSheetSnap] = useState<MobileWorkbenchSheetSnap>("half"); const [mobileSheetSnap, setMobileSheetSnap] = useState<MobileWorkbenchSheetSnap>("half");
const [mobileSheetClosing, setMobileSheetClosing] = useState(false);
const [agentCollapsedForCondition, setAgentCollapsedForCondition] = useState(false); const [agentCollapsedForCondition, setAgentCollapsedForCondition] = useState(false);
const prefersReducedMotion = useReducedMotion(); const prefersReducedMotion = useReducedMotion();
const [taskTickerVisible, setTaskTickerVisible] = useState(true); const [taskTickerVisible, setTaskTickerVisible] = useState(true);
@@ -149,7 +148,6 @@ export function MapWorkbenchPage() {
setViewportWidth(window.innerWidth); setViewportWidth(window.innerWidth);
if (mediaQuery.matches) { if (mediaQuery.matches) {
setMobileSheet(null); setMobileSheet(null);
setMobileSheetClosing(false);
} }
}; };
@@ -193,24 +191,12 @@ export function MapWorkbenchPage() {
return; return;
} }
setMobileSheetClosing(false);
setMobileSheet("agent"); setMobileSheet("agent");
setMobileSheetSnap("half"); setMobileSheetSnap("half");
} }
const closeMobileSheet = useCallback(() => { const closeMobileSheet = useCallback(() => {
if (prefersReducedMotion) {
setMobileSheet(null);
setMobileSheetClosing(false);
return;
}
setMobileSheetClosing(true);
}, [prefersReducedMotion]);
const completeMobileSheetClose = useCallback(() => {
setMobileSheet(null); setMobileSheet(null);
setMobileSheetClosing(false);
}, []); }, []);
function handleConditionExpandedChange(nextExpanded: boolean) { function handleConditionExpandedChange(nextExpanded: boolean) {
@@ -255,7 +241,6 @@ export function MapWorkbenchPage() {
} }
setConditionFeedExpanded(false); setConditionFeedExpanded(false);
setMobileSheetClosing(false);
setMobileSheetSnap("half"); setMobileSheetSnap("half");
setMobileSheet("condition"); setMobileSheet("condition");
} }
@@ -577,7 +562,6 @@ export function MapWorkbenchPage() {
setConditionFeedVisible(true); setConditionFeedVisible(true);
setActiveToolId(null); setActiveToolId(null);
if (!isLargeScreen) { if (!isLargeScreen) {
setMobileSheetClosing(false);
setMobileSheet("condition"); setMobileSheet("condition");
setMobileSheetSnap("half"); setMobileSheetSnap("half");
} }
@@ -998,17 +982,21 @@ export function MapWorkbenchPage() {
aria-label="打开 Agent 面板" aria-label="打开 Agent 面板"
title="打开 Agent 面板" title="打开 Agent 面板"
onClick={openAgentPanelForViewport} onClick={openAgentPanelForViewport}
className="acrylic-control grid h-12 w-12 shrink-0 place-items-center rounded-xl border text-violet-700 active:scale-95" className="acrylic-control grid h-11 w-11 shrink-0 place-items-center rounded-xl border text-violet-700 active:scale-95"
> >
<AgentPersona className="pointer-events-none h-9 w-9" state={agent.personaState} /> <AgentPersona className="pointer-events-none h-8 w-8" state={agent.personaState} />
</button> </button>
<MapToolbar items={toolbarItems} orientation="horizontal" className="justify-center" /> <MapToolbar
items={toolbarItems}
orientation="horizontal"
className="h-11 justify-center"
/>
<button <button
type="button" type="button"
aria-label="打开工况任务" aria-label="打开工况任务"
title="打开工况任务" title="打开工况任务"
onClick={toggleConditionFeedForViewport} onClick={toggleConditionFeedForViewport}
className="acrylic-control grid h-12 w-12 shrink-0 place-items-center rounded-xl border text-blue-700 active:scale-95" className="acrylic-control grid h-11 w-11 shrink-0 place-items-center rounded-xl border text-blue-700 active:scale-95"
> >
<CalendarClock size={20} aria-hidden="true" /> <CalendarClock size={20} aria-hidden="true" />
</button> </button>
@@ -1022,8 +1010,6 @@ export function MapWorkbenchPage() {
snap={mobileSheetSnap} snap={mobileSheetSnap}
onSnapChange={setMobileSheetSnap} onSnapChange={setMobileSheetSnap}
onClose={closeMobileSheet} onClose={closeMobileSheet}
closing={mobileSheetClosing}
onCloseComplete={completeMobileSheetClose}
> >
{mobileSheet === "agent" ? ( {mobileSheet === "agent" ? (
<AgentCommandPanel <AgentCommandPanel
@@ -1044,6 +1030,7 @@ export function MapWorkbenchPage() {
onFocusRequestHandled={handleConditionFocusRequestHandled} onFocusRequestHandled={handleConditionFocusRequestHandled}
onSelectedConditionChange={setSelectedConditionId} onSelectedConditionChange={setSelectedConditionId}
onExpandAgent={openAgentPanelForViewport} onExpandAgent={openAgentPanelForViewport}
onClose={closeMobileSheet}
onLoadHistorySession={handleLoadAgentHistorySession} onLoadHistorySession={handleLoadAgentHistorySession}
onSubmitPrompt={agent.submitPrompt} onSubmitPrompt={agent.submitPrompt}
/> />
+43 -7
View File
@@ -3,14 +3,40 @@ import { expect, test } from "playwright/test";
test.describe("mobile workbench sheet", () => { test.describe("mobile workbench sheet", () => {
test.use({ viewport: { width: 390, height: 844 } }); test.use({ viewport: { width: 390, height: 844 } });
test("supports all snap heights, keyboard control, and Escape close", async ({ page }) => { test("keeps the bottom launcher controls at one height", async ({ page }) => {
await page.goto("/", { waitUntil: "domcontentloaded" });
const agentButton = page.getByRole("button", { name: "打开 Agent 面板" });
const mapToolbar = page.locator('nav[aria-label="地图工具"]:visible');
const conditionButton = page.getByRole("button", { name: "打开工况任务" });
const boxes = await Promise.all([
agentButton.boundingBox(),
mapToolbar.boundingBox(),
conditionButton.boundingBox()
]);
boxes.forEach((box) => expect(box).not.toBeNull());
expect(boxes.map((box) => Math.round(box!.height))).toEqual([44, 44, 44]);
expect(boxes.map((box) => Math.round(box!.y))).toEqual([
Math.round(boxes[0]!.y),
Math.round(boxes[0]!.y),
Math.round(boxes[0]!.y)
]);
});
test("supports half and full heights, keyboard control, and Escape close", async ({ page }) => {
await page.goto("/", { waitUntil: "domcontentloaded" }); await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByRole("button", { name: "打开 Agent 面板" }).click(); await page.getByRole("button", { name: "打开 Agent 面板" }).click();
const sheet = page.getByRole("region", { name: "Agent 工作台抽屉" }); const sheet = page.getByRole("region", { name: "Agent 工作台抽屉" });
const handle = page.getByRole("button", { name: /Agent 工作台抽屉高度/ }); const handle = page.getByRole("button", { name: /Agent 工作台抽屉高度/ });
const closeButton = page.getByRole("button", { name: "关闭 Agent 面板" });
await expect(sheet).toBeVisible(); await expect(sheet).toBeVisible();
await expect(closeButton).toHaveCount(1);
await expect.poll(async () => Math.round((await closeButton.boundingBox())?.height ?? 0)).toBe(
40
);
await expect(sheet).toHaveAttribute("data-snap", "half"); await expect(sheet).toHaveAttribute("data-snap", "half");
await expect.poll(async () => Math.round((await sheet.boundingBox())?.height ?? 0)).toBe(439); await expect.poll(async () => Math.round((await sheet.boundingBox())?.height ?? 0)).toBe(439);
await expect await expect
@@ -42,10 +68,12 @@ test.describe("mobile workbench sheet", () => {
await handle.focus(); await handle.focus();
await page.keyboard.press("Home"); await page.keyboard.press("Home");
await expect(sheet).toHaveAttribute("data-snap", "peek"); await expect(sheet).toHaveAttribute("data-snap", "half");
await expect.poll(async () => Math.round((await sheet.boundingBox())?.height ?? 0)).toBe(96); await expect.poll(async () => Math.round((await sheet.boundingBox())?.height ?? 0)).toBe(439);
await page.keyboard.press("ArrowUp"); await page.keyboard.press("ArrowUp");
await expect(sheet).toHaveAttribute("data-snap", "full");
await page.keyboard.press("ArrowDown");
await expect(sheet).toHaveAttribute("data-snap", "half"); await expect(sheet).toHaveAttribute("data-snap", "half");
await page.keyboard.press("End"); await page.keyboard.press("End");
await expect(sheet).toHaveAttribute("data-snap", "full"); await expect(sheet).toHaveAttribute("data-snap", "full");
@@ -62,11 +90,19 @@ test.describe("mobile workbench sheet", () => {
await page.goto("/", { waitUntil: "domcontentloaded" }); await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByRole("button", { name: "打开 Agent 面板" }).click(); await page.getByRole("button", { name: "打开 Agent 面板" }).click();
await expect(page.getByRole("region", { name: "Agent 工作台抽屉" })).toBeVisible(); const agentSheet = page.getByRole("region", { name: "Agent 工作台抽屉" });
await expect(agentSheet).toBeVisible();
await expect.poll(async () => Math.round((await agentSheet.boundingBox())?.height ?? 0)).toBe(
439
);
await page.keyboard.press("Escape"); await page.keyboard.press("Escape");
await page.getByRole("button", { name: "打开工况任务" }).click(); await page.getByRole("button", { name: "打开工况任务" }).click();
await expect(page.getByRole("region", { name: "工况任务抽屉" })).toBeVisible(); const conditionSheet = page.getByRole("region", { name: "工况任务抽屉" });
await expect(conditionSheet).toBeVisible();
await expect.poll(async () =>
Math.round((await conditionSheet.boundingBox())?.height ?? 0)
).toBe(439);
await expect( await expect(
page.locator('aside[aria-label="Agent 命令面板"]').filter({ visible: true }) page.locator('aside[aria-label="Agent 命令面板"]').filter({ visible: true })
).toHaveCount(0); ).toHaveCount(0);
@@ -78,8 +114,8 @@ test.describe("mobile workbench sheet", () => {
const sheet = page.getByRole("region", { name: "工况任务抽屉" }); const sheet = page.getByRole("region", { name: "工况任务抽屉" });
await expect(sheet).toBeVisible(); await expect(sheet).toBeVisible();
await page.getByRole("button", { name: "关闭工况任务抽屉" }).click(); await page.getByRole("button", { name: "关闭工况任务" }).click();
await expect(sheet).toBeHidden(); expect(await sheet.count()).toBe(0);
await expect(page.getByRole("button", { name: "打开工况任务" })).toBeVisible(); await expect(page.getByRole("button", { name: "打开工况任务" })).toBeVisible();
}); });
+12
View File
@@ -70,6 +70,18 @@ test.describe("neutral blue mist workbench", () => {
}); });
}); });
test("mobile launcher keeps Agent, map tools, and conditions visually balanced", async ({
page
}) => {
await page.setViewportSize({ width: 390, height: 844 });
await openWorkbench(page);
await expect(page).toHaveScreenshot("workbench-mobile-launcher-light.png", {
animations: "disabled",
maxDiffPixelRatio: 0.01
});
});
test("mobile light basemap shows the Agent half sheet", async ({ page }) => { test("mobile light basemap shows the Agent half sheet", async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 }); await page.setViewportSize({ width: 390, height: 844 });
await openWorkbench(page); await openWorkbench(page);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB