From 93345e331bf58b85f723f63f8d09f7bfc684efeb Mon Sep 17 00:00:00 2001 From: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:10:27 -0700 Subject: [PATCH] Fix workspace sidebar appearance setting (#5725) Co-authored-by: Orca --- .../src/components/sidebar/Sidebar.test.tsx | 115 ++++++++++++++++++ src/renderer/src/components/sidebar/index.tsx | 12 +- 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/renderer/src/components/sidebar/Sidebar.test.tsx diff --git a/src/renderer/src/components/sidebar/Sidebar.test.tsx b/src/renderer/src/components/sidebar/Sidebar.test.tsx new file mode 100644 index 00000000000..c97f3514b21 --- /dev/null +++ b/src/renderer/src/components/sidebar/Sidebar.test.tsx @@ -0,0 +1,115 @@ +import type { CSSProperties, ReactNode } from 'react' +import { renderToStaticMarkup } from 'react-dom/server' +import { describe, expect, it, vi } from 'vitest' +import { getDefaultSettings } from '../../../../shared/constants' +import type { GlobalSettings } from '../../../../shared/types' + +const mocks = vi.hoisted(() => ({ + state: {} as Record +})) + +vi.mock('@/store', () => ({ + useAppStore: (selector: (state: Record) => unknown) => selector(mocks.state) +})) + +vi.mock('@/hooks/useSidebarResize', () => ({ + useSidebarResize: () => ({ + containerRef: { current: null }, + isResizing: false, + onResizeStart: vi.fn() + }) +})) + +vi.mock('@/components/ui/tooltip', () => ({ + TooltipProvider: ({ children }: { children: ReactNode }) => <>{children} +})) + +vi.mock('./SidebarHeader', () => ({ + default: () =>
+})) + +vi.mock('./SidebarNav', () => ({ + default: () =>
+})) + +vi.mock('./SetupScriptPromptCard', () => ({ + default: () =>
+})) + +vi.mock('./WorktreeList', () => ({ + default: () =>
+})) + +vi.mock('./SidebarToolbar', () => ({ + default: () =>
+})) + +vi.mock('./WorkspaceKanbanDrawer', () => ({ + default: ({ leftSidebarStyle }: { leftSidebarStyle?: CSSProperties }) => ( +
+ ) +})) + +vi.mock('./useSidebarProjectDrop', () => ({ + useSidebarProjectDrop: () => ({ + nativeDropTarget: undefined, + dropHandlers: {}, + affordance: { visible: false } + }) +})) + +vi.mock('./useWorkspaceBoardPanel', () => ({ + useWorkspaceBoardPanel: () => ({ + workspaceBoardOpen: false, + workspaceBoardRenderedOpen: true, + workspaceBoardDragPreviewOpen: false, + workspaceBoardMenuOpen: false, + toggleWorkspaceBoard: vi.fn(), + handleWorkspaceBoardOpenChange: vi.fn(), + setWorkspaceBoardMenuOpen: vi.fn(), + closeWorkspaceBoard: vi.fn(), + previewWorkspaceBoardFromDrag: vi.fn(), + solidifyWorkspaceBoardFromDrag: vi.fn(), + cancelWorkspaceBoardDragPreview: vi.fn() + }) +})) + +import Sidebar from './index' + +function setSidebarState(settings: GlobalSettings): void { + mocks.state = { + activeModal: null, + fetchAllWorktrees: vi.fn(), + repos: [], + setSidebarWidth: vi.fn(), + settings, + sidebarOpen: true, + sidebarWidth: 320 + } +} + +function renderSidebar(): string { + return renderToStaticMarkup( + + ) +} + +describe('Sidebar', () => { + it('applies left sidebar appearance variables to the workspace sidebar surface', () => { + setSidebarState({ + ...getDefaultSettings('/tmp'), + leftSidebarAppearanceMode: 'match-terminal', + terminalColorOverrides: { + background: '#101820', + foreground: '#f0f4f8' + } + }) + + const markup = renderSidebar() + + expect(markup).toContain('--worktree-sidebar:#101820') + expect(markup).toContain('--worktree-sidebar-foreground:#f0f4f8') + expect(markup).toContain('data-testid="workspace-kanban-drawer"') + expect(markup.match(/--worktree-sidebar:#101820/g)).toHaveLength(2) + }) +}) diff --git a/src/renderer/src/components/sidebar/index.tsx b/src/renderer/src/components/sidebar/index.tsx index 9cf478afc4d..524fcb5d87f 100644 --- a/src/renderer/src/components/sidebar/index.tsx +++ b/src/renderer/src/components/sidebar/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react' +import React, { useEffect, useMemo } from 'react' import { useAppStore } from '@/store' import { TooltipProvider } from '@/components/ui/tooltip' import { useSidebarResize } from '@/hooks/useSidebarResize' @@ -13,6 +13,8 @@ import { cn } from '@/lib/utils' import { FolderPlus, Loader2 } from 'lucide-react' import { useSidebarProjectDrop } from './useSidebarProjectDrop' import { useWorkspaceBoardPanel } from './useWorkspaceBoardPanel' +import { resolveLeftSidebarStyleVariables } from '@/lib/left-sidebar-appearance' +import { useSystemPrefersDark } from '@/components/terminal-pane/use-system-prefers-dark' const WorktreeMetaDialog = React.lazy(() => import('./WorktreeMetaDialog')) const RemoveFolderDialog = React.lazy(() => import('./RemoveFolderDialog')) @@ -38,8 +40,14 @@ function Sidebar({ const sidebarWidth = useAppStore((s) => s.sidebarWidth) const setSidebarWidth = useAppStore((s) => s.setSidebarWidth) const repos = useAppStore((s) => s.repos) + const settings = useAppStore((s) => s.settings) const fetchAllWorktrees = useAppStore((s) => s.fetchAllWorktrees) const activeModal = useAppStore((s) => s.activeModal) + const systemPrefersDark = useSystemPrefersDark() + const leftSidebarStyle = useMemo( + () => resolveLeftSidebarStyleVariables(settings, systemPrefersDark), + [settings, systemPrefersDark] + ) as React.CSSProperties | undefined const { nativeDropTarget, dropHandlers, affordance } = useSidebarProjectDrop() const { workspaceBoardOpen, @@ -89,6 +97,7 @@ function Sidebar({ ref={containerRef} data-native-file-drop-target={sidebarOpen ? nativeDropTarget : undefined} className="relative min-h-0 flex-shrink-0 bg-worktree-sidebar flex flex-col overflow-hidden scrollbar-sleek-parent" + style={leftSidebarStyle} {...dropHandlers} > {sidebarOpen && ( @@ -155,6 +164,7 @@ function Sidebar({ {sidebarOpen ? (