mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(desktop): hide the offcanvas-collapsed sidebar so it stops painting over the community rail (#5947)
## Summary Collapsing the sidebar left a phantom copy of it painted over the community/relay rail — opaquely on flat themes (vesper et al., which made the rail look *removed*), and as ghost fragments (muted search-box fill, truncated channel-name tails) on the Buzz themes whose chrome is intentionally transparent for the gradient. **Cause:** #4281 made the app-sidebar layer `overflow-visible` (the huddle drawer needs to escape it). That removed the ancestor clipping the offcanvas collapse relied on: the sidebar slides to `left: -sidebar-width` but kept painting, exactly over the `z-0` rail (`z-10` sidebar layer). **Fix:** the offcanvas-collapsed sidebar container is now `invisible` + `pointer-events-none`, with `visibility` added to the transition list so the 200 ms slide-out still animates and the flip happens only at the transition's end. Theme-independent; no per-theme CSS touched; the huddle drawer's `overflow-visible` is preserved. ## Before / after Left 420px of the app with the sidebar collapsed. Before = unpatched `origin/main` @ 69107dc3b; after = this branch. Same seeded state, same build pipeline (`build:e2e` between checkouts). | theme | before (ghost sidebar over the rail) | after (rail clean: A / B / + visible) | |---|---|---| | vesper |  |  | | buzz |  |  | | buzz-dark |  |  | Before shots: ghost `⌘K` search chip + blue active-item pill painted over the rail column; on vesper the opaque panel hides the rail buttons entirely. After: the rail's community buttons (A, B) and `+` are visible and clickable in all three themes. Reported by Thomas P in #buzz-bugs: buzz://message?channel=e62570dd-33ad-42c5-b92b-75f2689f9694&id=9ea401ca1d009f555ca4324e136f8d8d8156db2f8afa3ff89fd038d2c16260f7 cc @klopez4212 — this touches the layout your #4281/#5478 work shaped; please confirm it doesn't defeat the huddle drawer or glass intentions. The change deliberately hides only the *offcanvas-collapsed* container, nothing in the expanded path. ## Test plan - [x] New Playwright regression spec `sidebar-offcanvas-rail.spec.ts` (buzz / buzz-dark / vesper): collapsed sidebar must be `visibility: hidden` + `pointer-events: none`, community rail stays visible and interactive. **Fails on unpatched build** (verified), passes with the fix. - [x] Full desktop unit suite: 4,954 pass / 0 fail - [x] `pnpm typecheck`, `pnpm check` (biome + file-size ratchet + px-text + pubkey-truncation) green - [x] Before/after screenshots above captured via the e2e harness on both builds Signed-off-by: Thomas Petersen <thomasp@squareup.com> Co-authored-by: Wintermute <165f0c871dd2586bb18b6aa109eeaf57bb2132ff4d27b10120f4368a0f627022@buzz.block.builderlab.xyz>
This commit is contained in:
co-authored by
Wintermute
parent
69107dc3bf
commit
78cbffeb64
@@ -20,6 +20,7 @@ export default defineConfig({
|
||||
name: "smoke",
|
||||
testMatch: [
|
||||
"**/smoke.spec.ts",
|
||||
"**/sidebar-offcanvas-rail.spec.ts",
|
||||
"**/search-scope-screenshots.spec.ts",
|
||||
"**/onboarding-docked-cta-screenshots.spec.ts",
|
||||
"**/identity-key-help.spec.ts",
|
||||
|
||||
@@ -351,7 +351,7 @@ const Sidebar = React.forwardRef<
|
||||
data-variant={variant}
|
||||
data-side={side}
|
||||
>
|
||||
{/* This is what handles the sidebar gap on desktop */}
|
||||
{/* Sidebar gap on desktop; the offcanvas sibling below also goes invisible, else it paints over the community rail past the overflow-visible shell. */}
|
||||
<div
|
||||
className={cn(
|
||||
"relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
|
||||
@@ -365,8 +365,8 @@ const Sidebar = React.forwardRef<
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
"absolute inset-y-0 z-10 hidden h-full w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
|
||||
"group-data-[resizing=true]:transition-none",
|
||||
"absolute inset-y-0 z-10 hidden h-full w-(--sidebar-width) transition-[left,right,width,visibility] duration-200 ease-linear md:flex",
|
||||
"group-data-[resizing=true]:transition-none group-data-[collapsible=offcanvas]:pointer-events-none group-data-[collapsible=offcanvas]:invisible",
|
||||
side === "left"
|
||||
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
|
||||
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
|
||||
import { installMockBridge } from "../helpers/bridge";
|
||||
|
||||
const SHOTS = "test-results/sidebar-offcanvas-rail";
|
||||
const THEME_STORAGE_KEY = "buzz-theme";
|
||||
const RELAY_URL = "ws://localhost:3000";
|
||||
|
||||
const COMMUNITY_A = {
|
||||
id: "ws-a",
|
||||
name: "Alpha",
|
||||
relayUrl: RELAY_URL,
|
||||
addedAt: "2026-01-01T00:00:00.000Z",
|
||||
};
|
||||
const COMMUNITY_B = {
|
||||
id: "ws-b",
|
||||
name: "Bravo",
|
||||
relayUrl: "ws://localhost:3001",
|
||||
addedAt: "2026-01-02T00:00:00.000Z",
|
||||
};
|
||||
|
||||
async function setup(page: Page, theme: string) {
|
||||
await page.setViewportSize({ width: 1280, height: 800 });
|
||||
await page.addInitScript(
|
||||
({ key, value }) => {
|
||||
window.localStorage.setItem(key, value);
|
||||
},
|
||||
{ key: THEME_STORAGE_KEY, value: theme },
|
||||
);
|
||||
await installMockBridge(page, undefined, { skipCommunitySeed: true });
|
||||
await page.addInitScript(
|
||||
({ list, active }) => {
|
||||
window.localStorage.setItem("buzz-communities", JSON.stringify(list));
|
||||
window.localStorage.setItem("buzz-active-community-id", active);
|
||||
},
|
||||
{ list: [COMMUNITY_A, COMMUNITY_B], active: COMMUNITY_A.id },
|
||||
);
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await expect(page.getByTestId("community-rail")).toBeVisible();
|
||||
await expect(page.getByTestId("app-sidebar")).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression: the app-sidebar layer is overflow-visible (huddle drawer), so
|
||||
* the offcanvas-collapsed sidebar slides out of its container but kept
|
||||
* painting over the community rail — opaquely on flat themes, as ghost
|
||||
* fragments on the transparent Buzz chrome. The collapsed sidebar must be
|
||||
* invisible and non-interactive, leaving the rail clean in every theme.
|
||||
*/
|
||||
for (const theme of ["buzz", "buzz-dark", "vesper"]) {
|
||||
test(`collapsed sidebar leaves the community rail clean — ${theme}`, async ({
|
||||
page,
|
||||
}) => {
|
||||
await setup(page, theme);
|
||||
await page.screenshot({ path: `${SHOTS}/${theme}-expanded.png` });
|
||||
|
||||
await page.locator('[data-sidebar="trigger"]').first().click();
|
||||
const shell = page.locator(
|
||||
'[data-state="collapsed"][data-collapsible="offcanvas"]',
|
||||
);
|
||||
await expect(shell).toHaveCount(1);
|
||||
// Let the 200ms slide finish; visibility flips at the transition's end.
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Second direct child = the sliding sidebar container (first is the gap).
|
||||
const offscreenSidebar = shell.locator("> div").nth(1);
|
||||
await expect(offscreenSidebar).toHaveCSS("visibility", "hidden");
|
||||
await expect(offscreenSidebar).toHaveCSS("pointer-events", "none");
|
||||
|
||||
// The community rail stays visible and interactive beneath it.
|
||||
await expect(page.getByTestId("community-rail")).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId(`community-rail-button-${COMMUNITY_B.id}`),
|
||||
).toBeVisible();
|
||||
await page.screenshot({ path: `${SHOTS}/${theme}-collapsed.png` });
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user