From 96dec91ef5470bf97f38dd722ff434b8e2821534 Mon Sep 17 00:00:00 2001 From: Wintermute Date: Mon, 31 Aug 2026 14:57:37 -0400 Subject: [PATCH] fix(desktop): back split thread headers Signed-off-by: Wintermute --- .../shared/layout/AuxiliaryPanelHeader.tsx | 36 +++++++----- .../layout/auxiliaryPanelContext.test.mjs | 48 ++++++++++++++++ .../channel-shared-header-backdrop.spec.ts | 56 ++++++++++++++++++- 3 files changed, 124 insertions(+), 16 deletions(-) diff --git a/desktop/src/shared/layout/AuxiliaryPanelHeader.tsx b/desktop/src/shared/layout/AuxiliaryPanelHeader.tsx index 5140c4d8d52..78a133dbf12 100644 --- a/desktop/src/shared/layout/AuxiliaryPanelHeader.tsx +++ b/desktop/src/shared/layout/AuxiliaryPanelHeader.tsx @@ -99,6 +99,7 @@ function AuxiliaryPanelHeaderBackdrop({ "pointer-events-none absolute inset-x-0 top-0 z-40 h-13", getAuxiliaryPanelSurfaceClass(surface), )} + data-testid="auxiliary-panel-header-backdrop" /> ); } @@ -166,25 +167,30 @@ export function AuxiliaryPanelHeader({ } return ( -
+ <> + {backdrop && backdropSurface !== "transparent" ? ( + + ) : null}
-
- {renderAuxiliaryPanelHeaderContent(children)} +
+
+ {renderAuxiliaryPanelHeaderContent(children)} +
-
+ ); } diff --git a/desktop/src/shared/layout/auxiliaryPanelContext.test.mjs b/desktop/src/shared/layout/auxiliaryPanelContext.test.mjs index 69cea299740..e59d3ee5c83 100644 --- a/desktop/src/shared/layout/auxiliaryPanelContext.test.mjs +++ b/desktop/src/shared/layout/auxiliaryPanelContext.test.mjs @@ -177,6 +177,54 @@ test("AuxiliaryPanelHeader renders a generic close action from context", () => { assert.match(html, /data-testid="auxiliary-panel-close"/); }); +test("AuxiliaryPanelHeader adds its requested backdrop in docked mode", () => { + const html = render( + React.createElement( + AuxiliaryPanel, + { + header: React.createElement( + AuxiliaryPanelHeader, + { backdrop: true }, + React.createElement(AuxiliaryPanelHeaderGroup, null, "Title"), + ), + layout: "split", + onClose: () => {}, + widthPx: 420, + }, + "Panel", + ), + ); + + assert.match(html, /data-testid="auxiliary-panel-header-backdrop"/); + assert.match(html, /pointer-events-none absolute inset-x-0 top-0 z-40 h-13/); +}); + +test("AuxiliaryPanelHeader honors an explicit transparent docked backdrop", () => { + const html = render( + React.createElement( + AuxiliaryPanel, + { + header: React.createElement( + AuxiliaryPanelHeader, + { backdrop: true, backdropSurface: "transparent" }, + React.createElement(AuxiliaryPanelHeaderGroup, null, "Title"), + ), + layout: "split", + onClose: () => {}, + transparentChrome: true, + widthPx: 420, + }, + "Panel", + ), + ); + + assert.doesNotMatch(html, /data-testid="auxiliary-panel-header-backdrop"/); + assert.doesNotMatch( + html, + /pointer-events-none absolute inset-x-0 top-0 z-40 h-13/, + ); +}); + test("AuxiliaryPanelHeader keeps resize border in single-panel mode when requested", () => { const html = render( React.createElement( diff --git a/desktop/tests/e2e/channel-shared-header-backdrop.spec.ts b/desktop/tests/e2e/channel-shared-header-backdrop.spec.ts index 901d1477a76..55fe6148ced 100644 --- a/desktop/tests/e2e/channel-shared-header-backdrop.spec.ts +++ b/desktop/tests/e2e/channel-shared-header-backdrop.spec.ts @@ -41,7 +41,7 @@ async function waitForMockLiveSubscription( test.describe("channel shared header backdrop", () => { test.use({ viewport: { width: 1280, height: 720 } }); - test("spans channel and split auxiliary columns with one backdrop", async ({ + test("backs a scrolled split auxiliary header above the shared channel backdrop", async ({ page, }) => { await installMockBridge(page); @@ -82,6 +82,43 @@ test.describe("channel shared header backdrop", () => { await replyButton.click({ force: true }); await expect(page.getByTestId("message-thread-panel")).toBeVisible(); + await page.evaluate( + ({ channelName, parentEventId, pubkey }) => { + for (let index = 0; index < 24; index += 1) { + (window as MockMessageWindow).__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({ + channelName, + content: `Scrollable thread reply ${index + 1}. `.repeat(4), + parentEventId, + pubkey, + }); + } + }, + { + channelName: CHANNEL_NAME, + parentEventId: rootId, + pubkey: ALICE_PUBKEY, + }, + ); + + const threadBody = page.getByTestId("message-thread-body"); + await expect + .poll(() => + threadBody.evaluate( + (element) => element.scrollHeight > element.clientHeight, + ), + ) + .toBe(true); + await threadBody.evaluate((element) => { + element.scrollTop = element.scrollHeight; + element.dispatchEvent(new Event("scroll")); + }); + await expect + .poll(() => threadBody.evaluate((element) => element.scrollTop)) + .toBeGreaterThan(0); + + const paneBackdrop = page.getByTestId("auxiliary-panel-header-backdrop"); + await expect(paneBackdrop).toHaveCount(1); + const sharedBackdrop = page.getByTestId("channel-shared-header-backdrop"); await expect(sharedBackdrop).toHaveCount(1); @@ -93,6 +130,9 @@ test.describe("channel shared header backdrop", () => { const [ hostBox, backdropBox, + paneBackdropBox, + paneBackdropBackground, + paneBackdropFilter, backdropFilter, backdropZIndex, headerZIndex, @@ -101,6 +141,13 @@ test.describe("channel shared header backdrop", () => { ] = await Promise.all([ page.getByTestId("channel-drop-zone").locator("..").boundingBox(), sharedBackdrop.boundingBox(), + paneBackdrop.boundingBox(), + paneBackdrop.evaluate( + (element) => getComputedStyle(element).backgroundColor, + ), + paneBackdrop.evaluate( + (element) => getComputedStyle(element).backdropFilter, + ), sharedBackdrop.evaluate( (element) => getComputedStyle(element).backdropFilter, ), @@ -120,6 +167,13 @@ test.describe("channel shared header backdrop", () => { expect(hostBox).not.toBeNull(); expect(backdropBox).not.toBeNull(); + expect(paneBackdropBox).not.toBeNull(); + expect(Math.round(paneBackdropBox?.y ?? 0)).toBe( + Math.round(backdropBox?.y ?? 0), + ); + expect(Math.round(paneBackdropBox?.height ?? 0)).toBe(52); + expect(paneBackdropBackground).not.toBe("rgba(0, 0, 0, 0)"); + expect(paneBackdropFilter).not.toBe("none"); expect(Math.round(backdropBox?.x ?? 0)).toBe(Math.round(hostBox?.x ?? 0)); expect(Math.round(backdropBox?.width ?? 0)).toBe( Math.round(hostBox?.width ?? 0),