import { useState, useEffect } from 'react'; import { X, Snail, Rocket, SkipForward } from '@/lib/lucide-icons'; import { useTranslation } from 'react-i18next'; interface WebGPUFallbackDialogProps { isOpen: boolean; onClose: () => void; onUseCPU: () => void; onSkip: () => void; nodeCount: number; } /** * Fun dialog shown when WebGPU isn't available * Lets user choose: CPU fallback (slow) or skip embeddings */ export const WebGPUFallbackDialog = ({ isOpen, onClose, onUseCPU, onSkip, nodeCount, }: WebGPUFallbackDialogProps) => { const { t } = useTranslation('graph'); const [isAnimating, setIsAnimating] = useState(true); const [isVisible, setIsVisible] = useState(false); useEffect(() => { if (isOpen) { // Trigger animation after mount requestAnimationFrame(() => setIsVisible(true)); } else { setIsVisible(false); } }, [isOpen]); if (!isOpen) return null; // Estimate time based on node count (rough: ~50ms per node on CPU) const estimatedMinutes = Math.ceil((nodeCount * 50) / 60000); const isSmallCodebase = nodeCount < 200; return (
{/* Backdrop */}
{/* Dialog */}
{/* Header with scratching emoji */}
{/* Animated emoji */}
setIsAnimating(false)} onClick={() => setIsAnimating(true)} > 🤔

{t('embedding.fallback.title')}

{t('embedding.fallback.subtitle')}

{/* Content */}

{t('embedding.fallback.description')}

{t('embedding.fallback.options')}

  • {t('embedding.fallback.useCpu')}{' '} —{' '} {isSmallCodebase ? t('embedding.fallback.useCpuDescriptionSmall') : t('embedding.fallback.useCpuDescriptionLarge')} {nodeCount > 0 && ( {' '} {t('embedding.fallback.estimated', { minutes: estimatedMinutes, count: nodeCount, })} )}
  • {t('embedding.fallback.skipIt')}{' '} — {t('embedding.fallback.skipDescription')}
{isSmallCodebase && (

{t('embedding.fallback.smallCodebase')}

)}

{t('embedding.fallback.tip')}

{/* Actions */}
); };