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