128 lines
4.9 KiB
TypeScript
128 lines
4.9 KiB
TypeScript
|
|
import React, { useState } from 'react';
|
|
import { MessageCircle, Sparkles, Mic2, BookOpen, X, ArrowRight, Check, Globe } from 'lucide-react';
|
|
import { Language } from '../types';
|
|
import { translations } from '../utils/localization';
|
|
|
|
interface OnboardingProps {
|
|
language: Language;
|
|
setLanguage: (lang: Language) => void;
|
|
onComplete: () => void;
|
|
}
|
|
|
|
const Onboarding: React.FC<OnboardingProps> = ({ language, setLanguage, onComplete }) => {
|
|
const t = translations[language].onboarding;
|
|
const [step, setStep] = useState(0);
|
|
|
|
const steps = [
|
|
{
|
|
title: t.step1Title,
|
|
desc: t.step1Desc,
|
|
icon: <MessageCircle size={48} className="text-indigo-500" />,
|
|
color: 'bg-indigo-50',
|
|
},
|
|
{
|
|
title: t.step2Title,
|
|
desc: t.step2Desc,
|
|
icon: <Mic2 size={48} className="text-orange-500" />,
|
|
color: 'bg-orange-50',
|
|
},
|
|
{
|
|
title: t.step3Title,
|
|
desc: t.step3Desc,
|
|
icon: <Sparkles size={48} className="text-blue-500" />,
|
|
color: 'bg-blue-50',
|
|
}
|
|
];
|
|
|
|
const handleNext = () => {
|
|
if (step < steps.length - 1) {
|
|
setStep(step + 1);
|
|
} else {
|
|
onComplete();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-[100] bg-slate-900/60 backdrop-blur-sm flex items-center justify-center p-4 animate-fade-in">
|
|
<div className="bg-white rounded-3xl shadow-2xl max-w-md w-full overflow-hidden relative animate-scale-in">
|
|
{/* Skip/Close */}
|
|
<button onClick={onComplete} className="absolute top-4 right-4 text-white/80 hover:text-white z-10">
|
|
<X size={24} />
|
|
</button>
|
|
|
|
{/* Header Image/Graphic */}
|
|
<div className="h-48 bg-gradient-to-br from-pink-400 to-rose-500 flex flex-col items-center justify-center relative overflow-hidden">
|
|
<div className="absolute -bottom-10 -left-10 w-32 h-32 bg-white/20 rounded-full blur-xl"></div>
|
|
<div className="absolute top-10 right-10 w-20 h-20 bg-white/20 rounded-full blur-lg"></div>
|
|
|
|
<Sparkles className="text-white w-16 h-16 mb-2 animate-pulse" />
|
|
<h2 className="text-2xl font-extrabold text-white tracking-tight">Sakura Sensei</h2>
|
|
|
|
{/* Language Switcher in Header (Step 0) */}
|
|
{step === 0 && (
|
|
<div className="mt-4 flex gap-2 bg-white/20 p-1 rounded-full backdrop-blur-sm">
|
|
{(['en', 'ja', 'zh'] as Language[]).map(lang => (
|
|
<button
|
|
key={lang}
|
|
onClick={() => setLanguage(lang)}
|
|
className={`px-3 py-1 rounded-full text-xs font-bold transition-all ${
|
|
language === lang ? 'bg-white text-rose-500 shadow-md' : 'text-white hover:bg-white/20'
|
|
}`}
|
|
>
|
|
{lang === 'en' ? 'English' : lang === 'ja' ? '日本語' : '中文'}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="p-8">
|
|
<div className="mb-6">
|
|
<h3 className="text-2xl font-bold text-slate-800 mb-2">{t.welcome}</h3>
|
|
<p className="text-slate-500">{t.desc1}</p>
|
|
</div>
|
|
|
|
{/* Step Card */}
|
|
<div className="relative h-48">
|
|
{steps.map((s, idx) => (
|
|
<div
|
|
key={idx}
|
|
className={`absolute inset-0 flex flex-col items-center text-center transition-all duration-500 transform ${
|
|
idx === step ? 'opacity-100 translate-x-0' : idx < step ? 'opacity-0 -translate-x-full' : 'opacity-0 translate-x-full'
|
|
}`}
|
|
>
|
|
<div className={`w-20 h-20 rounded-2xl ${s.color} flex items-center justify-center mb-4 shadow-inner`}>
|
|
{s.icon}
|
|
</div>
|
|
<h4 className="text-lg font-bold text-slate-800 mb-2">{s.title}</h4>
|
|
<p className="text-sm text-slate-500 leading-relaxed">{s.desc}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Controls */}
|
|
<div className="flex items-center justify-between mt-8">
|
|
{/* Indicators */}
|
|
<div className="flex gap-2">
|
|
{steps.map((_, idx) => (
|
|
<div key={idx} className={`h-2 rounded-full transition-all duration-300 ${idx === step ? 'w-6 bg-indigo-500' : 'w-2 bg-slate-200'}`} />
|
|
))}
|
|
</div>
|
|
|
|
<button
|
|
onClick={handleNext}
|
|
className="flex items-center gap-2 px-6 py-3 bg-slate-900 text-white rounded-xl font-bold hover:bg-slate-800 transition-all active:scale-95 shadow-lg"
|
|
>
|
|
{step === steps.length - 1 ? t.startBtn : translations[language].common.next}
|
|
{step === steps.length - 1 ? <Check size={18} /> : <ArrowRight size={18} />}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Onboarding;
|