Skip to content

Commit f9546c7

Browse files
ibetitsmikeethanndickson
authored andcommitted
🤖 fix: keep header + sidebar tabs clear of win/linux titlebar (#1651)
On Windows/Linux desktop with titlebar overlay, the native window controls (min/max/close) overlap the top-right of the app. - When the right sidebar is collapsed, the workspace header action buttons (MCP / open-in-editor / terminal) can end up under the window controls. - The right sidebar tab strip can also render/scroll tabs under the window controls area. This change reserves a right-side inset in those headers when running on Windows/Linux so the controls stay visible/clickable. Validation: - `make static-check` --- _Generated with `mux` • Model: `openai:gpt-5.2` • Thinking: `xhigh`_
1 parent 22c9fd5 commit f9546c7

File tree

2 files changed

+52
-29
lines changed

2 files changed

+52
-29
lines changed

src/browser/components/RightSidebar/RightSidebarTabStrip.tsx

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export const RightSidebarTabStrip: React.FC<RightSidebarTabStripProps> = ({
131131
<div
132132
ref={setNodeRef}
133133
className={cn(
134-
"border-border-light flex min-w-0 items-center gap-1 overflow-x-auto border-b px-2 transition-colors",
134+
"border-border-light flex min-w-0 items-center border-b px-2 transition-colors",
135135
isDesktop ? "h-10" : "py-1.5",
136136
showDropHighlight && "bg-accent/30",
137137
isDraggingFromHere && "bg-accent/10",
@@ -142,33 +142,42 @@ export const RightSidebarTabStrip: React.FC<RightSidebarTabStripProps> = ({
142142
role="tablist"
143143
aria-label={ariaLabel}
144144
>
145-
{items.map((item, index) => (
146-
<SortableTab
147-
key={item.id}
148-
item={item}
149-
index={index}
150-
tabsetId={tabsetId}
151-
isDesktop={isDesktop}
152-
/>
153-
))}
154-
{onAddTerminal && (
155-
<Tooltip>
156-
<TooltipTrigger asChild>
157-
<button
158-
type="button"
159-
className={cn(
160-
"text-muted hover:bg-hover hover:text-foreground shrink-0 rounded-md p-1 transition-colors",
161-
isDesktop && "titlebar-no-drag"
162-
)}
163-
onClick={onAddTerminal}
164-
aria-label="New terminal"
165-
>
166-
<Plus className="h-3.5 w-3.5" />
167-
</button>
168-
</TooltipTrigger>
169-
<TooltipContent side="bottom">New terminal</TooltipContent>
170-
</Tooltip>
171-
)}
145+
<div
146+
className={cn(
147+
"flex min-w-0 flex-1 items-center gap-1 overflow-x-auto",
148+
// In desktop mode, the tab strip sits in the titlebar drag region.
149+
// Mark the scroll container as no-drag so horizontal scrolling works.
150+
isDesktop && "titlebar-no-drag"
151+
)}
152+
>
153+
{items.map((item, index) => (
154+
<SortableTab
155+
key={item.id}
156+
item={item}
157+
index={index}
158+
tabsetId={tabsetId}
159+
isDesktop={isDesktop}
160+
/>
161+
))}
162+
{onAddTerminal && (
163+
<Tooltip>
164+
<TooltipTrigger asChild>
165+
<button
166+
type="button"
167+
className={cn(
168+
"text-muted hover:bg-hover hover:text-foreground shrink-0 rounded-md p-1 transition-colors",
169+
isDesktop && "titlebar-no-drag"
170+
)}
171+
onClick={onAddTerminal}
172+
aria-label="New terminal"
173+
>
174+
<Plus className="h-3.5 w-3.5" />
175+
</button>
176+
</TooltipTrigger>
177+
<TooltipContent side="bottom">New terminal</TooltipContent>
178+
</Tooltip>
179+
)}
180+
</div>
172181
</div>
173182
);
174183
};

src/browser/components/WorkspaceHeader.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useCallback, useEffect, useState } from "react";
22
import { Pencil, Server } from "lucide-react";
33
import { cn } from "@/common/lib/utils";
4+
import { RIGHT_SIDEBAR_COLLAPSED_KEY } from "@/common/constants/storage";
45
import { GitStatusIndicator } from "./GitStatusIndicator";
56
import { RuntimeBadge } from "./RuntimeBadge";
67
import { BranchSelector } from "./BranchSelector";
@@ -14,7 +15,8 @@ import type { RuntimeConfig } from "@/common/types/runtime";
1415
import { useTutorial } from "@/browser/contexts/TutorialContext";
1516
import { useOpenTerminal } from "@/browser/hooks/useOpenTerminal";
1617
import { useOpenInEditor } from "@/browser/hooks/useOpenInEditor";
17-
import { isDesktopMode } from "@/browser/hooks/useDesktopTitlebar";
18+
import { usePersistedState } from "@/browser/hooks/usePersistedState";
19+
import { getTitlebarRightInset, isDesktopMode } from "@/browser/hooks/useDesktopTitlebar";
1820
import { WorkspaceLinks } from "./WorkspaceLinks";
1921

2022
interface WorkspaceHeaderProps {
@@ -45,6 +47,11 @@ export const WorkspaceHeader: React.FC<WorkspaceHeaderProps> = ({
4547
const [editorError, setEditorError] = useState<string | null>(null);
4648
const [mcpModalOpen, setMcpModalOpen] = useState(false);
4749

50+
const [rightSidebarCollapsed] = usePersistedState<boolean>(RIGHT_SIDEBAR_COLLAPSED_KEY, false, {
51+
// This state is toggled from RightSidebar, so we need cross-component updates.
52+
listener: true,
53+
});
54+
4855
const handleOpenTerminal = useCallback(() => {
4956
if (onOpenTerminal) {
5057
onOpenTerminal();
@@ -78,10 +85,17 @@ export const WorkspaceHeader: React.FC<WorkspaceHeaderProps> = ({
7885
return () => clearTimeout(timer);
7986
}, [startTutorial, isSequenceCompleted]);
8087

88+
// On Windows/Linux, the native window controls overlay the top-right of the app.
89+
// When the right sidebar is collapsed (20px), this header stretches underneath
90+
// those controls and the MCP/editor/terminal buttons become unclickable.
91+
const titlebarRightInset = getTitlebarRightInset();
92+
const headerRightPadding =
93+
rightSidebarCollapsed && titlebarRightInset > 0 ? Math.max(0, titlebarRightInset - 20) : 0;
8194
const isDesktop = isDesktopMode();
8295

8396
return (
8497
<div
98+
style={headerRightPadding > 0 ? { paddingRight: headerRightPadding } : undefined}
8599
data-testid="workspace-header"
86100
className={cn(
87101
"bg-sidebar border-border-light flex items-center justify-between border-b px-[15px] [@media(max-width:768px)]:h-auto [@media(max-width:768px)]:flex-wrap [@media(max-width:768px)]:gap-2 [@media(max-width:768px)]:py-2 [@media(max-width:768px)]:pl-[60px]",

0 commit comments

Comments
 (0)