diff --git a/src/components/ui/loader.tsx b/src/components/ui/loader.tsx new file mode 100644 index 00000000..05eca1e5 --- /dev/null +++ b/src/components/ui/loader.tsx @@ -0,0 +1,141 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const loaderVariants = cva( + "inline-block animate-spin rounded-full border-2 border-solid border-current border-r-transparent motion-reduce:animate-[spin_1.5s_linear_infinite]", + { + variants: { + size: { + sm: "h-4 w-4", + default: "h-6 w-6", + lg: "h-8 w-8", + xl: "h-12 w-12", + }, + }, + defaultVariants: { + size: "default", + }, + }, +); + +const wrenchLoaderVariants = cva( + "inline-block motion-reduce:animate-[wrench-spin_2s_ease-in-out_infinite]", + { + variants: { + size: { + sm: "h-4 w-4", + default: "h-6 w-6", + lg: "h-8 w-8", + xl: "h-12 w-12", + }, + }, + defaultVariants: { + size: "default", + }, + }, +); + +interface LoaderProps + extends React.HTMLAttributes, + VariantProps { + text?: string; + variant?: "spinner" | "wrench"; +} + +function Loader({ + className, + size, + text, + variant = "spinner", + ...props +}: LoaderProps) { + const WrenchIcon = () => ( + + {/* Wrench - moved down and left to get into bolt */} + + + + + {/* Hex bolt - moved up and right more and made 5% smaller */} + + {/* Regular hexagon (radius 40) */} + + + + {/* Circular hole */} + + + + + + ); + + return ( +
+ {variant === "wrench" ? ( + + ) : ( +
+ )} + {text && {text}} +
+ ); +} + +export { Loader, loaderVariants }; diff --git a/src/styles/globals.css b/src/styles/globals.css index 9cf9b70f..f7707b06 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -119,6 +119,25 @@ transform: translateZ(0) rotate(360deg); } } + @keyframes wrench-spin { + 9% { + transform: translateX(0) translateY(0) rotate(0deg); + } + 13% { + transform: translateX(0) translateY(0) rotate(0deg); + } + 25% { + transform: translateX(-15px) translateY(0) rotate(120deg); + } + 28% { + transform: translateX(-15px) translateY(0) rotate(120deg); + } + 79% { + transform: translateX(0) translateY(0) rotate(0deg); + } + } + + --animate-shiny-text: shiny-text 8s infinite; @keyframes shiny-text { 0%, diff --git a/src/toolkits/toolkits/image/tools/generate/client.tsx b/src/toolkits/toolkits/image/tools/generate/client.tsx index 7325a6b5..6e23d0a6 100644 --- a/src/toolkits/toolkits/image/tools/generate/client.tsx +++ b/src/toolkits/toolkits/image/tools/generate/client.tsx @@ -2,6 +2,7 @@ import React from "react"; import Image from "next/image"; +import { Loader } from "@/components/ui/loader"; import type { baseGenerateTool } from "./base"; import type { ClientToolConfig } from "@/toolkits/types"; @@ -10,8 +11,18 @@ export const generateToolConfigClient: ClientToolConfig< typeof baseGenerateTool.inputSchema.shape, typeof baseGenerateTool.outputSchema.shape > = { - CallComponent: ({ args }) => { - return {args.prompt}; + CallComponent: ({ args, isPartial }) => { + return ( +
+ + + Generating your image... + + + "{args.prompt}" + +
+ ); }, ResultComponent: ({ result }) => { return ( diff --git a/src/toolkits/toolkits/video/tools/generate/client.tsx b/src/toolkits/toolkits/video/tools/generate/client.tsx index 9c9bcf1c..e77474c1 100644 --- a/src/toolkits/toolkits/video/tools/generate/client.tsx +++ b/src/toolkits/toolkits/video/tools/generate/client.tsx @@ -1,5 +1,6 @@ import React from "react"; +import { Loader } from "@/components/ui/loader"; import type { baseGenerateTool } from "./base"; import type { ClientToolConfig } from "@/toolkits/types"; @@ -8,8 +9,18 @@ export const generateToolConfigClient: ClientToolConfig< typeof baseGenerateTool.inputSchema.shape, typeof baseGenerateTool.outputSchema.shape > = { - CallComponent: ({ args }) => { - return {args.prompt}; + CallComponent: ({ args, isPartial }) => { + return ( +
+ + + Generating your video... + + + "{args.prompt}" + +
+ ); }, ResultComponent: ({ result }) => { return