Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/desktop/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,28 @@ app.whenReady().then(async () => {
currentWorkspaceCwd = cwd;
});

// Theme sync: update window background and title bar overlay
const themeColors = {
dark: { bg: '#1e1e1e', overlay: '#1a1a1a', symbol: '#858585' },
light: { bg: '#ffffff', overlay: '#f5f5f5', symbol: '#666666' },
paper: { bg: '#f5f0e8', overlay: '#ede8de', symbol: '#7a7872' },
};

ipcMain.on('theme:change', (_e, theme: string) => {
if (!mainWindow) return;
const c = themeColors[theme as keyof typeof themeColors];
if (!c) return;

mainWindow.setBackgroundColor(c.bg);

if (process.platform === 'win32') {
mainWindow.setTitleBarOverlay({
color: c.overlay,
symbolColor: c.symbol,
});
}
});

registerFsHandlers();
registerGitHandlers();

Expand Down
3 changes: 3 additions & 0 deletions packages/desktop/electron/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ const api = {
// Workspace cwd sync (renderer -> main)
setWorkspaceCwd: (cwd: string): void => ipcRenderer.send('workspace:setCwd', cwd),

// Theme sync (renderer -> main)
setTheme: (theme: string): void => ipcRenderer.send('theme:change', theme),

// Git (explicit cwd)
gitStatus: (cwd: string): Promise<unknown> => ipcRenderer.invoke('git:status', cwd),
gitBranches: (cwd: string): Promise<string[]> => ipcRenderer.invoke('git:branches', cwd),
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"react-dom": "^19.1.0",
"react-markdown": "^10.1.0",
"react-resizable-panels": "^2.1.7",
"react-virtuoso": "^4.12.6",
"@tanstack/react-virtual": "^3.12.6",
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.1",
"simple-git": "^3.27.0",
Expand Down
9 changes: 8 additions & 1 deletion packages/desktop/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ErrorBoundary from './shared/ErrorBoundary';

export default function App() {
const mode = useGlobalStore((s) => s.ui.mode);
const theme = useGlobalStore((s) => s.ui.theme);
const setMode = useGlobalStore((s) => s.setMode);
const rootPath = useGlobalStore((s) => s.workspace.rootPath);

Expand All @@ -17,6 +18,12 @@ export default function App() {
}
}, [rootPath]);

// Sync theme to document and main process
useEffect(() => {
document.documentElement.dataset.theme = theme;
window.electronAPI?.setTheme?.(theme);
}, [theme]);

