From 52ea7f4b67e31292589810cc54779ba3117760de Mon Sep 17 00:00:00 2001 From: Badcuban <108198679+badcuban@users.noreply.github.com> Date: Wed, 9 Sep 2026 15:52:00 -0400 Subject: [PATCH] fix(web): sheet-mode panel puts its close button at the edge At narrow widths the right panel opens as a sheet below the chat header, but its tab strip still reserved room for the Windows window-controls cluster and acted as a window drag region. The close button landed in the middle of the row and did not take clicks until the drag region was recomputed. The strip now takes an `overlay` flag from ChatRightPanel (present exactly when the sheet's dismiss handler is), and in that mode drops both the window-controls clearance and the drag region. The inline layout is unchanged. --- apps/web/src/components/ChatRightPanel.tsx | 1 + .../components/chat/RightPanelTabStrip.tsx | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/ChatRightPanel.tsx b/apps/web/src/components/ChatRightPanel.tsx index 97599358d..758f3a40f 100644 --- a/apps/web/src/components/ChatRightPanel.tsx +++ b/apps/web/src/components/ChatRightPanel.tsx @@ -49,6 +49,7 @@ export function ChatRightPanel(props: { onSelectTab={props.onSelectTab} onCloseTab={props.onCloseTab} onReorderTab={props.onReorderTab} + overlay={onDismiss !== undefined} {...(onDismiss ? { trailing: ( diff --git a/apps/web/src/components/chat/RightPanelTabStrip.tsx b/apps/web/src/components/chat/RightPanelTabStrip.tsx index 0fa520ed3..dbf78f3b1 100644 --- a/apps/web/src/components/chat/RightPanelTabStrip.tsx +++ b/apps/web/src/components/chat/RightPanelTabStrip.tsx @@ -682,6 +682,7 @@ export const RightPanelTabStrip = memo(function RightPanelTabStrip({ onCloseTab, onReorderTab, trailing, + overlay = false, }: { openTabs: ReadonlyArray; availableTabs: ReadonlyArray; @@ -697,6 +698,9 @@ export const RightPanelTabStrip = memo(function RightPanelTabStrip({ onReorderTab?: ((tab: RightPanelTab, toIndex: number) => void) | undefined; /** Sheet-mode dismissal, parked at the end of the row. */ trailing?: React.ReactNode; + /** Sheet mode: the panel starts below the chat header, so the strip neither + * shares its row with the window controls nor acts as a window drag handle. */ + overlay?: boolean; }) { const stripRef = useRef(null); const { mode, rowRef, measureRef, actionsRef, trailingRef } = useTabStripMode(openTabs.join(",")); @@ -732,7 +736,7 @@ export const RightPanelTabStrip = memo(function RightPanelTabStrip({ return (
@@ -745,10 +749,19 @@ export const RightPanelTabStrip = memo(function RightPanelTabStrip({ titlebar rows add 1em. They end in text or labelled controls that would read as crowded against the buttons; this row ends in the `+`, whose own padding is the breathing room, so the extra 12px only pushed it away - from the controls it sits beside. */} + from the controls it sits beside. + + None of that applies in sheet mode: the sheet starts below the chat + header, so the row is not under the controls and must not pad clear of + them (the ✕ would land mid-row), and a drag region floating over the + conversation only got in the way of its own dismiss button. */}
{/* The labelled row the mode decision is measured against. Out of the