← back to Dear Bubbe Nextjs
components/TalkButton.tsx
72 lines
'use client'
import { useState, useEffect } from 'react'
interface TalkButtonProps {
onClick: () => void
isActive?: boolean
showPulse?: boolean
}
export default function TalkButton({ onClick, isActive = false, showPulse = true }: TalkButtonProps) {
const [isHovered, setIsHovered] = useState(false)
return (
<button
onClick={onClick}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={`fixed bottom-6 right-6 z-40 group transition-all transform hover:scale-110 active:scale-95 touch-manipulation ${
isActive ? 'scale-110' : ''
} md:bottom-6 md:right-6 sm:bottom-4 sm:right-4`}
aria-label="Talk to Bubbe"
>
{/* Pulse Animation */}
{showPulse && !isActive && (
<>
<div className="absolute inset-0 bg-amber-500 rounded-full animate-ping opacity-25"></div>
<div className="absolute inset-0 bg-amber-500 rounded-full animate-ping animation-delay-200 opacity-25"></div>
</>
)}
{/* Main Button */}
<div className={`relative w-20 h-20 min-w-[64px] min-h-[64px] rounded-full shadow-2xl transition-all ${
isActive
? 'bg-gradient-to-br from-green-500 to-green-600'
: 'bg-gradient-to-br from-amber-500 to-orange-600'
} flex items-center justify-center md:w-20 md:h-20 sm:w-16 sm:h-16`}>
{/* Icon */}
<div className="text-white">
{isActive ? (
// Active/Talking state
<svg className="w-10 h-10 md:w-10 md:h-10 sm:w-8 sm:h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
d="M5.636 18.364a9 9 0 010-12.728m12.728 0a9 9 0 010 12.728m-9.9-2.829a5 5 0 010-7.07m7.072 0a5 5 0 010 7.07M13 12a1 1 0 11-2 0 1 1 0 012 0z" />
</svg>
) : (
// Inactive state - microphone
<svg className="w-10 h-10 md:w-10 md:h-10 sm:w-8 sm:h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" />
</svg>
)}
</div>
{/* Label on Hover - Hidden on mobile to avoid touch issues */}
{isHovered && (
<div className="absolute -top-12 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white px-3 py-1 rounded-lg text-sm whitespace-nowrap hidden md:block">
{isActive ? 'Bubbe is listening...' : 'Talk to Bubbe'}
<div className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-1/2 rotate-45 w-2 h-2 bg-gray-800"></div>
</div>
)}
</div>
{/* Text Label */}
<div className={`mt-1 text-xs md:text-sm font-semibold transition-colors ${
isActive ? 'text-green-600' : 'text-amber-600'
}`}>
{isActive ? 'TALKING' : 'TALK'}
</div>
</button>
)
}