diff --git a/frontend/src/components/navigation/DesktopSidebar.tsx b/frontend/src/components/navigation/DesktopSidebar.tsx index 79d1cdb3..a6a195d5 100644 --- a/frontend/src/components/navigation/DesktopSidebar.tsx +++ b/frontend/src/components/navigation/DesktopSidebar.tsx @@ -12,7 +12,6 @@ import { Sidebar, SidebarSection, SidebarItem, - SidebarCollapseToggle, } from '@/components/ui/sidebar' import { FolderGit2 } from 'lucide-react' @@ -78,10 +77,6 @@ export function DesktopSidebar() { return ( <> -
- -
- {primary.length > 0 && ( {primary.map((item: NavPrimaryCta) => ( diff --git a/frontend/src/components/source-control/BranchesTab.tsx b/frontend/src/components/source-control/BranchesTab.tsx index 5623a302..ec18377a 100644 --- a/frontend/src/components/source-control/BranchesTab.tsx +++ b/frontend/src/components/source-control/BranchesTab.tsx @@ -1,10 +1,10 @@ import { useMemo, useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { listBranches, switchBranch, GitAuthError, getRepo } from '@/api/repos' -import { fetchGitStatus, useGitStatus } from '@/api/git' +import { fetchGitStatus } from '@/api/git' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' -import { Loader2, GitBranch, GitBranchPlus, Check, Plus, AlertCircle, ArrowUp, ArrowDown, Globe } from 'lucide-react' +import { Loader2, GitBranch, GitBranchPlus, Check, Plus, AlertCircle, Globe } from 'lucide-react' import { cn } from '@/lib/utils' import { showToast } from '@/lib/toast' import { useGit } from '@/hooks/useGit' @@ -25,8 +25,6 @@ export function BranchesTab({ repoId, currentBranch }: BranchesTabProps) { const [worktreeDialogOpen, setWorktreeDialogOpen] = useState(false) const git = useGit(repoId) - const { data: status } = useGitStatus(repoId) - const { data: branches, isLoading, error, refetch } = useQuery({ queryKey: ['branches', repoId], queryFn: () => listBranches(repoId), @@ -103,36 +101,18 @@ export function BranchesTab({ repoId, currentBranch }: BranchesTabProps) { } const activeBranch = branches?.branches?.find(b => b.current)?.name || currentBranch + const hasBranches = (branches?.branches?.length ?? 0) > 0 return (
-
-
- - Current: {activeBranch} - {status && (status.ahead > 0 || status.behind > 0) && ( -
- {status.ahead > 0 && ( - - {status.ahead} - - )} - {status.behind > 0 && ( - - {status.behind} - - )} -
- )} -
- +
{isCreating ? (
setNewBranchName(e.target.value)} - className="h-8 md:text-sm" + className="h-10 md:h-8 md:text-sm" autoFocus onKeyDown={(e) => { if (e.key === 'Enter') handleCreateBranch() @@ -144,7 +124,7 @@ export function BranchesTab({ repoId, currentBranch }: BranchesTabProps) { />
) : (
+ {hasBranches && ( + setSearchQuery(e.target.value)} + className="h-10 md:h-8 md:text-sm flex-1 min-w-0" + /> + )} {repoUrl && ( )}
)} - {branches?.branches && branches.branches.length > 0 && ( -
- setSearchQuery(e.target.value)} - className="h-8 md:text-sm" - /> -
- )}
@@ -228,7 +207,7 @@ export function BranchesTab({ repoId, currentBranch }: BranchesTabProps) { key={branch.name} className={cn( 'flex items-center gap-2 px-3 py-2 w-full text-left transition-colors', - isCurrent && 'bg-accent', + isCurrent && 'bg-orange-500/10', isCheckedOutElsewhere ? 'opacity-60 cursor-not-allowed' : 'hover:bg-accent/50' )} onClick={handleClick} diff --git a/frontend/src/components/source-control/SourceControlPanel.tsx b/frontend/src/components/source-control/SourceControlPanel.tsx index 6451da85..20210695 100644 --- a/frontend/src/components/source-control/SourceControlPanel.tsx +++ b/frontend/src/components/source-control/SourceControlPanel.tsx @@ -112,8 +112,8 @@ export function SourceControlPanel({
- - {displayBranch} + + {displayBranch}
{status && (status.ahead > 0 || status.behind > 0) && (
diff --git a/frontend/src/components/ui/sidebar.test.tsx b/frontend/src/components/ui/sidebar.test.tsx index 46142c5b..59dada0b 100644 --- a/frontend/src/components/ui/sidebar.test.tsx +++ b/frontend/src/components/ui/sidebar.test.tsx @@ -114,4 +114,31 @@ describe('SidebarCollapseToggle', () => { fireEvent.click(screen.getByRole('button')) expect(handleToggle).toHaveBeenCalledTimes(1) }) + + it('calls onToggle when clicked while collapsed', () => { + const handleToggle = vi.fn() + + render( + + ) + + fireEvent.click(screen.getByRole('button', { name: 'Expand sidebar' })) + expect(handleToggle).toHaveBeenCalledTimes(1) + }) + + it('exposes expanded state via accessible name and aria-expanded', () => { + const { rerender } = render( + + ) + + expect( + screen.getByRole('button', { name: 'Collapse sidebar' }) + ).toHaveAttribute('aria-expanded', 'true') + + rerender() + + expect( + screen.getByRole('button', { name: 'Expand sidebar' }) + ).toHaveAttribute('aria-expanded', 'false') + }) }) diff --git a/frontend/src/components/ui/sidebar.tsx b/frontend/src/components/ui/sidebar.tsx index d82e1a7e..cc3c2b4c 100644 --- a/frontend/src/components/ui/sidebar.tsx +++ b/frontend/src/components/ui/sidebar.tsx @@ -1,11 +1,11 @@ import type { LucideIcon } from 'lucide-react' -import { PanelLeft, PanelLeftClose } from 'lucide-react' +import { ChevronLeft, ChevronRight } from 'lucide-react' import { cn } from '@/lib/utils' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' export interface SidebarProps { collapsed: boolean - onToggle: () => void + onToggle?: () => void widthClass?: string collapsedWidthClass?: string className?: string @@ -15,6 +15,7 @@ export interface SidebarProps { export function Sidebar({ collapsed, + onToggle, widthClass = 'w-60', collapsedWidthClass = 'w-14', className, @@ -24,12 +25,13 @@ export function Sidebar({ return ( ) @@ -125,14 +127,36 @@ export function SidebarCollapseToggle({ collapsed, onToggle }: SidebarCollapseTo type="button" onClick={onToggle} className={cn( - 'rounded-md p-2.5', - 'hover:bg-accent hover:text-accent-foreground', - 'transition-colors duration-150' + 'group absolute -right-3 top-1/2 z-20 h-16 w-6 -translate-y-1/2', + 'flex items-center justify-center bg-transparent', + 'focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background' )} title={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} + aria-expanded={!collapsed} > - {collapsed ? : } +