authorgravatar for 72981323+antiisaint@users.noreply.github.comANTI <72981323+antiisaint@users.noreply.github.com> 2026-03-24 05:28:41-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-24 09:28:41+00:00
logbe1abc88fda0beacb606b2e7de6f4e82cc31155f
tree2cf34b5b5ec7703a9a75dc721997aa466ddeaa33
parent384f35084e8a94985d37c95e17b3da83ed153e57
signature Signed by PGP key B5690EEEBB952194

feat: add terminal toggle button to chat header (#633)

Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com>

2 files changed, 41 insertions(+), 1 deletions(-)

apps/web/src/components/ChatView.tsx+8
...@@ -1119,6 +1119,10 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -1119,6 +1119,10 @@ export default function ChatView({ threadId }: ChatViewProps) {
1119 }, [activeProjectCwd, activeThreadWorktreePath]);1119 }, [activeProjectCwd, activeThreadWorktreePath]);
1120 // Default true while loading to avoid toolbar flicker.1120 // Default true while loading to avoid toolbar flicker.
1121 const isGitRepo = branchesQuery.data?.isRepo ?? true;1121 const isGitRepo = branchesQuery.data?.isRepo ?? true;
1122 const terminalToggleShortcutLabel = useMemo(
1123 () => shortcutLabelForCommand(keybindings, "terminal.toggle"),
1124 [keybindings],
1125 );
1122 const splitTerminalShortcutLabel = useMemo(1126 const splitTerminalShortcutLabel = useMemo(
1123 () => shortcutLabelForCommand(keybindings, "terminal.split"),1127 () => shortcutLabelForCommand(keybindings, "terminal.split"),
1124 [keybindings],1128 [keybindings],
...@@ -3474,6 +3478,9 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -3474,6 +3478,9 @@ export default function ChatView({ threadId }: ChatViewProps) {
3474 }3478 }
3475 keybindings={keybindings}3479 keybindings={keybindings}
3476 availableEditors={availableEditors}3480 availableEditors={availableEditors}
3481 terminalAvailable={activeProject !== undefined}
3482 terminalOpen={terminalState.terminalOpen}
3483 terminalToggleShortcutLabel={terminalToggleShortcutLabel}
3477 diffToggleShortcutLabel={diffPanelShortcutLabel}3484 diffToggleShortcutLabel={diffPanelShortcutLabel}
3478 gitCwd={gitCwd}3485 gitCwd={gitCwd}
3479 diffOpen={diffOpen}3486 diffOpen={diffOpen}
...@@ -3483,6 +3490,7 @@ export default function ChatView({ threadId }: ChatViewProps) {...@@ -3483,6 +3490,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
3483 onAddProjectScript={saveProjectScript}3490 onAddProjectScript={saveProjectScript}
3484 onUpdateProjectScript={updateProjectScript}3491 onUpdateProjectScript={updateProjectScript}
3485 onDeleteProjectScript={deleteProjectScript}3492 onDeleteProjectScript={deleteProjectScript}
3493 onToggleTerminal={toggleTerminalVisibility}
3486 onToggleDiff={onToggleDiff}3494 onToggleDiff={onToggleDiff}
3487 />3495 />
3488 </header>3496 </header>
apps/web/src/components/chat/ChatHeader.tsx+33-1
...@@ -6,7 +6,7 @@ import {...@@ -6,7 +6,7 @@ import {
6} from "@t3tools/contracts";6} from "@t3tools/contracts";
7import { memo } from "react";7import { memo } from "react";
8import GitActionsControl from "../GitActionsControl";8import GitActionsControl from "../GitActionsControl";
9import { DiffIcon } from "lucide-react";9import { DiffIcon, TerminalSquareIcon } from "lucide-react";
10import { Badge } from "../ui/badge";10import { Badge } from "../ui/badge";
11import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";11import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
12import ProjectScriptsControl, { type NewProjectScriptInput } from "../ProjectScriptsControl";12import ProjectScriptsControl, { type NewProjectScriptInput } from "../ProjectScriptsControl";
...@@ -24,6 +24,9 @@ interface ChatHeaderProps {...@@ -24,6 +24,9 @@ interface ChatHeaderProps {
24 preferredScriptId: string | null;24 preferredScriptId: string | null;
25 keybindings: ResolvedKeybindingsConfig;25 keybindings: ResolvedKeybindingsConfig;
26 availableEditors: ReadonlyArray<EditorId>;26 availableEditors: ReadonlyArray<EditorId>;
27 terminalAvailable: boolean;
28 terminalOpen: boolean;
29 terminalToggleShortcutLabel: string | null;
27 diffToggleShortcutLabel: string | null;30 diffToggleShortcutLabel: string | null;
28 gitCwd: string | null;31 gitCwd: string | null;
29 diffOpen: boolean;32 diffOpen: boolean;
...@@ -31,6 +34,7 @@ interface ChatHeaderProps {...@@ -31,6 +34,7 @@ interface ChatHeaderProps {
31 onAddProjectScript: (input: NewProjectScriptInput) => Promise<void>;34 onAddProjectScript: (input: NewProjectScriptInput) => Promise<void>;
32 onUpdateProjectScript: (scriptId: string, input: NewProjectScriptInput) => Promise<void>;35 onUpdateProjectScript: (scriptId: string, input: NewProjectScriptInput) => Promise<void>;
33 onDeleteProjectScript: (scriptId: string) => Promise<void>;36 onDeleteProjectScript: (scriptId: string) => Promise<void>;
37 onToggleTerminal: () => void;
34 onToggleDiff: () => void;38 onToggleDiff: () => void;
35}39}
3640
...@@ -44,6 +48,9 @@ export const ChatHeader = memo(function ChatHeader({...@@ -44,6 +48,9 @@ export const ChatHeader = memo(function ChatHeader({
44 preferredScriptId,48 preferredScriptId,
45 keybindings,49 keybindings,
46 availableEditors,50 availableEditors,
51 terminalAvailable,
52 terminalOpen,
53 terminalToggleShortcutLabel,
47 diffToggleShortcutLabel,54 diffToggleShortcutLabel,
48 gitCwd,55 gitCwd,
49 diffOpen,56 diffOpen,
...@@ -51,6 +58,7 @@ export const ChatHeader = memo(function ChatHeader({...@@ -51,6 +58,7 @@ export const ChatHeader = memo(function ChatHeader({
51 onAddProjectScript,58 onAddProjectScript,
52 onUpdateProjectScript,59 onUpdateProjectScript,
53 onDeleteProjectScript,60 onDeleteProjectScript,
61 onToggleTerminal,
54 onToggleDiff,62 onToggleDiff,
55}: ChatHeaderProps) {63}: ChatHeaderProps) {
56 return (64 return (
...@@ -94,6 +102,30 @@ export const ChatHeader = memo(function ChatHeader({...@@ -94,6 +102,30 @@ export const ChatHeader = memo(function ChatHeader({
94 />102 />
95 )}103 )}
96 {activeProjectName && <GitActionsControl gitCwd={gitCwd} activeThreadId={activeThreadId} />}104 {activeProjectName && <GitActionsControl gitCwd={gitCwd} activeThreadId={activeThreadId} />}
105 <Tooltip>
106 <TooltipTrigger
107 render={
108 <Toggle
109 className="shrink-0"
110 pressed={terminalOpen}
111 onPressedChange={onToggleTerminal}
112 aria-label="Toggle terminal drawer"
113 variant="outline"
114 size="xs"
115 disabled={!terminalAvailable}
116 >
117 <TerminalSquareIcon className="size-3" />
118 </Toggle>
119 }
120 />
121 <TooltipPopup side="bottom">
122 {!terminalAvailable
123 ? "Terminal is unavailable until this thread has an active project."
124 : terminalToggleShortcutLabel
125 ? `Toggle terminal drawer (${terminalToggleShortcutLabel})`
126 : "Toggle terminal drawer"}
127 </TooltipPopup>
128 </Tooltip>
97 <Tooltip>129 <Tooltip>
98 <TooltipTrigger130 <TooltipTrigger
99 render={131 render={