import { type EditorId, type ProjectScript, type ResolvedKeybindingsConfig, type ThreadId,} from "@t3tools/contracts";import { memo } from "react";import GitActionsControl from "../GitActionsControl";import { DiffIcon } 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"; interface ChatHeaderProps { activeThreadId: ThreadId; activeThreadTitle: string; activeProjectName: string | undefined; isGitRepo: boolean; openInCwd: string | null; activeProjectScripts: ProjectScript[] | undefined; preferredScriptId: string | null; keybindings: ResolvedKeybindingsConfig; availableEditors: ReadonlyArray<EditorId>; diffToggleShortcutLabel: string | null; gitCwd: string | null; diffOpen: boolean; onRunProjectScript: (script: ProjectScript) => void; onAddProjectScript: (input: NewProjectScriptInput) => Promise<void>; onUpdateProjectScript: (scriptId: string, input: NewProjectScriptInput) => Promise<void>; onDeleteProjectScript: (scriptId: string) => Promise<void>; onToggleDiff: () => void;} export const ChatHeader = memo(function ChatHeader({ activeThreadId, activeThreadTitle, activeProjectName, isGitRepo, openInCwd, activeProjectScripts, preferredScriptId, keybindings, availableEditors, diffToggleShortcutLabel, gitCwd, diffOpen, onRunProjectScript, onAddProjectScript, onUpdateProjectScript, onDeleteProjectScript, onToggleDiff,}: ChatHeaderProps) { return ( <div className="flex min-w-0 flex-1 items-center gap-2"> <div className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden sm:gap-3"> <SidebarTrigger className="size-7 shrink-0 md:hidden" /> <h2 className="min-w-0 shrink truncate text-sm font-medium text-foreground" title={activeThreadTitle} > {activeThreadTitle} </h2> {activeProjectName && ( <Badge variant="outline" className="min-w-0 shrink truncate"> {activeProjectName} </Badge> )} {activeProjectName && !isGitRepo && ( <Badge variant="outline" className="shrink-0 text-[10px] text-amber-700"> No Git </Badge> )} </div> <div className="@container/header-actions flex min-w-0 flex-1 items-center justify-end gap-2 @sm/header-actions:gap-3"> {activeProjectScripts && ( <ProjectScriptsControl scripts={activeProjectScripts} keybindings={keybindings} preferredScriptId={preferredScriptId} onRunScript={onRunProjectScript} onAddScript={onAddProjectScript} onUpdateScript={onUpdateProjectScript} onDeleteScript={onDeleteProjectScript} /> )} {activeProjectName && ( <OpenInPicker keybindings={keybindings} availableEditors={availableEditors} openInCwd={openInCwd} /> )} {activeProjectName && <GitActionsControl gitCwd={gitCwd} activeThreadId={activeThreadId} />} <Tooltip> <TooltipTrigger render={ <Toggle className="shrink-0" pressed={diffOpen} onPressedChange={onToggleDiff} aria-label="Toggle diff panel" variant="outline" size="xs" disabled={!isGitRepo} > <DiffIcon className="size-3" /> </Toggle> } /> <TooltipPopup side="bottom"> {!isGitRepo ? "Diff panel is unavailable because this project is not a git repository." : diffToggleShortcutLabel ? `Toggle diff panel (${diffToggleShortcutLabel})` : "Toggle diff panel"} </TooltipPopup> </Tooltip> </div> </div> );});
import {
type EditorId,
type ProjectScript,
type ResolvedKeybindingsConfig,
type ThreadId,
} from "@t3tools/contracts";
import { memo } from "react";
import GitActionsControl from "../GitActionsControl";
import { DiffIcon } 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";
interface ChatHeaderProps {
activeThreadId: ThreadId;
activeThreadTitle: string;
activeProjectName: string | undefined;
isGitRepo: boolean;
openInCwd: string | null;
activeProjectScripts: ProjectScript[] | undefined;
preferredScriptId: string | null;
keybindings: ResolvedKeybindingsConfig;
availableEditors: ReadonlyArray<EditorId>;
diffToggleShortcutLabel: string | null;
gitCwd: string | null;
diffOpen: boolean;
onRunProjectScript: (script: ProjectScript) => void;
onAddProjectScript: (input: NewProjectScriptInput) => Promise<void>;
onUpdateProjectScript: (scriptId: string, input: NewProjectScriptInput) => Promise<void>;
onDeleteProjectScript: (scriptId: string) => Promise<void>;
onToggleDiff: () => void;
}
export const ChatHeader = memo(function ChatHeader({
activeThreadId,
activeThreadTitle,
activeProjectName,
isGitRepo,
openInCwd,
activeProjectScripts,
preferredScriptId,
keybindings,
availableEditors,
diffToggleShortcutLabel,
gitCwd,
diffOpen,
onRunProjectScript,
onAddProjectScript,
onUpdateProjectScript,
onDeleteProjectScript,
onToggleDiff,
}: ChatHeaderProps) {
return (
<div className="flex min-w-0 flex-1 items-center gap-2">
<div className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden sm:gap-3">
<SidebarTrigger className="size-7 shrink-0 md:hidden" />
<h2
className="min-w-0 shrink truncate text-sm font-medium text-foreground"
title={activeThreadTitle}
>
{activeThreadTitle}
</h2>
{activeProjectName && (
<Badge variant="outline" className="min-w-0 shrink truncate">
{activeProjectName}
</Badge>
)}
{activeProjectName && !isGitRepo && (
<Badge variant="outline" className="shrink-0 text-[10px] text-amber-700">
No Git
</Badge>
)}
</div>
<div className="@container/header-actions flex min-w-0 flex-1 items-center justify-end gap-2 @sm/header-actions:gap-3">
{activeProjectScripts && (
<ProjectScriptsControl
scripts={activeProjectScripts}
keybindings={keybindings}
preferredScriptId={preferredScriptId}
onRunScript={onRunProjectScript}
onAddScript={onAddProjectScript}
onUpdateScript={onUpdateProjectScript}
onDeleteScript={onDeleteProjectScript}
/>
)}
{activeProjectName && (
<OpenInPicker
keybindings={keybindings}
availableEditors={availableEditors}
openInCwd={openInCwd}
/>
)}
{activeProjectName && <GitActionsControl gitCwd={gitCwd} activeThreadId={activeThreadId} />}
<Tooltip>
<TooltipTrigger
render={
<Toggle
className="shrink-0"
pressed={diffOpen}
onPressedChange={onToggleDiff}
aria-label="Toggle diff panel"
variant="outline"
size="xs"
disabled={!isGitRepo}
>
<DiffIcon className="size-3" />
</Toggle>
}
/>
<TooltipPopup side="bottom">
{!isGitRepo
? "Diff panel is unavailable because this project is not a git repository."
: diffToggleShortcutLabel
? `Toggle diff panel (${diffToggleShortcutLabel})`
: "Toggle diff panel"}
</TooltipPopup>
</Tooltip>
</div>
</div>
);
});