fix(app): align compact menu sheet content

Route composer attachments through the shared compact menu sheet so headers and rows use the same alignment rails. Base the final-row padding on the device safe area to keep actions clear of system navigation.
This commit is contained in:
Mohamed Boudra
2026-08-04 13:09:26 +02:00
parent 683f38443c
commit 238047eaa8
9 changed files with 114 additions and 152 deletions
+23 -1
View File
@@ -7,6 +7,7 @@ import { connectWorkspaceSetupClient } from "./workspace-setup";
import { selectWorkspaceInSidebar } from "./sidebar";
import { getServerId } from "./server-id";
import { waitForTabBar } from "./launcher";
import { waitForSettledPosition } from "./sheet-layout";
function composerInput(page: Page) {
return page.getByRole("textbox", { name: "Message agent..." }).first();
@@ -71,7 +72,28 @@ export async function pressInterruptShortcut(page: Page): Promise<void> {
export async function openAttachmentMenu(page: Page): Promise<void> {
await page.getByTestId("message-input-attach-button").filter({ visible: true }).first().click();
await expect(page.getByTestId("message-input-attachment-menu")).toBeVisible({ timeout: 5_000 });
await expect(
page
.getByTestId("message-input-attachment-menu")
.or(page.getByTestId("message-input-attachment-menu-content")),
).toBeVisible({ timeout: 5_000 });
}
export async function expectAttachmentSheetRowsOnTitleRail(page: Page): Promise<void> {
const title = page.getByText("Add attachment", { exact: true });
const firstItemGlyph = page
.getByRole("button", { name: "Add image", exact: true })
.locator("svg")
.first();
await waitForSettledPosition(title);
const [titleBox, glyphBox] = await Promise.all([
title.boundingBox(),
firstItemGlyph.boundingBox(),
]);
if (!titleBox || !glyphBox) {
throw new Error("Attachment sheet geometry could not be measured");
}
expect(Math.abs(glyphBox.x - titleBox.x)).toBeLessThanOrEqual(1);
}
export async function expectAttachButtonDisabled(page: Page): Promise<void> {
@@ -235,6 +235,27 @@ export async function expectNewWorkspaceProjectSelected(
await expect(projectPicker).toContainText(projectDisplayName);
}
export async function expectNewWorkspaceTriggerLabelsAligned(
page: Page,
input: { projectLabel: string; hostLabel: string },
): Promise<void> {
const projectTrigger = page.getByRole("button", { name: "Workspace project" });
const hostTrigger = page.getByRole("button", { name: "Host", exact: true });
const [projectTriggerBox, projectLabelBox, hostTriggerBox, hostLabelBox] = await Promise.all([
projectTrigger.boundingBox(),
projectTrigger.getByText(input.projectLabel, { exact: true }).boundingBox(),
hostTrigger.boundingBox(),
hostTrigger.getByText(input.hostLabel, { exact: true }).boundingBox(),
]);
if (!projectTriggerBox || !projectLabelBox || !hostTriggerBox || !hostLabelBox) {
throw new Error("New Workspace trigger geometry could not be measured");
}
const projectLabelInset = projectLabelBox.x - projectTriggerBox.x;
const hostLabelInset = hostLabelBox.x - hostTriggerBox.x;
expect(hostLabelInset).toBeCloseTo(projectLabelInset, 0);
}
export async function fillNewWorkspaceDraft(page: Page, draft: string): Promise<void> {
const composer = page.getByRole("textbox", { name: "Message agent..." });
await expect(composer).toBeVisible({ timeout: 30_000 });