diff --git a/packages/electron/main.mjs b/packages/electron/main.mjs
index 2c51c1b8..1ea1100c 100644
--- a/packages/electron/main.mjs
+++ b/packages/electron/main.mjs
@@ -2101,7 +2101,9 @@ const createMiniChatWindow = async ({ mode, sessionId = '', directory = '', proj
icon: getWindowIconPath(),
show: false,
backgroundColor: '#151313',
- titleBarStyle: process.platform === 'darwin' ? 'hidden' : 'default',
+ frame: process.platform === 'win32' ? false : undefined,
+ autoHideMenuBar: process.platform !== 'darwin',
+ titleBarStyle: process.platform === 'darwin' || process.platform === 'win32' ? 'hidden' : 'default',
trafficLightPosition: process.platform === 'darwin' ? { x: 16, y: 17 } : undefined,
webPreferences: {
additionalArguments: [
diff --git a/packages/ui/src/components/desktop/WindowsWindowControls.tsx b/packages/ui/src/components/desktop/WindowsWindowControls.tsx
new file mode 100644
index 00000000..153850cb
--- /dev/null
+++ b/packages/ui/src/components/desktop/WindowsWindowControls.tsx
@@ -0,0 +1,83 @@
+import React, { useEffect } from 'react';
+
+import { Icon } from '@/components/icon/Icon';
+import { useI18n } from '@/lib/i18n';
+import { cn } from '@/lib/utils';
+import { invokeDesktop } from '@/lib/desktop';
+
+type WindowsWindowControlsProps = {
+ visible: boolean;
+};
+
+export const WindowsWindowControls = React.memo(function WindowsWindowControls({ visible }: WindowsWindowControlsProps) {
+ const { t } = useI18n();
+ const [isMaximized, setIsMaximized] = React.useState(false);
+
+ useEffect(() => {
+ if (!visible) {
+ return;
+ }
+
+ let disposed = false;
+ void invokeDesktop<{ maximized?: boolean }>('desktop_get_current_window_state')
+ .then((state) => {
+ if (!disposed) {
+ setIsMaximized(Boolean(state?.maximized));
+ }
+ })
+ .catch(() => {});
+
+ const handleMaximizedChange = (event: Event) => {
+ const detail = (event as CustomEvent<{ maximized?: boolean }>).detail;
+ setIsMaximized(Boolean(detail?.maximized));
+ };
+
+ window.addEventListener('openchamber:window-maximized-changed', handleMaximizedChange);
+ return () => {
+ disposed = true;
+ window.removeEventListener('openchamber:window-maximized-changed', handleMaximizedChange);
+ };
+ }, [visible]);
+
+ if (!visible) {
+ return null;
+ }
+
+ const buttonClassName = 'app-region-no-drag inline-flex h-12 w-11 items-center justify-center text-muted-foreground transition-colors hover:bg-interactive-hover hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary';
+
+ return (
+
+
+
+
+
+ );
+});
diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx
index 2c3b850d..67bce021 100644
--- a/packages/ui/src/components/layout/Header.tsx
+++ b/packages/ui/src/components/layout/Header.tsx
@@ -32,6 +32,7 @@ import { useFeatureFlagsStore } from '@/stores/useFeatureFlagsStore';
import { useGitHubAuthStore } from '@/stores/useGitHubAuthStore';
import { useRuntimeAPIs } from '@/hooks/useRuntimeAPIs';
import { ContextUsageDisplay } from '@/components/ui/ContextUsageDisplay';
+import { WindowsWindowControls } from '@/components/desktop/WindowsWindowControls';
import { UpdateDialog } from '@/components/ui/UpdateDialog';
import { useDeviceInfo, useTabletStandalonePwaRuntime } from '@/lib/device';
import { cn, hasModifier } from '@/lib/utils';
@@ -127,83 +128,6 @@ const HeaderIconActionButton = React.memo(function HeaderIconActionButton({
);
});
-type WindowsWindowControlsProps = {
- visible: boolean;
-};
-
-const WindowsWindowControls = React.memo(function WindowsWindowControls({ visible }: WindowsWindowControlsProps) {
- const { t } = useI18n();
- const [isMaximized, setIsMaximized] = React.useState(false);
-
- useEffect(() => {
- if (!visible) {
- return;
- }
-
- let disposed = false;
- void invokeDesktop<{ maximized?: boolean }>('desktop_get_current_window_state')
- .then((state) => {
- if (!disposed) {
- setIsMaximized(Boolean(state?.maximized));
- }
- })
- .catch(() => {});
-
- const handleMaximizedChange = (event: Event) => {
- const detail = (event as CustomEvent<{ maximized?: boolean }>).detail;
- setIsMaximized(Boolean(detail?.maximized));
- };
-
- window.addEventListener('openchamber:window-maximized-changed', handleMaximizedChange);
- return () => {
- disposed = true;
- window.removeEventListener('openchamber:window-maximized-changed', handleMaximizedChange);
- };
- }, [visible]);
-
- if (!visible) {
- return null;
- }
-
- const buttonClassName = 'app-region-no-drag inline-flex h-12 w-11 items-center justify-center text-muted-foreground transition-colors hover:bg-interactive-hover hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary';
-
- return (
-
-
-
-
-
- );
-});
-
type DesktopGitHubControlProps = {
isMobile: boolean;
githubAuthStatus: GitHubAuthStatus | null;
diff --git a/packages/ui/src/components/mini-chat/MiniChatLayout.tsx b/packages/ui/src/components/mini-chat/MiniChatLayout.tsx
index 5d5002c2..bff69eb7 100644
--- a/packages/ui/src/components/mini-chat/MiniChatLayout.tsx
+++ b/packages/ui/src/components/mini-chat/MiniChatLayout.tsx
@@ -3,6 +3,7 @@ import { Button } from '@/components/ui/button';
import { ChatContainer } from '@/components/chat/ChatContainer';
import { ChatSurfaceProvider } from '@/components/chat/ChatSurfaceContext';
import { ContextUsageDisplay } from '@/components/ui/ContextUsageDisplay';
+import { WindowsWindowControls } from '@/components/desktop/WindowsWindowControls';
import { SessionSwitcherDropdown } from '@/components/session/SessionSwitcherDropdown';
import { cn } from '@/lib/utils';
import { useI18n } from '@/lib/i18n';
@@ -69,6 +70,9 @@ const MiniChatHeader: React.FC<{ mode: MiniChatMode }> = ({ mode }) => {
const [pinned, setPinned] = React.useState(false);
const macosMajor = typeof window !== 'undefined' ? window.__OPENCHAMBER_MACOS_MAJOR__ ?? 0 : 0;
const hasMacTrafficLights = Number.isFinite(macosMajor) && macosMajor > 0;
+ const isWindowsElectronDesktop = typeof window !== 'undefined'
+ && Boolean(window.__OPENCHAMBER_ELECTRON__)
+ && window.__OPENCHAMBER_PLATFORM__ === 'win32';
const macosHeaderSizeClass = hasMacTrafficLights
? macosMajor >= 26
? 'h-12'
@@ -258,7 +262,7 @@ const MiniChatHeader: React.FC<{ mode: MiniChatMode }> = ({ mode }) => {
className={cn(
'flex items-center gap-3 border-b border-[var(--interactive-border)] bg-sidebar pr-3',
hasMacTrafficLights ? 'pl-[5.5rem]' : 'pl-3',
- macosHeaderSizeClass || 'min-h-14',
+ isWindowsElectronDesktop ? 'h-12' : macosHeaderSizeClass || 'min-h-14',
)}
style={dragRegionStyle}
>
@@ -327,6 +331,7 @@ const MiniChatHeader: React.FC<{ mode: MiniChatMode }> = ({ mode }) => {
>
+
);
};