Skip to content

Commit 0413b78

Browse files
committed
feat: better spinner
1 parent 93d0e45 commit 0413b78

1 file changed

Lines changed: 36 additions & 12 deletions

File tree

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

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,24 @@ import { cn } from "@/lib/utils";
66

77
export const Spinner = ({ className }: { className?: string }) => {
88
const [rotation, setRotation] = useState(0);
9+
const [isSpread, setIsSpread] = useState(false);
910

10-
// Start the animation loop
11+
// Start the spreading animation first, then rotation
1112
useEffect(() => {
12-
const timer = setTimeout(() => {
13+
// Start spreading animation after a short delay
14+
const spreadTimer = setTimeout(() => {
15+
setIsSpread(true);
16+
}, 100);
17+
18+
// Start rotation animation after spreading is complete
19+
const rotationTimer = setTimeout(() => {
1320
setRotation(240); // Start by rotating right with overshoot
14-
}, 20);
15-
return () => clearTimeout(timer);
21+
}, 300); // Delay to allow spreading animation to complete
22+
23+
return () => {
24+
clearTimeout(spreadTimer);
25+
clearTimeout(rotationTimer);
26+
};
1627
}, []);
1728

1829
// Create 7 circles positioned in a circle
@@ -33,14 +44,16 @@ export const Spinner = ({ className }: { className?: string }) => {
3344
{/* Container that rotates */}
3445
<motion.div
3546
className="absolute inset-0 flex items-center justify-center"
47+
initial={{
48+
rotate: 0,
49+
}}
3650
animate={{
3751
rotate: rotation,
3852
}}
3953
transition={{
40-
type: "spring",
41-
stiffness: 120,
42-
damping: 15,
43-
duration: 3,
54+
type: "tween",
55+
duration: 2,
56+
ease: "easeInOut",
4457
}}
4558
onAnimationComplete={() => {
4659
// After animation completes, switch to the opposite rotation with 60° overshoot
@@ -50,12 +63,23 @@ export const Spinner = ({ className }: { className?: string }) => {
5063
}}
5164
>
5265
{circles.map((circle, index) => (
53-
<div
66+
<motion.div
5467
key={index}
5568
className="absolute size-1 bg-current rounded-full"
56-
style={{
57-
left: 12 + circle.x - 2, // Center (12) + offset - half circle size (2)
58-
top: 12 + circle.y - 2,
69+
initial={{
70+
left: 12 - 2, // Start at center
71+
top: 12 - 2,
72+
}}
73+
animate={{
74+
left: isSpread ? 12 + circle.x - 2 : 12 - 2, // Animate to target position or stay at center
75+
top: isSpread ? 12 + circle.y - 2 : 12 - 2,
76+
}}
77+
transition={{
78+
type: "spring",
79+
stiffness: 200,
80+
damping: 20,
81+
duration: 0.6,
82+
delay: index * 0.05, // Stagger the animation slightly for each circle
5983
}}
6084
/>
6185
))}

0 commit comments

Comments
 (0)