106 lines · 3.8 KB · TypeScript
RawDownload
import { type EnvironmentId } from "@t3tools/contracts";import { memo } from "react";import { readLocalApi } from "~/localApi"; import { cn } from "~/lib/utils";import { ProjectFavicon } from "../ProjectFavicon";import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; interface ChatHeaderProps {  activeThreadEnvironmentId: EnvironmentId;  activeThreadTitle: string;  activeProjectName: string | undefined;  activeProjectCwd: string | null;  activeProjectFaviconPath: string | null;  activeProjectIcon: import("@t3tools/contracts").ProjectIconOverride | null;  rightPanelOpen: boolean;  onNewThreadInProject: () => void;  onOpenProjectSettings?: (() => void) | undefined;} export const ChatHeader = memo(function ChatHeader({  activeThreadEnvironmentId,  activeThreadTitle,  activeProjectName,  activeProjectCwd,  activeProjectFaviconPath,  activeProjectIcon,  rightPanelOpen,  onNewThreadInProject,  onOpenProjectSettings,}: ChatHeaderProps) {  return (    <div      onContextMenu={        onOpenProjectSettings === undefined          ? undefined          : (event) => {              event.preventDefault();              const api = readLocalApi();              if (!api) return;              void api.contextMenu                .show([{ id: "project-settings", label: "Project settings", icon: "settings" }], {                  x: event.clientX,                  y: event.clientY,                })                .then((action) => {                  if (action === "project-settings") onOpenProjectSettings();                });            }      }      className={cn(        "flex min-w-0 flex-1 items-center gap-2 sm:gap-3",        rightPanelOpen ? "pr-10" : "pr-24",      )}    >      <div className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden sm:gap-3">        {/* The project always leads the header: knowing which project a            thread lives in is priority zero, and the thread title alone            doesn't answer it. */}        {activeProjectName ? (          <span className="inline-flex shrink-0 items-center gap-2">            <Tooltip>              <TooltipTrigger                render={                  <button                    type="button"                    aria-label={`New thread in ${activeProjectName}`}                    onClick={onNewThreadInProject}                    className="inline-flex min-w-0 cursor-pointer items-center gap-1.5 rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"                  />                }              >                <ProjectFavicon                  environmentId={activeThreadEnvironmentId}                  cwd={activeProjectCwd ?? ""}                  faviconPath={activeProjectFaviconPath}                  projectIcon={activeProjectIcon}                  projectName={activeProjectName}                  className="size-3.5"                />                <span className="max-w-40 truncate text-sm font-medium">{activeProjectName}</span>              </TooltipTrigger>              <TooltipPopup side="top">New thread in {activeProjectName}</TooltipPopup>            </Tooltip>            <span aria-hidden className="text-muted-foreground/40">              /            </span>          </span>        ) : null}        <Tooltip>          <TooltipTrigger            render={              <h2                aria-label={activeThreadTitle}                className="min-w-0 flex-1 truncate text-sm font-medium text-foreground"              >                {activeThreadTitle}              </h2>            }          />          <TooltipPopup side="top">{activeThreadTitle}</TooltipPopup>        </Tooltip>      </div>    </div>  );});