mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-02 02:45:18 -05:00
refactor(components): enhance FindBlocksTool and MorphingTextAnimation
- Updated the `FindBlocksTool` to utilize the new `MorphingTextAnimation` for improved visual feedback. - Refactored `MorphingTextAnimation` to accept a `text` prop, simplifying its usage and enhancing flexibility. - Improved the rendering logic in `ChatMessagesContainer` to ensure proper key assignment for dynamic elements. These changes aim to enhance the user experience by providing better visual transitions and cleaner component interactions.
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
MessageResponse,
|
||||
} from "@/components/ai-elements/message";
|
||||
import { MessageSquareIcon } from "lucide-react";
|
||||
import { UIMessage, UIDataTypes, UITools } from "ai";
|
||||
import { UIMessage, UIDataTypes, UITools, ToolUIPart } from "ai";
|
||||
import { FindBlocksTool } from "../../tools/FindBlocks/FindBlocks";
|
||||
|
||||
interface ChatMessagesContainerProps {
|
||||
@@ -54,7 +54,10 @@ export const ChatMessagesContainer = ({
|
||||
);
|
||||
case "tool-find_block":
|
||||
return (
|
||||
<FindBlocksTool message={message} i={i} part={part} />
|
||||
<FindBlocksTool
|
||||
key={`${message.id}-${i}`}
|
||||
part={part as ToolUIPart}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
|
||||
@@ -1,57 +1,52 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
|
||||
const MorphingTextAnimationComponent = ({
|
||||
currentText,
|
||||
}: {
|
||||
currentText: string;
|
||||
}) => {
|
||||
const letters = currentText.split("");
|
||||
return (
|
||||
<motion.span className="inline-flex overflow-hidden">
|
||||
{letters.map((char, index) => (
|
||||
<motion.span
|
||||
key={`${currentText}-${index}`}
|
||||
initial={{ opacity: 0, y: 8, rotateX: "80deg", filter: "blur(6px)" }}
|
||||
animate={{ opacity: 1, y: 0, rotateX: "0deg", filter: "blur(0px)" }}
|
||||
exit={{ opacity: 0, y: -8, rotateX: "-80deg", filter: "blur(6px)" }}
|
||||
style={{ willChange: "transform" }}
|
||||
transition={{
|
||||
delay: 0.015 * index,
|
||||
interface Props {
|
||||
text: string;
|
||||
}
|
||||
|
||||
type: "spring",
|
||||
bounce: 0.5,
|
||||
}}
|
||||
className="inline-block"
|
||||
>
|
||||
{char === " " ? "\u00A0" : char}
|
||||
</motion.span>
|
||||
))}
|
||||
</motion.span>
|
||||
);
|
||||
};
|
||||
|
||||
export const MorphingTextAnimation = () => {
|
||||
const textArray = ["Searching for Twitter blocks", "Found 10 twitter blocks"];
|
||||
const [currentText, setCurrentText] = useState(textArray[0]);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setCurrentText(textArray[Math.floor(Math.random() * textArray.length)]);
|
||||
}, 1000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
export function MorphingTextAnimation({ text }: Props) {
|
||||
const letters = text.split("");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<AnimatePresence mode="popLayout" initial={false}>
|
||||
<motion.div
|
||||
key={currentText}
|
||||
className="whitespace-nowrap text-sm text-muted-foreground"
|
||||
>
|
||||
<MorphingTextAnimationComponent currentText={currentText} />
|
||||
<motion.div key={text} className="whitespace-nowrap">
|
||||
<motion.span className="inline-flex overflow-hidden">
|
||||
{letters.map((char, index) => (
|
||||
<motion.span
|
||||
key={`${text}-${index}`}
|
||||
initial={{
|
||||
opacity: 0,
|
||||
y: 8,
|
||||
rotateX: "80deg",
|
||||
filter: "blur(6px)",
|
||||
}}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
rotateX: "0deg",
|
||||
filter: "blur(0px)",
|
||||
}}
|
||||
exit={{
|
||||
opacity: 0,
|
||||
y: -8,
|
||||
rotateX: "-80deg",
|
||||
filter: "blur(6px)",
|
||||
}}
|
||||
style={{ willChange: "transform" }}
|
||||
transition={{
|
||||
delay: 0.015 * index,
|
||||
type: "spring",
|
||||
bounce: 0.5,
|
||||
}}
|
||||
className="inline-block"
|
||||
>
|
||||
{char === " " ? "\u00A0" : char}
|
||||
</motion.span>
|
||||
))}
|
||||
</motion.span>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,17 +1,43 @@
|
||||
import { UIMessage, UIDataTypes, UITools, UIMessagePart } from "ai";
|
||||
import { MorphingTextAnimation } from "../../components/MorphingTextAnimation/MorphingTextAnimation";
|
||||
import { BlockInfo } from "@/app/api/__generated__/models/blockInfo";
|
||||
import { ToolUIPart } from "ai";
|
||||
import { getAnimationText, StateIcon } from "./helpers";
|
||||
|
||||
export interface FindBlockInput {
|
||||
query: string;
|
||||
}
|
||||
|
||||
export interface FindBlockOutput {
|
||||
type: "block_list";
|
||||
message: string;
|
||||
session_id: string;
|
||||
blocks: BlockInfo[];
|
||||
count: number;
|
||||
query: string;
|
||||
usage_hint: string;
|
||||
}
|
||||
|
||||
export interface FindBlockToolPart {
|
||||
type: string;
|
||||
toolName?: string;
|
||||
toolCallId: string;
|
||||
state: ToolUIPart["state"];
|
||||
input?: FindBlockInput | unknown;
|
||||
output?: string | FindBlockOutput | unknown;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
part: FindBlockToolPart;
|
||||
}
|
||||
|
||||
export function FindBlocksTool({ part }: Props) {
|
||||
const text = getAnimationText(part);
|
||||
|
||||
export const FindBlocksTool = ({
|
||||
message,
|
||||
i,
|
||||
part,
|
||||
}: {
|
||||
message: UIMessage<unknown, UIDataTypes, UITools>;
|
||||
i: number;
|
||||
part: UIMessagePart<any, any>;
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Find Blocks</h1>
|
||||
<div className="flex items-center gap-2 py-2 text-sm text-muted-foreground">
|
||||
<StateIcon state={part.state} />
|
||||
<MorphingTextAnimation text={text} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { ToolUIPart } from "ai";
|
||||
import { FindBlockInput, FindBlockOutput, FindBlockToolPart } from "./FindBlocks";
|
||||
import { CheckCircleIcon, CircleNotchIcon, XCircleIcon } from "@phosphor-icons/react";
|
||||
|
||||
export const getAnimationText = (part: FindBlockToolPart): string => {
|
||||
switch (part.state) {
|
||||
case "input-streaming":
|
||||
return "Searching blocks for you";
|
||||
|
||||
case "input-available": {
|
||||
const query = (part.input as FindBlockInput).query;
|
||||
return `Finding "${query}" blocks`;
|
||||
}
|
||||
|
||||
case "output-available": {
|
||||
const parsed = JSON.parse(part.output as string) as FindBlockOutput;
|
||||
if (parsed) {
|
||||
return `Found ${parsed.count} "${(part.input as FindBlockInput).query}" blocks`;
|
||||
}
|
||||
return "Found blocks";
|
||||
}
|
||||
|
||||
case "output-error":
|
||||
return "Error finding blocks";
|
||||
|
||||
default:
|
||||
return "Processing";
|
||||
}
|
||||
}
|
||||
|
||||
export const StateIcon = ({ state }: { state: ToolUIPart["state"] }) => {
|
||||
switch (state) {
|
||||
case "input-streaming":
|
||||
case "input-available":
|
||||
return (
|
||||
<CircleNotchIcon
|
||||
className="h-4 w-4 animate-spin text-muted-foreground"
|
||||
weight="bold"
|
||||
/>
|
||||
);
|
||||
case "output-available":
|
||||
return (
|
||||
<CheckCircleIcon
|
||||
className="h-4 w-4 text-green-500"
|
||||
/>
|
||||
);
|
||||
case "output-error":
|
||||
return (
|
||||
<XCircleIcon
|
||||
className="h-4 w-4 text-red-500"
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { MorphingTextAnimation } from "@/app/(platform)/copilot-2/components/MorphingTextAnimation/MorphingTextAnimation";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ArrowDownIcon } from "lucide-react";
|
||||
@@ -67,7 +66,6 @@ export const ConversationEmptyState = ({
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
<MorphingTextAnimation />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user