| 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 thinking-spin { |
| 0% { transform: rotate(0deg); } |
| 100% { transform: rotate(360deg); } |
| } |
| |
| @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> |
| </> |
| ); |
| }; |