feat(desktop): show selected community in rail (#5000)

## Summary
- add a persistent vertical pill beside the active community
- keep the selected state visually distinct from unread dots and mention
badges
- preserve the existing `aria-current` selection semantics

## Screenshot
![Selected community
indicator](https://d24qwcpro867f5.cloudfront.net/repos/block/buzz/prs/5000/selected-community-indicator-v2.png)

## Test plan
- `pnpm exec biome check src/features/sidebar/ui/CommunityRail.tsx
tests/e2e/community-rail.spec.ts`
- `pnpm test` (4,387 passed)
- `pnpm build:e2e && pnpm exec playwright test
tests/e2e/community-rail.spec.ts --project=smoke` (20 passed)
- pre-push hooks: desktop check and 4,387 desktop tests passed on
`c1e80c66d12f73c4eb5c03a19e932439b14caf2d`

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
This commit is contained in:
Wes
2026-08-06 08:39:36 -06:00
committed by GitHub
parent 19b41e9c8e
commit 5babb97ca3
2 changed files with 23 additions and 6 deletions

View File

@@ -133,10 +133,17 @@ function CommunityButton({
{...dragAttributes} {...dragAttributes}
{...dragListeners} {...dragListeners}
> >
{isActive ? (
<span
aria-hidden="true"
className="absolute -left-2.5 h-5 w-1 rounded-r-full bg-primary"
data-testid={`community-rail-active-${community.id}`}
/>
) : null}
<span <span
className={cn( className={cn(
"flex h-9 w-9 items-center justify-center overflow-hidden rounded-xl bg-sidebar-accent/60 text-xs font-semibold text-sidebar-foreground/80 outline-2 outline-offset-2 outline-primary/0 transition-[outline-color]", "flex h-9 w-9 items-center justify-center overflow-hidden rounded-xl bg-sidebar-accent/60 text-xs font-semibold text-sidebar-foreground/80 outline-2 outline-offset-2 outline-primary/0 transition-[outline-color]",
isActive ? "outline-primary" : "hover:outline-primary/50", !isActive && "hover:outline-primary/50",
)} )}
> >
{iconUrl ? ( {iconUrl ? (

View File

@@ -66,13 +66,21 @@ test.describe("community rail", () => {
await expect(buttonA).toBeVisible(); await expect(buttonA).toBeVisible();
await expect(buttonB).toBeVisible(); await expect(buttonB).toBeVisible();
// The active community is marked via aria-current. // The active community is marked semantically and with a persistent rail.
await expect(buttonA).toHaveAttribute("aria-current", "true"); await expect(buttonA).toHaveAttribute("aria-current", "true");
await expect(buttonB).not.toHaveAttribute("aria-current", "true"); await expect(buttonB).not.toHaveAttribute("aria-current", "true");
await expect(buttonA.locator(":scope > span").first()).toHaveCSS( const activeIndicator = page.getByTestId(
"opacity", `community-rail-active-${COMMUNITY_A.id}`,
"1",
); );
await expect(activeIndicator).toBeVisible();
await expect(
page.getByTestId(`community-rail-active-${COMMUNITY_B.id}`),
).toHaveCount(0);
await expect(activeIndicator).toHaveCSS("height", "20px");
await expect(activeIndicator).toHaveCSS("width", "4px");
await expect(
buttonA.locator(":scope > span:not([data-testid])").first(),
).toHaveCSS("opacity", "1");
await expect(buttonB.locator(":scope > span").first()).toHaveCSS( await expect(buttonB.locator(":scope > span").first()).toHaveCSS(
"opacity", "opacity",
"1", "1",
@@ -80,7 +88,7 @@ test.describe("community rail", () => {
const [activeStyle, inactiveStyle] = await Promise.all( const [activeStyle, inactiveStyle] = await Promise.all(
[buttonA, buttonB].map((button) => [buttonA, buttonB].map((button) =>
button button
.locator(":scope > span") .locator(":scope > span:not([data-testid])")
.first() .first()
.evaluate((element) => { .evaluate((element) => {
const style = getComputedStyle(element); const style = getComputedStyle(element);
@@ -88,6 +96,7 @@ test.describe("community rail", () => {
backgroundColor: style.backgroundColor, backgroundColor: style.backgroundColor,
borderRadius: style.borderRadius, borderRadius: style.borderRadius,
color: style.color, color: style.color,
outlineColor: style.outlineColor,
outlineStyle: style.outlineStyle, outlineStyle: style.outlineStyle,
outlineWidth: style.outlineWidth, outlineWidth: style.outlineWidth,
}; };
@@ -98,6 +107,7 @@ test.describe("community rail", () => {
expect(activeStyle.borderRadius).toBe(inactiveStyle.borderRadius); expect(activeStyle.borderRadius).toBe(inactiveStyle.borderRadius);
expect(activeStyle.borderRadius).toBe("12px"); expect(activeStyle.borderRadius).toBe("12px");
expect(activeStyle.color).toBe(inactiveStyle.color); expect(activeStyle.color).toBe(inactiveStyle.color);
expect(activeStyle.outlineColor).toBe(inactiveStyle.outlineColor);
expect(activeStyle.outlineStyle).toBe("solid"); expect(activeStyle.outlineStyle).toBe("solid");
expect(activeStyle.outlineWidth).toBe("2px"); expect(activeStyle.outlineWidth).toBe("2px");
expect(inactiveStyle.outlineStyle).toBe("solid"); expect(inactiveStyle.outlineStyle).toBe("solid");