muthuk1's picture
Convert OpenMAIC from Next.js to React (Vite)
f56a29b verified
import { motion } from 'motion/react';
import type { PercentageGeometry } from '@/lib/types/action';
interface LaserOverlayProps {
geometry: PercentageGeometry;
color?: string;
duration?: number;
}
/**
* Laser pointer overlay component
*
* Features:
* - Smoothly flies in from the nearest corner to the element center
* - Elegant light dot with soft breathing glow
* - Uses percentage positioning (0-100)
*/
export function LaserOverlay({
geometry,
color = '#ff3b30',
duration: _duration = 3000,
}: LaserOverlayProps) {
const { centerX, centerY } = geometry;
const startPos = {
x: centerX > 50 ? 105 : -5,
y: centerY > 50 ? 105 : -5,
};
return (
<motion.div
key={`laser-${centerX}-${centerY}`}
initial={{
opacity: 0,
left: `${startPos.x}%`,
top: `${startPos.y}%`,
}}
animate={{
opacity: 1,
left: `${centerX}%`,
top: `${centerY}%`,
}}
exit={{
opacity: 0,
left: `${startPos.x}%`,
top: `${startPos.y}%`,
transition: { duration: 0.25, ease: [0.4, 0, 1, 1] },
}}
transition={{
left: { duration: 0.5, ease: [0.22, 1, 0.36, 1] },
top: { duration: 0.5, ease: [0.22, 1, 0.36, 1] },
opacity: { duration: 0.15 },
}}
className="absolute z-[101] pointer-events-none"
>
<div className="relative -translate-x-1/2 -translate-y-1/2">
{/* Ring pulse */}
<motion.div
animate={{ scale: [1, 2.8], opacity: [0.6, 0] }}
transition={{
repeat: Infinity,
duration: 1.5,
ease: 'easeOut',
repeatDelay: 0.3,
}}
className="absolute inset-0 rounded-full"
style={{ border: `1.5px solid ${color}` }}
/>
{/* Light core */}
<div
className="w-2.5 h-2.5 rounded-full"
style={{
backgroundColor: color,
boxShadow: `0 0 8px 2px ${color}60`,
}}
/>
</div>
</motion.div>
);
}