"use client"; import { useRef, type ReactNode } from "react"; import { useAnimationFrame, useReducedMotion } from "motion/react"; type OrbitButtonProps = { children: ReactNode; className?: string; onClick?: () => void; /** Colour of the orbiting dot. */ color?: string; /** Seconds for one lap at rest. Hover and focus run it 2.5x faster. */ speed?: number; /** Pixels between the button edge and the orbit. */ gap?: number; }; /* OrbitButton: a glowing dot circles the button, passing behind it on the top half and in front on the bottom half. */ export function OrbitButton({ children, className = "rounded-full border border-[#a78bfa]/40 bg-[#1a1530] px-9 py-4 text-[15px] font-medium text-[#ede9fe]", onClick, color = "#a78bfa", speed = 4, gap = 10, }: OrbitButtonProps) { const reduce = useReducedMotion(); const btn = useRef(null); const dot = useRef(null); const fast = useRef(false); const angle = useRef(-Math.PI / 4); useAnimationFrame((_, delta) => { const b = btn.current; const d = dot.current; if (!b || !d) return; if (!reduce) angle.current += (delta / 1000) * ((2 * Math.PI) / speed) * (fast.current ? 2.5 : 1); const s = Math.sin(angle.current); const x = Math.cos(angle.current) * (b.offsetWidth / 2 + gap); const y = s * (b.offsetHeight / 2 + gap); // Bigger in front, smaller behind: reads as depth. d.style.transform = `translate(${x}px, ${y}px) scale(${0.75 + 0.2 * (s + 1)})`; d.style.zIndex = s < 0 ? "0" : "2"; }); return ( ); }