diff --git a/apps/web/src/components/Sidebar.logic.test.ts b/apps/web/src/components/Sidebar.logic.test.ts index d56c7a69..3a8c9da5 100644 --- a/apps/web/src/components/Sidebar.logic.test.ts +++ b/apps/web/src/components/Sidebar.logic.test.ts @@ -6,6 +6,7 @@ import { getProjectSortTimestamp, hasUnseenCompletion, resolveProjectStatusIndicator, + resolveProjectNameTone, resolveSidebarNewThreadEnvMode, resolveThreadRowClassName, resolveThreadStatusPill, @@ -315,6 +316,22 @@ describe("resolveThreadRowClassName", () => { }); }); +describe("resolveProjectNameTone", () => { + it("keeps the selected project name on its assigned project color", () => { + expect(resolveProjectNameTone({ isSelectedProject: true, visualIndex: 3 })).toBe("project"); + }); + + it("starts inactive project names on the stronger muted grey", () => { + expect(resolveProjectNameTone({ isSelectedProject: false, visualIndex: 0 })).toBe( + "mutedStrong", + ); + }); + + it("alternates inactive project names to a softer muted grey on the next row", () => { + expect(resolveProjectNameTone({ isSelectedProject: false, visualIndex: 1 })).toBe("mutedSoft"); + }); +}); + describe("resolveProjectStatusIndicator", () => { it("returns null when no threads have a notable status", () => { expect(resolveProjectStatusIndicator([null, null])).toBeNull(); diff --git a/apps/web/src/components/Sidebar.logic.ts b/apps/web/src/components/Sidebar.logic.ts index 2377c3db..0711cb97 100644 --- a/apps/web/src/components/Sidebar.logic.ts +++ b/apps/web/src/components/Sidebar.logic.ts @@ -113,6 +113,17 @@ export function resolveThreadRowClassName(input: { return cn(baseClassName, "text-muted-foreground hover:bg-accent hover:text-foreground"); } +export function resolveProjectNameTone(input: { + isSelectedProject: boolean; + visualIndex: number; +}): "project" | "mutedStrong" | "mutedSoft" { + if (input.isSelectedProject) { + return "project"; + } + + return input.visualIndex % 2 === 0 ? "mutedStrong" : "mutedSoft"; +} + export function resolveThreadStatusPill(input: { thread: ThreadStatusInput; hasPendingApprovals: boolean; diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 22675e23..85af274f 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -95,6 +95,7 @@ import { OkCodeMark } from "./OkCodeMark"; import { getVisibleThreadsForProject, isActionableThreadStatus, + resolveProjectNameTone, resolveSidebarNewThreadEnvMode, resolveThreadStatusPill, shouldClearThreadSelectionOnMouseDown, @@ -556,6 +557,7 @@ export default function Sidebar() { () => new Map(threads.map((thread) => [thread.id, thread] as const)), [threads], ); + const activeProjectId = routeThreadId ? (threadById.get(routeThreadId)?.projectId ?? null) : null; const sortedThreadsByProjectId = useMemo( () => sortThreadsByProjectIdForSidebar(threads, appSettings.sidebarThreadSortOrder), [appSettings.sidebarThreadSortOrder, threads], @@ -1258,6 +1260,7 @@ export default function Sidebar() { function renderProjectItem( project: (typeof sortedProjects)[number], dragHandleProps: SortableProjectHandleProps | null, + visualIndex: number, ) { const projectThreads = sortedThreadsByProjectId.get(project.id) ?? EMPTY_THREADS; const activeThreadId = routeThreadId ?? undefined; @@ -1277,6 +1280,10 @@ export default function Sidebar() { const renderedThreads = pinnedCollapsedThread ? [pinnedCollapsedThread] : visibleThreads; const pColor = getProjectColor(project.id); const isDark = resolvedTheme === "dark"; + const projectNameTone = resolveProjectNameTone({ + isSelectedProject: activeProjectId === project.id, + visualIndex, + }); return ( @@ -1326,8 +1333,16 @@ export default function Sidebar() { ) : ( { e.stopPropagation(); startProjectEditing({ @@ -2020,9 +2035,9 @@ export default function Sidebar() { items={sortedProjects.map((project) => project.id)} strategy={verticalListSortingStrategy} > - {sortedProjects.map((project) => ( + {sortedProjects.map((project, index) => ( - {(dragHandleProps) => renderProjectItem(project, dragHandleProps)} + {(dragHandleProps) => renderProjectItem(project, dragHandleProps, index)} ))} @@ -2030,9 +2045,9 @@ export default function Sidebar() { ) : ( - {sortedProjects.map((project) => ( + {sortedProjects.map((project, index) => ( - {renderProjectItem(project, null)} + {renderProjectItem(project, null, index)} ))}