From 0f22e1e9051663a627bee78d2be91e44459fa5b2 Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Thu, 3 Sep 2026 11:16:40 -0700 Subject: [PATCH] Fix table header transparency with opaque background (#18499) Replace the translucent bg-muted/25 with an opaque color-mix blend (40% muted on background) to ensure scrolled rows don't show through the sticky header. Add test coverage for header styling and layout. --- .../AutomationListTableHeader.test.tsx | 45 +++++++++++++++++++ src/renderer/src/lib/list-table-layout.ts | 4 +- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/renderer/src/components/automations/AutomationListTableHeader.test.tsx diff --git a/src/renderer/src/components/automations/AutomationListTableHeader.test.tsx b/src/renderer/src/components/automations/AutomationListTableHeader.test.tsx new file mode 100644 index 00000000000..5c5bbe8e568 --- /dev/null +++ b/src/renderer/src/components/automations/AutomationListTableHeader.test.tsx @@ -0,0 +1,45 @@ +// @vitest-environment happy-dom + +import { cleanup, render, screen } from '@testing-library/react' +import { afterEach, describe, expect, it } from 'vitest' +import { AutomationListTableHeader } from './AutomationListTableHeader' +import { + LIST_TABLE_HEADER_CLASS, + LIST_TABLE_STICKY_HEADER_CELL_CLASS +} from '@/lib/list-table-layout' + +describe('AutomationListTableHeader', () => { + afterEach(cleanup) + + it('renders all expected columns', () => { + render() + + expect(screen.getByText('Name')).toBeDefined() + expect(screen.getByText('Schedule')).toBeDefined() + expect(screen.getByText('Project')).toBeDefined() + expect(screen.getByText('Host')).toBeDefined() + expect(screen.getByText('Next run')).toBeDefined() + expect(screen.getByText('Last run')).toBeDefined() + expect(screen.getByText('Status')).toBeDefined() + expect(screen.getByText('Agent')).toBeDefined() + expect(screen.getByText('Actions')).toBeDefined() + }) + + it('uses opaque background and sticky positioning on the header row', () => { + const { container } = render() + const header = container.firstElementChild as HTMLElement + + expect(header.className).toContain(LIST_TABLE_HEADER_CLASS) + expect(header.className).toContain('sticky') + expect(header.className).toContain('top-0') + expect(header.className).toContain('bg-[color-mix(in_srgb,var(--muted)_40%,var(--background))]') + expect(header.className).not.toContain('bg-muted/25') + }) + + it('applies sticky cell styling to the first column', () => { + render() + const nameCell = screen.getByText('Name') + + expect(nameCell.className).toBe(LIST_TABLE_STICKY_HEADER_CELL_CLASS) + }) +}) diff --git a/src/renderer/src/lib/list-table-layout.ts b/src/renderer/src/lib/list-table-layout.ts index c40607ee944..89b85d0aab5 100644 --- a/src/renderer/src/lib/list-table-layout.ts +++ b/src/renderer/src/lib/list-table-layout.ts @@ -5,9 +5,9 @@ */ export const LIST_TABLE_CONTAINER_CLASS = 'rounded-md border border-border/50 bg-muted/20' -// Why: z-30 must beat the rows' sticky first cells (z-20) so the header still covers them. +// Why: z-30 and opaque wash ensure scrolled rows cannot show through the sticky header. export const LIST_TABLE_HEADER_CLASS = - 'sticky top-0 z-30 h-8 items-center gap-3 border-b border-border/50 bg-muted/25 px-3 text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground' + 'sticky top-0 z-30 h-8 items-center gap-3 border-b border-border/50 bg-[color-mix(in_srgb,var(--muted)_40%,var(--background))] px-3 text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground' // Why: keep keyboard-selected rows clear of the sticky table header. export const LIST_TABLE_ROW_CLASS =