mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(desktop): outline the selected community (#4969)
**Category:** improvement **User Impact:** Selected communities now use a clear offset outline without tinting or covering their icon. **Problem:** The selected community state replaced the icon surface with an accent fill, obscuring image icons and changing the tile's content treatment. Hover also changed the fill, text color, shape, and opacity, making navigation states visually jumpy. **Solution:** Preserve each community tile's neutral surface and content while using a primary CSS outline for selection and a lighter outline for hover. The transparent outline offset leaves the space around image edges unpainted, and adjusted spacing prevents neighboring outlines from colliding. <img width="200" height="152" alt="Screen Recording 2026-08-05 at 3 23 32 PM" src="https://github.com/user-attachments/assets/5c25b1c0-4be8-41c4-8f1d-ad0010310c92" /> <details> <summary>File changes</summary> **desktop/src/features/sidebar/ui/CommunityRail.tsx** Replaces selected and hover fills with offset outlines, keeps icon presentation stable across states, and adjusts rail and tooltip spacing for the new outline geometry. **desktop/tests/e2e/community-rail.spec.ts** Covers the shared active/inactive surface, radius, text color, opacity, and outline behavior, including hover invariants. </details> ## Reproduction steps 1. Run the desktop app with two or more communities. 2. Give the active community an image icon. 3. Confirm the active icon keeps its original image and receives a 2px primary outline with a transparent 2px gap. 4. Hover another community and confirm only a lighter outline appears; its fill, text color, opacity, and corner radius remain unchanged. 5. Switch communities and confirm the outline follows the active community. ## Screenshots **Full desktop context**  --------- Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
@@ -106,7 +106,7 @@ function CommunityButton({
|
||||
dragAttributes?: React.HTMLAttributes<HTMLElement>;
|
||||
isDragging?: boolean;
|
||||
}) {
|
||||
const { mentionCount, showBadge, showDot, pending, badgeLabel } =
|
||||
const { mentionCount, showBadge, showDot, badgeLabel } =
|
||||
communityRailIndicators(unread);
|
||||
|
||||
const tooltipLabel = showBadge
|
||||
@@ -135,11 +135,8 @@ function CommunityButton({
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"flex h-9 w-9 items-center justify-center overflow-hidden rounded-2xl text-xs font-semibold transition-all",
|
||||
isActive
|
||||
? "rounded-xl bg-primary text-primary-foreground"
|
||||
: "bg-sidebar-accent/60 text-sidebar-foreground/80 hover:rounded-xl hover:bg-primary/80 hover:text-primary-foreground",
|
||||
pending && !isActive && "opacity-60",
|
||||
"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",
|
||||
)}
|
||||
>
|
||||
{iconUrl ? (
|
||||
@@ -172,7 +169,9 @@ function CommunityButton({
|
||||
</button>
|
||||
</ContextMenuTrigger>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">{tooltipLabel}</TooltipContent>
|
||||
<TooltipContent side="right" sideOffset={8}>
|
||||
{tooltipLabel}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<ContextMenuContent data-testid={`community-rail-menu-${community.id}`}>
|
||||
{menu}
|
||||
@@ -368,7 +367,7 @@ export function CommunityRail({
|
||||
return (
|
||||
<nav
|
||||
aria-label="Communities"
|
||||
className="relative z-0 flex w-14 shrink-0 flex-col items-center gap-2 overflow-y-auto bg-sidebar px-2.5 pb-5 pt-[calc(var(--buzz-top-chrome-height,40px)+7px)]"
|
||||
className="relative z-0 flex w-14 shrink-0 flex-col items-center gap-2.5 overflow-y-auto bg-sidebar px-2.5 pb-5 pt-[calc(var(--buzz-top-chrome-height,40px)+7px)]"
|
||||
data-testid="community-rail"
|
||||
>
|
||||
<DndContext
|
||||
@@ -418,7 +417,9 @@ export function CommunityRail({
|
||||
<Plus className="h-4 w-4" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Add community</TooltipContent>
|
||||
<TooltipContent side="right" sideOffset={8}>
|
||||
Add community
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<EditCommunityDialog
|
||||
onOpenChange={(open) => {
|
||||
|
||||
@@ -73,6 +73,52 @@ test.describe("community rail", () => {
|
||||
"opacity",
|
||||
"1",
|
||||
);
|
||||
await expect(buttonB.locator(":scope > span").first()).toHaveCSS(
|
||||
"opacity",
|
||||
"1",
|
||||
);
|
||||
const [activeStyle, inactiveStyle] = await Promise.all(
|
||||
[buttonA, buttonB].map((button) =>
|
||||
button
|
||||
.locator(":scope > span")
|
||||
.first()
|
||||
.evaluate((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
return {
|
||||
backgroundColor: style.backgroundColor,
|
||||
borderRadius: style.borderRadius,
|
||||
color: style.color,
|
||||
outlineStyle: style.outlineStyle,
|
||||
outlineWidth: style.outlineWidth,
|
||||
};
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(activeStyle.backgroundColor).toBe(inactiveStyle.backgroundColor);
|
||||
expect(activeStyle.borderRadius).toBe(inactiveStyle.borderRadius);
|
||||
expect(activeStyle.borderRadius).toBe("12px");
|
||||
expect(activeStyle.color).toBe(inactiveStyle.color);
|
||||
expect(activeStyle.outlineStyle).toBe("solid");
|
||||
expect(activeStyle.outlineWidth).toBe("2px");
|
||||
expect(inactiveStyle.outlineStyle).toBe("solid");
|
||||
expect(inactiveStyle.outlineWidth).toBe("2px");
|
||||
|
||||
const inactiveIcon = buttonB.locator(":scope > span").first();
|
||||
await buttonB.hover();
|
||||
await expect(inactiveIcon).toHaveCSS("outline-width", "2px");
|
||||
const hoverStyle = await inactiveIcon.evaluate((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
return {
|
||||
backgroundColor: style.backgroundColor,
|
||||
borderRadius: style.borderRadius,
|
||||
color: style.color,
|
||||
outlineStyle: style.outlineStyle,
|
||||
};
|
||||
});
|
||||
expect(hoverStyle.backgroundColor).toBe(inactiveStyle.backgroundColor);
|
||||
expect(hoverStyle.borderRadius).toBe(inactiveStyle.borderRadius);
|
||||
expect(hoverStyle.color).toBe(inactiveStyle.color);
|
||||
expect(hoverStyle.outlineStyle).toBe("solid");
|
||||
|
||||
// The add-community affordance lives at the bottom of the rail.
|
||||
await expect(page.getByTestId("community-rail-add")).toBeVisible();
|
||||
|
||||
Reference in New Issue
Block a user