diff --git a/ui/src/e2e/chat-composer-redesign.e2e.test.ts b/ui/src/e2e/chat-composer-redesign.e2e.test.ts index c10c34b2fc36..9f7dcac61ec7 100644 --- a/ui/src/e2e/chat-composer-redesign.e2e.test.ts +++ b/ui/src/e2e/chat-composer-redesign.e2e.test.ts @@ -130,6 +130,7 @@ describeControlUiE2e("Control UI chat composer redesign", () => { const settings = composer.getByRole("button", { name: "View", exact: true }); const splitView = page.getByRole("button", { name: "Open split view" }); const voice = page.getByRole("button", { name: "Start voice input" }); + const microphonePicker = page.getByRole("button", { name: "Microphone input" }); await expect.poll(() => model.isVisible()).toBe(true); expect(await gateway.getRequests("chat.metadata")).toHaveLength(0); @@ -538,6 +539,26 @@ describeControlUiE2e("Control UI chat composer redesign", () => { await expect.poll(() => viewMenu.isVisible()).toBe(true); await settings.click(); await expect.poll(() => viewMenu.isVisible()).toBe(false); + + await page.setViewportSize({ width: 1280, height: 900 }); + await gateway.setOnline(false); + await expect.poll(() => voice.isDisabled()).toBe(true); + await expect + .poll(async () => { + const [voiceBackground, pickerBackground] = await Promise.all([ + voice.evaluate((node) => getComputedStyle(node).backgroundColor), + microphonePicker.evaluate((node) => getComputedStyle(node).backgroundColor), + ]); + return voiceBackground === pickerBackground; + }) + .toBe(true); + const artifactDir = process.env.OPENCLAW_UI_E2E_ARTIFACT_DIR?.trim(); + if (artifactDir) { + await composerShell.screenshot({ + animations: "disabled", + path: `${artifactDir}/voice-picker-disabled-background.png`, + }); + } } finally { await context.close(); } diff --git a/ui/src/styles/chat/layout.css b/ui/src/styles/chat/layout.css index 7fd63edd7dce..f7a5ea9b7a59 100644 --- a/ui/src/styles/chat/layout.css +++ b/ui/src/styles/chat/layout.css @@ -2813,6 +2813,11 @@ openclaw-chat-page { background: color-mix(in srgb, var(--accent) 20%, transparent); } +/* Keep both halves of the voice pill visually joined when Talk is unavailable. */ +.chat-talk-control:has(.chat-send-btn:disabled) .chat-talk-input-picker__trigger { + background: color-mix(in srgb, var(--muted) 16%, transparent); +} + .chat-talk-input-picker__trigger:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px;