Skip to content

Commit

Permalink
fix(chat-message): allow passing classnames
Browse files Browse the repository at this point in the history
  • Loading branch information
iipanda committed Nov 28, 2024
1 parent ad86492 commit c325a63
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 12 deletions.
2 changes: 1 addition & 1 deletion apps/www/public/r/chat-message.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"files": [
{
"path": "ui/chat-message.tsx",
"content": "\"use client\"\n\nimport React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport { MarkdownRenderer } from \"@/registry/default/ui/markdown-renderer\"\n\nconst chatBubbleVariants = cva(\n \"group/message relative break-words rounded-lg p-3 text-sm sm:max-w-[70%]\",\n {\n variants: {\n isUser: {\n true: \"bg-primary\",\n false: \"bg-muted\",\n },\n animation: {\n none: \"\",\n slide: \"animate-in fade-in-0 duration-300\",\n scale: \"animate-in fade-in-0 zoom-in-75 duration-300\",\n fade: \"animate-in fade-in-0 duration-500\",\n },\n },\n compoundVariants: [\n {\n isUser: true,\n animation: \"slide\",\n class: \"slide-in-from-right\",\n },\n {\n isUser: false,\n animation: \"slide\",\n class: \"slide-in-from-left\",\n },\n {\n isUser: true,\n animation: \"scale\",\n class: \"origin-bottom-right\",\n },\n {\n isUser: false,\n animation: \"scale\",\n class: \"origin-bottom-left\",\n },\n ],\n }\n)\n\ntype Animation = VariantProps<typeof chatBubbleVariants>[\"animation\"]\n\nexport interface Message {\n id: string\n role: \"user\" | \"assistant\" | (string & {})\n content: string\n createdAt?: Date\n attachments?: File[]\n}\n\nexport interface ChatMessageProps extends Message {\n showTimeStamp?: boolean\n animation?: Animation\n actions?: React.ReactNode\n}\n\nexport const ChatMessage: React.FC<ChatMessageProps> = ({\n role,\n content,\n createdAt,\n showTimeStamp = false,\n animation = \"scale\",\n actions,\n}) => {\n const isUser = role === \"user\"\n\n const formattedTime = createdAt?.toLocaleTimeString(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n })\n\n return (\n <div className={cn(\"flex flex-col\", isUser ? \"items-end\" : \"items-start\")}>\n <div className={chatBubbleVariants({ isUser, animation })}>\n <div className={isUser ? \"text-primary-foreground\" : \"text-foreground\"}>\n <MarkdownRenderer>{content}</MarkdownRenderer>\n </div>\n\n {role === \"assistant\" && actions ? (\n <div className=\"bg-background absolute -bottom-4 right-2 flex space-x-1 rounded-lg border p-1 opacity-0 transition-opacity group-hover/message:opacity-100\">\n {actions}\n </div>\n ) : null}\n </div>\n\n {showTimeStamp && createdAt ? (\n <span\n className={cn(\n \"mt-1 block px-1 text-xs opacity-50\",\n animation !== \"none\" && \"animate-in fade-in-0 duration-500\"\n )}\n >\n {formattedTime}\n </span>\n ) : null}\n </div>\n )\n}\n",
"content": "\"use client\"\n\nimport React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport { MarkdownRenderer } from \"@/registry/default/ui/markdown-renderer\"\n\nconst chatBubbleVariants = cva(\n \"group/message relative break-words rounded-lg p-3 text-sm sm:max-w-[70%]\",\n {\n variants: {\n isUser: {\n true: \"bg-primary text-primary-foreground\",\n false: \"bg-muted text-foreground\",\n },\n animation: {\n none: \"\",\n slide: \"duration-300 animate-in fade-in-0\",\n scale: \"duration-300 animate-in fade-in-0 zoom-in-75\",\n fade: \"duration-500 animate-in fade-in-0\",\n },\n },\n compoundVariants: [\n {\n isUser: true,\n animation: \"slide\",\n class: \"slide-in-from-right\",\n },\n {\n isUser: false,\n animation: \"slide\",\n class: \"slide-in-from-left\",\n },\n {\n isUser: true,\n animation: \"scale\",\n class: \"origin-bottom-right\",\n },\n {\n isUser: false,\n animation: \"scale\",\n class: \"origin-bottom-left\",\n },\n ],\n }\n)\n\ntype Animation = VariantProps<typeof chatBubbleVariants>[\"animation\"]\n\nexport interface Message {\n id: string\n role: \"user\" | \"assistant\" | (string & {})\n content: string\n createdAt?: Date\n attachments?: File[]\n}\n\nexport interface ChatMessageProps extends Message {\n showTimeStamp?: boolean\n animation?: Animation\n actions?: React.ReactNode\n className?: string\n}\n\nexport const ChatMessage: React.FC<ChatMessageProps> = ({\n role,\n content,\n createdAt,\n showTimeStamp = false,\n animation = \"scale\",\n actions,\n className,\n}) => {\n const isUser = role === \"user\"\n\n const formattedTime = createdAt?.toLocaleTimeString(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n })\n\n return (\n <div className={cn(\"flex flex-col\", isUser ? \"items-end\" : \"items-start\")}>\n <div className={cn(chatBubbleVariants({ isUser, animation }), className)}>\n <div>\n <MarkdownRenderer>{content}</MarkdownRenderer>\n </div>\n\n {role === \"assistant\" && actions ? (\n <div className=\"absolute -bottom-4 right-2 flex space-x-1 rounded-lg border bg-background p-1 opacity-0 transition-opacity group-hover/message:opacity-100 text-foreground\">\n {actions}\n </div>\n ) : null}\n </div>\n\n {showTimeStamp && createdAt ? (\n <time\n dateTime={createdAt.toISOString()}\n className={cn(\n \"mt-1 block px-1 text-xs opacity-50\",\n animation !== \"none\" && \"duration-500 animate-in fade-in-0\"\n )}\n >\n {formattedTime}\n </time>\n ) : null}\n </div>\n )\n}\n",
"type": "registry:ui",
"target": ""
}
Expand Down
25 changes: 14 additions & 11 deletions apps/www/registry/default/ui/chat-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ const chatBubbleVariants = cva(
{
variants: {
isUser: {
true: "bg-primary",
false: "bg-muted",
true: "bg-primary text-primary-foreground",
false: "bg-muted text-foreground",
},
animation: {
none: "",
slide: "animate-in fade-in-0 duration-300",
scale: "animate-in fade-in-0 zoom-in-75 duration-300",
fade: "animate-in fade-in-0 duration-500",
slide: "duration-300 animate-in fade-in-0",
scale: "duration-300 animate-in fade-in-0 zoom-in-75",
fade: "duration-500 animate-in fade-in-0",
},
},
compoundVariants: [
Expand Down Expand Up @@ -60,6 +60,7 @@ export interface ChatMessageProps extends Message {
showTimeStamp?: boolean
animation?: Animation
actions?: React.ReactNode
className?: string
}

export const ChatMessage: React.FC<ChatMessageProps> = ({
Expand All @@ -69,6 +70,7 @@ export const ChatMessage: React.FC<ChatMessageProps> = ({
showTimeStamp = false,
animation = "scale",
actions,
className,
}) => {
const isUser = role === "user"

Expand All @@ -79,27 +81,28 @@ export const ChatMessage: React.FC<ChatMessageProps> = ({

return (
<div className={cn("flex flex-col", isUser ? "items-end" : "items-start")}>
<div className={chatBubbleVariants({ isUser, animation })}>
<div className={isUser ? "text-primary-foreground" : "text-foreground"}>
<div className={cn(chatBubbleVariants({ isUser, animation }), className)}>
<div>
<MarkdownRenderer>{content}</MarkdownRenderer>
</div>

{role === "assistant" && actions ? (
<div className="bg-background absolute -bottom-4 right-2 flex space-x-1 rounded-lg border p-1 opacity-0 transition-opacity group-hover/message:opacity-100">
<div className="absolute -bottom-4 right-2 flex space-x-1 rounded-lg border bg-background p-1 opacity-0 transition-opacity group-hover/message:opacity-100 text-foreground">
{actions}
</div>
) : null}
</div>

{showTimeStamp && createdAt ? (
<span
<time
dateTime={createdAt.toISOString()}
className={cn(
"mt-1 block px-1 text-xs opacity-50",
animation !== "none" && "animate-in fade-in-0 duration-500"
animation !== "none" && "duration-500 animate-in fade-in-0"
)}
>
{formattedTime}
</span>
</time>
) : null}
</div>
)
Expand Down

0 comments on commit c325a63

Please sign in to comment.