Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions src/components/ui/loader.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLDivElement>,
VariantProps<typeof loaderVariants> {
text?: string;
variant?: "spinner" | "wrench";
}

function Loader({
className,
size,
text,
variant = "spinner",
...props
}: LoaderProps) {
const WrenchIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="-80 -290 520 800"
className="h-52 w-32"
preserveAspectRatio="xMidYMid meet"
>
{/* Wrench - moved down and left to get into bolt */}
<g
transform="translate(-61, 63)"
className={cn(wrenchLoaderVariants({ size }))}
style={{
animation:
variant === "wrench"
? "wrench-spin 2.7s ease-in-out infinite"
: undefined,
transformOrigin: "365px 130px",
}}
>
<path
d="M 325.500 57.121 C 323.300 57.623, 319.250 58.518, 316.500 59.109 C 303.651 61.870, 285.869 69.675, 273.414 78.020 C 269.061 80.936, 261.398 87.412, 256.384 92.411 C 248.803 99.970, 246.589 102.931, 243.236 110 C 237.975 121.092, 236.529 127.428, 236.616 139 C 236.700 150.194, 238.721 159.307, 243.680 170.854 L 247.280 179.234 202.890 223.107 L 158.500 266.979 145 267.025 C 131.660 267.071, 125.711 267.974, 115.500 271.506 C 95.541 278.409, 77.291 294.458, 67.747 313.500 C 55.045 338.842, 54.855 365.924, 67.207 390.500 C 77.673 411.325, 96.262 426.635, 119.500 433.567 C 127.296 435.893, 130.372 436.264, 142.500 436.341 C 154.080 436.414, 157.823 436.052, 164.157 434.243 C 194.624 425.544, 216.578 403.677, 224.705 373.934 C 226.622 366.919, 227.179 345.186, 225.703 335 L 224.906 329.500 238.203 315.973 C 245.516 308.532, 261.397 292.107, 273.493 279.473 C 285.590 266.838, 299.316 252.545, 303.996 247.710 L 312.505 238.921 317.502 241.480 C 320.251 242.887, 326.325 245.265, 331 246.764 C 338.611 249.205, 340.964 249.487, 353.500 249.465 C 365.842 249.443, 368.211 249.160, 373.500 247.069 C 384.552 242.702, 395.592 234.173, 403.256 224.082 C 405.587 221.012, 407.766 218.275, 408.098 218 C 409.463 216.868, 414.440 208.216, 418.937 199.155 C 427.231 182.445, 431.639 166.623, 432.646 149.956 C 433.826 130.402, 431.410 123, 423.847 123 C 420.960 123, 418.236 125.356, 399.052 144.445 C 387.198 156.239, 376.352 166.319, 374.949 166.844 C 369.212 168.992, 367.424 167.686, 343.750 144.048 L 321 121.334 321 116.482 L 321 111.629 341.750 90.872 C 353.163 79.456, 362.918 68.982, 363.429 67.598 C 364.684 64.198, 362.897 60.517, 358.770 58.001 C 355.919 56.263, 353.835 56.020, 342.500 56.107 C 335.350 56.162, 327.700 56.618, 325.500 57.121 M 331 72.070 C 297.867 77.107, 268.196 95.054, 257.125 116.754 C 252.314 126.186, 250.728 139.734, 253.093 151.201 C 253.694 154.115, 256.394 161.170, 259.093 166.879 C 261.792 172.587, 264 178.657, 264 180.367 C 264 183.140, 258.604 188.866, 214.250 233.159 L 164.500 282.840 149 282.288 C 135.287 281.799, 132.622 281.977, 125.884 283.828 C 112.746 287.437, 101.551 294.367, 91.745 304.958 C 55.894 343.680, 74.101 405.791, 125.500 420.107 C 128.734 421.008, 135.267 421.469, 144 421.413 C 156.576 421.333, 158.073 421.112, 165.874 418.188 C 188.511 409.703, 204.362 392.544, 210.028 370.391 C 212.582 360.406, 212.633 346.210, 210.153 335.846 C 208.739 329.938, 208.569 327.615, 209.411 325.659 C 210.010 324.266, 215.450 318.020, 221.500 311.779 C 227.550 305.538, 242.850 289.651, 255.500 276.474 C 310.971 218.693, 306.434 223.018, 311.591 223.007 C 313.292 223.003, 318.242 224.755, 322.591 226.901 C 333.333 232.200, 339.852 234.014, 350.614 234.698 C 368.461 235.833, 379.510 230.027, 393.176 212.334 C 399.205 204.528, 406.385 191.348, 410.349 180.810 C 414.487 169.807, 418.460 149, 416.422 149 C 416.104 149, 409.241 155.725, 401.172 163.945 C 391.060 174.244, 385.101 179.521, 382 180.923 C 376.082 183.597, 366.996 183.635, 361.214 181.011 C 356.081 178.681, 311.531 135.069, 308.163 129.077 C 305.406 124.171, 304.400 114.911, 305.981 109 C 307.008 105.161, 309.521 102.145, 323.093 88.462 C 331.842 79.641, 339 72.103, 339 71.712 C 339 70.902, 338.555 70.921, 331 72.070 M 150 307.794 C 148.625 308.007, 145.025 308.845, 142 309.657 C 138.975 310.469, 131.437 312.465, 125.248 314.092 C 107.140 318.854, 108.397 317.830, 104.970 330.600 C 102.152 341.102, 100.051 348.733, 98.803 353 C 98.240 354.925, 97.558 358.421, 97.287 360.770 L 96.795 365.039 111.648 379.559 C 119.816 387.544, 127.757 394.757, 129.292 395.587 C 131.912 397.002, 133.301 396.777, 151.792 391.941 C 162.632 389.106, 172.443 386.195, 173.597 385.471 C 174.750 384.747, 176.197 382.883, 176.814 381.327 C 179.126 375.491, 187 345.058, 187 341.955 C 187 339.098, 185.196 336.976, 171.404 323.612 C 162.826 315.300, 155.063 308.254, 154.154 307.954 C 153.244 307.653, 151.375 307.582, 150 307.794 M 135.180 326.521 C 119.668 330.700, 120.356 330.403, 119.771 333.168 C 119.500 334.451, 117.835 340.862, 116.071 347.416 L 112.864 359.331 123.634 370.134 C 133.031 379.561, 134.728 380.860, 136.952 380.333 C 149.684 377.318, 163.389 373.050, 164.015 371.906 C 164.804 370.464, 169.864 351.566, 170.711 346.900 C 171.117 344.665, 169.686 342.840, 160.513 333.900 C 154.644 328.180, 149.315 323.433, 148.671 323.351 C 148.027 323.269, 141.956 324.695, 135.180 326.521"
stroke="none"
fill="#4299e1"
fillRule="evenodd"
/>
</g>

{/* Hex bolt - moved up and right more and made 5% smaller */}
<g
fill="none"
stroke="#4299e1"
strokeWidth="12"
strokeLinejoin="round"
transform="translate(363, 126) scale(0.95)"
>
{/* Regular hexagon (radius 40) */}
<polygon
points="
40,0
20,34.641
-20,34.641
-40,0
-20,-34.641
20,-34.641
"
>
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
values="15;15;135;135;135"
keyTimes="0;0.14;0.26;0.28;1"
dur="2.7s"
repeatCount="indefinite"
/>
</polygon>
{/* Circular hole */}
<circle cx="0" cy="0" r="14">
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
values="15;15;135;135;135"
keyTimes="0;0.14;0.26;0.28;1"
dur="2.7s"
repeatCount="indefinite"
/>
</circle>
</g>
</svg>
);

