fix(desktop): clarify sidebar project hierarchy (#733)

Indent session rows under their project group and switch project folder icons between open and closed states when collapsed.

Tested: cd desktop && bun run test --run src/components/layout/Sidebar.test.tsx -t "groups sessions by project|collapses a project group"
Tested: cd desktop && bun run test --run src/components/layout/Sidebar.test.tsx
Tested: bun run check:desktop
Tested: Browser plugin smoke on http://127.0.0.1:3456/ confirmed first project open -> closed state, icon state, and pl-6 session indentation.
Confidence: high
Scope-risk: narrow
This commit is contained in:
程序员阿江(Relakkes) 2026-06-04 19:51:18 +08:00
parent 7f7d0d89ae
commit d2a99e01c2
2 changed files with 27 additions and 6 deletions

View File

@ -282,7 +282,9 @@ describe('Sidebar', () => {
expect(screen.getByText('beta')).toBeInTheDocument()
expect(screen.getByRole('button', { name: /Alpha newest/ })).toBeInTheDocument()
expect(screen.queryByRole('button', { name: /Alpha hidden/ })).not.toBeInTheDocument()
expect(screen.getByRole('button', { name: /Alpha newest/ }).closest('[class*="pl-0"]')).toBeInTheDocument()
expect(screen.getByTestId('sidebar-project-session-list-workspace-alpha').parentElement).toHaveClass('pl-6')
expect(screen.getByRole('button', { name: 'Collapse alpha' })).toHaveAttribute('data-state', 'open')
expect(screen.getByTestId('sidebar-project-icon-workspace-alpha')).toHaveAttribute('data-icon-state', 'open')
fireEvent.click(screen.getByRole('button', { name: 'Expand display' }))
@ -378,6 +380,8 @@ describe('Sidebar', () => {
expect(screen.queryByRole('button', { name: /Alpha Session/ })).not.toBeInTheDocument()
expect(screen.getByRole('button', { name: /Beta Session/ })).toBeInTheDocument()
expect(screen.getByRole('button', { name: 'Expand alpha' })).toBeInTheDocument()
expect(screen.getByRole('button', { name: 'Expand alpha' })).toHaveAttribute('data-state', 'closed')
expect(screen.getByTestId('sidebar-project-icon-workspace-alpha')).toHaveAttribute('data-icon-state', 'closed')
})
it('uses a bounded per-project session scroller for large expanded groups', () => {

View File

@ -853,15 +853,32 @@ export function Sidebar({ isMobile = false, onRequestClose }: SidebarProps) {
onDragStart={(event) => handleProjectDragStart(event, project.key)}
onDragEnd={clearProjectDragState}
onClick={() => toggleProjectCollapsed(project.key)}
className="flex min-w-0 flex-1 cursor-grab items-center gap-2 rounded-xl px-1.5 py-2 text-left transition-colors active:cursor-grabbing hover:bg-[var(--color-sidebar-item-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-focus)]"
data-state={projectCollapsed ? 'closed' : 'open'}
className="flex min-w-0 flex-1 cursor-grab items-center gap-2 rounded-xl px-1.5 py-2 text-left transition-[background,color] active:cursor-grabbing hover:bg-[var(--color-sidebar-item-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-focus)]"
aria-expanded={!projectCollapsed}
aria-label={t(projectCollapsed ? 'sidebar.expandProject' : 'sidebar.collapseProject', { project: project.title })}
title={project.subtitle || project.title}
>
<span className="flex h-5 w-5 flex-shrink-0 items-center justify-center text-[var(--color-text-primary)]">
<Folder className="h-[18px] w-[18px]" strokeWidth={1.9} aria-hidden="true" />
<span
data-testid={`sidebar-project-icon-${domSafeProjectKey(project.key)}`}
data-icon-state={projectCollapsed ? 'closed' : 'open'}
className={`flex h-5 w-5 flex-shrink-0 items-center justify-center transition-colors ${
projectCollapsed
? 'text-[var(--color-text-secondary)]'
: 'text-[var(--color-text-primary)]'
}`}
>
{projectCollapsed ? (
<Folder className="h-[18px] w-[18px]" strokeWidth={1.9} aria-hidden="true" />
) : (
<FolderOpen className="h-[18px] w-[18px]" strokeWidth={1.9} aria-hidden="true" />
)}
</span>
<span className="min-w-0 flex-1 truncate text-[13px] font-semibold leading-5 text-[var(--color-text-primary)]">
<span className={`min-w-0 flex-1 truncate text-[13px] font-semibold leading-5 transition-colors ${
projectCollapsed
? 'text-[var(--color-text-secondary)]'
: 'text-[var(--color-text-primary)]'
}`}>
{project.title}
</span>
{isProjectPinned && (
@ -917,7 +934,7 @@ export function Sidebar({ isMobile = false, onRequestClose }: SidebarProps) {
</div>
</div>
{!projectCollapsed && (
<div className="mt-0.5 pl-0">
<div className="mt-0.5 pl-6">
<div
className={hasInternalScroll ? 'max-h-[420px] overflow-y-auto pr-1' : undefined}
data-testid={`sidebar-project-session-list-${domSafeProjectKey(project.key)}`}