AgentGPT-Web-GUI / next /src /components /console /MacWindowHeader.tsx
dia-gov's picture
Upload 569 files
cd6f98e verified
import clsx from "clsx";
import * as htmlToImage from "html-to-image";
import { useTranslation } from "next-i18next";
import type { PropsWithChildren, ReactNode } from "react";
import React from "react";
import { CgExport } from "react-icons/cg";
import { FaImage } from "react-icons/fa";
import { FiClipboard } from "react-icons/fi";
import type { Message } from "../../types/message";
import Menu from "../Menu";
import Expand from "../motions/expand";
import PopIn from "../motions/popin";
import PDFButton from "../pdf/PDFButton";
import WindowButton from "../WindowButton";
export const messageListId = "chat-window-message-list";
export interface HeaderProps {
title?: string | ReactNode;
messages: Message[];
}
export const MacWindowHeader = (props: HeaderProps) => {
const [t] = useTranslation();
const saveElementAsImage = (elementId: string) => {
const element = document.getElementById(elementId);
if (!element) {
return;
}
htmlToImage
.toJpeg(element, {
height: element.scrollHeight,
style: {
overflowY: "visible",
maxHeight: "none",
border: "none",
},
})
.then((dataUrl) => {
const link = document.createElement("a");
link.href = dataUrl;
link.download = "agent-gpt-output.png";
link.click();
})
.catch(() =>
alert("Error saving image! Note this doesn't work if the AI generated an image")
);
};
const copyElementText = (elementId: string) => {
const element = document.getElementById(elementId);
if (!element) {
return;
}
const text = element.innerText;
if (navigator.clipboard) {
void navigator.clipboard.writeText(text);
} else {
// Fallback to a different method for unsupported browsers
const textArea = document.createElement("textarea");
textArea.value = text;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand("copy");
console.log("Text copied to clipboard");
} catch (err) {
console.error("Unable to copy text to clipboard", err);
}
document.body.removeChild(textArea);
}
};
const exportOptions = [
<WindowButton
key="Image"
onClick={(): void => saveElementAsImage(messageListId)}
icon={<FaImage size={12} />}
text={t("IMAGE", { ns: "common" })}
/>,
<WindowButton
key="Copy"
onClick={(): void => copyElementText(messageListId)}
icon={<FiClipboard size={12} />}
text={t("COPY", { ns: "common" })}
/>,
<PDFButton key="PDF" name="PDF" messages={props.messages} />,
];
return (
<div className="flex items-center gap-1 overflow-visible rounded-t-3xl p-1.5 px-1">
<PopIn delay={0.4}>
<div className="h-3 w-3 rounded-full bg-red-500" />
</PopIn>
<PopIn delay={0.5}>
<div className="h-3 w-3 rounded-full bg-yellow-500" />
</PopIn>
<PopIn delay={0.6}>
<div className="h-3 w-3 rounded-full bg-green-500" />
</PopIn>
<Expand
delay={0.75}
className="flex flex-grow font-mono text-xs font-bold text-gray-500 sm:ml-2 sm:text-sm"
>
{props.title}
</Expand>
<Menu icon={<CgExport size={15} />} items={exportOptions} />
</div>
);
};
interface MacWindowInternalProps extends PropsWithChildren {
className?: string;
}
export const MacWindowInternal = (props: MacWindowInternalProps) => {
return (
<div
className={clsx(
"ml-2 flex items-baseline gap-1 overflow-visible rounded-t-3xl p-1.5",
props.className
)}
>
<PopIn delay={0.4}>
<div className="h-2 w-2 rounded-full bg-red-500" />
</PopIn>
<PopIn delay={0.5}>
<div className="h-2 w-2 rounded-full bg-yellow-500" />
</PopIn>
<PopIn delay={0.6}>
<div className="h-2 w-2 rounded-full bg-green-500" />
</PopIn>
<Expand
delay={0.75}
className="ml-1 flex flex-grow font-mono text-[8pt] font-bold text-gray-400"
>
{props.children}
</Expand>
</div>
);
};