fix: integrate deepseek, resolve silent google api errors, fix google cloud keys
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2s
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Sidebar } from './layout/Sidebar';
|
||||
import { Topbar } from './layout/Topbar';
|
||||
import { TranslateView } from './views/TranslateView';
|
||||
import { ProfileView } from './views/ProfileView';
|
||||
import { ContextView } from './views/ContextView';
|
||||
import { ApiKeysView } from './views/ApiKeysView';
|
||||
import { GlossaryMainView } from './views/GlossaryMainView';
|
||||
import { PricingView } from './views/PricingView';
|
||||
|
||||
type View = 'translate' | 'profile' | 'context' | 'glossary' | 'api-keys' | 'pricing';
|
||||
|
||||
export const Dashboard: React.FC<{ onLogout: () => void }> = ({ onLogout }) => {
|
||||
const [currentView, setCurrentView] = useState<View>('translate');
|
||||
const [profileTab, setProfileTab] = useState<'account' | 'subscription' | 'preferences'>('account');
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-brand-bg text-brand-dark font-sans">
|
||||
<Sidebar currentView={currentView} setCurrentView={setCurrentView} onLogout={onLogout} />
|
||||
|
||||
<main className="flex-1 flex flex-col overflow-hidden">
|
||||
<Topbar />
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-16">
|
||||
{currentView === 'translate' && <TranslateView />}
|
||||
{currentView === 'profile' && <ProfileView tab={profileTab} setTab={setProfileTab} onUpgrade={() => setCurrentView('pricing')} />}
|
||||
{currentView === 'context' && <ContextView />}
|
||||
{currentView === 'api-keys' && <ApiKeysView />}
|
||||
{currentView === 'glossary' && <GlossaryMainView />}
|
||||
{currentView === 'pricing' && <PricingView onBack={() => setCurrentView('profile')} />}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
ArrowRight,
|
||||
Mail,
|
||||
Lock,
|
||||
Github,
|
||||
Chrome,
|
||||
ChevronLeft
|
||||
} from 'lucide-react';
|
||||
import { motion } from 'motion/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface LoginProps {
|
||||
onLogin: () => void;
|
||||
onBack: () => void;
|
||||
}
|
||||
|
||||
export const Login: React.FC<LoginProps> = ({ onLogin, onBack }) => {
|
||||
const { t } = useTranslation();
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
// Simulate login
|
||||
onLogin();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-brand-bg flex flex-col items-center justify-center p-6 selection:bg-brand-accent/20 overflow-hidden relative">
|
||||
{/* Background Decorative Elements */}
|
||||
<div className="absolute -top-24 -left-24 w-96 h-96 bg-brand-accent/10 rounded-full blur-3xl opacity-50" />
|
||||
<div className="absolute -bottom-24 -right-24 w-96 h-96 bg-brand-dark/5 rounded-full blur-3xl opacity-50" />
|
||||
|
||||
<motion.button
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
onClick={onBack}
|
||||
className="fixed top-12 left-12 flex items-center gap-3 text-[10px] font-black uppercase tracking-[0.4em] text-brand-dark/30 hover:text-brand-dark transition-all group z-10"
|
||||
>
|
||||
<ChevronLeft size={16} className="group-hover:-translate-x-1 transition-transform" />
|
||||
Retour à l'accueil
|
||||
</motion.button>
|
||||
|
||||
<div className="w-full max-w-[480px] relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<div className="inline-flex items-center gap-5 group mb-10">
|
||||
<div className="w-14 h-14 bg-brand-dark rounded-2xl flex items-center justify-center text-white font-bold text-3xl shadow-2xl transition-all duration-500 group-hover:rotate-[15deg] group-hover:scale-110">
|
||||
W
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<span className="text-3xl font-black tracking-tighter uppercase block leading-none">Wordly</span>
|
||||
<span className="text-[9px] font-black uppercase tracking-[0.4em] text-brand-accent">Neural Engine</span>
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-5xl font-black uppercase tracking-tighter mb-4 leading-none text-brand-dark">Connexion</h1>
|
||||
<p className="text-brand-dark/40 font-medium">L'excellence de la traduction, propulsée par l'IA.</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30, scale: 0.98 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1], delay: 0.1 }}
|
||||
className="editorial-card p-12 bg-white border-none shadow-editorial relative overflow-hidden"
|
||||
>
|
||||
<div className="absolute top-0 right-0 w-24 h-24 bg-brand-accent/5 rounded-bl-full pointer-events-none" />
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-8 relative">
|
||||
<div>
|
||||
<label className="text-[9px] font-black text-brand-dark/40 uppercase tracking-[0.2em] block mb-3">Email professionnel</label>
|
||||
<div className="relative group">
|
||||
<Mail className="absolute left-5 top-1/2 -translate-y-1/2 text-brand-dark/20 group-focus-within:text-brand-accent transition-colors" size={18} />
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="sepehr@wordly.art"
|
||||
required
|
||||
className="w-full pl-14 pr-6 py-5 bg-brand-muted rounded-2xl border border-transparent focus:border-brand-accent/30 focus:ring-4 focus:ring-brand-accent/5 outline-none text-sm transition-all font-medium"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-3">
|
||||
<label className="text-[9px] font-black text-brand-dark/40 uppercase tracking-[0.2em]">Mot de passe</label>
|
||||
<button type="button" className="text-[9px] font-black text-brand-accent uppercase tracking-widest hover:underline">Oublié ?</button>
|
||||
</div>
|
||||
<div className="relative group">
|
||||
<Lock className="absolute left-5 top-1/2 -translate-y-1/2 text-brand-dark/20 group-focus-within:text-brand-accent transition-colors" size={18} />
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder="••••••••"
|
||||
required
|
||||
className="w-full pl-14 pr-6 py-5 bg-brand-muted rounded-2xl border border-transparent focus:border-brand-accent/30 focus:ring-4 focus:ring-brand-accent/5 outline-none text-sm transition-all font-medium"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="premium-button w-full py-6 text-[11px] uppercase tracking-[0.3em] flex items-center justify-center gap-3 !rounded-2xl"
|
||||
>
|
||||
Se connecter <ArrowRight size={18} className="text-brand-accent" />
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div className="relative my-12">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-black/5"></div>
|
||||
</div>
|
||||
<div className="relative flex justify-center text-[9px] uppercase tracking-[0.4em] font-black px-4 bg-white text-brand-dark/20">
|
||||
Ou continuer avec
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<button className="flex items-center justify-center gap-3 py-4 border border-black/5 rounded-2xl text-[10px] font-black uppercase tracking-widest hover:bg-brand-muted transition-all">
|
||||
<Github size={16} /> Github
|
||||
</button>
|
||||
<button className="flex items-center justify-center gap-3 py-4 border border-black/5 rounded-2xl text-[10px] font-black uppercase tracking-widest hover:bg-brand-muted transition-all">
|
||||
<Chrome size={16} /> Google
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.p
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="text-center mt-12 text-[10px] font-black uppercase tracking-widest text-brand-dark/30"
|
||||
>
|
||||
Nouveau chez Wordly ? <button className="text-brand-accent hover:underline ml-1">Créer un compte</button>
|
||||
</motion.p>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="fixed bottom-12 text-[9px] font-black uppercase tracking-[0.4em] text-brand-dark/10"
|
||||
>
|
||||
Wordly — Excellence in Neural Translation
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,115 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
FileText,
|
||||
User,
|
||||
Book,
|
||||
Key,
|
||||
Library,
|
||||
Moon,
|
||||
LogOut
|
||||
} from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface SidebarProps {
|
||||
currentView: string;
|
||||
setCurrentView: (view: any) => void;
|
||||
onLogout: () => void;
|
||||
}
|
||||
|
||||
export const Sidebar: React.FC<SidebarProps> = ({ currentView, setCurrentView, onLogout }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<aside className="w-72 border-r border-black/5 bg-white flex flex-col shadow-editorial">
|
||||
<div className="p-8">
|
||||
<div className="flex items-center gap-4 group cursor-pointer" onClick={() => setCurrentView('translate')}>
|
||||
<div className="w-10 h-10 bg-brand-dark rounded-xl flex items-center justify-center text-white font-bold text-2xl shadow-lg transition-transform group-hover:rotate-12">
|
||||
W
|
||||
</div>
|
||||
<span className="text-xl font-black tracking-tighter uppercase">Office Translator</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav className="flex-1 px-4 space-y-1 mt-4">
|
||||
<button
|
||||
onClick={() => setCurrentView('translate')}
|
||||
className={`w-full flex items-center gap-4 px-6 py-4 rounded-2xl text-[11px] font-black uppercase tracking-[0.2em] transition-all ${currentView === 'translate' ? 'bg-brand-dark text-white shadow-xl' : 'text-brand-dark/40 hover:bg-brand-muted hover:text-brand-dark'}`}
|
||||
>
|
||||
<FileText size={18} />
|
||||
Traduire
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentView('profile')}
|
||||
className={`w-full flex items-center gap-4 px-6 py-4 rounded-2xl text-[11px] font-black uppercase tracking-[0.2em] transition-all ${currentView === 'profile' ? 'bg-brand-dark text-white shadow-xl' : 'text-brand-dark/40 hover:bg-brand-muted hover:text-brand-dark'}`}
|
||||
>
|
||||
<User size={18} />
|
||||
Mon Profil
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentView('context')}
|
||||
className={`w-full flex items-center gap-4 px-6 py-4 rounded-2xl text-[11px] font-black uppercase tracking-[0.2em] transition-all ${currentView === 'context' ? 'bg-brand-dark text-white shadow-xl' : 'text-brand-dark/40 hover:bg-brand-muted hover:text-brand-dark'}`}
|
||||
>
|
||||
<Book size={18} />
|
||||
Contexte
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentView('api-keys')}
|
||||
className={`w-full flex items-center gap-4 px-6 py-4 rounded-2xl text-[11px] font-black uppercase tracking-[0.2em] transition-all ${currentView === 'api-keys' ? 'bg-brand-dark text-white shadow-xl' : 'text-brand-dark/40 hover:bg-brand-muted hover:text-brand-dark'}`}
|
||||
>
|
||||
<Key size={18} />
|
||||
Clés API
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentView('glossary')}
|
||||
className={`w-full flex items-center gap-4 px-6 py-4 rounded-2xl text-[11px] font-black uppercase tracking-[0.2em] transition-all ${currentView === 'glossary' ? 'bg-brand-dark text-white shadow-xl' : 'text-brand-dark/40 hover:bg-brand-muted hover:text-brand-dark'}`}
|
||||
>
|
||||
<Library size={18} />
|
||||
Glossaires
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div className="px-6 py-4">
|
||||
<div className="bg-brand-muted/50 rounded-3xl p-6 border border-black/5 group cursor-pointer hover:bg-brand-dark transition-all duration-500">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-8 h-8 bg-brand-dark group-hover:bg-brand-accent rounded-lg flex items-center justify-center text-white text-xs font-black shadow-sm transition-all group-hover:rotate-12">M</div>
|
||||
<span className="text-[10px] font-black uppercase tracking-widest text-brand-dark group-hover:text-white transition-colors">{t('memento.title')}</span>
|
||||
</div>
|
||||
<p className="text-[9px] text-brand-dark/40 group-hover:text-white/60 font-medium leading-relaxed mb-6">
|
||||
{t('memento.slogan').substring(0, 80)}...
|
||||
</p>
|
||||
<div className="flex flex-col gap-2">
|
||||
<button className="w-full py-2.5 bg-brand-dark group-hover:bg-white text-white group-hover:text-brand-dark rounded-xl text-[8px] font-black uppercase tracking-widest shadow-sm transition-all">
|
||||
{t('memento.ctaFree')}
|
||||
</button>
|
||||
<button className="w-full py-2 text-brand-dark/30 group-hover:text-white/40 text-[8px] font-black uppercase tracking-widest transition-all">
|
||||
{t('memento.ctaMore')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6 border-t border-black/5">
|
||||
<div className="flex items-center justify-between group p-4 rounded-2xl hover:bg-brand-muted/50 transition-all">
|
||||
<div className="flex items-center gap-3 overflow-hidden">
|
||||
<div className="w-10 h-10 bg-brand-dark rounded-xl flex items-center justify-center text-white text-[11px] font-bold shadow-sm transition-transform group-hover:rotate-6">SR</div>
|
||||
<div className="overflow-hidden">
|
||||
<p className="text-[11px] font-black uppercase tracking-tight truncate">Sepehr Ramezani</p>
|
||||
<p className="text-[9px] text-brand-dark/40 font-bold truncate">sepehr1151@gmail.com</p>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<span className="accent-pill !px-1.5 !py-0 text-[7px] uppercase tracking-widest bg-brand-accent/10 border-brand-accent/20">pro</span>
|
||||
<button className="text-brand-dark/20 hover:text-brand-dark transition-colors"><Moon size={10} /></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={onLogout}
|
||||
className="p-2 text-brand-dark/20 hover:text-red-500 transition-colors"
|
||||
title="Déconnexion"
|
||||
>
|
||||
<LogOut size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { Moon } from 'lucide-react';
|
||||
|
||||
export const Topbar: React.FC = () => {
|
||||
return (
|
||||
<header className="h-20 border-b border-black/5 bg-white/50 backdrop-blur-md px-12 flex items-center justify-between">
|
||||
<span className="text-[10px] font-bold uppercase tracking-[0.4em] text-brand-dark/30">Interface de traduction</span>
|
||||
<div className="flex items-center gap-6">
|
||||
<button className="p-3 text-brand-dark/30 hover:text-brand-dark transition-colors bg-brand-muted rounded-xl"><Moon size={18} /></button>
|
||||
<div className="h-6 w-[1px] bg-black/10"></div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-right">
|
||||
<p className="text-[10px] font-black uppercase leading-none">Premium Access</p>
|
||||
<p className="text-[9px] text-brand-accent font-bold uppercase tracking-widest mt-1">Status: Active</p>
|
||||
</div>
|
||||
<div className="w-10 h-10 rounded-xl bg-brand-dark flex items-center justify-center text-white text-xs font-black">SR</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { Clock } from 'lucide-react';
|
||||
|
||||
export const ApiKeysView: React.FC = () => {
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="mb-12">
|
||||
<span className="accent-pill mb-4 block w-fit">Accès API</span>
|
||||
<h1 className="text-5xl font-black uppercase tracking-tighter mb-4 leading-none">Clés API</h1>
|
||||
<p className="text-brand-dark/40 font-medium">Intégrez Office Translator directement dans vos outils.</p>
|
||||
</div>
|
||||
|
||||
<div className="editorial-card p-12 bg-white border-none shadow-editorial">
|
||||
<div className="flex items-center justify-between p-8 bg-brand-muted rounded-3xl border border-black/5">
|
||||
<div>
|
||||
<p className="text-[9px] text-brand-dark/40 font-black uppercase tracking-[0.3em] mb-2">Clé de production</p>
|
||||
<p className="text-sm font-mono text-brand-dark">sk_live_************************************</p>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<button className="p-3 bg-white rounded-xl text-brand-dark/40 hover:text-brand-dark border border-black/5 transition-all"><Clock size={16}/></button>
|
||||
<button className="px-6 py-3 bg-brand-dark text-white rounded-xl text-[9px] font-black uppercase tracking-widest">Révéler</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Zap,
|
||||
Wrench,
|
||||
HardHat,
|
||||
Monitor,
|
||||
Scale,
|
||||
Stethoscope,
|
||||
BarChart3,
|
||||
Megaphone,
|
||||
Car,
|
||||
MessageSquare,
|
||||
Save,
|
||||
Database
|
||||
} from 'lucide-react';
|
||||
|
||||
export const ContextView: React.FC = () => {
|
||||
return (
|
||||
<div className="max-w-5xl mx-auto">
|
||||
<div className="mb-12">
|
||||
<span className="accent-pill mb-4 block w-fit italic">Personnalisation IA</span>
|
||||
<h1 className="text-5xl font-black uppercase tracking-tighter mb-4 leading-none">Contexte & Glossaire</h1>
|
||||
<p className="text-brand-dark/40 font-medium max-w-2xl">Améliorez la qualité de traduction avec des instructions et un vocabulaire spécifiques à votre domaine.</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-12">
|
||||
{/* Professional Glossaries */}
|
||||
<section className="editorial-card p-12 bg-white border-none shadow-editorial">
|
||||
<div className="flex items-center gap-4 mb-8 text-brand-accent">
|
||||
<Zap size={20} />
|
||||
<h3 className="text-[11px] font-black uppercase tracking-[0.3em] text-brand-dark">Glossaires professionnels</h3>
|
||||
</div>
|
||||
<p className="text-sm text-brand-dark/40 mb-12 font-medium">Chargez un glossaire complet avec instructions et terminologie spécialisée</p>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
{[
|
||||
{ id: 'hvac', label: 'HVAC / Génie climatique', desc: 'Thermique, ventilation, climatisation', icon: <Wrench size={24} /> },
|
||||
{ id: 'btp', label: 'BTP / Construction', desc: 'Gros œuvre, second œuvre, normes', icon: <HardHat size={24} /> },
|
||||
{ id: 'it', label: 'IT / Logiciel', desc: 'Développement, infrastructure, DevOps', icon: <Monitor size={24} /> },
|
||||
{ id: 'legal', label: 'Juridique / Contrats', desc: 'Droit des affaires, contentieux', icon: <Scale size={24} /> },
|
||||
{ id: 'medical', label: 'Médical / Santé', desc: 'Pharmacologie, chirurgie, diagnostic', icon: <Stethoscope size={24} /> },
|
||||
{ id: 'finance', label: 'Finance / Comptabilité', desc: 'IFRS, bilans, fiscalité', icon: <BarChart3 size={24} /> },
|
||||
{ id: 'marketing', label: 'Marketing / Publicité', desc: 'Digital, branding, analytics', icon: <Megaphone size={24} /> },
|
||||
{ id: 'auto', label: 'Automobile', desc: 'Motorisation, ADAS, homologation', icon: <Car size={24} /> },
|
||||
].map((p) => (
|
||||
<button key={p.id} className="p-6 bg-brand-muted hover:bg-brand-dark group transition-all rounded-[32px] text-center border border-black/5 hover:shadow-2xl hover:-translate-y-1">
|
||||
<div className="flex justify-center mb-4 text-brand-dark group-hover:text-brand-accent group-hover:scale-125 transition-all">
|
||||
{p.icon}
|
||||
</div>
|
||||
<h4 className="text-[11px] font-black uppercase tracking-tight text-brand-dark group-hover:text-white mb-2">{p.label}</h4>
|
||||
<p className="text-[8px] text-brand-dark/30 group-hover:text-white/40 font-bold uppercase tracking-widest leading-relaxed">{p.desc}</p>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Context Instructions */}
|
||||
<section className="editorial-card p-12 bg-white border-none shadow-editorial">
|
||||
<div className="flex items-center gap-4 mb-8 text-brand-accent">
|
||||
<MessageSquare size={20} />
|
||||
<h3 className="text-[11px] font-black uppercase tracking-[0.3em] text-brand-dark">Instructions de contexte</h3>
|
||||
</div>
|
||||
<p className="text-sm text-brand-dark/40 mb-10 font-medium">Instructions que l'IA suivra pendant la traduction</p>
|
||||
<textarea
|
||||
className="w-full h-48 p-8 bg-brand-muted rounded-[32px] border border-black/5 text-sm focus:ring-2 focus:ring-brand-accent/20 focus:border-brand-accent/30 transition-all outline-none"
|
||||
placeholder="Ex : Vous traduisez des documents techniques HVAC. Utilisez une terminologie d'ingénierie précise..."
|
||||
/>
|
||||
<div className="flex justify-end mt-6 gap-4">
|
||||
<button className="px-8 py-3 bg-brand-muted text-brand-dark/40 rounded-xl text-[9px] font-black uppercase tracking-widest hover:text-brand-dark transition-all">Effacer</button>
|
||||
<button className="premium-button px-10 py-3 text-[9px] uppercase tracking-widest !rounded-xl flex items-center gap-3"><Save size={14}/> Enregistrer</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Technical Glossary */}
|
||||
<section className="editorial-card p-12 bg-white border-none shadow-editorial">
|
||||
<div className="flex items-center gap-4 mb-8 text-brand-accent">
|
||||
<Database size={20} />
|
||||
<h3 className="text-[11px] font-black uppercase tracking-[0.3em] text-brand-dark">Glossaire technique</h3>
|
||||
</div>
|
||||
<p className="text-sm text-brand-dark/40 mb-10 font-medium">Format : source=cible (un par ligne). Les glossaires chargés via preset sont modifiables.</p>
|
||||
<textarea
|
||||
className="w-full h-64 p-8 bg-brand-muted rounded-[32px] border border-black/5 text-sm font-mono focus:ring-2 focus:ring-brand-accent/20 focus:border-brand-accent/30 transition-all outline-none"
|
||||
defaultValue={`pression statique=static pressure\nrécupérateur de chaleur=heat recovery unit`}
|
||||
/>
|
||||
<div className="flex justify-between items-center mt-6">
|
||||
<span className="text-[9px] text-brand-dark/20 font-black uppercase tracking-widest">2 termes définis</span>
|
||||
<div className="flex gap-4">
|
||||
<button className="px-8 py-3 bg-brand-muted text-brand-dark/40 rounded-xl text-[9px] font-black uppercase tracking-widest hover:text-brand-dark transition-all">Importer CSV</button>
|
||||
<button className="premium-button px-10 py-3 text-[9px] uppercase tracking-widest !rounded-xl flex items-center gap-3"><Save size={14}/> Appliquer</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { Library } from 'lucide-react';
|
||||
|
||||
export const GlossaryMainView: React.FC = () => {
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="flex justify-between items-end mb-12">
|
||||
<div>
|
||||
<span className="accent-pill mb-4 block w-fit">Bibliothèque</span>
|
||||
<h1 className="text-5xl font-black uppercase tracking-tighter mb-4 leading-none">Mes Glossaires</h1>
|
||||
<p className="text-brand-dark/40 font-medium">Gérez vos listes de terminologies personnalisées.</p>
|
||||
</div>
|
||||
<button className="premium-button px-10 py-4 text-[11px] uppercase tracking-widest !rounded-2xl">+ Nouveau glossaire</button>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{[
|
||||
{ name: 'Technique HVAC', count: 124, date: '12 Mai 2026', type: 'Ingénierie' },
|
||||
{ name: 'Marketing Digital', count: 45, date: '10 Mai 2026', type: 'Communication' },
|
||||
{ name: 'Contrats Vente', count: 89, date: '08 Mai 2026', type: 'Juridique' },
|
||||
].map((g, i) => (
|
||||
<div key={i} className="editorial-card p-8 bg-white border-none shadow-editorial group hover:-translate-y-2 transition-all">
|
||||
<div className="flex justify-between items-start mb-10">
|
||||
<div className="w-12 h-12 bg-brand-muted rounded-2xl flex items-center justify-center text-brand-accent group-hover:bg-brand-dark group-hover:text-white transition-all">
|
||||
<Library size={24} />
|
||||
</div>
|
||||
<span className="text-[8px] bg-brand-accent/10 text-brand-accent px-3 py-1 rounded-full font-black uppercase tracking-widest">{g.type}</span>
|
||||
</div>
|
||||
<h3 className="text-2xl font-black uppercase tracking-tight mb-2 text-brand-dark">{g.name}</h3>
|
||||
<div className="flex justify-between items-center pt-8 border-t border-black/5">
|
||||
<span className="text-[9px] text-brand-dark/30 font-black uppercase tracking-widest">{g.count} termes</span>
|
||||
<span className="text-[9px] text-brand-dark/30 font-black uppercase tracking-widest">{g.date}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,313 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
CheckCircle2,
|
||||
ArrowRight,
|
||||
Zap,
|
||||
ChevronLeft,
|
||||
ShieldCheck,
|
||||
Globe,
|
||||
Star,
|
||||
Activity,
|
||||
Layers,
|
||||
FileText
|
||||
} from 'lucide-react';
|
||||
import { motion } from 'motion/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface PricingViewProps {
|
||||
onBack: () => void;
|
||||
}
|
||||
|
||||
export const PricingView: React.FC<PricingViewProps> = ({ onBack }) => {
|
||||
const { t } = useTranslation();
|
||||
const [isAnnual, setIsAnnual] = useState(true);
|
||||
|
||||
const plans = [
|
||||
{
|
||||
id: 'free',
|
||||
name: 'Free',
|
||||
title: 'Gratuit',
|
||||
desc: 'Parfait pour découvrir l\'application',
|
||||
price: { monthly: 0, annual: 0 },
|
||||
color: 'bg-brand-muted !text-brand-dark',
|
||||
iconColor: 'text-brand-dark/20',
|
||||
metrics: { docs: '2 / mois', pages: '10 p / doc' },
|
||||
features: [
|
||||
'5 documents / mois',
|
||||
'Jusqu\'à 15 pages par document',
|
||||
'Google Traduction inclus',
|
||||
'Toutes les langues (130+)',
|
||||
'Support communautaire'
|
||||
],
|
||||
cta: 'Choisir ce forfait'
|
||||
},
|
||||
{
|
||||
id: 'starter',
|
||||
name: 'Starter',
|
||||
title: '7 €',
|
||||
period: '/mois',
|
||||
desc: 'Pour les particuliers et petits projets',
|
||||
price: { monthly: 9, annual: 7 },
|
||||
color: 'bg-brand-dark',
|
||||
iconColor: 'text-white/20',
|
||||
metrics: { docs: '50 / mois', pages: '50 p / doc' },
|
||||
features: [
|
||||
'50 documents / mois',
|
||||
'Jusqu\'à 50 pages par document',
|
||||
'Google Traduction + DeepL',
|
||||
'Fichiers jusqu\'à 10 Mo',
|
||||
'Support par e-mail',
|
||||
'Historique 30 jours'
|
||||
],
|
||||
cta: 'Choisir ce forfait'
|
||||
},
|
||||
{
|
||||
id: 'pro',
|
||||
name: 'Pro',
|
||||
title: '19 €',
|
||||
period: '/mois',
|
||||
desc: 'Pour les professionnels et équipes en croissance',
|
||||
price: { monthly: 25, annual: 19 },
|
||||
color: 'bg-brand-accent',
|
||||
iconColor: 'text-white/30',
|
||||
popular: true,
|
||||
current: true,
|
||||
metrics: { docs: '200 / mois', pages: '200 p / doc' },
|
||||
features: [
|
||||
'200 documents / mois',
|
||||
'Jusqu\'à 200 pages par document',
|
||||
'Traduction IA Essentielle (DeepSeek V3.2)',
|
||||
'Google Traduction + DeepL',
|
||||
'Fichiers jusqu\'à 25 Mo',
|
||||
'Glossaires personnalisés',
|
||||
'Support prioritaire',
|
||||
'Historique 90 jours'
|
||||
],
|
||||
cta: 'Gérer mon forfait'
|
||||
},
|
||||
{
|
||||
id: 'business',
|
||||
name: 'Business',
|
||||
title: '49 €',
|
||||
period: '/mois',
|
||||
desc: 'Pour les équipes et organisations',
|
||||
price: { monthly: 65, annual: 49 },
|
||||
color: 'bg-brand-dark',
|
||||
iconColor: 'text-brand-accent/40',
|
||||
metrics: { docs: '1000 / mois', pages: '500 p / doc' },
|
||||
features: [
|
||||
'1 000 documents / mois',
|
||||
'Jusqu\'à 500 pages par document',
|
||||
'IA Essentielle + Premium (Claude Haiku)',
|
||||
'Tous les fournisseurs de traduction',
|
||||
'Fichiers jusqu\'à 50 Mo',
|
||||
'Accès API (10 000 appels/mois)',
|
||||
'Webhooks de notification',
|
||||
'Support dédié',
|
||||
'Historique 1 an',
|
||||
'Analytiques avancées'
|
||||
],
|
||||
cta: 'Choisir ce forfait'
|
||||
},
|
||||
{
|
||||
id: 'enterprise',
|
||||
name: 'Enterprise',
|
||||
title: 'Sur devis',
|
||||
desc: 'Solutions sur mesure pour grandes organisations',
|
||||
price: { monthly: 'Sur devis', annual: 'Sur devis' },
|
||||
color: 'bg-[#252525]',
|
||||
iconColor: 'text-white/10',
|
||||
tag: 'ON REQUEST',
|
||||
metrics: { docs: 'Illimité', pages: 'Illimité' },
|
||||
features: [
|
||||
'Documents illimités',
|
||||
'Tous les modèles IA (GPT-5, Claude Opus 4.6...)',
|
||||
'Déploiement on-premise ou cloud dédié',
|
||||
'SLA 99,9 % garanti',
|
||||
'Support 24/7 dédié',
|
||||
'Marque blanche (white-label)',
|
||||
'Équipes illimitées',
|
||||
'Intégrations sur mesure'
|
||||
],
|
||||
cta: 'Nous contacter'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="max-w-[1400px] mx-auto pb-20">
|
||||
<div className="flex justify-between items-center mb-20">
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="flex items-center gap-3 text-[10px] font-black uppercase tracking-[0.4em] text-brand-dark/30 hover:text-brand-dark transition-all group"
|
||||
>
|
||||
<ChevronLeft size={16} className="group-hover:-translate-x-1 transition-transform" />
|
||||
Retour
|
||||
</button>
|
||||
|
||||
<div className="flex gap-2 p-1.5 bg-brand-muted rounded-full border border-black/5 shadow-inner">
|
||||
<button
|
||||
onClick={() => onBack()}
|
||||
className="px-6 py-2 rounded-full text-[9px] font-black uppercase tracking-widest text-brand-dark/40 hover:text-brand-dark transition-all"
|
||||
>
|
||||
Dashboard
|
||||
</button>
|
||||
<button className="px-6 py-2 bg-white rounded-full text-[9px] font-black uppercase tracking-widest text-brand-dark shadow-sm border border-black/5">
|
||||
Mon abonnement
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center mb-20">
|
||||
<span className="accent-pill !bg-transparent border border-black/5 mb-6 block w-fit mx-auto scale-90">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-brand-accent rounded-full animate-pulse" />
|
||||
<span className="text-[10px] font-black tracking-[0.3em] opacity-40">Modèles IA mis à jour — Mars 2026</span>
|
||||
</div>
|
||||
</span>
|
||||
<h1 className="text-7xl font-black uppercase tracking-tighter mb-6 leading-none">
|
||||
Un forfait pour <span className="text-brand-accent">chaque besoin</span>
|
||||
</h1>
|
||||
<p className="text-brand-dark/40 font-medium text-xl max-w-2xl mx-auto leading-relaxed">
|
||||
Traduisez vos documents Word, Excel et PowerPoint en conservant la mise en page originale. Sans jamais saisir de clé API.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center gap-10 mb-20">
|
||||
<div className="flex p-1 bg-brand-muted rounded-full border border-black/5 shadow-inner px-2">
|
||||
<button
|
||||
onClick={() => setIsAnnual(false)}
|
||||
className={`px-8 py-3 rounded-full text-[10px] font-black uppercase tracking-widest transition-all ${!isAnnual ? 'bg-brand-dark text-white shadow-xl' : 'text-brand-dark/60 hover:text-brand-dark'}`}
|
||||
>
|
||||
Mensuel
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsAnnual(true)}
|
||||
className={`px-8 py-3 rounded-full text-[10px] font-black uppercase tracking-widest transition-all ${isAnnual ? 'bg-brand-dark text-white shadow-xl' : 'text-brand-dark/60 hover:text-brand-dark'}`}
|
||||
>
|
||||
Annuel <span className={`ml-2 transition-colors ${isAnnual ? 'text-brand-accent' : 'text-brand-accent/60'}`}>-20 %</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 lg:grid-cols-5 gap-6 items-stretch">
|
||||
{plans.map((p) => (
|
||||
<div
|
||||
key={p.id}
|
||||
className={`flex flex-col bg-white rounded-[24px] border border-black/[0.08] overflow-hidden transition-all duration-500 hover:shadow-[0_20px_50px_rgba(0,0,0,0.08)] hover:-translate-y-2 group ${p.popular ? 'border-brand-accent/30 ring-4 ring-brand-accent/5' : ''}`}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className={`p-8 ${p.color} text-white relative h-48 flex flex-col justify-end`}>
|
||||
{p.popular && (
|
||||
<div className="absolute top-0 right-0 p-3 flex gap-2">
|
||||
<span className="bg-brand-dark/20 backdrop-blur-md text-white text-[8px] font-black uppercase tracking-widest px-3 py-1 rounded-full border border-white/20 shadow-lg">POPULAR</span>
|
||||
<span className="bg-brand-dark/40 backdrop-blur-md text-white text-[8px] font-black uppercase tracking-widest px-3 py-1 rounded-full border border-white/20 shadow-lg flex items-center gap-1">
|
||||
<div className="w-1.5 h-1.5 bg-brand-accent rounded-full animate-pulse" /> Mon forfait
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{p.tag && (
|
||||
<div className="absolute top-0 right-0 p-3">
|
||||
<span className="bg-white/10 backdrop-blur-md text-white text-[8px] font-black uppercase tracking-widest px-3 py-1 rounded-full border border-white/10">{p.tag}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
{p.id === 'free' && <Star size={20} className={p.iconColor} />}
|
||||
{p.id === 'starter' && <Zap size={20} className={p.iconColor} />}
|
||||
{p.id === 'pro' && <Crown size={20} className={p.iconColor} />}
|
||||
{p.id === 'business' && <Globe size={20} className={p.iconColor} />}
|
||||
{p.id === 'enterprise' && <ShieldCheck size={20} className={p.iconColor} />}
|
||||
<span className={`text-sm font-black uppercase tracking-widest ${p.id === 'free' ? 'text-brand-dark/40' : 'text-white/50'}`}>{p.name}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-baseline gap-2">
|
||||
<h3 className={`text-3xl font-black uppercase tracking-tighter ${p.id === 'free' ? 'text-brand-dark' : 'text-white'}`}>{isAnnual && typeof p.price.annual === 'number' ? p.price.annual + ' €' : (p.price.monthly === 'Sur devis' ? 'Sur devis' : p.title)}</h3>
|
||||
{p.period && <span className={`text-[10px] font-bold uppercase tracking-widest ${p.id === 'free' ? 'text-brand-dark/30' : 'text-white/40'}`}>{p.period}</span>}
|
||||
</div>
|
||||
|
||||
<p className={`text-[10px] font-medium uppercase mt-3 tracking-widest leading-relaxed ${p.id === 'free' ? 'text-brand-dark/40' : 'text-white/60'}`}>
|
||||
{p.desc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="p-8 flex-1 flex flex-col">
|
||||
{/* Metrics Box */}
|
||||
<div className="space-y-2 mb-10">
|
||||
<div className="flex justify-between items-center py-2 border-b border-black/[0.03]">
|
||||
<div className="flex items-center gap-2">
|
||||
<FileText size={12} className="text-brand-dark/20" />
|
||||
<span className="text-[9px] font-black uppercase tracking-widest text-brand-dark/40">Documents</span>
|
||||
</div>
|
||||
<span className="text-[10px] font-black uppercase text-brand-dark">{p.metrics.docs}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center py-2 border-b border-black/[0.03]">
|
||||
<div className="flex items-center gap-2">
|
||||
<Layers size={12} className="text-brand-dark/20" />
|
||||
<span className="text-[9px] font-black uppercase tracking-widest text-brand-dark/40">Pages max</span>
|
||||
</div>
|
||||
<span className="text-[10px] font-black uppercase text-brand-dark">{p.metrics.pages}</span>
|
||||
</div>
|
||||
{p.id === 'pro' && (
|
||||
<div className="flex justify-between items-center py-3 bg-brand-accent/5 px-3 rounded-lg mt-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Activity size={12} className="text-brand-accent/40" />
|
||||
<span className="text-[9px] font-black uppercase tracking-widest text-brand-accent/60">Traduction IA</span>
|
||||
</div>
|
||||
<span className="text-[9px] font-black uppercase text-brand-accent">Essentielle</span>
|
||||
</div>
|
||||
)}
|
||||
{p.id === 'business' && (
|
||||
<div className="flex justify-between items-center py-3 bg-brand-dark/5 px-3 rounded-lg mt-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Activity size={12} className="text-brand-dark/20" />
|
||||
<span className="text-[9px] font-black uppercase tracking-widest text-brand-dark/40">Traduction IA</span>
|
||||
</div>
|
||||
<span className="text-[9px] font-black uppercase text-brand-dark">Premium</span>
|
||||
</div>
|
||||
)}
|
||||
{p.id === 'enterprise' && (
|
||||
<div className="flex justify-between items-center py-3 bg-black/5 px-3 rounded-lg mt-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Activity size={12} className="text-brand-dark/20" />
|
||||
<span className="text-[9px] font-black uppercase tracking-widest text-brand-dark/40">Traduction IA</span>
|
||||
</div>
|
||||
<span className="text-[9px] font-black uppercase text-brand-dark">Custom</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Features */}
|
||||
<ul className="space-y-4 mb-12 flex-1">
|
||||
{p.features.map((f, i) => (
|
||||
<li key={i} className="flex items-start gap-3">
|
||||
<div className="w-4 h-4 rounded-full bg-brand-accent/10 flex items-center justify-center shrink-0 mt-0.5">
|
||||
<CheckCircle2 size={10} className="text-brand-accent" />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-brand-dark/60 leading-normal">{f}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
{/* CTA */}
|
||||
<button
|
||||
className={`w-full py-4 rounded-2xl text-[11px] font-black uppercase tracking-widest transition-all flex items-center justify-center gap-3 border shadow-sm hover:shadow-xl active:scale-95 ${p.id === 'pro' ? 'bg-brand-muted text-brand-dark border-black/5 hover:bg-brand-dark hover:text-white' : (p.id === 'starter' || p.id === 'business' || p.id === 'enterprise' ? 'bg-brand-dark text-white border-transparent hover:bg-brand-accent' : 'bg-brand-dark text-white border-transparent hover:bg-brand-accent')}`}
|
||||
>
|
||||
{p.cta}
|
||||
<ArrowRight size={14} className="opacity-40" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Crown = ({ size, className }: { size: number, className: string }) => (
|
||||
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
|
||||
<path d="M2 4l3 12h14l3-12-6 7-4-7-4 7-6-7z" />
|
||||
<path d="M12 17v4" />
|
||||
<path d="M9 21h6" />
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,198 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Globe,
|
||||
Activity,
|
||||
FileText,
|
||||
Layers,
|
||||
Zap,
|
||||
Crown,
|
||||
CheckCircle2,
|
||||
ChevronDown
|
||||
} from 'lucide-react';
|
||||
|
||||
interface ProfileViewProps {
|
||||
tab: string;
|
||||
setTab: (t: any) => void;
|
||||
onUpgrade: () => void;
|
||||
}
|
||||
|
||||
export const ProfileView: React.FC<ProfileViewProps> = ({ tab, setTab, onUpgrade }) => {
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="mb-12">
|
||||
<span className="accent-pill mb-4 block w-fit">Compte utilisateur</span>
|
||||
<h1 className="text-5xl font-black uppercase tracking-tighter mb-4 leading-none">Mon Profil</h1>
|
||||
<p className="text-brand-dark/40 font-medium">Gérez votre compte et vos préférences de traduction.</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 p-2 bg-brand-muted rounded-2xl mb-12 w-fit border border-black/5">
|
||||
{['account', 'subscription', 'preferences'].map((t) => (
|
||||
<button
|
||||
key={t}
|
||||
onClick={() => setTab(t)}
|
||||
className={`px-10 py-3 rounded-xl text-[11px] font-black uppercase tracking-widest transition-all ${tab === t ? 'bg-brand-dark text-white shadow-xl' : 'text-brand-dark/30 hover:text-brand-dark'}`}
|
||||
>
|
||||
{t === 'account' ? 'Compte' : t === 'subscription' ? 'Abonnement' : 'Préférences'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{tab === 'account' && (
|
||||
<div className="editorial-card p-12 flex items-center gap-10 bg-white border-none shadow-editorial">
|
||||
<div className="w-24 h-24 bg-brand-dark rounded-[32px] flex items-center justify-center text-white text-4xl font-black shadow-2xl">SR</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-4 mb-3">
|
||||
<h2 className="text-3xl font-black uppercase tracking-tight">Sepehr Ramezani</h2>
|
||||
<span className="accent-pill !px-3 !py-1 text-[9px]">Gérant</span>
|
||||
</div>
|
||||
<p className="text-[11px] font-bold uppercase tracking-widest text-brand-dark/40 mb-3 flex items-center gap-2">
|
||||
<Globe size={12} className="text-brand-accent"/> sepehr1151@gmail.com
|
||||
</p>
|
||||
<p className="text-[9px] text-brand-dark/20 font-black uppercase tracking-widest">Membre d'élite depuis le 10 mai 2026</p>
|
||||
</div>
|
||||
<button className="px-8 py-3 border border-black/10 rounded-xl text-[10px] font-black uppercase tracking-widest hover:bg-brand-muted transition-all">Modifier</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tab === 'subscription' && (
|
||||
<div className="space-y-8">
|
||||
<div className="editorial-card !bg-brand-dark p-12 flex items-center justify-between text-white border-none shadow-2xl relative overflow-hidden">
|
||||
{/* Decorative element */}
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-brand-accent/10 rounded-bl-full pointer-events-none" />
|
||||
|
||||
<div className="flex items-center gap-8 relative z-10">
|
||||
<div className="w-16 h-16 bg-white/10 backdrop-blur-xl rounded-2xl flex items-center justify-center text-brand-accent border border-white/10 shadow-inner">
|
||||
<Crown size={28} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-3">
|
||||
<h3 className="text-2xl font-black uppercase tracking-tight text-white">Forfait Pro</h3>
|
||||
<span className="px-3 py-1 bg-brand-accent/20 rounded-full text-[9px] font-black uppercase tracking-widest text-brand-accent border border-brand-accent/30 shadow-sm">Actif</span>
|
||||
</div>
|
||||
<p className="text-white/60 text-[10px] font-black uppercase tracking-widest mt-1">Facturation mensuelle • 19 €/mois</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={onUpgrade}
|
||||
className="relative z-10 px-10 py-4 bg-white text-brand-dark rounded-xl font-black text-[10px] uppercase tracking-widest shadow-xl hover:scale-105 transition-all"
|
||||
>
|
||||
Changer de forfait
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="editorial-card p-12 bg-white border-none shadow-editorial">
|
||||
<div className="flex justify-between items-center mb-12">
|
||||
<div className="flex items-center gap-4 text-brand-accent">
|
||||
<Activity size={20} />
|
||||
<span className="text-[11px] font-black uppercase tracking-[0.3em] text-brand-dark">Métriques d'utilisation</span>
|
||||
</div>
|
||||
<span className="text-[9px] font-black text-brand-dark/20 uppercase tracking-widest border-b border-black/10 pb-1">Reset prévu le 1 juin 2026</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-16">
|
||||
<div>
|
||||
<div className="flex justify-between text-[10px] font-black uppercase tracking-widest mb-4">
|
||||
<span className="flex items-center gap-3 text-brand-dark/40"><FileText size={16} className="text-brand-accent"/> Documents</span>
|
||||
<span className="text-brand-dark font-black">5 / 200</span>
|
||||
</div>
|
||||
<div className="h-2 bg-brand-muted rounded-full overflow-hidden p-0.5 border border-black/5">
|
||||
<div className="h-full bg-brand-accent rounded-full shadow-[0_0_10px_rgba(197,161,122,0.5)]" style={{ width: '2.5%' }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex justify-between text-[10px] font-black uppercase tracking-widest mb-4">
|
||||
<span className="flex items-center gap-3 text-brand-dark/40"><Layers size={16} className="text-brand-accent"/> Pages</span>
|
||||
<span className="text-brand-dark font-black">13 / 200</span>
|
||||
</div>
|
||||
<div className="h-2 bg-brand-muted rounded-full overflow-hidden p-0.5 border border-black/5">
|
||||
<div className="h-full bg-brand-accent rounded-full shadow-[0_0_10px_rgba(197,161,122,0.5)]" style={{ width: '6.5%' }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-16 p-8 bg-brand-muted rounded-[32px] border border-black/5 flex items-center justify-between group">
|
||||
<div className="flex items-center gap-6 text-brand-dark">
|
||||
<div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center text-brand-accent shadow-sm group-hover:rotate-12 transition-transform">
|
||||
<Zap size={24} />
|
||||
</div>
|
||||
<p className="text-[11px] font-black uppercase tracking-tight max-w-[200px] leading-relaxed">Passez au niveau supérieur pour des documents illimités.</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={onUpgrade}
|
||||
className="px-8 py-3 bg-brand-dark text-white rounded-xl text-[9px] font-black uppercase tracking-widest shadow-lg hover:bg-brand-accent transition-all"
|
||||
>
|
||||
Voir les offres
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="editorial-card p-12 bg-white border-none shadow-editorial">
|
||||
<div className="flex items-center gap-4 text-brand-accent mb-12">
|
||||
<CheckCircle2 size={20} />
|
||||
<span className="text-[11px] font-black uppercase tracking-[0.3em] text-brand-dark">Inclus dans votre forfait</span>
|
||||
</div>
|
||||
<div className="grid md:grid-cols-2 gap-y-6 gap-x-12">
|
||||
{[
|
||||
"200 documents / mois",
|
||||
"Jusqu'à 200 pages par document",
|
||||
"Traduction IA Essentielle (DeepSeek V3.2)",
|
||||
"Google Traduction + DeepL",
|
||||
"Fichiers jusqu'à 25 Mo",
|
||||
"Glossaires personnalisés",
|
||||
"Support prioritaire",
|
||||
"Historique 90 jours"
|
||||
].map((feature, i) => (
|
||||
<div key={i} className="flex items-center gap-3">
|
||||
<div className="w-5 h-5 rounded-full border border-brand-accent/30 flex items-center justify-center bg-brand-accent/5">
|
||||
<CheckCircle2 size={12} className="text-brand-accent" />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold uppercase tracking-tight text-brand-dark/60">{feature}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tab === 'preferences' && (
|
||||
<div className="space-y-8">
|
||||
<div className="editorial-card p-12 bg-white border-none shadow-editorial">
|
||||
<div className="flex items-center gap-5 mb-12">
|
||||
<div className="w-12 h-12 bg-brand-muted rounded-2xl flex items-center justify-center text-brand-accent">
|
||||
<Globe size={24} />
|
||||
</div>
|
||||
<h3 className="text-2xl font-black uppercase tracking-tight text-brand-dark">Langue de l'interface</h3>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-4">
|
||||
{['English', 'Français', 'Español', 'Deutsch', 'Português', 'Italiano', 'Nederlands', 'Русский', '日本語', '한국어'].map((l) => (
|
||||
<button key={l} className={`px-6 py-4 rounded-2xl text-[10px] font-black uppercase tracking-widest border transition-all ${l === 'Français' ? 'bg-brand-dark border-brand-dark text-white shadow-xl' : 'bg-white border-black/5 text-brand-dark/30 hover:border-brand-accent/30 hover:text-brand-dark'}`}>
|
||||
{l}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<p className="mt-12 text-[9px] text-brand-dark/20 font-black uppercase tracking-widest italic border-t border-black/5 pt-6">La langue est détectée automatiquement selon votre navigateur.</p>
|
||||
</div>
|
||||
|
||||
<div className="editorial-card p-12 bg-white border-none shadow-editorial flex items-center justify-between">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="w-14 h-14 bg-brand-muted rounded-2xl flex items-center justify-center text-brand-accent">
|
||||
<FileText size={28} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-black uppercase tracking-tight text-brand-dark">Cible par défaut</h3>
|
||||
<p className="text-brand-dark/30 text-[10px] font-black uppercase tracking-widest mt-2 leading-relaxed">Pré-sélection automatique lors de l'import.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<div className="px-8 py-4 bg-brand-muted rounded-2xl text-[10px] font-black uppercase tracking-widest flex items-center gap-5 border border-black/5">
|
||||
Français <ChevronDown size={14} className="text-brand-accent" />
|
||||
</div>
|
||||
<button className="premium-button px-10 py-4 text-[10px] uppercase tracking-widest !rounded-2xl">Enregistrer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,163 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
CheckCircle2,
|
||||
Download,
|
||||
Activity,
|
||||
Upload,
|
||||
Globe,
|
||||
Zap,
|
||||
Clock,
|
||||
Presentation,
|
||||
FileText
|
||||
} from 'lucide-react';
|
||||
import { motion } from 'motion/react';
|
||||
|
||||
interface StatusOverlayProps {
|
||||
status: string;
|
||||
progress: number;
|
||||
onReset: () => void;
|
||||
}
|
||||
|
||||
export const StatusOverlay: React.FC<StatusOverlayProps> = ({ status, progress, onReset }) => {
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="mb-12">
|
||||
<span className="accent-pill mb-4 block w-fit italic">Traitement en cours</span>
|
||||
<h1 className="text-5xl font-black uppercase tracking-tighter mb-4 leading-none">Analyse IA Active</h1>
|
||||
<p className="text-brand-dark/40 font-medium">Votre mise en page est en cours de préservation</p>
|
||||
</div>
|
||||
|
||||
<div className="grid lg:grid-cols-12 gap-12">
|
||||
<div className="lg:col-span-8">
|
||||
<div className="editorial-card p-16 h-full border-none shadow-editorial bg-white">
|
||||
{status === 'done' ? (
|
||||
<div className="h-full flex flex-col">
|
||||
<div className="p-8 bg-brand-accent/5 border border-brand-accent/10 rounded-[32px] flex items-center justify-between mb-16 shadow-inner">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="w-14 h-14 bg-brand-accent rounded-full flex items-center justify-center text-white shadow-xl">
|
||||
<CheckCircle2 size={28} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[13px] font-black uppercase tracking-[0.1em] text-brand-dark">Traduction terminée</p>
|
||||
<p className="text-[10px] text-brand-dark/40 font-bold uppercase mt-1 tracking-widest">super_complex_translated.pptx</p>
|
||||
</div>
|
||||
</div>
|
||||
<span className="px-5 py-2 bg-white rounded-full text-[9px] font-black uppercase tracking-widest text-brand-accent border border-brand-accent/20 shadow-sm">✓ Qualité Maître</span>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 flex flex-col items-center justify-center py-20 bg-brand-muted/20 rounded-[40px] border border-black/5">
|
||||
<button className="premium-button px-24 py-6 text-xl !rounded-full flex items-center gap-6 mb-8 group">
|
||||
<Download size={28} className="group-hover:translate-y-1 transition-transform" />
|
||||
Télécharger
|
||||
</button>
|
||||
<button
|
||||
onClick={onReset}
|
||||
className="text-[10px] font-black uppercase tracking-[0.3em] text-brand-dark/20 hover:text-brand-dark transition-colors"
|
||||
>
|
||||
+ Nouvelle traduction
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center gap-6 mb-20">
|
||||
<div className="w-16 h-16 bg-brand-muted rounded-2xl flex items-center justify-center text-brand-accent border border-brand-accent/10 animate-pulse">
|
||||
<Activity size={32} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-black uppercase tracking-tight mb-2">Moteur contextuel actif</h3>
|
||||
<p className="text-[10px] text-brand-dark/30 font-black uppercase tracking-widest">super_complex_document.docx</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress Line */}
|
||||
<div className="relative h-2 bg-brand-muted rounded-full mb-24">
|
||||
<div className="absolute top-1/2 left-0 w-full -translate-y-1/2 flex justify-between px-2">
|
||||
{[Upload, Activity, Globe, Zap, CheckCircle2].map((Icon, i) => (
|
||||
<div key={i} className={`w-12 h-12 rounded-2xl border-4 border-white shadow-xl flex items-center justify-center z-10 transition-all duration-500 ${progress > (i * 25) ? 'bg-brand-dark text-white scale-110' : 'bg-brand-muted text-brand-dark/20'}`}>
|
||||
<Icon size={18} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<motion.div
|
||||
className="absolute top-0 left-0 h-full bg-brand-accent shadow-[0_0_20px_rgba(197,161,122,0.4)]"
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: `${progress}%` }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<span className="text-[10px] font-black text-brand-dark/30 uppercase tracking-[0.3em]">{status === 'uploading' ? 'Phase 1: Initialisation' : 'Phase 2: Reconstruction Contextuelle'}</span>
|
||||
<span className="text-7xl font-black text-brand-dark">{progress}%</span>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-4 gap-6 pt-12 border-t border-black/5">
|
||||
{[
|
||||
{ label: 'segments', val: progress + '%', icon: <FileText size={18}/> },
|
||||
{ label: 'précision', val: '99.9%', icon: <Zap size={18} /> },
|
||||
{ label: 'vitesse', val: 'Turbo', icon: <Clock size={18} /> },
|
||||
{ label: 'temps', val: '0:01', icon: <Activity size={18} /> }
|
||||
].map((s, i) => (
|
||||
<div key={i} className="p-6 bg-brand-muted/30 rounded-3xl text-center border border-transparent hover:border-brand-accent/10 transition-all">
|
||||
<div className="text-brand-accent flex justify-center mb-4">{s.icon}</div>
|
||||
<p className="text-[12px] font-black text-brand-dark mb-1 uppercase tracking-tight">{s.val}</p>
|
||||
<p className="text-[8px] font-black text-brand-dark/30 uppercase tracking-[0.2em]">{s.label}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="lg:col-span-4">
|
||||
<div className="editorial-card p-10 bg-white border-none shadow-editorial h-full">
|
||||
<h4 className="text-[10px] font-black uppercase tracking-[0.4em] mb-12 flex items-center gap-3 text-brand-dark/30">
|
||||
<div className="w-2 h-2 bg-brand-accent rounded-full animate-ping" />
|
||||
Moniteur IA
|
||||
</h4>
|
||||
|
||||
<div className="p-6 bg-brand-muted rounded-[32px] mb-10 flex items-center gap-5 border border-black/5">
|
||||
<div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center text-brand-accent shadow-sm">
|
||||
<Presentation size={24} />
|
||||
</div>
|
||||
<div className="overflow-hidden">
|
||||
<p className="text-[11px] font-black uppercase tracking-tight truncate">super_complex_translated.pptx</p>
|
||||
<p className="text-[9px] text-brand-dark/40 font-bold uppercase tracking-widest mt-1">89.1 KB • PowerPoint</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-8 mb-16 px-2">
|
||||
<div className="flex justify-between items-center text-[10px] font-black uppercase tracking-[0.4em] text-brand-dark/30">
|
||||
<span>Source</span>
|
||||
<span className="text-brand-dark">AUTO</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-[10px] font-black uppercase tracking-[0.4em] text-brand-dark/30">
|
||||
<span>Cible</span>
|
||||
<span className="text-brand-accent">FRANÇAIS</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-[10px] font-black uppercase tracking-[0.4em] text-brand-dark/30">
|
||||
<span>Algorithme</span>
|
||||
<span className="text-brand-dark">NEURAL V4</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-10 border-t border-black/10">
|
||||
<div className="flex justify-between text-[10px] font-black uppercase tracking-[0.4em] mb-4">
|
||||
<span className="text-brand-dark/30">Intégrité Layout</span>
|
||||
<span className="text-brand-accent">100% SECURE</span>
|
||||
</div>
|
||||
<div className="h-2 bg-brand-muted rounded-full overflow-hidden p-0.5">
|
||||
<motion.div animate={{ width: progress + '%' }} className="h-full bg-brand-accent rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button className="w-full mt-16 py-5 border border-red-50 text-red-500 rounded-2xl text-[10px] font-black uppercase tracking-[0.3em] flex items-center justify-center gap-3 hover:bg-red-50 transition-all">
|
||||
⟳ Annuler le processus
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Upload,
|
||||
FileText,
|
||||
ChevronDown,
|
||||
ArrowRight
|
||||
} from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StatusOverlay } from './StatusOverlay';
|
||||
|
||||
export const TranslateView: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const [status, setStatus] = useState<'idle' | 'uploading' | 'translating' | 'done'>('idle');
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
const handleStart = () => {
|
||||
setStatus('uploading');
|
||||
let p = 0;
|
||||
const interval = setInterval(() => {
|
||||
p += 5;
|
||||
setProgress(p);
|
||||
if (p >= 25) setStatus('translating');
|
||||
if (p >= 100) {
|
||||
clearInterval(interval);
|
||||
setStatus('done');
|
||||
}
|
||||
}, 150);
|
||||
};
|
||||
|
||||
if (status !== 'idle') {
|
||||
return <StatusOverlay status={status} progress={progress} onReset={() => setStatus('idle')} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="mb-12">
|
||||
<span className="accent-pill mb-4 block w-fit">Nouveau projet</span>
|
||||
<h1 className="text-5xl font-black uppercase tracking-tighter mb-4 leading-none">Traduire un document</h1>
|
||||
<p className="text-brand-dark/40 font-medium">Importez un fichier et choisissez la langue cible</p>
|
||||
</div>
|
||||
|
||||
<div className="grid lg:grid-cols-12 gap-12">
|
||||
<div className="lg:col-span-8">
|
||||
<div className="bg-white border-2 border-dashed border-brand-accent/20 rounded-[40px] p-20 flex flex-col items-center justify-center text-center group cursor-pointer hover:border-brand-accent transition-all shadow-editorial">
|
||||
<div className="w-20 h-20 bg-brand-muted rounded-3xl flex items-center justify-center text-brand-accent group-hover:scale-110 group-hover:bg-brand-dark group-hover:text-white transition-all mb-8 shadow-sm">
|
||||
<Upload size={32} />
|
||||
</div>
|
||||
<h3 className="text-2xl font-black uppercase tracking-tight mb-4 text-brand-dark">Glissez-déposez ici</h3>
|
||||
<p className="text-sm text-brand-dark/40 mb-12 font-medium">Fichiers DOCX, XLSX, PPTX ou PDF supportés</p>
|
||||
<div className="flex flex-wrap justify-center gap-4">
|
||||
{['Word', 'Excel', 'Slides', 'PDF'].map(f => (
|
||||
<span key={f} className="flex items-center gap-3 px-4 py-2 bg-brand-muted rounded-xl text-[10px] font-black uppercase tracking-widest text-brand-dark/60 border border-transparent hover:border-brand-accent/30 transition-all">
|
||||
<FileText size={12} className="text-brand-accent"/> {f}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="lg:col-span-4 space-y-8">
|
||||
<div className="editorial-card p-10 bg-white border-none">
|
||||
<h4 className="text-[10px] font-black uppercase tracking-[0.3em] mb-10 text-brand-dark/30 border-b border-black/5 pb-6">Configuration</h4>
|
||||
|
||||
<div className="space-y-8">
|
||||
<div>
|
||||
<label className="text-[9px] font-black text-brand-dark/40 uppercase tracking-[0.2em] block mb-3">Langue source</label>
|
||||
<div className="w-full p-4 bg-brand-muted rounded-2xl border border-transparent flex items-center justify-between cursor-pointer hover:border-brand-accent/20 transition-all">
|
||||
<span className="text-[11px] font-black uppercase tracking-widest">Auto-détection</span>
|
||||
<ChevronDown size={16} className="text-brand-accent" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-[9px] font-black text-brand-dark/40 uppercase tracking-[0.2em] block mb-3">Langue cible</label>
|
||||
<div className="w-full p-4 bg-brand-muted rounded-2xl border border-brand-accent/30 flex items-center justify-between cursor-pointer hover:border-brand-accent transition-all ring-2 ring-brand-accent/5">
|
||||
<span className="text-[11px] font-black uppercase tracking-widest text-brand-dark">Français</span>
|
||||
<ChevronDown size={16} className="text-brand-accent" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-[9px] font-black text-brand-dark/40 uppercase tracking-[0.2em] block mb-6">Moteur de traduction</label>
|
||||
<div className="space-y-4">
|
||||
<div className="p-5 border-2 border-brand-accent bg-brand-accent/5 rounded-2xl flex items-start gap-4">
|
||||
<div className="w-5 h-5 rounded-full border-2 border-brand-accent bg-white flex items-center justify-center mt-0.5 shrink-0">
|
||||
<div className="w-2.5 h-2.5 bg-brand-accent rounded-full" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[11px] font-black uppercase tracking-tight text-brand-dark mb-1 leading-none">Intelligence Visuelle</p>
|
||||
<p className="text-[9px] text-brand-dark/50 font-bold uppercase tracking-widest leading-relaxed">Maintien strict du formatage</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-5 border border-black/5 bg-brand-muted/30 rounded-2xl flex items-start gap-4 grayscale opacity-40">
|
||||
<div className="w-5 h-5 rounded-full border-2 border-black/10 bg-white mt-0.5 shrink-0" />
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<p className="text-[11px] font-black uppercase tracking-tight text-brand-dark leading-none">GPT-4o Enhanced</p>
|
||||
<span className="text-[8px] bg-brand-dark text-white px-2 py-0.5 rounded-full font-black uppercase tracking-widest">pro</span>
|
||||
</div>
|
||||
<p className="text-[9px] text-brand-dark/50 font-bold uppercase tracking-widest">Traduction créative contextualisée</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleStart}
|
||||
className="premium-button w-full py-6 text-[11px] uppercase tracking-[0.3em] flex items-center justify-center gap-3 !rounded-2xl"
|
||||
>
|
||||
Lancer la traduction <ArrowRight size={18} className="text-brand-accent" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between px-6 text-[9px] font-black uppercase tracking-[0.2em] text-brand-dark/20">
|
||||
<span className="flex items-center gap-2">✓ Rétention zéro</span>
|
||||
<span className="flex items-center gap-2">🕒 Privacy auto</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Momento Promotion Banner */}
|
||||
<div className="mt-20 editorial-card p-12 bg-white border-none shadow-editorial flex flex-col md:flex-row items-center gap-10 group overflow-hidden relative">
|
||||
<div className="absolute -right-20 -top-20 w-64 h-64 bg-brand-accent/5 rounded-full blur-3xl group-hover:bg-brand-accent/10 transition-colors" />
|
||||
|
||||
<div className="w-24 h-24 bg-brand-dark rounded-[32px] flex items-center justify-center text-white text-5xl font-black shadow-2xl shrink-0 group-hover:rotate-12 transition-transform duration-500">
|
||||
M
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-4 mb-4">
|
||||
<span className="accent-pill !px-3 !py-1 text-[9px] italic">Ecosystème Wordly</span>
|
||||
<h3 className="text-2xl font-black uppercase tracking-tight">{t('memento.title')}</h3>
|
||||
</div>
|
||||
<p className="text-sm text-brand-dark/40 font-medium leading-relaxed max-w-2xl">
|
||||
{t('memento.slogan')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4 shrink-0 w-full md:w-auto">
|
||||
<button className="premium-button px-10 py-4 text-[11px] uppercase tracking-widest !rounded-2xl">
|
||||
{t('memento.ctaFree')}
|
||||
</button>
|
||||
<button className="px-10 py-4 border border-black/5 bg-brand-muted text-brand-dark/40 rounded-2xl text-[10px] font-black uppercase tracking-widest hover:text-brand-dark transition-all">
|
||||
{t('memento.ctaMore')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user