({
message,
isLatestMessage,
status,
}: {
message: TMessage;
isLoading: boolean;
status: "error" | "submitted" | "streaming" | "ready";
isLatestMessage: boolean;
})
| 139 | } |
| 140 | |
| 141 | const PurePreviewMessage = ({ |
| 142 | message, |
| 143 | isLatestMessage, |
| 144 | status, |
| 145 | }: { |
| 146 | message: TMessage; |
| 147 | isLoading: boolean; |
| 148 | status: "error" | "submitted" | "streaming" | "ready"; |
| 149 | isLatestMessage: boolean; |
| 150 | }) => { |
| 151 | // Create a string with all text parts for copy functionality |
| 152 | const getMessageText = () => { |
| 153 | if (!message.parts) return ""; |
| 154 | return message.parts |
| 155 | .filter((part) => part.type === "text") |
| 156 | .map((part) => (part.type === "text" ? part.text : "")) |
| 157 | .join("\n\n"); |
| 158 | }; |
| 159 | |
| 160 | // Only show copy button if the message is from the assistant and not currently streaming |
| 161 | const shouldShowCopyButton = |
| 162 | message.role === "assistant" && |
| 163 | (!isLatestMessage || status !== "streaming"); |
| 164 | |
| 165 | return ( |
| 166 | <AnimatePresence key={message.id}> |
| 167 | <motion.div |
| 168 | className={cn( |
| 169 | "w-full mx-auto px-4 group/message", |
| 170 | message.role === "assistant" ? "mb-8" : "mb-6", |
| 171 | )} |
| 172 | initial={{ y: 5, opacity: 0 }} |
| 173 | animate={{ y: 0, opacity: 1 }} |
| 174 | key={`message-${message.id}`} |
| 175 | data-role={message.role} |
| 176 | > |
| 177 | <div |
| 178 | className={cn( |
| 179 | "flex gap-4 w-full group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl", |
| 180 | "group-data-[role=user]/message:w-fit", |
| 181 | )} |
| 182 | > |
| 183 | <div className="flex flex-col w-full space-y-3"> |
| 184 | {message.parts?.map((part, i) => { |
| 185 | switch (part.type) { |
| 186 | case "text": |
| 187 | return ( |
| 188 | <motion.div |
| 189 | initial={{ y: 5, opacity: 0 }} |
| 190 | animate={{ y: 0, opacity: 1 }} |
| 191 | key={`message-${message.id}-part-${i}`} |
| 192 | className="flex flex-row gap-2 items-start w-full" |
| 193 | > |
| 194 | <div |
| 195 | className={cn("flex flex-col gap-3 w-full", { |
| 196 | "bg-secondary text-secondary-foreground px-4 py-3 rounded-2xl": |
| 197 | message.role === "user", |
| 198 | })} |
nothing calls this directly
no test coverage detected