From 6e1f6478fb8ad8ea1605521c4a6ec497252c87d8 Mon Sep 17 00:00:00 2001 From: Val Alexander Date: Wed, 1 Apr 2026 08:52:28 -0500 Subject: [PATCH 1/2] Consolidate header panel controls into overflow menu - Move terminal, preview, diff, and code viewer toggles into a single menu - Reduce header crowding on smaller screens and keep project context readable --- apps/web/src/components/chat/ChatHeader.tsx | 168 +++++------------- .../src/components/chat/HeaderPanelsMenu.tsx | 124 +++++++++++++ 2 files changed, 169 insertions(+), 123 deletions(-) create mode 100644 apps/web/src/components/chat/HeaderPanelsMenu.tsx diff --git a/apps/web/src/components/chat/ChatHeader.tsx b/apps/web/src/components/chat/ChatHeader.tsx index fc1aac541..bedb3995a 100644 --- a/apps/web/src/components/chat/ChatHeader.tsx +++ b/apps/web/src/components/chat/ChatHeader.tsx @@ -6,25 +6,15 @@ import { import { memo, useEffect } from "react"; import type { ProjectScriptDraft } from "~/projectScriptDefaults"; import GitActionsControl from "../GitActionsControl"; -import { - ArrowLeftRightIcon, - ArrowUpDownIcon, - DiffIcon, - MonitorIcon, - TerminalSquareIcon, -} from "lucide-react"; import { EditableThreadTitle } from "../EditableThreadTitle"; 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 { useThreadTitleEditor } from "~/hooks/useThreadTitleEditor"; -import { OpenInPicker } from "./OpenInPicker"; import { useCodeViewerStore } from "~/codeViewerStore"; import type { ClientMode } from "~/lib/clientMode"; - import type { PreviewDock } from "~/previewStateStore"; +import { HeaderPanelsMenu } from "./HeaderPanelsMenu"; interface ChatHeaderProps { activeThreadId: ThreadId; @@ -77,7 +67,7 @@ export const ChatHeader = memo(function ChatHeader({ diffToggleShortcutLabel, previewAvailable, previewOpen, - previewDock, + previewDock: _previewDock, gitCwd, diffOpen, clientMode, @@ -90,7 +80,7 @@ export const ChatHeader = memo(function ChatHeader({ onToggleTerminal, onToggleDiff, onTogglePreview, - onTogglePreviewLayout, + onTogglePreviewLayout: _onTogglePreviewLayout, onToggleCodeViewer, }: ChatHeaderProps) { const isMobileCompanion = clientMode === "mobile"; @@ -117,6 +107,7 @@ export const ChatHeader = memo(function ChatHeader({ return (
+ {/* Left: Identity — thread title + project context */}
{activeProjectName && ( - + {activeProjectName} )} - {activeProjectName && !isGitRepo && ( - - No Git - - )}
-
+ + {/* Right: Actions — only primary actions visible, panels in overflow */} +
{!isMobileCompanion && activeProjectScripts && ( )} - {activeProjectName && hasCodeViewerTabs && ( - - )} {!isMobileCompanion && activeProjectName && ( )} + {/* Overflow menu: all panel toggles consolidated */} {!isMobileCompanion && ( - - - - - } - /> - - {!terminalAvailable - ? "Terminal is unavailable until this thread has an active project." - : terminalToggleShortcutLabel - ? `Toggle terminal drawer (${terminalToggleShortcutLabel})` - : "Toggle terminal drawer"} - - - )} - {!isMobileCompanion && previewOpen && previewAvailable ? ( - - - {previewDock === "top" || previewDock === "bottom" ? ( - - ) : ( - - )} - - } - /> - - {previewDock === "top" || previewDock === "bottom" - ? "Switch to side-by-side preview" - : "Switch to stacked preview"} - - - ) : null} - {!isMobileCompanion && ( - - - - - } - /> - - {!previewAvailable - ? "Preview is available in the desktop app when this thread has an active project." - : previewOpen - ? "Hide preview panel" - : "Show preview panel"} - - + )} - - - - - } + {/* Mobile: only diff toggle */} + {isMobileCompanion && ( + {}} + onTogglePreview={() => {}} + onToggleDiff={onToggleDiff} + onToggleCodeViewer={() => {}} /> - - {!isGitRepo - ? "Diff panel is unavailable because this project is not a git repository." - : diffToggleShortcutLabel - ? `Toggle diff panel (${diffToggleShortcutLabel})` - : "Toggle diff panel"} - - + )}
); diff --git a/apps/web/src/components/chat/HeaderPanelsMenu.tsx b/apps/web/src/components/chat/HeaderPanelsMenu.tsx new file mode 100644 index 000000000..5b0ffc35b --- /dev/null +++ b/apps/web/src/components/chat/HeaderPanelsMenu.tsx @@ -0,0 +1,124 @@ +import { memo } from "react"; +import { + DiffIcon, + EllipsisIcon, + FileCodeIcon, + MonitorIcon, + TerminalSquareIcon, +} from "lucide-react"; +import { Button } from "../ui/button"; +import { Menu, MenuCheckboxItem, MenuPopup, MenuSeparator, MenuTrigger } from "../ui/menu"; +import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; + +interface HeaderPanelsMenuProps { + terminalAvailable: boolean; + terminalOpen: boolean; + terminalToggleShortcutLabel: string | null; + previewAvailable: boolean; + previewOpen: boolean; + diffOpen: boolean; + diffToggleShortcutLabel: string | null; + isGitRepo: boolean; + codeViewerOpen: boolean; + hasCodeViewerTabs: boolean; + hasProject: boolean; + onToggleTerminal: () => void; + onTogglePreview: () => void; + onToggleDiff: () => void; + onToggleCodeViewer: () => void; +} + +export const HeaderPanelsMenu = memo(function HeaderPanelsMenu({ + terminalAvailable, + terminalOpen, + terminalToggleShortcutLabel, + previewAvailable, + previewOpen, + diffOpen, + diffToggleShortcutLabel, + isGitRepo, + codeViewerOpen, + hasCodeViewerTabs, + hasProject, + onToggleTerminal, + onTogglePreview, + onToggleDiff, + onToggleCodeViewer, +}: HeaderPanelsMenuProps) { + return ( + + + + + + } + /> + } + /> + Panels + + + + + + Terminal + {terminalToggleShortcutLabel ? ( + + {terminalToggleShortcutLabel} + + ) : null} + + + + + + Preview + + + + + + + Diff + {diffToggleShortcutLabel ? ( + + {diffToggleShortcutLabel} + + ) : null} + + + {hasProject && hasCodeViewerTabs ? ( + + + + Code viewer + + + ) : null} + + + ); +}); From f4a34370bab3fa8aa1e9e0c2dc75107de003320b Mon Sep 17 00:00:00 2001 From: Val Alexander Date: Wed, 1 Apr 2026 09:00:36 -0500 Subject: [PATCH 2/2] Add project color accents to sidebar and chat header - Tint project headers, thread accents, and chat badges with deterministic colors - Reduce header crowding by leaning on color instead of extra chrome --- apps/web/src/components/ChatView.tsx | 1 + apps/web/src/components/Sidebar.tsx | 65 +++++--- apps/web/src/components/chat/ChatHeader.tsx | 21 ++- apps/web/src/projectColors.ts | 162 ++++++++++++++++++++ 4 files changed, 227 insertions(+), 22 deletions(-) create mode 100644 apps/web/src/projectColors.ts diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 8272abe33..25c34a911 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -4588,6 +4588,7 @@ export default function ChatView({ threadId }: ChatViewProps) { + + {/* Project color accent bar */} +