From fa577dfe5384c7276fb8133c22a24848a7c9fc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fiere?= Date: Fri, 31 Jul 2026 15:33:57 +0200 Subject: [PATCH] fix: darken auto-scroll toggle green, drop ban overlay, maximize icon size (#2073) --- .../chat/auto-scroll-toggle-button.test.tsx | 14 ++++++++++++++ .../task/chat/auto-scroll-toggle-button.tsx | 16 ++++++++++------ .../e2e/tests/chat/auto-scroll-toggle.spec.ts | 5 +++++ .../2073-auto-scroll-toggle-disabled.png | Bin 0 -> 1639 bytes .../2073-auto-scroll-toggle-enabled.png | Bin 0 -> 1526 bytes 5 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 docs/pr-screenshots/2073-auto-scroll-toggle-disabled.png create mode 100644 docs/pr-screenshots/2073-auto-scroll-toggle-enabled.png diff --git a/apps/web/components/task/chat/auto-scroll-toggle-button.test.tsx b/apps/web/components/task/chat/auto-scroll-toggle-button.test.tsx index f9ff962de5..7c47ef94c1 100644 --- a/apps/web/components/task/chat/auto-scroll-toggle-button.test.tsx +++ b/apps/web/components/task/chat/auto-scroll-toggle-button.test.tsx @@ -49,6 +49,13 @@ describe("AutoScrollToggleButton", () => { expect(button.getAttribute("aria-label")).toMatch(/turn off/i); }); + it("shows the icon in dark green, maximized to fill its box, when enabled", () => { + renderButton("session-a"); + const icon = screen.getByTestId("auto-scroll-toggle-icon"); + expect(icon.getAttribute("class")).toMatch(/text-green-600/); + expect(icon.getAttribute("class")).toMatch(/h-6 w-6/); + }); + it("clicking while enabled disables auto-scroll for the session", () => { renderButton("session-a"); fireEvent.click(getButton()); @@ -63,6 +70,13 @@ describe("AutoScrollToggleButton", () => { expect(button.getAttribute("aria-label")).toMatch(/turn on/i); }); + it("shows the icon with no color when disabled", () => { + enabledBySessionId = { "session-a": false }; + renderButton("session-a"); + const icon = screen.getByTestId("auto-scroll-toggle-icon"); + expect(icon.getAttribute("class")).not.toMatch(/text-green-600/); + }); + it("clicking while disabled re-enables auto-scroll for the session", () => { enabledBySessionId = { "session-a": false }; renderButton("session-a"); diff --git a/apps/web/components/task/chat/auto-scroll-toggle-button.tsx b/apps/web/components/task/chat/auto-scroll-toggle-button.tsx index dfaf247a75..a029548de2 100644 --- a/apps/web/components/task/chat/auto-scroll-toggle-button.tsx +++ b/apps/web/components/task/chat/auto-scroll-toggle-button.tsx @@ -1,9 +1,10 @@ "use client"; -import { IconArrowBarToDown, IconArrowBarToDownDashed } from "@tabler/icons-react"; +import { IconArrowBarToDown } from "@tabler/icons-react"; import { Button } from "@kandev/ui/button"; import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip"; +import { cn } from "@/lib/utils"; import { useAppStore } from "@/components/state-provider"; import { useTranscriptAutoScrollEnabled } from "./use-transcript-auto-scroll-enabled"; @@ -23,6 +24,10 @@ type Props = { * auto-scroll and catches the view up if the transcript progressed while * disabled. See message-list-native.tsx / message-list-virtuoso.tsx for the * renderer-side behavior driven by this preference. + * + * The icon renders dark green while enabled and reverts to the default + * muted color when disabled — the color swap alone carries the on/off + * signal. */ export function AutoScrollToggleButton({ sessionId }: Props) { const showControl = useAppStore((state) => state.userSettings.showTranscriptAutoScrollControl); @@ -46,11 +51,10 @@ export function AutoScrollToggleButton({ sessionId }: Props) { aria-pressed={enabled} data-testid="auto-scroll-toggle-button" > - {enabled ? ( - - ) : ( - - )} + {label} diff --git a/apps/web/e2e/tests/chat/auto-scroll-toggle.spec.ts b/apps/web/e2e/tests/chat/auto-scroll-toggle.spec.ts index a8258acd8b..ff3ca1b515 100644 --- a/apps/web/e2e/tests/chat/auto-scroll-toggle.spec.ts +++ b/apps/web/e2e/tests/chat/auto-scroll-toggle.spec.ts @@ -99,6 +99,9 @@ test.describe("Transcript auto-scroll toggle", () => { await expect(toggle).toBeVisible({ timeout: 10_000 }); await expect(toggle).toHaveAttribute("aria-pressed", "true"); + const icon = toggle.getByTestId("auto-scroll-toggle-icon"); + await expect(icon).toHaveClass(/text-green-600/); + // Sits immediately to the left of Share within the same right-aligned cluster. const shareButton = statusBar.getByTestId("share-task-button"); if (await shareButton.isVisible()) { @@ -113,9 +116,11 @@ test.describe("Transcript auto-scroll toggle", () => { await toggle.click(); await expect(toggle).toHaveAttribute("aria-pressed", "false"); + await expect(icon).not.toHaveClass(/text-green-600/); await toggle.click(); await expect(toggle).toHaveAttribute("aria-pressed", "true"); + await expect(icon).toHaveClass(/text-green-600/); }); test("disabling freezes the position and suppresses auto-scroll for new messages", async ({ diff --git a/docs/pr-screenshots/2073-auto-scroll-toggle-disabled.png b/docs/pr-screenshots/2073-auto-scroll-toggle-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..f3082f72fb85a1989cbf61ceded84c28268bc1ad GIT binary patch literal 1639 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