added markdown to onboarding step

This commit is contained in:
Lucas Oliveira 2025-10-17 17:12:33 -03:00
parent b5c0788ab9
commit f8e1e64b81

View file

@ -2,89 +2,116 @@ import { AnimatePresence, motion } from "motion/react";
import { type ReactNode, useEffect, useState } from "react"; import { type ReactNode, useEffect, useState } from "react";
import { Message } from "@/app/chat/components/message"; import { Message } from "@/app/chat/components/message";
import DogIcon from "@/components/logo/dog-icon"; import DogIcon from "@/components/logo/dog-icon";
import { MarkdownRenderer } from "@/components/markdown-renderer";
import { cn } from "@/lib/utils";
interface OnboardingStepProps { interface OnboardingStepProps {
text: string; text: string;
children: ReactNode; children?: ReactNode;
isVisible: boolean; isVisible: boolean;
isCompleted?: boolean; isCompleted?: boolean;
icon?: ReactNode;
isMarkdown?: boolean;
} }
export function OnboardingStep({ export function OnboardingStep({
text, text,
children, children,
isVisible, isVisible,
isCompleted = false, isCompleted = false,
icon,
isMarkdown = false,
}: OnboardingStepProps) { }: OnboardingStepProps) {
const [displayedText, setDisplayedText] = useState(""); const [displayedText, setDisplayedText] = useState("");
const [showChildren, setShowChildren] = useState(false); const [showChildren, setShowChildren] = useState(false);
useEffect(() => { useEffect(() => {
if (!isVisible) { if (!isVisible) {
setDisplayedText(""); setDisplayedText("");
setShowChildren(false); setShowChildren(false);
return; return;
} }
let currentIndex = 0; let currentIndex = 0;
setDisplayedText(""); setDisplayedText("");
setShowChildren(false); setShowChildren(false);
const interval = setInterval(() => { const interval = setInterval(() => {
if (currentIndex < text.length) { if (currentIndex < text.length) {
setDisplayedText(text.slice(0, currentIndex + 1)); setDisplayedText(text.slice(0, currentIndex + 1));
currentIndex++; currentIndex++;
} else { } else {
clearInterval(interval); clearInterval(interval);
setShowChildren(true); setShowChildren(true);
} }
}, 20); // 20ms per character }, 20); // 20ms per character
return () => clearInterval(interval); return () => clearInterval(interval);
}, [text, isVisible]); }, [text, isVisible]);
if (!isVisible) return null; if (!isVisible) return null;
return ( return (
<motion.div <motion.div
initial={{ opacity: 0, y: -20 }} initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.4, ease: "easeOut" }} transition={{ duration: 0.4, delay: 0.4, ease: "easeOut" }}
className={isCompleted ? "opacity-50" : ""} 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"> icon || (
<DogIcon <div className="w-8 h-8 rounded-lg bg-accent/20 flex items-center justify-center flex-shrink-0 select-none">
className="h-6 w-6 text-accent-foreground" <DogIcon
disabled={isCompleted} className="h-6 w-6 text-accent-foreground"
/> disabled={isCompleted}
</div> />
} </div>
> )
<div className="space-y-4"> }
<p >
className={`text-foreground text-sm py-1.5 ${isCompleted ? "text-placeholder-foreground" : ""}`} <div className="space-y-4">
> {isMarkdown ? (
{displayedText} <div className="py-1.5">
{!showChildren && !isCompleted && ( <MarkdownRenderer
<span className="inline-block w-1 h-4 bg-primary ml-1 animate-pulse" /> className={cn(
)} isCompleted
</p> ? "text-placeholder-foreground"
<AnimatePresence> : "text-foreground",
{showChildren && !isCompleted && ( "text-sm py-1.5",
<motion.div )}
initial={{ opacity: 0, y: -10 }} chatMessage={text}
animate={{ opacity: 1, y: 0 }} />
exit={{ opacity: 0, height: 0 }} <span className="inline-block w-1 h-4 bg-primary ml-1 animate-pulse" />
transition={{ duration: 0.3, delay: 0.3, ease: "easeOut" }} </div>
> ) : (
{children} <p
</motion.div> className={`text-foreground text-sm py-1.5 ${
)} isCompleted ? "text-placeholder-foreground" : ""
</AnimatePresence> }`}
</div> >
</Message> {displayedText}
</motion.div> {!showChildren && !isCompleted && (
); <span className="inline-block w-1 h-4 bg-primary ml-1 animate-pulse" />
)}
</p>
)}
{children && (
<AnimatePresence>
{showChildren && !isCompleted && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.3, delay: 0.3, ease: "easeOut" }}
>
{children}
</motion.div>
)}
</AnimatePresence>
)}
</div>
</Message>
</motion.div>
);
} }