|
import { useRef, useEffect } from 'react'; |
|
|
|
|
|
|
|
|
|
export const StatusIndicator = ({ handDetected }) => { |
|
return ( |
|
<div className="absolute bottom-4 left-4 flex items-center"> |
|
<div className={`w-3 h-3 rounded-full ${handDetected ? 'bg-[#217BFE]' : 'bg-gray-400'}`}></div> |
|
<span className={`ml-2 text-xs ${handDetected ? 'text-[#217BFE] font-medium' : 'text-gray-500'}`}> |
|
{handDetected ? 'Hand detected' : 'No hand detected'} |
|
</span> |
|
</div> |
|
); |
|
}; |
|
|
|
|
|
|
|
|
|
export const AudioEffects = ({ isThinking }) => { |
|
const bloopSoundRef = useRef(null); |
|
|
|
|
|
useEffect(() => { |
|
if (isThinking && bloopSoundRef.current) { |
|
bloopSoundRef.current.currentTime = 0; |
|
bloopSoundRef.current.play().catch(err => { |
|
|
|
console.log("Could not play sound effect:", err); |
|
}); |
|
} |
|
}, [isThinking]); |
|
|
|
return ( |
|
<audio |
|
ref={bloopSoundRef} |
|
src="/sounds/bloop.mp3" |
|
preload="auto" |
|
/> |
|
); |
|
}; |
|
|
|
|
|
|
|
|
|
export const AnimationStyles = () => { |
|
return ( |
|
<> |
|
<style jsx global>{` |
|
@keyframes thinking-blink { |
|
0%, 100% { opacity: 1; transform: scale(1); } |
|
50% { opacity: 0.7; transform: scale(0.95); } |
|
} |
|
|
|
@keyframes spring-out { |
|
0% { |
|
transform: scale(0) translateY(0); |
|
opacity: 0; |
|
} |
|
20% { |
|
transform: scale(0.3) translateY(-5px); |
|
opacity: 0.7; |
|
} |
|
40% { |
|
transform: scale(1.5) translateY(-30px); |
|
} |
|
60% { |
|
transform: scale(0.8) translateY(15px); |
|
} |
|
75% { |
|
transform: scale(1.2) translateY(-10px); |
|
} |
|
90% { |
|
transform: scale(0.95) translateY(5px); |
|
} |
|
100% { |
|
transform: scale(1) translateY(0); |
|
opacity: 1; |
|
} |
|
} |
|
|
|
@keyframes wiggle { |
|
0% { transform: rotate(0deg); } |
|
15% { transform: rotate(-15deg); } |
|
30% { transform: rotate(12deg); } |
|
45% { transform: rotate(-8deg); } |
|
60% { transform: rotate(5deg); } |
|
75% { transform: rotate(-2deg); } |
|
100% { transform: rotate(0deg); } |
|
} |
|
|
|
|
|
@keyframes spring-wiggle { |
|
0% { |
|
transform: scale(0) rotate(0deg) translateY(0); |
|
opacity: 0; |
|
} |
|
15% { |
|
transform: scale(0.2) rotate(-5deg) translateY(-5px); |
|
opacity: 0.5; |
|
} |
|
30% { |
|
transform: scale(1.5) rotate(12deg) translateY(-30px); |
|
opacity: 1; |
|
} |
|
45% { |
|
transform: scale(0.8) rotate(-8deg) translateY(15px); |
|
} |
|
60% { |
|
transform: scale(1.2) rotate(5deg) translateY(-10px); |
|
} |
|
75% { |
|
transform: scale(0.95) rotate(-2deg) translateY(5px); |
|
} |
|
90% { |
|
transform: scale(1.05) rotate(1deg) translateY(-2px); |
|
} |
|
100% { |
|
transform: scale(1) rotate(0deg) translateY(0); |
|
} |
|
} |
|
|
|
|
|
@keyframes float-particle { |
|
0% { |
|
transform: translate(0, 0) rotate(0deg); |
|
opacity: 1; |
|
} |
|
100% { |
|
transform: translate(var(--tx), var(--ty)) rotate(var(--r)); |
|
opacity: 0; |
|
} |
|
} |
|
|
|
@keyframes pop-out { |
|
0% { |
|
transform: scale(1); |
|
opacity: 1; |
|
} |
|
50% { |
|
transform: scale(1.2); |
|
} |
|
100% { |
|
transform: scale(0); |
|
opacity: 0; |
|
} |
|
} |
|
|
|
|
|
.particle { |
|
position: absolute; |
|
pointer-events: none; |
|
background: linear-gradient(135deg, #217BFE, #AC87EB); |
|
border-radius: 50%; |
|
animation: float-particle 1s ease-out forwards; |
|
} |
|
|
|
.pop-particle { |
|
position: absolute; |
|
pointer-events: none; |
|
background: linear-gradient(135deg, #217BFE, #AC87EB); |
|
border-radius: 50%; |
|
animation: float-particle 0.6s ease-out forwards; |
|
} |
|
`}</style> |
|
</> |
|
); |
|
}; |