import { HTMLAttributes, memo, useEffect, useRef } from "react";
import { animate } from "motion";
import { AnimatePresence, motion } from "motion/react";
import Check from "@/components/shared/icons/check";
import { cn } from "@/utils/cn";
export default memo(function Spinner({
finished,
...attrs
}: HTMLAttributes & { finished?: boolean }) {
return (
{!finished && }
{finished && (
)}
);
});
const Canvas = memo(function Canvas() {
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
// Initialize canvas
const dpr = window.devicePixelRatio || 1;
canvas.width = 20 * dpr;
canvas.height = 20 * dpr;
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.scale(dpr, dpr);
let activeGroup = -1;
const rects = Array.from({ length: 16 }, (_, i) => ({
x: 3 + (i % 4) * 4,
y: 3 + Math.floor(i / 4) * 4,
width: 2,
height: 2,
alpha: 0,
borderRadius: 0,
}));
let dead = false;
const grid = [
[0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 1, 1, 0, 1, 0.2, 0.2, 1, 1, 0.2, 0.2, 1, 0, 1, 1, 0],
[
1, 0.4, 0.4, 1, 0.4, 0.12, 0.12, 0.4, 0.4, 0.12, 0.12, 0.4, 1, 0.4, 0.4,
1,
],
[
0.4, 0.12, 0.12, 0.4, 0.12, 0.04, 0.04, 0.12, 0.12, 0.04, 0.04, 0.12,
0.4, 0.12, 0.12, 0.4,
],
[
0.12, 0.04, 0.04, 0.12, 0.04, 0, 0, 0.04, 0.04, 0, 0, 0.04, 0.12, 0.04,
0.04, 0.12,
],
[0.04, 0, 0, 0.04, 0, 0, 0, 0, 0, 0, 0, 0, 0.04, 0, 0, 0.04],
Array.from({ length: 16 }, () => 0),
];
const render = () => {
if (dead) return;
ctx.fillStyle = "#FA5D19";
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let index = 0; index < 16; index++) {
ctx.globalAlpha = rects[index].alpha;
ctx.beginPath();
ctx.roundRect(
rects[index].x,
rects[index].y,
rects[index].width,
rects[index].height,
rects[index].borderRadius,
);
ctx.fill();
}
requestAnimationFrame(render);
};
const cycle = () => {
if (activeGroup === 2 && dead) return;
activeGroup = (activeGroup + 1) % 6;
grid[activeGroup].forEach((alpha, index) => {
animate(rects[index].alpha, alpha, {
duration: 0.05,
onUpdate: (value) => {
rects[index].alpha = value;
},
});
});
setTimeout(
() => {
if (!dead) {
cycle();
}
},
activeGroup === 5 ? 200 : 100,
);
};
cycle();
render();
canvas.addEventListener("resize", render);
return () => {
dead = true;
};
}, []);
return (
);
});