added fade in and color transition

This commit is contained in:
Lucas Oliveira 2025-10-21 16:19:22 -03:00 committed by Mike Fortman
parent a56a39f4c4
commit b65195f0bd
3 changed files with 81 additions and 62 deletions

View file

@ -1,4 +1,5 @@
import { GitBranch } from "lucide-react"; import { GitBranch } from "lucide-react";
import { motion } from "motion/react";
import DogIcon from "@/components/logo/dog-icon"; import DogIcon from "@/components/logo/dog-icon";
import { MarkdownRenderer } from "@/components/markdown-renderer"; import { MarkdownRenderer } from "@/components/markdown-renderer";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@ -30,11 +31,17 @@ export function AssistantMessage({
isCompleted = false, isCompleted = false,
}: AssistantMessageProps) { }: AssistantMessageProps) {
return ( return (
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.2, ease: "easeOut" }}
className={isCompleted ? "opacity-50" : ""}
>
<Message <Message
icon={ icon={
<div className="w-8 h-8 rounded-lg bg-accent/20 flex items-center justify-center flex-shrink-0 select-none"> <div className="w-8 h-8 rounded-lg bg-accent/20 flex items-center justify-center flex-shrink-0 select-none">
<DogIcon <DogIcon
className="h-6 w-6" className="h-6 w-6 transition-colors duration-300"
disabled={isCompleted} disabled={isCompleted}
/> />
</div> </div>
@ -42,6 +49,7 @@ export function AssistantMessage({
actions={ actions={
showForkButton && onFork ? ( showForkButton && onFork ? (
<button <button
type="button"
onClick={onFork} onClick={onFork}
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 hover:bg-accent rounded text-muted-foreground hover:text-foreground" className="opacity-0 group-hover:opacity-100 transition-opacity p-1 hover:bg-accent rounded text-muted-foreground hover:text-foreground"
title="Fork conversation from here" title="Fork conversation from here"
@ -59,7 +67,7 @@ export function AssistantMessage({
/> />
<div className="relative"> <div className="relative">
<MarkdownRenderer <MarkdownRenderer
className={cn("text-sm py-1.5", isCompleted ? "text-placeholder-foreground" : "text-foreground")} className={cn("text-sm py-1.5 transition-colors duration-300", isCompleted ? "text-placeholder-foreground" : "text-foreground")}
chatMessage={ chatMessage={
isStreaming isStreaming
? content + ? content +
@ -69,5 +77,6 @@ export function AssistantMessage({
/> />
</div> </div>
</Message> </Message>
</motion.div>
); );
} }

View file

@ -1,4 +1,5 @@
import { User } from "lucide-react"; import { User } from "lucide-react";
import { motion } from "motion/react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { useAuth } from "@/contexts/auth-context"; import { useAuth } from "@/contexts/auth-context";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@ -13,6 +14,12 @@ export function UserMessage({ content, isCompleted }: UserMessageProps) {
const { user } = useAuth(); const { user } = useAuth();
return ( return (
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.2, ease: "easeOut" }}
className={isCompleted ? "opacity-50" : ""}
>
<Message <Message
icon={ icon={
<Avatar className="w-8 h-8 rounded-lg flex-shrink-0 select-none"> <Avatar className="w-8 h-8 rounded-lg flex-shrink-0 select-none">
@ -20,7 +27,7 @@ export function UserMessage({ content, isCompleted }: UserMessageProps) {
<AvatarFallback <AvatarFallback
className={cn( className={cn(
isCompleted ? "text-placeholder-foreground" : "text-primary", isCompleted ? "text-placeholder-foreground" : "text-primary",
"text-sm bg-accent/20 rounded-lg", "text-sm bg-accent/20 rounded-lg transition-colors duration-300",
)} )}
> >
{user?.name ? user.name.charAt(0).toUpperCase() : <User className="h-4 w-4" />} {user?.name ? user.name.charAt(0).toUpperCase() : <User className="h-4 w-4" />}
@ -30,12 +37,13 @@ export function UserMessage({ content, isCompleted }: UserMessageProps) {
> >
<p <p
className={cn( className={cn(
"text-foreground text-sm py-1.5 whitespace-pre-wrap break-words overflow-wrap-anywhere", "text-foreground text-sm py-1.5 whitespace-pre-wrap break-words overflow-wrap-anywhere transition-colors duration-300",
isCompleted ? "text-placeholder-foreground" : "text-foreground", isCompleted ? "text-placeholder-foreground" : "text-foreground",
)} )}
> >
{content} {content}
</p> </p>
</Message> </Message>
</motion.div>
); );
} }

View file

@ -45,10 +45,12 @@ export function OnboardingContent({
const handleNudgeClick = async (nudge: string) => { const handleNudgeClick = async (nudge: string) => {
setSelectedNudge(nudge); setSelectedNudge(nudge);
setAssistantMessage(null); setAssistantMessage(null);
setTimeout(async () => {
await sendMessage({ await sendMessage({
prompt: nudge, prompt: nudge,
previousResponseId: responseId || undefined, previousResponseId: responseId || undefined,
}); });
}, 1500);
}; };
// Determine which message to show (streaming takes precedence) // Determine which message to show (streaming takes precedence)