useEffect(() => {
const off = window.electronAPI?.onFsChange?.(() => {});
const handler = ((e: CustomEvent<'agent' | 'ide'>) => {
Expand All @@ -31,7 +38,7 @@ export default function App() {

return (
<ErrorBoundary>
<div className="h-screen flex flex-col bg-[#1e1e1e] text-[#cccccc] overflow-hidden">
<div className="h-screen flex flex-col bg-[var(--bg-base)] text-[var(--text-primary)] overflow-hidden">
<TitleBar />
{/* Both layouts stay mounted; visibility toggled via display to preserve Monaco + PTY state */}
<div className={`${mode === 'agent' ? 'flex' : 'hidden'} flex-1 flex-col overflow-hidden`}>
Expand Down
12 changes: 6 additions & 6 deletions packages/desktop/src/TitleBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export default function TitleBar() {

return (
<div
className="shrink-0 flex items-center px-3 bg-[#1a1a1a] select-none"
className="shrink-0 flex items-center px-3 bg-[var(--bg-card)] select-none"
style={
{
height: 'env(titlebar-area-height, 36px)',
WebkitAppRegion: 'drag',
} as React.CSSProperties
}
>
<span className="text-[#858585] text-xs font-medium">Coding Code</span>
<span className="text-[var(--text-tertiary)] text-xs font-medium">Coding Code</span>
<div
className="flex items-center gap-0.5 ml-4"
style={{ WebkitAppRegion: 'no-drag' } as React.CSSProperties}
Expand All @@ -27,8 +27,8 @@ export default function TitleBar() {
onClick={() => setMode('agent')}
className={`px-3 h-6 text-xs rounded transition-colors ${
mode === 'agent'
? 'bg-[#0e639c] text-white'
: 'text-[#858585] hover:text-[#cccccc] hover:bg-[#2d2d2d]'
? 'bg-[var(--accent-primary)] text-[var(--text-inverse)]'
: 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]'
}`}
>
Agent
Expand All @@ -37,8 +37,8 @@ export default function TitleBar() {
onClick={() => setMode('ide')}
className={`px-3 h-6 text-xs rounded transition-colors ${
mode === 'ide'
? 'bg-[#0e639c] text-white'
: 'text-[#858585] hover:text-[#cccccc] hover:bg-[#2d2d2d]'
? 'bg-[var(--accent-primary)] text-[var(--text-inverse)]'
: 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]'
}`}
>
IDE
Expand Down
36 changes: 18 additions & 18 deletions packages/desktop/src/agent/AgentSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ export default function AgentSidebar() {

if (sidebarCollapsed) {
return (
<div className="flex flex-col items-center w-10 shrink-0 bg-[#161616] border-r border-[#222] pt-2 gap-1">
<div className="flex flex-col items-center w-10 shrink-0 bg-[var(--bg-sidebar)] border-r border-[var(--border-default)] pt-2 gap-1">
<button
type="button"
onClick={toggleSidebar}
title="展开侧边栏"
className="w-7 h-7 flex items-center justify-center text-[#555] hover:text-[#ccc] hover:bg-[#252525] rounded transition-colors"
className="w-7 h-7 flex items-center justify-center text-[var(--text-placeholder)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)] rounded transition-colors"
>
<ChevronRight size={16} strokeWidth={1.5} />
</button>
Expand All @@ -83,17 +83,17 @@ export default function AgentSidebar() {
}

return (
<div className="flex flex-col shrink-0 bg-[#161616] border-r border-[#222] w-64 select-none">
<div className="flex flex-col shrink-0 bg-[var(--bg-sidebar)] border-r border-[var(--border-default)] w-64 select-none">
{/* 顶部栏:项目名 + 收起按钮 */}
<div className="flex items-center justify-between px-2 pt-2">
<span className="text-[13px] font-semibold text-[#888] truncate ml-2">
<span className="text-[13px] font-semibold text-[var(--text-tertiary)] truncate ml-2">
{projectName || '项目'}
</span>
<button
type="button"
onClick={toggleSidebar}
title="收起侧边栏"
className="w-7 h-7 flex items-center justify-center text-[#555] hover:text-[#ccc] hover:bg-[#252525] rounded transition-colors"
className="w-7 h-7 flex items-center justify-center text-[var(--text-placeholder)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)] rounded transition-colors"
>
<ChevronLeft size={16} strokeWidth={1.5} />
</button>
Expand All @@ -104,7 +104,7 @@ export default function AgentSidebar() {
<button
type="button"
onClick={() => setCurrentThread(null)}
className="w-full flex items-center gap-2.5 px-4 py-2.5 rounded-lg text-[14px] text-[#bbb] hover:text-white hover:bg-[#252525] transition-colors border border-[#2a2a2a] hover:border-[#3a3a3a]"
className="w-full flex items-center gap-2.5 px-4 py-2.5 rounded-lg text-[14px] text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)] transition-colors border border-[var(--border-card)] hover:border-[var(--border-hover)]"
>
<Plus size={16} strokeWidth={1.5} />
<span>新对话</span>
Expand All @@ -117,12 +117,12 @@ export default function AgentSidebar() {
<NavItem icon={<Zap size={16} strokeWidth={1.5} />} label="自动化" />
</nav>

<div className="mx-3 border-t border-[#222]" />
<div className="mx-3 border-t border-[var(--border-default)]" />

{/* 会话列表 */}
<div className="flex-1 overflow-y-auto py-3 min-h-0">
<div className="px-3 pb-1.5">
<span className="text-[11px] font-semibold text-[#444] uppercase tracking-wider">
<span className="text-[11px] font-semibold text-[var(--text-disabled)] uppercase tracking-wider">
会话
</span>
</div>
Expand All @@ -135,8 +135,8 @@ export default function AgentSidebar() {
onMouseLeave={() => setHoveredThreadId(null)}
className={`w-full text-left px-4 py-2.5 rounded-lg flex items-center gap-2 transition-colors ${
currentThreadId === t.id
? 'bg-[#0d2d4a] text-[#cde]'
: 'text-[#888] hover:bg-[#1c1c1c] hover:text-[#bbb]'
? 'bg-[var(--bg-selected)] text-[var(--text-primary)]'
: 'text-[var(--text-tertiary)] hover:bg-[var(--bg-card-hover)] hover:text-[var(--text-secondary)]'
}`}
>
<span className="flex-1 text-[14px] truncate">{t.title || '未命名对话'}</span>
Expand All @@ -147,7 +147,7 @@ export default function AgentSidebar() {
e.stopPropagation();
handleDelete(t.id);
}}
className="shrink-0 p-0.5 text-[#555] hover:text-red-400 transition-colors"
className="shrink-0 p-0.5 text-[var(--text-placeholder)] hover:text-red-400 transition-colors"
title="删除对话"
>
<svg
Expand All @@ -168,7 +168,7 @@ export default function AgentSidebar() {
</svg>
</button>
) : (
<span className="text-[12px] text-[#3a3a3a] shrink-0">
<span className="text-[12px] text-[var(--text-disabled)] shrink-0">
{relativeTime(t.updatedAt)}
</span>
)}
Expand All @@ -177,24 +177,24 @@ export default function AgentSidebar() {
{threadList.length > 15 && (
<button
type="button"
className="w-full text-left px-4 py-1.5 text-[12px] text-[#3a3a3a] hover:text-[#555] transition-colors"
className="w-full text-left px-4 py-1.5 text-[12px] text-[var(--text-disabled)] hover:text-[var(--text-placeholder)] transition-colors"
>
+{threadList.length - 15} 条更多
</button>
)}
{threadList.length === 0 && (
<div className="px-3 py-4 text-[13px] text-[#3a3a3a]">暂无对话</div>
<div className="px-3 py-4 text-[13px] text-[var(--text-disabled)]">暂无对话</div>
)}
</div>

<div className="mx-3 border-t border-[#222]" />
<div className="mx-3 border-t border-[var(--border-default)]" />

{/* 底部 */}
<div className="px-2 py-2.5">
<button
type="button"
onClick={() => useGlobalStore.getState().setView('settings')}
className="w-full flex items-center gap-2 px-3 py-2 text-[13px] text-[#555] hover:text-[#ccc] hover:bg-[#252525] rounded-lg transition-colors"
className="w-full flex items-center gap-2 px-3 py-2 text-[13px] text-[var(--text-placeholder)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)] rounded-lg transition-colors"
>
<Settings size={16} strokeWidth={1.5} />
<span>设置</span>
Expand All @@ -208,11 +208,11 @@ function NavItem({ icon, label, shortcut }: { icon: React.ReactNode; label: stri
return (
<button
type="button"
className="w-full flex items-center gap-2.5 px-4 py-2 rounded-lg text-[14px] text-[#666] hover:text-[#ccc] hover:bg-[#1e1e1e] transition-colors"
className="w-full flex items-center gap-2.5 px-4 py-2 rounded-lg text-[14px] text-[var(--text-muted)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-base)] transition-colors"
>
<span className="w-4 flex items-center justify-center shrink-0">{icon}</span>
<span className="flex-1 text-left">{label}</span>
{shortcut && <span className="text-[11px] text-[#333]">{shortcut}</span>}
{shortcut && <span className="text-[11px] text-[var(--text-disabled)]">{shortcut}</span>}
</button>
);
}
Loading
Loading