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:
573
wordly.art---traduction-de-documents-2/src/App.tsx
Normal file
573
wordly.art---traduction-de-documents-2/src/App.tsx
Normal file
@@ -0,0 +1,573 @@
|
||||
/**
|
||||
* @license
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
FileText,
|
||||
Layers,
|
||||
MousePointer2,
|
||||
Download,
|
||||
Globe,
|
||||
Cpu,
|
||||
CheckCircle2,
|
||||
ArrowRight,
|
||||
Layout,
|
||||
PieChart,
|
||||
FileSpreadsheet,
|
||||
Presentation,
|
||||
MessageSquare,
|
||||
ShieldCheck,
|
||||
Zap,
|
||||
Menu,
|
||||
X,
|
||||
Languages,
|
||||
Monitor,
|
||||
Eye,
|
||||
Lock,
|
||||
Clock,
|
||||
Activity
|
||||
} from 'lucide-react';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Dashboard } from './components/Dashboard';
|
||||
|
||||
const Logo = () => (
|
||||
<div className="flex items-center gap-4 group cursor-pointer">
|
||||
<div className="w-10 h-10 bg-brand-dark rounded-xl flex items-center justify-center text-white font-bold text-2xl shadow-xl transition-all duration-500 group-hover:rotate-[15deg] group-hover:scale-110">
|
||||
W
|
||||
</div>
|
||||
<span className="text-2xl font-bold tracking-tighter text-brand-dark">
|
||||
Wordly<span className="text-brand-accent">.art</span>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
const Navbar = ({ onLogin }: { onLogin: () => void }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
const toggleLanguage = () => {
|
||||
const nextLang = i18n.language === 'fr' ? 'en' : 'fr';
|
||||
i18n.changeLanguage(nextLang);
|
||||
};
|
||||
|
||||
return (
|
||||
<nav className="fixed top-0 left-0 right-0 z-50 bg-brand-bg/80 backdrop-blur-md border-b border-black/5">
|
||||
<div className="max-w-7xl mx-auto px-6 h-20 flex justify-between items-center">
|
||||
<Logo />
|
||||
|
||||
<div className="hidden md:flex items-center space-x-10">
|
||||
<a href="#features" className="text-brand-dark/60 hover:text-brand-dark transition-colors text-[11px] font-bold uppercase tracking-widest">{t('nav.why')}</a>
|
||||
<a href="#formats" className="text-brand-dark/60 hover:text-brand-dark transition-colors text-[11px] font-bold uppercase tracking-widest">{t('nav.formats')}</a>
|
||||
<a href="#pricing" className="text-brand-dark/60 hover:text-brand-dark transition-colors text-[11px] font-bold uppercase tracking-widest">{t('nav.pricing')}</a>
|
||||
<div className="h-4 w-[1px] bg-black/10"></div>
|
||||
<button
|
||||
onClick={toggleLanguage}
|
||||
className="text-[10px] font-bold text-brand-dark hover:text-brand-accent transition-colors uppercase tracking-[0.2em]"
|
||||
>
|
||||
{i18n.language === 'fr' ? 'English' : 'Français'}
|
||||
</button>
|
||||
<button onClick={onLogin} className="premium-button py-2.5 px-6 leading-none">
|
||||
{t('nav.startFree')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="md:hidden">
|
||||
<button onClick={() => setIsOpen(!isOpen)} className="text-brand-dark p-2 hover:bg-black/5 rounded-lg transition-colors">
|
||||
{isOpen ? <X size={24} /> : <Menu size={24} />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
className="md:hidden bg-white border-b border-gray-100 overflow-hidden"
|
||||
>
|
||||
<div className="px-6 pt-4 pb-10 space-y-4 text-center">
|
||||
<button
|
||||
onClick={toggleLanguage}
|
||||
className="w-full py-2 text-sm font-black text-[#004777] bg-gray-50 rounded-xl"
|
||||
>
|
||||
{t('common.language', { lang: i18n.language === 'fr' ? 'English' : 'Français' })}
|
||||
<span className="ml-2 opacity-50 uppercase">{i18n.language === 'fr' ? 'en' : 'fr'}</span>
|
||||
</button>
|
||||
<a href="#features" onClick={() => setIsOpen(false)} className="block py-3 text-lg font-bold text-gray-700">{t('nav.why')}</a>
|
||||
<a href="#formats" onClick={() => setIsOpen(false)} className="block py-3 text-lg font-bold text-gray-700">{t('nav.formats')}</a>
|
||||
<a href="#pricing" onClick={() => setIsOpen(false)} className="block py-3 text-lg font-bold text-gray-700">{t('nav.pricing')}</a>
|
||||
<div className="pt-6 grid grid-cols-2 gap-4">
|
||||
<button onClick={onLogin} className="flex items-center justify-center py-4 text-brand-dark/60 font-bold border-2 border-black/5 rounded-2xl">{t('nav.login')}</button>
|
||||
<button onClick={onLogin} className="flex items-center justify-center py-4 bg-brand-dark text-white rounded-2xl font-bold">{t('nav.startFree')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
const Hero = ({ onLogin }: { onLogin: () => void }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<section className="relative pt-48 pb-32 lg:pt-64 lg:pb-48 px-4 text-center">
|
||||
<div className="max-w-5xl mx-auto relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
<div className="inline-flex items-center gap-2 px-4 py-1.5 mb-10 text-[10px] font-bold tracking-[0.3em] text-brand-dark/40 uppercase bg-transparent border border-black/10 rounded-full">
|
||||
<Languages size={10} /> {t('hero.tag')}
|
||||
</div>
|
||||
<h1 className="text-7xl lg:text-9xl mb-10 text-brand-dark font-extrabold uppercase">
|
||||
{t('hero.titleLine1')}<br />
|
||||
<span className="block mt-4">{t('hero.titleLine2')}</span>
|
||||
</h1>
|
||||
<p className="text-lg lg:text-xl text-brand-dark/50 mb-14 max-w-2xl mx-auto leading-relaxed font-medium">
|
||||
{t('hero.description')}
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-24">
|
||||
<button onClick={onLogin} className="premium-button px-12 py-5 text-base">
|
||||
{t('hero.ctaMain')}
|
||||
</button>
|
||||
<button className="px-12 py-5 rounded-xl border border-black/10 font-bold text-base hover:bg-black/5 transition-all">
|
||||
{t('hero.ctaSec')}
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.98, y: 30 }}
|
||||
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||
transition={{ duration: 1.2, ease: [0.16, 1, 0.3, 1], delay: 0.2 }}
|
||||
className="relative max-w-5xl mx-auto"
|
||||
>
|
||||
<div className="editorial-card p-4 lg:p-6 overflow-hidden bg-brand-muted/30">
|
||||
<div className="aspect-[16/9] lg:aspect-[21/9] bg-white rounded-2xl relative overflow-hidden shadow-sm border border-black/5">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1499951360447-b19be8fe80f5?auto=format&fit=crop&q=80&w=2000"
|
||||
alt="Workspace"
|
||||
className="w-full h-full object-cover filter saturate-[0.8] grayscale-[0.1]"
|
||||
referrerPolicy="no-referrer"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-brand-dark/5" />
|
||||
|
||||
{/* Floating Badges */}
|
||||
<div className="absolute top-8 right-8 w-64 bg-white/90 backdrop-blur-xl border border-black/5 p-6 rounded-2xl shadow-2xl text-left hidden md:block">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-8 h-8 rounded-full bg-brand-accent/20 flex items-center justify-center text-brand-accent">
|
||||
<Zap size={16} />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold uppercase tracking-widest text-brand-dark">Context Engine</span>
|
||||
</div>
|
||||
<p className="text-xs text-brand-dark/70 leading-relaxed font-medium">"Translation detected: Technical maintenance term for HVAC systems..."</p>
|
||||
</div>
|
||||
|
||||
<div className="absolute bottom-8 left-8 w-64 bg-brand-dark text-white p-6 rounded-2xl shadow-2xl text-left hidden md:block">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<Activity size={16} className="text-brand-accent" />
|
||||
<span className="text-[10px] font-bold uppercase tracking-widest text-brand-accent">Live Analysis</span>
|
||||
</div>
|
||||
<div className="flex items-center -space-x-2">
|
||||
{[1,2,3].map(i => (
|
||||
<div key={i} className="w-6 h-6 rounded-full border-2 border-brand-dark bg-brand-muted text-[8px] flex items-center justify-center font-bold text-brand-dark">JD</div>
|
||||
))}
|
||||
<span className="text-[10px] ml-4 text-white/60">+12 terms detected</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const Steps = () => {
|
||||
const { t } = useTranslation();
|
||||
const steps = [
|
||||
{
|
||||
num: t('steps.step1.num'),
|
||||
title: t('steps.step1.title'),
|
||||
desc: t('steps.step1.desc'),
|
||||
icon: <MousePointer2 size={24} />,
|
||||
},
|
||||
{
|
||||
num: t('steps.step2.num'),
|
||||
title: t('steps.step2.title'),
|
||||
desc: t('steps.step2.desc'),
|
||||
icon: <Cpu size={24} />,
|
||||
},
|
||||
{
|
||||
num: t('steps.step3.num'),
|
||||
title: t('steps.step3.title'),
|
||||
desc: t('steps.step3.desc'),
|
||||
icon: <Download size={24} />,
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="py-32 px-4 border-y border-black/5">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="mb-24">
|
||||
<span className="accent-pill mb-6 block w-fit">{t('steps.stepLabel', { num: '0' })} PROCESUS</span>
|
||||
<h2 className="text-5xl lg:text-7xl text-brand-dark mb-6">{t('steps.title')}</h2>
|
||||
<p className="text-brand-dark/40 text-lg max-w-xl font-medium">{t('steps.subtitle')}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-16">
|
||||
{steps.map((st, i) => (
|
||||
<div key={i} className="group">
|
||||
<div className="w-12 h-12 rounded-xl bg-brand-muted flex items-center justify-center text-brand-dark mb-8 group-hover:bg-brand-dark group-hover:text-white transition-all duration-500">
|
||||
{st.icon}
|
||||
</div>
|
||||
<h3 className="text-3xl text-brand-dark mb-4">{st.title}</h3>
|
||||
<p className="text-brand-dark/40 leading-relaxed font-medium">{st.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
const FeaturesContext = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<section id="features" className="py-32 px-4 bg-brand-muted/30">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid lg:grid-cols-12 gap-20 items-end mb-24">
|
||||
<div className="lg:col-span-12">
|
||||
<span className="accent-pill mb-6 block w-fit font-bold uppercase tracking-widest">intelligence intégrée</span>
|
||||
<h2 className="text-6xl lg:text-8xl text-brand-dark leading-none">
|
||||
{t('features.title')}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{[
|
||||
{ icon: <Monitor className="text-brand-dark/40" />, title: t('features.context.title'), desc: t('features.context.desc') },
|
||||
{ icon: <Layers className="text-brand-dark/40" />, title: t('features.glossary.title'), desc: t('features.glossary.desc') },
|
||||
{ icon: <Eye className="text-brand-dark/40" />, title: t('features.vision.title'), desc: t('features.vision.desc') }
|
||||
].map((item, i) => (
|
||||
<div key={i} className="editorial-card p-10 flex flex-col items-start gap-8">
|
||||
<div className="w-10 h-10 border border-black/5 rounded-full flex items-center justify-center">
|
||||
{item.icon}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-2xl font-bold mb-4 text-brand-dark">{item.title}</h4>
|
||||
<p className="text-brand-dark/40 leading-relaxed font-medium text-sm">{item.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const LayoutFeatures = () => {
|
||||
const { t } = useTranslation();
|
||||
const points = (t('layout.points', { returnObjects: true }) as any[]).map((p, i) => ({
|
||||
...p,
|
||||
icon: i === 0 ? <Layers size={22} /> :
|
||||
i === 1 ? <Layout size={22} /> :
|
||||
i === 2 ? <PieChart size={22} /> :
|
||||
i === 3 ? <Zap size={22} /> :
|
||||
i === 4 ? <MessageSquare size={22} /> :
|
||||
<Globe size={22} />
|
||||
}));
|
||||
|
||||
return (
|
||||
<section className="py-32 px-4 bg-brand-dark text-white">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-32">
|
||||
<h2 className="text-6xl lg:text-8xl mb-10 leading-tight">
|
||||
{t('layout.title')}<br /> <span>{t('layout.title2')}</span>
|
||||
</h2>
|
||||
<p className="text-white/40 max-w-2xl mx-auto text-xl font-medium uppercase tracking-widest">
|
||||
{t('layout.subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-px bg-white/5 border border-white/10 rounded-3xl overflow-hidden shadow-2xl">
|
||||
{points.map((p, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="group p-14 bg-brand-dark hover:bg-white/[0.02] transition-all duration-700"
|
||||
>
|
||||
<div className="w-12 h-12 border border-white/10 rounded-xl flex items-center justify-center text-brand-accent mb-10 group-hover:scale-110 group-hover:border-white/20 transition-all">
|
||||
{p.icon}
|
||||
</div>
|
||||
<h4 className="text-3xl font-bold mb-6 leading-none">{p.title}</h4>
|
||||
<p className="text-white/30 text-base leading-relaxed font-medium">{p.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const FormatsSection = () => {
|
||||
const { t } = useTranslation();
|
||||
const formats = [
|
||||
{
|
||||
id: ".DOCX",
|
||||
name: t('formats.word.name'),
|
||||
icon: <FileText className="text-brand-dark/40" />,
|
||||
items: t('formats.word.items', { returnObjects: true }) as string[],
|
||||
},
|
||||
{
|
||||
id: ".XLSX",
|
||||
name: t('formats.excel.name'),
|
||||
icon: <FileSpreadsheet className="text-brand-dark/40" />,
|
||||
items: t('formats.excel.items', { returnObjects: true }) as string[],
|
||||
},
|
||||
{
|
||||
id: ".PPTX",
|
||||
name: t('formats.pptx.name'),
|
||||
icon: <Presentation className="text-brand-dark/40" />,
|
||||
items: t('formats.pptx.items', { returnObjects: true }) as string[],
|
||||
},
|
||||
{
|
||||
id: ".PDF",
|
||||
name: t('formats.pdf.name'),
|
||||
icon: <FileText className="text-brand-dark/40" />,
|
||||
items: t('formats.pdf.items', { returnObjects: true }) as string[],
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="formats" className="py-40 px-4">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="mb-24">
|
||||
<span className="accent-pill mb-6 block w-fit">COMPATIBILITÉ</span>
|
||||
<h2 className="text-5xl lg:text-7xl text-brand-dark mb-6 leading-tight uppercase font-black">{t('formats.title')} <span>{t('formats.title2')}</span></h2>
|
||||
<p className="text-brand-dark/40 max-w-xl text-lg font-medium">{t('formats.subtitle')}</p>
|
||||
</div>
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{formats.map((f, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="editorial-card p-10 group"
|
||||
>
|
||||
<div className="flex justify-between items-start mb-10">
|
||||
<div className={`w-12 h-12 bg-brand-muted rounded-xl flex items-center justify-center text-xl group-hover:bg-brand-dark group-hover:text-white transition-all`}>
|
||||
{f.icon}
|
||||
</div>
|
||||
<span className="text-[9px] font-bold text-brand-dark/20 uppercase tracking-[0.2em]">{f.id}</span>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold mb-6 text-brand-dark uppercase tracking-tighter">{f.name}</h3>
|
||||
<ul className="space-y-4">
|
||||
{f.items.map((item, j) => (
|
||||
<li key={j} className="flex items-start gap-3 text-xs text-brand-dark/40 font-medium">
|
||||
<div className="w-1 h-1 bg-brand-accent rounded-full mt-1.5 shrink-0 opacity-40"></div> {item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const PricingSection = () => {
|
||||
const { t } = useTranslation();
|
||||
const [isAnnual, setIsAnnual] = useState(true);
|
||||
|
||||
const plans = [
|
||||
{
|
||||
name: t('pricing.starter.name'),
|
||||
desc: t('pricing.starter.desc'),
|
||||
monthlyPrice: 9,
|
||||
annualPrice: 7,
|
||||
features: t('pricing.starter.features', { returnObjects: true }) as string[],
|
||||
cta: t('pricing.starter.cta'),
|
||||
popular: false
|
||||
},
|
||||
{
|
||||
name: t('pricing.pro.name'),
|
||||
desc: t('pricing.pro.desc'),
|
||||
monthlyPrice: 25,
|
||||
annualPrice: 19,
|
||||
features: t('pricing.pro.features', { returnObjects: true }) as string[],
|
||||
cta: t('pricing.pro.cta'),
|
||||
popular: true
|
||||
},
|
||||
{
|
||||
name: t('pricing.business.name'),
|
||||
desc: t('pricing.business.desc'),
|
||||
monthlyPrice: 65,
|
||||
annualPrice: 49,
|
||||
features: t('pricing.business.features', { returnObjects: true }) as string[],
|
||||
cta: t('pricing.business.cta'),
|
||||
popular: false
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="pricing" className="py-40 px-4 bg-brand-bg">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-24">
|
||||
<h2 className="text-7xl lg:text-8xl mb-8 leading-tight">{t('pricing.title')}</h2>
|
||||
<p className="text-brand-dark/40 text-xl font-bold max-w-2xl mx-auto uppercase tracking-widest">{t('pricing.subtitle')}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center gap-12 mb-32">
|
||||
<button
|
||||
onClick={() => setIsAnnual(false)}
|
||||
className={`text-sm font-bold uppercase tracking-widest transition-all ${!isAnnual ? 'text-brand-dark underline underline-offset-8' : 'text-brand-dark/30 hover:text-brand-dark'}`}
|
||||
>
|
||||
{t('pricing.monthly')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsAnnual(true)}
|
||||
className={`text-sm font-bold uppercase tracking-widest transition-all relative ${isAnnual ? 'text-brand-dark underline underline-offset-8' : 'text-brand-dark/30 hover:text-brand-dark'}`}
|
||||
>
|
||||
{t('pricing.annual')}
|
||||
<span className="absolute -top-6 left-1/2 -translate-x-1/2 text-[9px] font-bold text-brand-accent whitespace-nowrap italic">
|
||||
(20% d'économie)
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-px bg-black/5 rounded-[40px] overflow-hidden border border-black/5">
|
||||
{plans.map((p, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={`p-16 bg-white flex flex-col text-left transition-all duration-500 hover:z-10 hover:shadow-2xl hover:scale-[1.01]`}
|
||||
>
|
||||
<h3 className="text-4xl font-black mb-2 text-brand-dark uppercase tracking-tighter">{p.name}</h3>
|
||||
<p className="text-brand-dark/40 text-xs font-bold mb-14 tracking-widest uppercase">{p.desc}</p>
|
||||
|
||||
<div className="mb-14">
|
||||
<span className="text-7xl font-black leading-none">€{isAnnual ? p.annualPrice : p.monthlyPrice}</span>
|
||||
<span className="text-brand-dark/30 font-bold ml-2 uppercase text-[10px] tracking-[0.2em]">/ {t('pricing.month')}</span>
|
||||
</div>
|
||||
|
||||
<ul className="space-y-6 mb-16 flex-grow">
|
||||
{p.features.map((f, j) => (
|
||||
<li key={j} className="flex items-start gap-4 text-sm text-brand-dark/50 font-medium leading-snug">
|
||||
<div className="w-1 h-1 rounded-full bg-brand-accent mt-2 shrink-0"></div> {f}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<button className={`w-full py-5 rounded-xl font-bold text-sm transition-all uppercase tracking-widest leading-none ${p.popular ? 'bg-brand-dark text-white shadow-xl' : 'bg-transparent text-brand-dark border border-black/10 hover:bg-black/5'}`}>
|
||||
{p.cta}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const CTASection = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<section className="py-40 px-4 text-center">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<h2 className="text-7xl lg:text-9xl text-brand-dark mb-10 leading-none tracking-tighter">
|
||||
{t('cta.title')}
|
||||
</h2>
|
||||
<p className="text-2xl text-brand-dark/40 mb-16 font-bold uppercase tracking-[0.2em]">
|
||||
{t('cta.subtitle')}
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-6 justify-center items-center">
|
||||
<button className="premium-button px-14 py-6 text-xl">
|
||||
{t('cta.button')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const Footer = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<footer className="bg-brand-muted/30 pt-40 pb-20 px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid md:grid-cols-12 gap-20 mb-40">
|
||||
<div className="md:col-span-12 lg:col-span-6">
|
||||
<Logo />
|
||||
<p className="text-brand-dark/40 text-lg font-medium mt-12 mb-12 max-w-sm leading-relaxed uppercase tracking-widest">
|
||||
{t('footer.desc')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-4 lg:col-span-2">
|
||||
<h4 className="text-[10px] font-bold uppercase tracking-[0.3em] text-brand-dark mb-10">{t('footer.product')}</h4>
|
||||
<ul className="space-y-6 text-xs text-brand-dark/40 font-bold uppercase tracking-widest leading-none">
|
||||
<li><a href="#features" className="hover:text-brand-dark transition-colors">{t('nav.why')}</a></li>
|
||||
<li><a href="#formats" className="hover:text-brand-dark transition-colors">{t('nav.formats')}</a></li>
|
||||
<li><a href="#pricing" className="hover:text-brand-dark transition-colors">{t('nav.pricing')}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-4 lg:col-span-2">
|
||||
<h4 className="text-[10px] font-bold uppercase tracking-[0.3em] text-brand-dark mb-10">{t('footer.resources')}</h4>
|
||||
<ul className="space-y-6 text-xs text-brand-dark/40 font-bold uppercase tracking-widest leading-none">
|
||||
<li><a href="#" className="hover:text-brand-dark transition-colors">Documentation</a></li>
|
||||
<li><a href="#" className="hover:text-brand-dark transition-colors">API</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-4 lg:col-span-2">
|
||||
<h4 className="text-[10px] font-bold uppercase tracking-[0.3em] text-brand-dark mb-10">{t('footer.legal')}</h4>
|
||||
<ul className="space-y-6 text-xs text-brand-dark/40 font-bold uppercase tracking-widest leading-none">
|
||||
<li><a href="#" className="hover:text-brand-dark transition-colors">Privacy</a></li>
|
||||
<li><a href="#" className="hover:text-brand-dark transition-colors">Terms</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-10 border-t border-black/5 flex flex-col md:flex-row justify-between items-center gap-10">
|
||||
<div className="text-[10px] font-bold text-brand-dark/20 uppercase tracking-[0.4em]">
|
||||
{t('footer.rights')}
|
||||
</div>
|
||||
<div className="text-[10px] font-mono text-brand-dark/20 uppercase tracking-widest">
|
||||
v2.4.0 • Built for excellence
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
|
||||
if (isLoggedIn) {
|
||||
return <Dashboard onLogout={() => setIsLoggedIn(false)} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen font-sans bg-brand-bg text-brand-dark selection:bg-brand-accent/20 overflow-x-hidden">
|
||||
<Navbar onLogin={() => setIsLoggedIn(true)} />
|
||||
<main>
|
||||
<Hero onLogin={() => setIsLoggedIn(true)} />
|
||||
<Steps />
|
||||
<FeaturesContext />
|
||||
<LayoutFeatures />
|
||||
<FormatsSection />
|
||||
<PricingSection />
|
||||
<CTASection />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,721 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
FileText,
|
||||
User,
|
||||
LogOut,
|
||||
Globe,
|
||||
Upload,
|
||||
Download,
|
||||
Zap,
|
||||
Activity,
|
||||
ChevronDown,
|
||||
Moon,
|
||||
CheckCircle2,
|
||||
Clock,
|
||||
Presentation,
|
||||
ArrowRight,
|
||||
Crown,
|
||||
Layers,
|
||||
Book,
|
||||
Key,
|
||||
FileCode,
|
||||
MessageSquare,
|
||||
Layout,
|
||||
Database,
|
||||
Cpu,
|
||||
Eraser,
|
||||
Save,
|
||||
Library,
|
||||
Wrench,
|
||||
HardHat,
|
||||
Monitor,
|
||||
Scale,
|
||||
Stethoscope,
|
||||
BarChart3,
|
||||
Megaphone,
|
||||
Car
|
||||
} from 'lucide-react';
|
||||
import { motion } from 'motion/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type View = 'translate' | 'profile' | 'context' | 'glossary' | 'api-keys';
|
||||
|
||||
export const Dashboard: React.FC<{ onLogout: () => void }> = ({ onLogout }) => {
|
||||
const { t } = useTranslation();
|
||||
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 */}
|
||||
<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="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>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="flex-1 flex flex-col overflow-hidden">
|
||||
{/* Topbar */}
|
||||
<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>
|
||||
|
||||
{/* View Content */}
|
||||
<div className="flex-1 overflow-y-auto p-16">
|
||||
{currentView === 'translate' && <TranslateView />}
|
||||
{currentView === 'profile' && <ProfileView tab={profileTab} setTab={setProfileTab} />}
|
||||
{currentView === 'context' && <ContextView />}
|
||||
{currentView === 'api-keys' && <ApiKeysView />}
|
||||
{currentView === 'glossary' && <GlossaryMainView />}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TranslateView = () => {
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
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>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const StatusOverlay = ({ status, progress, onReset }: { status: string, progress: number, onReset: () => void }) => {
|
||||
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)]"
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
const ProfileView = ({ tab, setTab }: { tab: string; setTab: (t: any) => void }) => {
|
||||
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 p-12 flex items-center justify-between bg-brand-dark text-white border-none shadow-2xl">
|
||||
<div className="flex items-center gap-8">
|
||||
<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">
|
||||
<Crown size={28} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-3">
|
||||
<h3 className="text-2xl font-black uppercase tracking-tight">Forfait Pro</h3>
|
||||
<span className="px-3 py-1 bg-white/10 rounded-full text-[9px] font-black uppercase tracking-widest text-white border border-white/10">Actif</span>
|
||||
</div>
|
||||
<p className="text-white/40 text-[10px] font-black uppercase tracking-widest mt-1">Facturation mensuelle • 19 €/mois</p>
|
||||
</div>
|
||||
</div>
|
||||
<button className="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 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>
|
||||
);
|
||||
};
|
||||
|
||||
const ContextView = () => {
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
const ApiKeysView = () => {
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
const GlossaryMainView = () => {
|
||||
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>
|
||||
);
|
||||
};
|
||||
285
wordly.art---traduction-de-documents-2/src/i18n.ts
Normal file
285
wordly.art---traduction-de-documents-2/src/i18n.ts
Normal file
@@ -0,0 +1,285 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
|
||||
i18n
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: 'fr',
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
resources: {
|
||||
fr: {
|
||||
translation: {
|
||||
nav: {
|
||||
why: "Pourquoi nous ?",
|
||||
formats: "Formats",
|
||||
pricing: "Tarification",
|
||||
login: "Connexion",
|
||||
startFree: "Essai gratuit",
|
||||
},
|
||||
hero: {
|
||||
tag: "Intelligence Artificielle Documentaire",
|
||||
titleLine1: "Traduisez vos documents.",
|
||||
titleLine2: "Formatage préservé.",
|
||||
description: "Le seul traducteur qui préserve les graphiques, tables des matières, formes et en-têtes — exactement tels qu'ils étaient.",
|
||||
ctaMain: "Essai gratuit",
|
||||
ctaSec: "Voir les offres",
|
||||
deleted: "Sécurisé de bout en bout",
|
||||
noHidden: "Zéro coût caché",
|
||||
preview: "Aperçu en temps réel",
|
||||
formattedOk: "Formatage OK",
|
||||
aiActive: "IA active"
|
||||
},
|
||||
steps: {
|
||||
title: "Comment ça marche ?",
|
||||
subtitle: "Trois étapes. Zéro perte de mise en page.",
|
||||
stepLabel: "ÉTAPE {{num}}",
|
||||
step1: {
|
||||
num: "01",
|
||||
title: "Déposez votre fichier",
|
||||
desc: "Glissez-déposez votre document Word, Excel, PowerPoint ou PDF."
|
||||
},
|
||||
step2: {
|
||||
num: "02",
|
||||
title: "Analyse IA",
|
||||
desc: "Notre IA identifie le texte et le contexte pour une précision maximale."
|
||||
},
|
||||
step3: {
|
||||
num: "03",
|
||||
title: "Téléchargement",
|
||||
desc: "Récupérez votre fichier traduit avec une mise en page identique."
|
||||
}
|
||||
},
|
||||
features: {
|
||||
tag: "Moteur IA",
|
||||
title: "La traduction qui comprend votre métier",
|
||||
description: "Wordly n'est pas qu'un traducteur. C'est un expert en mise en forme contextuelle.",
|
||||
context: {
|
||||
title: "Précision Contextuelle",
|
||||
desc: "L'IA comprend les nuances techniques de vos documents."
|
||||
},
|
||||
glossary: {
|
||||
title: "Support Multi-format",
|
||||
desc: "Word, Excel, PowerPoint et PDF supportés nativement."
|
||||
},
|
||||
vision: {
|
||||
title: "Mise en page intacte",
|
||||
desc: "Graphiques, SmartArt et en-têtes restent à leur place."
|
||||
}
|
||||
},
|
||||
layout: {
|
||||
title: "Votre mise en page,",
|
||||
title2: "parfaitement intacte",
|
||||
subtitle: "Nous traduisons le contenu sans jamais toucher à la structure de vos fichiers.",
|
||||
points: [
|
||||
{ title: "SmartArt & Diagrammes", desc: "Tout le texte à l'intérieur est localisé." },
|
||||
{ title: "Tables des matières", desc: "Mises à jour automatiquement après traduction." },
|
||||
{ title: "Graphiques complexes", desc: "Titres et légendes traduits sans erreur." },
|
||||
{ title: "Zones de texte", desc: "Ajustement automatique si le texte s'allonge." },
|
||||
{ title: "En-têtes & Pieds", desc: "Aucun élément n'est oublié par l'IA." },
|
||||
{ title: "130+ Langues", desc: "Support global pour tous vos besoins." }
|
||||
]
|
||||
},
|
||||
formats: {
|
||||
title: "Chaque format,",
|
||||
title2: "unifié",
|
||||
subtitle: "Momento ingère tout votre univers numérique pour une mémoire unifiée.",
|
||||
word: {
|
||||
name: "Documents",
|
||||
items: ["Notes structurées", "Fichiers PDF & Office", "Extractions Web", "Transcriptions Audio"]
|
||||
},
|
||||
excel: {
|
||||
name: "Connexions",
|
||||
items: ["Graphe de connaissance", "Backlinks bidirectionnels", "Tags sémantiques", "Métadonnées IA"]
|
||||
},
|
||||
pptx: {
|
||||
name: "Visualisation",
|
||||
items: ["Brainstorming radial", "Canevas infini", "Export MarkDown", "Slides interactives"]
|
||||
},
|
||||
pdf: {
|
||||
name: "Intégrations",
|
||||
items: ["API Ouverte", "Stratégie BYOK", "Extension Navigateur", "App Mobile Natice"]
|
||||
}
|
||||
},
|
||||
pricing: {
|
||||
title: "Le prix de l'excellence",
|
||||
subtitle: "Choisissez votre niveau d'amplification cognitive.",
|
||||
monthly: "Mensuel",
|
||||
annual: "Annuel",
|
||||
bestValue: "Recommandé",
|
||||
month: "mois",
|
||||
footer: "Engagement mensuel. Annulable à tout moment.",
|
||||
starter: {
|
||||
name: "Individu",
|
||||
desc: "Pour les esprits curieux",
|
||||
features: ["1 000 Notes maximum", "Recherche sémantique", "3 Agents classiques", "BYOK limité (OpenAI)"],
|
||||
cta: "Commencer"
|
||||
},
|
||||
pro: {
|
||||
name: "Expert",
|
||||
desc: "Pour les bâtisseurs de savoir",
|
||||
features: ["Notes illimitées", "Stratégie BYOK totale", "Tous les agents inclus", "Brainstorming illimité", "Support prioritaire"],
|
||||
cta: "Essayer Pro"
|
||||
},
|
||||
business: {
|
||||
name: "Studio",
|
||||
desc: "Pour les équipes créatives",
|
||||
features: ["Espace collaboratif", "Graphe partagé", "API de développement", "Contrôles admin", "10 sièges inclus"],
|
||||
cta: "Contacter"
|
||||
}
|
||||
},
|
||||
cta: {
|
||||
title: "Prêt à libérer votre plein potentiel ?",
|
||||
subtitle: "Rejoignez la révolution de la gestion de la connaissance assistée par IA.",
|
||||
button: "Lancer Momento"
|
||||
},
|
||||
footer: {
|
||||
desc: "Spécialiste de la traduction documentaire intelligente.",
|
||||
product: "Produit",
|
||||
resources: "Ressources",
|
||||
legal: "Légal",
|
||||
rights: "© 2026 WORDLY — Tous droits réservés."
|
||||
}
|
||||
}
|
||||
},
|
||||
en: {
|
||||
translation: {
|
||||
nav: {
|
||||
why: "Why Wordly?",
|
||||
formats: "Formats",
|
||||
pricing: "Pricing",
|
||||
login: "Login",
|
||||
startFree: "Start Free",
|
||||
},
|
||||
hero: {
|
||||
tag: "Document Artificial Intelligence",
|
||||
titleLine1: "Translate your documents.",
|
||||
titleLine2: "Preserve layout.",
|
||||
description: "The only translator that preserves charts, tables of contents, shapes, and headers — exactly as they were.",
|
||||
ctaMain: "Start for free",
|
||||
ctaSec: "See pricing",
|
||||
deleted: "End-to-end secure",
|
||||
noHidden: "Zero hidden costs",
|
||||
preview: "Real-time preview",
|
||||
formattedOk: "Formatting OK",
|
||||
aiActive: "AI active"
|
||||
},
|
||||
steps: {
|
||||
title: "How it works?",
|
||||
subtitle: "Three steps. Zero layout loss.",
|
||||
stepLabel: "STEP {{num}}",
|
||||
step1: {
|
||||
num: "01",
|
||||
title: "Upload your file",
|
||||
desc: "Drag & drop your Word, Excel, PowerPoint or PDF document."
|
||||
},
|
||||
step2: {
|
||||
num: "02",
|
||||
title: "AI Analysis",
|
||||
desc: "Our AI identifies text and context for maximum accuracy."
|
||||
},
|
||||
step3: {
|
||||
num: "03",
|
||||
title: "Download",
|
||||
desc: "Get your translated file with an identical layout."
|
||||
}
|
||||
},
|
||||
features: {
|
||||
tag: "AI Engine",
|
||||
title: "Translation that understands your business",
|
||||
description: "Wordly is more than a translator. It's a contextual formatting expert.",
|
||||
context: {
|
||||
title: "Contextual Accuracy",
|
||||
desc: "The AI understands the technical nuances of your documents."
|
||||
},
|
||||
glossary: {
|
||||
title: "Multi-format Support",
|
||||
desc: "Word, Excel, PowerPoint, and PDF supported natively."
|
||||
},
|
||||
vision: {
|
||||
title: "Intact Layout",
|
||||
desc: "Charts, SmartArt, and headers stay in their place."
|
||||
}
|
||||
},
|
||||
layout: {
|
||||
title: "Your layout,",
|
||||
title2: "perfectly intact",
|
||||
subtitle: "We translate the content without ever touching the structure of your files.",
|
||||
points: [
|
||||
{ title: "SmartArt & Diagrams", desc: "All text inside is localized." },
|
||||
{ title: "Tables of Contents", desc: "Updated automatically after translation." },
|
||||
{ title: "Complex Charts", desc: "Titles and legends translated without error." },
|
||||
{ title: "Text Zones", desc: "Automatic adjustment if text expands." },
|
||||
{ title: "Headers & Footers", desc: "No element is forgotten by the AI." },
|
||||
{ title: "130+ Languages", desc: "Global support for all your needs." }
|
||||
]
|
||||
},
|
||||
formats: {
|
||||
title: "Every format,",
|
||||
title2: "unified",
|
||||
subtitle: "Momento ingests your entire digital universe for a unified memory.",
|
||||
word: {
|
||||
name: "Documents",
|
||||
items: ["Structured notes", "PDF & Office files", "Web extractions", "Audio transcriptions"]
|
||||
},
|
||||
excel: {
|
||||
name: "Connections",
|
||||
items: ["Knowledge graph", "Bidirectional backlinks", "Semantic tags", "AI metadata"]
|
||||
},
|
||||
pptx: {
|
||||
name: "Visualization",
|
||||
items: ["Radial brainstorming", "Infinite canvas", "MarkDown export", "Interactive slides"]
|
||||
},
|
||||
pdf: {
|
||||
name: "Integrations",
|
||||
items: ["Open API", "BYOK Strategy", "Browser Extension", "Native Mobile App"]
|
||||
}
|
||||
},
|
||||
pricing: {
|
||||
title: "The price of excellence",
|
||||
subtitle: "Choose your cognitive amplification level.",
|
||||
monthly: "Monthly",
|
||||
annual: "Annual",
|
||||
bestValue: "Recommended",
|
||||
month: "month",
|
||||
footer: "Monthly commitment. Cancel anytime.",
|
||||
starter: {
|
||||
name: "Individual",
|
||||
desc: "For curious minds",
|
||||
features: ["1,000 Notes maximum", "Semantic search", "3 Classical agents", "Limited BYOK (OpenAI)"],
|
||||
cta: "Start"
|
||||
},
|
||||
pro: {
|
||||
name: "Expert",
|
||||
desc: "For knowledge builders",
|
||||
features: ["Unlimited notes", "Full BYOK strategy", "All agents included", "Unlimited brainstorming", "Priority support"],
|
||||
cta: "Try Pro"
|
||||
},
|
||||
business: {
|
||||
name: "Studio",
|
||||
desc: "For creative teams",
|
||||
features: ["Collaborative space", "Shared graph", "Developer API", "Admin controls", "10 seats included"],
|
||||
cta: "Contact"
|
||||
}
|
||||
},
|
||||
cta: {
|
||||
title: "Ready to unlock your full potential?",
|
||||
subtitle: "Join the revolution of AI-assisted knowledge management.",
|
||||
button: "Launch Momento"
|
||||
},
|
||||
footer: {
|
||||
desc: "Expert in intelligent document translation.",
|
||||
product: "Product",
|
||||
resources: "Resources",
|
||||
legal: "Legal",
|
||||
rights: "© 2026 WORDLY — All rights reserved."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
40
wordly.art---traduction-de-documents-2/src/index.css
Normal file
40
wordly.art---traduction-de-documents-2/src/index.css
Normal file
@@ -0,0 +1,40 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap');
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: "JetBrains Mono", monospace;
|
||||
|
||||
--color-brand-bg: #FDFCF9;
|
||||
--color-brand-dark: #1A1A1A;
|
||||
--color-brand-accent: #C5A17A;
|
||||
--color-brand-muted: #F3F1ED;
|
||||
|
||||
--shadow-editorial: 0 10px 40px -10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
body {
|
||||
@apply font-sans bg-brand-bg text-brand-dark selection:bg-brand-accent/20;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
@apply font-sans tracking-tight font-extrabold leading-[1.1];
|
||||
}
|
||||
}
|
||||
|
||||
.editorial-card {
|
||||
@apply bg-white border border-black/5 rounded-3xl shadow-editorial transition-all duration-500 hover:shadow-2xl hover:border-black/10;
|
||||
}
|
||||
|
||||
.dark-section {
|
||||
@apply bg-brand-dark text-white;
|
||||
}
|
||||
|
||||
.accent-pill {
|
||||
@apply px-4 py-1.5 rounded-full border border-brand-accent/30 text-brand-accent text-[11px] font-black uppercase tracking-widest bg-brand-accent/5;
|
||||
}
|
||||
|
||||
.premium-button {
|
||||
@apply bg-brand-dark text-white px-8 py-3.5 rounded-xl font-black text-sm transition-all hover:scale-[1.02] active:scale-95 hover:shadow-xl;
|
||||
}
|
||||
11
wordly.art---traduction-de-documents-2/src/main.tsx
Normal file
11
wordly.art---traduction-de-documents-2/src/main.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import {StrictMode} from 'react';
|
||||
import {createRoot} from 'react-dom/client';
|
||||
import App from './App.tsx';
|
||||
import './index.css';
|
||||
import './i18n';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
);
|
||||
Reference in New Issue
Block a user