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 07:39:36 -07:00
committed by GitHub
co-authored by Carl
parent 19b41e9c8e
commit 5babb97ca3
2 changed files with 23 additions and 6 deletions
@@ -133,10 +133,17 @@ function CommunityButton({
{...dragAttributes}
{...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
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]",
isActive ? "outline-primary" : "hover:outline-primary/50",
!isActive && "hover:outline-primary/50",
)}
>
{iconUrl ? (
+15 -5
View File
@@ -66,13 +66,21 @@ test.describe("community rail", () => {
await expect(buttonA).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(buttonB).not.toHaveAttribute("aria-current", "true");
await expect(buttonA.locator(":scope > span").first()).toHaveCSS(
"opacity",
"1",
const activeIndicator = page.getByTestId(
`community-rail-active-${COMMUNITY_A.id}`,
);
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(
"opacity",
"1",
@@ -80,7 +88,7 @@ test.describe("community rail", () => {
const [activeStyle, inactiveStyle] = await Promise.all(
[buttonA, buttonB].map((button) =>
button
.locator(":scope > span")
.locator(":scope > span:not([data-testid])")
.first()
.evaluate((element) => {
const style = getComputedStyle(element);
@@ -88,6 +96,7 @@ test.describe("community rail", () => {
backgroundColor: style.backgroundColor,
borderRadius: style.borderRadius,
color: style.color,
outlineColor: style.outlineColor,
outlineStyle: style.outlineStyle,
outlineWidth: style.outlineWidth,
};
@@ -98,6 +107,7 @@ test.describe("community rail", () => {
expect(activeStyle.borderRadius).toBe(inactiveStyle.borderRadius);
expect(activeStyle.borderRadius).toBe("12px");
expect(activeStyle.color).toBe(inactiveStyle.color);
expect(activeStyle.outlineColor).toBe(inactiveStyle.outlineColor);
expect(activeStyle.outlineStyle).toBe("solid");
expect(activeStyle.outlineWidth).toBe("2px");
expect(inactiveStyle.outlineStyle).toBe("solid");