return (
<div
className={cn("flex items-center justify-center gap-2", className)}
{...props}
>
{variant === "wrench" ? (
<WrenchIcon />
) : (
<div className={cn(loaderVariants({ size }))} />
)}
{text && <span className="text-muted-foreground text-sm">{text}</span>}
</div>
);
}

export { Loader, loaderVariants };
19 changes: 19 additions & 0 deletions src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -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%,
Expand Down
15 changes: 13 additions & 2 deletions src/toolkits/toolkits/image/tools/generate/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -10,8 +11,18 @@ export const generateToolConfigClient: ClientToolConfig<
typeof baseGenerateTool.inputSchema.shape,
typeof baseGenerateTool.outputSchema.shape
> = {
CallComponent: ({ args }) => {
return <span className="opacity/60 text-sm font-light">{args.prompt}</span>;
CallComponent: ({ args, isPartial }) => {
return (
<div className="flex flex-col items-center gap-4 py-4">
<Loader variant="wrench" />
<span className="text-foreground text-sm font-medium">
Generating your image...
</span>
<span className="text-muted-foreground text-sm font-light">
"{args.prompt}"
</span>
</div>
);
},
ResultComponent: ({ result }) => {
return (
Expand Down
15 changes: 13 additions & 2 deletions src/toolkits/toolkits/video/tools/generate/client.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -8,8 +9,18 @@ export const generateToolConfigClient: ClientToolConfig<
typeof baseGenerateTool.inputSchema.shape,
typeof baseGenerateTool.outputSchema.shape
> = {
CallComponent: ({ args }) => {
return <span className="opacity/60 text-sm font-light">{args.prompt}</span>;
CallComponent: ({ args, isPartial }) => {
return (
<div className="flex flex-col items-center gap-4 py-4">
<Loader variant="wrench" />
<span className="text-foreground text-sm font-medium">
Generating your video...
</span>
<span className="text-muted-foreground text-sm font-light">
"{args.prompt}"
</span>
</div>
);
},
ResultComponent: ({ result }) => {
return <video src={result.url} autoPlay loop muted playsInline />;
Expand Down
Loading