chatbot-template/artifacts/text/client.tsx

187 lines
4.8 KiB
TypeScript
Raw Normal View History

import { toast } from "sonner";
import { Artifact } from "@/components/chat/create-artifact";
import { DiffView } from "@/components/chat/diffview";
import { DocumentSkeleton } from "@/components/chat/document-skeleton";
2025-01-27 14:19:47 +05:30
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";
2025-01-27 14:19:47 +05:30
type TextArtifactMetadata = {
suggestions: Suggestion[];
};
2025-01-27 14:19:47 +05:30
export const textArtifact = new Artifact<"text", TextArtifactMetadata>({
kind: "text",
description: "Useful for text content, like drafting essays and emails.",
2025-01-27 14:19:47 +05:30
initialize: async ({ documentId, setMetadata }) => {
const suggestions = await getSuggestions({ documentId });
setMetadata({
suggestions,
});
},
onStreamPart: ({ streamPart, setMetadata, setArtifact }) => {
if (streamPart.type === "data-suggestion") {
2025-01-27 14:19:47 +05:30
setMetadata((metadata) => {
return {
suggestions: [...metadata.suggestions, streamPart.data],
2025-01-27 14:19:47 +05:30
};
});
}
if (streamPart.type === "data-textDelta") {
setArtifact((draftArtifact) => {
2025-01-27 14:19:47 +05:30
return {
...draftArtifact,
content: draftArtifact.content + streamPart.data,
2025-01-27 14:19:47 +05:30
isVisible:
draftArtifact.status === "streaming" &&
draftArtifact.content.length > 400 &&
draftArtifact.content.length < 450
2025-01-27 14:19:47 +05:30
? true
: draftArtifact.isVisible,
status: "streaming",
2025-01-27 14:19:47 +05:30
};
});
}
},
content: ({
mode,
status,
content,
isCurrentVersion,
currentVersionIndex,
onSaveContent,
getDocumentContentById,
isLoading,
metadata,
}) => {
if (isLoading) {
return <DocumentSkeleton artifactKind="text" />;
2025-01-27 14:19:47 +05:30
}
if (mode === "diff") {
const selectedContent = getDocumentContentById(currentVersionIndex);
const prevContent =
currentVersionIndex > 0
? getDocumentContentById(currentVersionIndex - 1)
: selectedContent;
2025-01-27 14:19:47 +05:30
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>
);
2025-01-27 14:19:47 +05:30
}
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 : []}
/>
2025-01-27 14:19:47 +05:30
{metadata?.suggestions && metadata.suggestions.length > 0 ? (
<div className="h-dvh w-12 shrink-0 md:hidden" />
) : null}
</div>
2025-01-27 14:19:47 +05:30
);
},
actions: [
{
icon: <ClockRewind size={18} />,
description: "View changes",
2025-01-27 14:19:47 +05:30
onClick: ({ handleVersionChange }) => {
handleVersionChange("toggle");
2025-01-27 14:19:47 +05:30
},
isDisabled: ({ currentVersionIndex }) => {
2025-01-27 14:19:47 +05:30
if (currentVersionIndex === 0) {
return true;
}
return false;
},
},
{
icon: <UndoIcon size={18} />,
description: "View Previous version",
2025-01-27 14:19:47 +05:30
onClick: ({ handleVersionChange }) => {
handleVersionChange("prev");
2025-01-27 14:19:47 +05:30
},
isDisabled: ({ currentVersionIndex }) => {
if (currentVersionIndex === 0) {
return true;
}
return false;
},
},
{
icon: <RedoIcon size={18} />,
description: "View Next version",
2025-01-27 14:19:47 +05:30
onClick: ({ handleVersionChange }) => {
handleVersionChange("next");
2025-01-27 14:19:47 +05:30
},
isDisabled: ({ isCurrentVersion }) => {
if (isCurrentVersion) {
return true;
}
return false;
},
},
{
icon: <CopyIcon size={18} />,
description: "Copy to clipboard",
2025-01-27 14:19:47 +05:30
onClick: ({ content }) => {
navigator.clipboard.writeText(content);
toast.success("Copied to clipboard!");
2025-01-27 14:19:47 +05:30
},
},
],
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.",
},
],
2025-01-27 14:19:47 +05:30
});
},
},
{
icon: <MessageIcon />,
description: "Request suggestions",
onClick: ({ sendMessage }) => {
sendMessage({
role: "user",
parts: [
{
type: "text",
text: "Please add suggestions you have that could improve the writing.",
},
],
2025-01-27 14:19:47 +05:30
});
},
},
],
});