diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index bf129eca..0b289e0b 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -1,14 +1,19 @@ import { ArrowLeftIcon, ArrowUpDownIcon, + CheckCircleIcon, ChevronRightIcon, + CircleDotIcon, + CloudUploadIcon, EyeIcon, EyeOffIcon, - ZapIcon, + ExternalLinkIcon, FolderIcon, GitBranchIcon, GitMergeIcon, GitPullRequestIcon, + LinkIcon, + UserIcon, XCircleIcon, PanelLeftCloseIcon, PlusIcon, @@ -17,7 +22,6 @@ import { TerminalIcon, TriangleAlertIcon, } from "lucide-react"; -import { ThemeModeSwitcher } from "./ThemeModeSwitcher"; import { OkCodeMark } from "./OkCodeMark"; import { ConnectionIndicator } from "./ConnectionIndicator"; import { memo, useCallback, useEffect, useMemo, useRef, useState, type MouseEvent } from "react"; @@ -110,7 +114,6 @@ import { isActionableThreadStatus, resolveProjectStatusIndicator, resolveSidebarNewThreadEnvMode, - resolveThreadRowClassName, resolveThreadStatusPill, shouldClearThreadSelectionOnMouseDown, sortProjectsForSidebar, @@ -350,7 +353,7 @@ function SortableProjectItem({ transform: CSS.Translate.toString(transform), transition, }} - className={`group/menu-item relative rounded-md mt-1.5 first:mt-0 ${ + className={`group/menu-item relative rounded-md mt-0.5 first:mt-0 ${ isDragging ? "z-20 opacity-80" : "" } ${isOver && !isDragging ? "ring-1 ring-primary/40" : ""}`} data-sidebar="menu-item" @@ -441,25 +444,41 @@ const MemoizedThreadRow = memo( selectThreadTerminalState(terminalStateByThreadId, thread.id).runningTerminalIds, ); + // Derive a type-based icon for the thread row + const ThreadIcon = prStatus + ? prStatus.icon + : threadStatus?.label === "Completed" + ? CheckCircleIcon + : threadStatus?.label === "Error" + ? XCircleIcon + : threadStatus?.label === "Working" || threadStatus?.label === "Connecting" + ? CircleDotIcon + : threadStatus?.label === "Pending Approval" || threadStatus?.label === "Awaiting Input" + ? UserIcon + : threadStatus?.label === "Plan Ready" + ? LinkIcon + : CircleDotIcon; + + const threadIconColor = prStatus + ? prStatus.colorClass + : threadStatus + ? threadStatus.colorClass + : "text-muted-foreground/50"; + return ( - {/* Project color accent bar */} - ); @@ -1447,39 +1416,17 @@ export default function Sidebar() { const orderedProjectThreadIds = projectThreads.map((thread) => thread.id); const renderedThreads = pinnedCollapsedThread ? [pinnedCollapsedThread] : visibleThreads; const pColor = getProjectColor(project.id); - const isDark = resolvedTheme === "dark"; return ( -
+
{ - const hoverBg = appSettings.sidebarAccentBgColorOverride - ? `color-mix(in srgb, ${appSettings.sidebarAccentBgColorOverride} 25%, transparent)` - : isDark - ? pColor.bgDark.replace("0.12)", "0.20)") - : pColor.bg.replace("0.08)", "0.14)"); - e.currentTarget.style.backgroundColor = hoverBg; - }} - onMouseLeave={(e) => { - e.currentTarget.style.backgroundColor = appSettings.sidebarAccentBgColorOverride - ? `color-mix(in srgb, ${appSettings.sidebarAccentBgColorOverride} 15%, transparent)` - : isDark - ? pColor.bgDark - : pColor.bg; - }} + className={cn( + "min-w-0 flex-1 gap-0 rounded-md px-2 py-1.5 text-left hover:bg-transparent", + isManualProjectSorting ? "cursor-grab active:cursor-grabbing" : "cursor-pointer", + )} {...(isManualProjectSorting && dragHandleProps ? dragHandleProps.attributes : {})} {...(isManualProjectSorting && dragHandleProps ? dragHandleProps.listeners : {})} onPointerDownCapture={handleProjectTitlePointerDownCapture} @@ -1493,35 +1440,12 @@ export default function Sidebar() { }); }} > - {!project.expanded && projectStatus ? ( - - - { - event.preventDefault(); - event.stopPropagation(); - void createNewThreadForProject(project.id); - }} - > - - - } - /> - - {newThreadShortcutLabel ? `New thread (${newThreadShortcutLabel})` : "New thread"} - -
- + {renderedThreads.map((thread) => ( {project.expanded && !appSettings.sidebarHideFiles ? ( -
+