diff --git a/src/styles/globals.css b/src/styles/globals.css index 9cf9b70f..09f5cd57 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -173,6 +173,49 @@ } } +.generation-loading-sweep { + animation: generation-loading-sweep 1.8s ease-in-out infinite; +} + +.generation-loading-float { + animation: generation-loading-float 2.4s ease-in-out infinite; +} + +.generation-loading-pan { + animation: generation-loading-pan 1.6s ease-in-out infinite; +} + +@keyframes generation-loading-sweep { + 0% { + transform: translateX(-60%); + } + 100% { + transform: translateX(360%); + } +} + +@keyframes generation-loading-float { + 0%, + 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-2px); + } +} + +@keyframes generation-loading-pan { + 0%, + 100% { + transform: translateX(-20%); + opacity: 0.55; + } + 50% { + transform: translateX(70%); + opacity: 1; + } +} + body { font-family: var(--font-sans); } diff --git a/src/toolkits/toolkits/components/generation-loading.tsx b/src/toolkits/toolkits/components/generation-loading.tsx new file mode 100644 index 00000000..e6616656 --- /dev/null +++ b/src/toolkits/toolkits/components/generation-loading.tsx @@ -0,0 +1,132 @@ +import { ImageIcon, Sparkles, VideoIcon } from "lucide-react"; +import React from "react"; + +import { cn } from "@/lib/utils"; + +type GenerationKind = "image" | "video"; + +type GenerationLoadingProps = { + kind: GenerationKind; + prompt?: string; + isPartial?: boolean; +}; + +const previewTiles = Array.from({ length: 9 }, (_, index) => index); +const videoFrames = Array.from({ length: 5 }, (_, index) => index); +const progressSegments = Array.from({ length: 3 }, (_, index) => index); + +export const GenerationLoading = ({ + kind, + prompt, + isPartial, +}: GenerationLoadingProps) => { + const isVideo = kind === "video"; + const Icon = isVideo ? VideoIcon : ImageIcon; + const trimmedPrompt = prompt?.trim(); + const promptText = + trimmedPrompt === undefined || trimmedPrompt.length === 0 + ? "Waiting for generation details" + : trimmedPrompt; + + return ( +
+ {isPartial + ? "Preparing prompt" + : isVideo + ? "Rendering video" + : "Composing image"} +
++ {promptText} +
+