Skip to content

Commit 93d0e45

Browse files
committed
feat: custom spinner
1 parent 2b22e60 commit 93d0e45

1 file changed

Lines changed: 23 additions & 15 deletions

File tree

apps/origami-web/src/components/ui/spinner.tsx

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
"use client";
22

33
import { motion } from "motion/react";
4+
import { useState, useEffect } from "react";
45
import { cn } from "@/lib/utils";
56

67
export const Spinner = ({ className }: { className?: string }) => {
8+
const [rotation, setRotation] = useState(0);
9+
10+
// Start the animation loop
11+
useEffect(() => {
12+
const timer = setTimeout(() => {
13+
setRotation(240); // Start by rotating right with overshoot
14+
}, 20);
15+
return () => clearTimeout(timer);
16+
}, []);
17+
718
// Create 7 circles positioned in a circle
819
const circles = Array.from({ length: 7 }, (_, i) => {
920
const angle = (i * 360) / 7; // Distribute circles evenly
1021
const radius = 7; // Distance from center
1122
const x = Math.cos((angle * Math.PI) / 180) * radius;
1223
const y = Math.sin((angle * Math.PI) / 180) * radius;
1324

14-
return { x, y, delay: i * 0.1 };
25+
return { x, y };
1526
});
1627

1728
return (
@@ -23,32 +34,29 @@ export const Spinner = ({ className }: { className?: string }) => {
2334
<motion.div
2435
className="absolute inset-0 flex items-center justify-center"
2536
animate={{
26-
rotate: [0, 360, 360, 0, 0], // Right, pause, left, pause
37+
rotate: rotation,
2738
}}
2839
transition={{
40+
type: "spring",
41+
stiffness: 120,
42+
damping: 15,
2943
duration: 3,
30-
repeat: Infinity,
31-
ease: "circInOut",
32-
times: [0, 0.4, 0.5, 0.9, 1], // Timing for each keyframe
44+
}}
45+
onAnimationComplete={() => {
46+
// After animation completes, switch to the opposite rotation with 60° overshoot
47+
setTimeout(() => {
48+
setRotation((prev) => (prev === 0 || prev === 240 ? -60 : 240));
49+
}, 20);
3350
}}
3451
>
3552
{circles.map((circle, index) => (
36-
<motion.div
53+
<div
3754
key={index}
3855
className="absolute size-1 bg-current rounded-full"
3956
style={{
4057
left: 12 + circle.x - 2, // Center (12) + offset - half circle size (2)
4158
top: 12 + circle.y - 2,
4259
}}
43-
animate={{
44-
scale: [1, 1, 1],
45-
}}
46-
transition={{
47-
duration: 4,
48-
repeat: Infinity,
49-
delay: circle.delay,
50-
ease: "easeInOut",
51-
}}
5260
/>
5361
))}
5462
</motion.div>

0 commit comments

Comments
 (0)