Files
breakpilot-core/pitch-deck/components/slides/IntroPresenterSlide.tsx
Benjamin Admin bcbceba31c feat(presenter): add browser TTS (Web Speech API) + fix German umlauts
- Integrate Web Speech API into usePresenterMode for text-to-speech
- Speech-driven paragraph advancement (falls back to timer if TTS unavailable)
- TTS toggle button (Volume2/VolumeX) in PresenterOverlay
- Chrome keepAlive workaround for long speeches
- Voice selection: prefers premium/neural voices, falls back to any matching lang
- Fix all German umlauts across presenter-script, presenter-faq, i18n, route.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 12:11:12 +01:00

117 lines
4.7 KiB
TypeScript

'use client'
import { motion } from 'framer-motion'
import { Play, MessageCircle, Pause } from 'lucide-react'
import { Language } from '@/lib/types'
import GradientText from '../ui/GradientText'
interface IntroPresenterSlideProps {
lang: Language
onStartPresenter?: () => void
isPresenting?: boolean
}
export default function IntroPresenterSlide({ lang, onStartPresenter, isPresenting }: IntroPresenterSlideProps) {
const isDE = lang === 'de'
return (
<div className="h-full flex flex-col items-center justify-center px-8 text-center">
{/* Avatar Placeholder Circle */}
<motion.div
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 0.6, ease: 'easeOut' }}
className="relative mb-8"
>
<div className="w-32 h-32 rounded-full bg-gradient-to-br from-indigo-500/30 to-purple-500/30 border-2 border-indigo-400/40 flex items-center justify-center">
{/* Pulse rings */}
<motion.div
className="absolute inset-0 rounded-full border-2 border-indigo-400/20"
animate={{ scale: [1, 1.3, 1], opacity: [0.4, 0, 0.4] }}
transition={{ duration: 2, repeat: Infinity, ease: 'easeInOut' }}
/>
<motion.div
className="absolute inset-0 rounded-full border-2 border-purple-400/20"
animate={{ scale: [1, 1.5, 1], opacity: [0.3, 0, 0.3] }}
transition={{ duration: 2.5, repeat: Infinity, ease: 'easeInOut', delay: 0.3 }}
/>
{/* Bot icon */}
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="text-indigo-300">
<rect x="3" y="11" width="18" height="10" rx="2" />
<circle cx="12" cy="5" r="2" />
<path d="M12 7v4" />
<circle cx="8" cy="16" r="1" fill="currentColor" />
<circle cx="16" cy="16" r="1" fill="currentColor" />
</svg>
</div>
</motion.div>
{/* Title */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.5 }}
>
<h1 className="text-4xl md:text-5xl font-bold mb-3">
<GradientText>{isDE ? 'KI-Präsentator' : 'AI Presenter'}</GradientText>
</h1>
<p className="text-lg text-white/60 max-w-lg mx-auto mb-8">
{isDE
? 'Ihr persönlicher KI-Guide durch das BreakPilot ComplAI Pitch Deck. 15 Minuten, alle Fakten, jederzeit unterbrechbar.'
: 'Your personal AI guide through the BreakPilot ComplAI pitch deck. 15 minutes, all facts, interruptible at any time.'}
</p>
</motion.div>
{/* Start Button */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5, duration: 0.5 }}
>
<button
onClick={onStartPresenter}
className="group relative px-8 py-4 rounded-2xl bg-gradient-to-r from-indigo-600 to-purple-600
hover:from-indigo-500 hover:to-purple-500 transition-all duration-300
text-white font-semibold text-lg shadow-lg shadow-indigo-600/30
hover:shadow-xl hover:shadow-indigo-600/40 hover:scale-105"
>
<span className="flex items-center gap-3">
{isPresenting ? (
<>
<Pause className="w-5 h-5" />
{isDE ? 'Präsentation läuft...' : 'Presentation running...'}
</>
) : (
<>
<Play className="w-5 h-5" />
{isDE ? 'Präsentation starten' : 'Start Presentation'}
</>
)}
</span>
</button>
</motion.div>
{/* Interaction hints */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.8, duration: 0.5 }}
className="mt-10 flex flex-col md:flex-row gap-4 text-sm text-white/40"
>
<div className="flex items-center gap-2">
<MessageCircle className="w-4 h-4" />
<span>{isDE ? 'Jederzeit Fragen im Chat stellen' : 'Ask questions in chat anytime'}</span>
</div>
<div className="flex items-center gap-2">
<span className="px-1.5 py-0.5 bg-white/10 rounded text-xs font-mono">P</span>
<span>{isDE ? 'Taste P: Presenter An/Aus' : 'Press P: Toggle Presenter'}</span>
</div>
<div className="flex items-center gap-2">
<span className="px-1.5 py-0.5 bg-white/10 rounded text-xs font-mono">ESC</span>
<span>{isDE ? 'Slide-Übersicht' : 'Slide Overview'}</span>
</div>
</motion.div>
</div>
)
}