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 ( ); });