fix(sidebar): always show project row action icons (#346)

* fix(sidebar): always show project row action icons

The hover-reveal mechanism (opacity-0 → group-hover/menu-item:opacity-100)
was not reliably triggering in the Electron app — icons never appeared on
hover. Instead of debugging CSS :hover group propagation in Chromium, make
the action icons always visible.

Changes:
- Remove opacity-0/opacity-100 hover gating from the action cluster div
- Change button padding from hover-gated pr-[84px] to always pr-[84px]
- Hide the session count badge (it was only shown when icons were hidden)
- Keep z-10 on the action cluster so session rows don't paint over it

Reported by phylolver(vaibhaav).

* fix(sidebar): correct inverted collapsed-count class

The count badge was set to hidden-by-default but shown-as-grid in
collapsed/icon mode — the opposite of correct. In icon mode there's no
room for a count badge and the action cluster is hidden anyway. Since the
action icons are now always visible and permanently replace the count,
the badge should be hidden in all states.

Reported by phylolver(vaibhaav).

---------

Co-authored-by: AO Bot <ao-bot@composio.dev>
This commit is contained in:
i-trytoohard 2026-06-20 21:17:39 +05:30 committed by GitHub
parent e175da0691
commit 83091ceb4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 10 additions and 18 deletions

View File

@ -97,18 +97,13 @@ describe("Sidebar", () => {
expect(navigateMock).toHaveBeenCalledWith({ to: "/projects/$projectId", params: { projectId: "proj-1" } });
});
it("hides the worker count in every state that reveals project actions", () => {
it("always shows action icons and reserves padding for them", () => {
renderSidebar();
const projectRow = screen.getByText("Project One").closest("button");
const count = screen.getByText("0");
if (!projectRow) throw new Error("Project row button not found");
expect(projectRow).toHaveClass("group-hover/menu-item:pr-[84px]");
expect(projectRow).toHaveClass("group-focus-within/menu-item:pr-[84px]");
expect(projectRow).toHaveClass("group-has-data-[state=open]/menu-item:pr-[84px]");
expect(count).toHaveClass("group-hover/menu-item:opacity-0");
expect(count).toHaveClass("group-focus-within/menu-item:opacity-0");
expect(count).toHaveClass("group-has-data-[state=open]/menu-item:opacity-0");
// Padding is always reserved for the action cluster (not hover-gated)
expect(projectRow).toHaveClass("pr-[84px]");
});
});

View File

@ -465,10 +465,9 @@ function ProjectItem({
"before:absolute before:top-2 before:bottom-2 before:left-0 before:w-px before:rounded-full before:bg-transparent",
"hover:bg-interactive-hover hover:text-foreground active:bg-interactive-hover active:text-foreground",
"data-[active=true]:bg-interactive-active data-[active=true]:font-semibold data-[active=true]:text-foreground data-[active=true]:before:bg-accent",
// Make room for the hover actions (dashboard, orchestrator, kebab)
// when the row is hovered, focused, or its menu is open (the
// absolutely-positioned cluster replaces the count).
"group-hover/menu-item:pr-[84px] group-focus-within/menu-item:pr-[84px] group-has-data-[state=open]/menu-item:pr-[84px]",
// Always reserve room for the action cluster (dashboard,
// orchestrator, kebab) — icons are always visible, not hover-gated.
"pr-[84px]",
// Icon rail: the old 36px letter tile.
"group-data-[collapsible=icon]:size-9! group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:rounded-lg group-data-[collapsible=icon]:p-0! group-data-[collapsible=icon]:font-semibold",
)}
@ -483,18 +482,16 @@ function ProjectItem({
/>
<span className="hidden group-data-[collapsible=icon]:block">{workspace.name.charAt(0).toUpperCase()}</span>
<span className="min-w-0 flex-1 truncate group-data-[collapsible=icon]:hidden">{workspace.name}</span>
<span className="grid h-4 min-w-4 shrink-0 place-items-center rounded bg-interactive-hover px-1 font-mono text-[10px] leading-none text-passive group-hover/menu-item:pointer-events-none group-hover/menu-item:opacity-0 group-focus-within/menu-item:opacity-0 group-focus-within/menu-item:pointer-events-none group-has-data-[state=open]/menu-item:opacity-0 group-has-data-[state=open]/menu-item:pointer-events-none group-data-[collapsible=icon]:hidden">
<span className="hidden h-4 min-w-4 shrink-0 place-items-center rounded bg-interactive-hover px-1 font-mono text-[10px] leading-none text-passive">
{sessions.length}
</span>
</SidebarMenuButton>
{/* Per-project hover actions: dashboard board, orchestrator, and a kebab
menu. The cluster reveals on row hover/focus (or while the kebab is
open), replacing the session count, and stays hidden in the icon rail. */}
{/* Per-project actions: dashboard board, orchestrator, and a kebab
menu. Always visible (not hover-gated) to avoid CSS :hover group
propagation issues in Electron's Chromium. Hidden in the icon rail. */}
<div
className={cn(
"absolute top-0 right-1 z-10 flex h-9 items-center gap-px",
"opacity-0 transition-opacity",
"group-hover/menu-item:opacity-100 group-focus-within/menu-item:opacity-100 group-has-data-[state=open]/menu-item:opacity-100",
"group-data-[collapsible=icon]:hidden",
)}
>