186 lines
4.8 KiB
TypeScript
186 lines
4.8 KiB
TypeScript
import { toast } from "sonner";
|
|
import { Artifact } from "@/components/chat/create-artifact";
|
|
import { DiffView } from "@/components/chat/diffview";
|
|
import { DocumentSkeleton } from "@/components/chat/document-skeleton";
|
|
import {
|
|
ClockRewind,
|
|
CopyIcon,
|
|
MessageIcon,
|
|
PenIcon,
|
|
RedoIcon,
|
|
UndoIcon,
|
|
} from "@/components/chat/icons";
|
|
import { Editor } from "@/components/chat/text-editor";
|
|
import type { Suggestion } from "@/lib/db/schema";
|
|
import { getSuggestions } from "../actions";
|
|
|
|
type TextArtifactMetadata = {
|
|
suggestions: Suggestion[];
|
|
};
|
|
|
|
export const textArtifact = new Artifact<"text", TextArtifactMetadata>({
|
|
kind: "text",
|
|
description: "Useful for text content, like drafting essays and emails.",
|
|
initialize: async ({ documentId, setMetadata }) => {
|
|
const suggestions = await getSuggestions({ documentId });
|
|
|
|
setMetadata({
|
|
suggestions,
|
|
});
|
|
},
|
|
onStreamPart: ({ streamPart, setMetadata, setArtifact }) => {
|
|
if (streamPart.type === "data-suggestion") {
|
|
setMetadata((metadata) => {
|
|
return {
|
|
suggestions: [...metadata.suggestions, streamPart.data],
|
|
};
|
|
});
|
|
}
|
|
|
|
if (streamPart.type === "data-textDelta") {
|
|
setArtifact((draftArtifact) => {
|
|
return {
|
|
...draftArtifact,
|
|
content: draftArtifact.content + streamPart.data,
|
|
isVisible:
|
|
draftArtifact.status === "streaming" &&
|
|
draftArtifact.content.length > 400 &&
|
|
draftArtifact.content.length < 450
|
|
? true
|
|
: draftArtifact.isVisible,
|
|
status: "streaming",
|
|
};
|
|
});
|
|
}
|
|
},
|
|
content: ({
|
|
mode,
|
|
status,
|
|
content,
|
|
isCurrentVersion,
|
|
currentVersionIndex,
|
|
onSaveContent,
|
|
getDocumentContentById,
|
|
isLoading,
|
|
metadata,
|
|
}) => {
|
|
if (isLoading) {
|
|
return <DocumentSkeleton artifactKind="text" />;
|
|
}
|
|
|
|
if (mode === "diff") {
|
|
const selectedContent = getDocumentContentById(currentVersionIndex);
|
|
const prevContent =
|
|
currentVersionIndex > 0
|
|
? getDocumentContentById(currentVersionIndex - 1)
|
|
: selectedContent;
|
|
|
|
return (
|
|
<div className="flex flex-row px-4 py-8 md:px-16 md:py-12 lg:px-20">
|
|
<DiffView newContent={selectedContent} oldContent={prevContent} />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-row px-4 py-8 md:px-16 md:py-12 lg:px-20">
|
|
<Editor
|
|
content={content}
|
|
currentVersionIndex={currentVersionIndex}
|
|
isCurrentVersion={isCurrentVersion}
|
|
onSaveContent={onSaveContent}
|
|
status={status}
|
|
suggestions={isCurrentVersion && metadata ? metadata.suggestions : []}
|
|
/>
|
|
|
|
{metadata?.suggestions && metadata.suggestions.length > 0 ? (
|
|
<div className="h-dvh w-12 shrink-0 md:hidden" />
|
|
) : null}
|
|
</div>
|
|
);
|
|
},
|
|
actions: [
|
|
{
|
|
icon: <ClockRewind size={18} />,
|
|
description: "View changes",
|
|
onClick: ({ handleVersionChange }) => {
|
|
handleVersionChange("toggle");
|
|
},
|
|
isDisabled: ({ currentVersionIndex }) => {
|
|
if (currentVersionIndex === 0) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
icon: <UndoIcon size={18} />,
|
|
description: "View Previous version",
|
|
onClick: ({ handleVersionChange }) => {
|
|
handleVersionChange("prev");
|
|
},
|
|
isDisabled: ({ currentVersionIndex }) => {
|
|
if (currentVersionIndex === 0) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
icon: <RedoIcon size={18} />,
|
|
description: "View Next version",
|
|
onClick: ({ handleVersionChange }) => {
|
|
handleVersionChange("next");
|
|
},
|
|
isDisabled: ({ isCurrentVersion }) => {
|
|
if (isCurrentVersion) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
icon: <CopyIcon size={18} />,
|
|
description: "Copy to clipboard",
|
|
onClick: ({ content }) => {
|
|
navigator.clipboard.writeText(content);
|
|
toast.success("Copied to clipboard!");
|
|
},
|
|
},
|
|
],
|
|
toolbar: [
|
|
{
|
|
icon: <PenIcon />,
|
|
description: "Add final polish",
|
|
onClick: ({ sendMessage }) => {
|
|
sendMessage({
|
|
role: "user",
|
|
parts: [
|
|
{
|
|
type: "text",
|
|
text: "Please add final polish and check for grammar, add section titles for better structure, and ensure everything reads smoothly.",
|
|
},
|
|
],
|
|
});
|
|
},
|
|
},
|
|
{
|
|
icon: <MessageIcon />,
|
|
description: "Request suggestions",
|
|
onClick: ({ sendMessage }) => {
|
|
sendMessage({
|
|
role: "user",
|
|
parts: [
|
|
{
|
|
type: "text",
|
|
text: "Please add suggestions you have that could improve the writing.",
|
|
},
|
|
],
|
|
});
|
|
},
|
|
},
|
|
],
|
|
});
|