From 9915bb90b421596186b9f62dfc9814f25f99e66f Mon Sep 17 00:00:00 2001 From: Henrik Date: Sun, 29 Mar 2026 18:52:00 +0000 Subject: [PATCH] fix(web): consolidate header actions into overflow menu on mobile On mobile viewports the chat header renders all action buttons (terminal, diff, open-in, git, scripts) inline, which overflows the narrow screen and makes the title unreadable. Wrap the action buttons in a Popover behind an ellipsis button when isMobile is true. Desktop layout is completely unchanged. Uses existing useIsMobile() hook, Button, and Popover primitives already established in the codebase. Related #1441 --- apps/web/src/components/chat/ChatHeader.tsx | 219 +++++++++++++------- 1 file changed, 149 insertions(+), 70 deletions(-) diff --git a/apps/web/src/components/chat/ChatHeader.tsx b/apps/web/src/components/chat/ChatHeader.tsx index f04c9879fa..2b293ffd92 100644 --- a/apps/web/src/components/chat/ChatHeader.tsx +++ b/apps/web/src/components/chat/ChatHeader.tsx @@ -6,13 +6,16 @@ import { } from "@t3tools/contracts"; import { memo } from "react"; import GitActionsControl from "../GitActionsControl"; -import { DiffIcon, TerminalSquareIcon } from "lucide-react"; +import { DiffIcon, EllipsisIcon, TerminalSquareIcon } from "lucide-react"; import { Badge } from "../ui/badge"; import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; import ProjectScriptsControl, { type NewProjectScriptInput } from "../ProjectScriptsControl"; import { Toggle } from "../ui/toggle"; import { SidebarTrigger } from "../ui/sidebar"; import { OpenInPicker } from "./OpenInPicker"; +import { useIsMobile } from "~/hooks/useMediaQuery"; +import { Button } from "../ui/button"; +import { Popover, PopoverPopup, PopoverTrigger } from "../ui/popover"; interface ChatHeaderProps { activeThreadId: ThreadId; @@ -61,6 +64,8 @@ export const ChatHeader = memo(function ChatHeader({ onToggleTerminal, onToggleDiff, }: ChatHeaderProps) { + const isMobile = useIsMobile(); + return (
@@ -82,75 +87,149 @@ export const ChatHeader = memo(function ChatHeader({ )}
-
- {activeProjectScripts && ( - - )} - {activeProjectName && ( - - )} - {activeProjectName && } - - - - - } - /> - - {!terminalAvailable - ? "Terminal is unavailable until this thread has an active project." - : terminalToggleShortcutLabel - ? `Toggle terminal drawer (${terminalToggleShortcutLabel})` - : "Toggle terminal drawer"} - - - - - - - } - /> - - {!isGitRepo - ? "Diff panel is unavailable because this project is not a git repository." - : diffToggleShortcutLabel - ? `Toggle diff panel (${diffToggleShortcutLabel})` - : "Toggle diff panel"} - - -
+ {isMobile ? ( + + } + > + + +
+
+ Terminal + + + +
+
+ Diff + + + +
+ {activeProjectName && ( + <> +
+
+ +
+ + )} + {activeProjectName && ( +
+ +
+ )} + {activeProjectScripts && ( +
+ +
+ )} +
+ + + ) : ( +
+ {activeProjectScripts && ( + + )} + {activeProjectName && ( + + )} + {activeProjectName && ( + + )} + + + + + } + /> + + {!terminalAvailable + ? "Terminal is unavailable until this thread has an active project." + : terminalToggleShortcutLabel + ? `Toggle terminal drawer (${terminalToggleShortcutLabel})` + : "Toggle terminal drawer"} + + + + + + + } + /> + + {!isGitRepo + ? "Diff panel is unavailable because this project is not a git repository." + : diffToggleShortcutLabel + ? `Toggle diff panel (${diffToggleShortcutLabel})` + : "Toggle diff panel"} + + +
+ )}
); });