Publication IA: - 4 templates (magazine, brief, essay, simple) avec CSS riche - Rewrite IA (article/exercises/tutorial/reference/mixed) - Modération avec timeout 12s + fallback safe - Quotas publish_enhance par tier (basic=2, pro=15, business=100) - Détection contenu stale (hash) - Migration DB publishedContent/publishedTemplate/publishedSourceHash Fixes: - cheerio v1.2: Element -> AnyNode (domhandler), decodeEntities cast - _isShared ajouté au type Note (champ virtuel serveur) - callout colors PDF export: extraction fonction pure testable - admin/published: guard note.userId null - Cmd+S fonctionne en mode dialog (pas seulement fullPage) i18n: - 23 clés publish* traduites dans les 15 locales - Extension Web Clipper: 13 locales mise à jour Tests: - callout-colors.test.ts (6 tests) - note-visible-in-view.test.ts (5 tests) - entitlements.test.ts + byok-entitlements.test.ts: mock usageLog + unstubAllEnvs - 199/199 tests passent Tracker: user-stories.md sync avec sprint-status.yaml
1016 lines
60 KiB
TypeScript
1016 lines
60 KiB
TypeScript
import React from 'react';
|
|
import { motion, AnimatePresence } from 'motion/react';
|
|
import {
|
|
BrainCircuit,
|
|
Search,
|
|
MessageSquare,
|
|
ArrowRight,
|
|
Sparkles,
|
|
Activity,
|
|
Play,
|
|
Terminal,
|
|
History,
|
|
ChevronRight,
|
|
Network,
|
|
Clock,
|
|
BookOpen,
|
|
Sliders,
|
|
CheckSquare,
|
|
Lock,
|
|
Compass,
|
|
Layers,
|
|
Heart,
|
|
PlusSquare,
|
|
FileText,
|
|
HelpCircle,
|
|
Eye,
|
|
RefreshCw,
|
|
Database
|
|
} from 'lucide-react';
|
|
|
|
interface LandingPageV2Props {
|
|
onEnter: () => void;
|
|
onLogin: () => void;
|
|
onRegister: () => void;
|
|
onSwitchVersion: (v: 'v1' | 'v2' | 'v3') => void;
|
|
}
|
|
|
|
export const LandingPageV2: React.FC<LandingPageV2Props> = ({
|
|
onEnter,
|
|
onLogin,
|
|
onRegister,
|
|
onSwitchVersion
|
|
}) => {
|
|
|
|
// Real world Memento note seeds to match constants.ts exactly
|
|
const realNotes = [
|
|
{
|
|
id: 'n1',
|
|
title: "Grid Systems & Geometry",
|
|
carnet: "Architecture Research",
|
|
date: "26 Oct 2024",
|
|
tags: ["Architecture", "Systems (IA)"],
|
|
content: `# Grid Systems & Geometry
|
|
|
|
Les trames géométriques constituent le fondement même du design cognitif. Elles structurent l'espace bâti en créant un sens d'ordre, de rythme, et d'harmonie de proportions esthétiques.
|
|
|
|
$$R_{ratio} = \\frac{1 + \\sqrt{5}}{2} \\approx 1.618$$
|
|
|
|
## 1. Grilles Orthogonales
|
|
L'utilisation séculaire du Nombre d'Or permet d'ancrer de manière pragmatique les volumes de construction dans une perspective visuelle harmonieuse.
|
|
|
|
* **Structure** : Délimitation et alignement rigoureux des ouvertures.
|
|
* **Rythme** : Répartition équilibrée de la lumière naturelle et des masses de soutien.`,
|
|
nodes: ["Nombre d'Or", "Trame Orthogonale", "Proportion", "Lumière"],
|
|
stats: { words: 86, lines: 11, equations: 1, graphs: 3, images: 1 }
|
|
},
|
|
{
|
|
id: 'n2',
|
|
title: "Sustainable Materiality",
|
|
carnet: "Sustainable Design",
|
|
date: "24 Oct 2024",
|
|
tags: ["Materials", "Sustainability (IA)"],
|
|
content: `# Sustainable Materiality
|
|
|
|
L'exploration du bois lamellé-croisé (CLT - Cross Laminated Timber) se présente comme l'une des meilleures alternatives écologiques au béton armé conventionnel.
|
|
|
|
$$\\Delta Carbon = E_{béton} - E_{CLT} = 410 \\text{ kg } CO_2/m^3$$
|
|
|
|
## 1. Avantages du CLT (Bois Massif)
|
|
L'exploitation raisonnée des forêts et l'empreinte carbone négative de la cellulose captent durablement les gaz polluants du Cycle Global.
|
|
|
|
* **Rapport Poids/Résistance** : Équivalent à la solidité de l'acier avec un poids divisé par quatre.
|
|
* **Isolation Passive** : Conductivité thermique extrêmement faible, limitant la déperdition durant l'hiver.`,
|
|
nodes: ["Bois CLT", "Éco-Conception", "Bilan Carbone", "Coût Thermique"],
|
|
stats: { words: 91, lines: 12, equations: 1, graphs: 4, images: 1 }
|
|
},
|
|
{
|
|
id: 'n3',
|
|
title: "Light & Minimalist Space",
|
|
carnet: "Modernism",
|
|
date: "22 Oct 2024",
|
|
tags: ["Lighting", "Atmosphere (IA)"],
|
|
content: `# Light & Minimalist Space
|
|
|
|
Le minimalisme consiste à soustraire le superflu pour ne laisser briller que l'essence même de l'espace. Dans cette optique, la lumière naturelle cesse d'être un simple facteur externe et devient un véritable matériau structurel.
|
|
|
|
## 1. La Diffraction Lumineuse
|
|
La transparence et la réflexion du verre feuilleté démultiplient l'espace sans exiger d'éléments cloisons additionnels.
|
|
|
|
* **Pureté Visuelle** : Transition fluide entre l'intérieur intime et l'extérieur sauvage.
|
|
* **Économie Formelle** : Utilisation de nuances de blanc mat pour emprisonner le rayonnement diffus.`,
|
|
nodes: ["Réfraction", "Verre Feuilleté", "Espace Continu", "Ombres Portées"],
|
|
stats: { words: 82, lines: 10, equations: 0, graphs: 3, images: 1 }
|
|
}
|
|
];
|
|
|
|
const [activeDemoIdx, setActiveDemoIdx] = React.useState<number>(0);
|
|
const [activeTab, setActiveTab] = React.useState<'editor' | 'graph' | 'agents' | 'reviews' | 'history'>('editor');
|
|
const [simulateState, setSimulateState] = React.useState<'searching' | 'writing' | 'idle' | 'complete'>('idle');
|
|
const [displayText, setDisplayText] = React.useState<string>('');
|
|
const [aiSidebarTab, setAiSidebarTab] = React.useState<'explore' | 'discussion' | 'relations'>('explore');
|
|
const [customPrompt, setCustomPrompt] = React.useState<string>('');
|
|
|
|
// Spaced-repetition simulated states
|
|
const [showFlashcardAnswer, setShowFlashcardAnswer] = React.useState(false);
|
|
const [flashcardIdx, setFlashcardIdx] = React.useState(0);
|
|
|
|
const simulatedFlashcards = [
|
|
{
|
|
id: 'f1',
|
|
question: "Quel rôle joue le Nombre d'Or (1.618) dans les structures d'architecture ?",
|
|
answer: "Il sert à définir des proportions optimales de fenêtrage et de colonnes, créant une harmonie visuelle captée naturellement par l'œil humain."
|
|
},
|
|
{
|
|
id: 'f2',
|
|
question: "Pourquoi privilégier le bois CLT (lamellé-croisé) au béton armé ?",
|
|
answer: "Il offre un stockage actif du CO2 (bilan carbone négatif) et présente un rapport poids/résistance exceptionnel tout en améliorant l'isolation passive."
|
|
}
|
|
];
|
|
|
|
// Launch simulated real-time streaming text writing in chunks
|
|
const triggerSimulation = (index: number, customText?: string) => {
|
|
setActiveDemoIdx(index);
|
|
setSimulateState('searching');
|
|
setDisplayText('');
|
|
setShowFlashcardAnswer(false);
|
|
|
|
// Auto shift corresponding sidebar layout to keep user context rich
|
|
if (index === 0) setAiSidebarTab('explore');
|
|
if (index === 1) setAiSidebarTab('relations');
|
|
if (index === 2) setAiSidebarTab('discussion');
|
|
|
|
const sourceText = customText || (index === -1 ? "" : realNotes[index].content);
|
|
|
|
setTimeout(() => {
|
|
setSimulateState('writing');
|
|
const totalLen = sourceText.length;
|
|
let currentLength = 0;
|
|
|
|
const timer = setInterval(() => {
|
|
currentLength += 22; // Quick interactive flow
|
|
if (currentLength >= totalLen) {
|
|
setDisplayText(sourceText);
|
|
setSimulateState('complete');
|
|
clearInterval(timer);
|
|
} else {
|
|
setDisplayText(sourceText.substring(0, currentLength));
|
|
}
|
|
}, 15);
|
|
}, 900);
|
|
};
|
|
|
|
const handleCustomSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (!customPrompt.trim()) return;
|
|
|
|
const query = customPrompt;
|
|
const generatedContent = `# Synthèse : ${query}
|
|
|
|
Analyse automatique issue de vos documents locaux avec intégration sémantique complète.
|
|
|
|
## 1. Formule Logique Relative
|
|
Les connexions de votre idée s'harmonisent selon le coefficient géométrique de structure :
|
|
|
|
$$\\Omega(x) = \\int_{0}^{\\Lambda} e^{-k \\cdot x} \\cdot dx$$
|
|
|
|
* **Analyse sémantique** : Les concepts périphériques sont cartographiés.
|
|
* **Consolidation passive** : Préservation totale des métadonnées du carnet.`;
|
|
|
|
triggerSimulation(-1, generatedContent);
|
|
};
|
|
|
|
React.useEffect(() => {
|
|
triggerSimulation(0);
|
|
}, []);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#FBFBFA] text-ink font-sans selection:bg-accent/20 paper-texture">
|
|
|
|
{/* 1. Sticky Navigation Header */}
|
|
<nav className="fixed top-0 left-0 right-0 z-[100] bg-[#FBFBFA]/90 backdrop-blur-md border-b border-border px-6 md:px-12 py-3.5 flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 bg-ink hover:rotate-3 transition-transform flex items-center justify-center rounded-xl shadow-md cursor-pointer">
|
|
<span className="text-paper font-serif text-2xl font-bold">M</span>
|
|
</div>
|
|
<div className="text-left">
|
|
<span className="font-serif text-2xl font-medium tracking-tight">Memento</span>
|
|
<span className="text-[9px] font-black text-accent uppercase tracking-widest block font-mono -mt-1.5 pl-0.5">Second Cerveau</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Interactive layout version switcher */}
|
|
<div className="bg-ink/5 p-0.5 rounded-full flex items-center gap-0.5 border border-border">
|
|
<button
|
|
onClick={() => onSwitchVersion('v1')}
|
|
className="px-4 py-1.5 text-[9.5px] uppercase tracking-widest font-bold rounded-full text-concrete hover:text-ink transition-all cursor-pointer"
|
|
>
|
|
Classique (V1)
|
|
</button>
|
|
<button
|
|
onClick={() => onSwitchVersion('v2')}
|
|
className="px-4.5 py-1.5 text-[9.5px] uppercase tracking-widest font-black rounded-full bg-ink text-paper shadow-sm cursor-pointer"
|
|
>
|
|
Interactif (V2)
|
|
</button>
|
|
<button
|
|
onClick={() => onSwitchVersion('v3')}
|
|
className="px-4 py-1.5 text-[9.5px] uppercase tracking-widest font-bold rounded-full text-concrete hover:text-ink transition-all cursor-pointer"
|
|
>
|
|
Bilingue (V3) ✨
|
|
</button>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-3">
|
|
<button
|
|
onClick={onLogin}
|
|
className="hidden sm:block px-4 py-2 text-concrete hover:text-ink text-[11px] font-bold uppercase tracking-widest cursor-pointer"
|
|
>
|
|
Se Connecter
|
|
</button>
|
|
<button
|
|
onClick={onEnter}
|
|
className="px-5 py-2.5 bg-ink text-paper rounded-xl text-[10.5px] font-bold uppercase tracking-widest hover:opacity-90 active:scale-95 transition-all flex items-center gap-2 cursor-pointer shadow-lg"
|
|
>
|
|
Lancer l'éditeur
|
|
<ArrowRight size={13} />
|
|
</button>
|
|
</div>
|
|
</nav>
|
|
|
|
{/* 2. Main High-Fidelity Introduction & Split Screen Grid */}
|
|
<section className="relative pt-32 pb-24 px-6 md:px-12 max-w-7xl mx-auto">
|
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-10 items-stretch">
|
|
|
|
{/* Left Hero Sidebar: Information on Memento's Core Features */}
|
|
<div className="lg:col-span-5 flex flex-col justify-between space-y-6 text-left">
|
|
<div className="space-y-5">
|
|
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-accent/10 border border-accent/20 text-accent text-[9px] font-bold font-mono tracking-widest uppercase">
|
|
<Sparkles size={11} className="text-accent animate-pulse" />
|
|
DÉMO EN DIRECT ET COMPLÈTE DE L'INTERFACE
|
|
</div>
|
|
|
|
<h1 className="text-4xl md:text-5xl font-serif font-bold tracking-tight text-ink leading-[1.08] lg:-mr-10">
|
|
Pensez local.<br />
|
|
<span className="text-accent italic font-normal">Savoirs interconnectés.</span>
|
|
</h1>
|
|
|
|
<p className="text-stone-600 text-sm leading-relaxed font-light">
|
|
Memento rassemble vos notes, vos formules mathématiques et votre logique dans une structure d'apprentissage offline d'une flexibilité absolue. Évitez les abonnements ruineux en apportant votre clé personnelle (BYOK) ou utilisez l'environnement de manière 100% autonome et sécurisée.
|
|
</p>
|
|
|
|
{/* Guided Feature Tabs Selector: Directly gives info on what the user can do */}
|
|
<div className="space-y-3 pt-2 bg-white p-5 rounded-2xl border border-border shadow-xs">
|
|
<span className="text-[10px] uppercase font-extrabold tracking-widest text-[#A47148] font-mono block pl-1">
|
|
💡 Cliquez pour explorer une fonctionnalité réelle :
|
|
</span>
|
|
|
|
<div className="grid grid-cols-1 gap-2">
|
|
{[
|
|
{ key: 'editor', title: "L'Éditeur Papier & Carnets", desc: "Notes hiérarchiques, listes et formules de calcul", icon: <BookOpen size={14} className="text-amber-700" />, activeColor: "border-amber-700/30 bg-amber-50/20" },
|
|
{ key: 'graph', title: "Le Graphe de Connaissances Spatiales", desc: "Modélisation sémantique interactive et liens de vos idées", icon: <Network size={14} className="text-purple-700" />, activeColor: "border-purple-650/30 bg-purple-50/25" },
|
|
{ key: 'agents', title: "Les 6 Agents IA d'Enrichissement", desc: "Recherches automatisées, cartes mentales et résumés actifs", icon: <BrainCircuit size={14} className="text-blue-700" />, activeColor: "border-blue-600/30 bg-blue-50/25" },
|
|
{ key: 'reviews', title: "Le Deck de Révisions Smart Cards", desc: "Génération de Flashcards & répétition intelligente espacée", icon: <CheckSquare size={14} className="text-emerald-700" />, activeColor: "border-emerald-600/30 bg-emerald-50/25" },
|
|
{ key: 'history', title: "Snapshots Historiques & Restauration", desc: "Versionning de sécurité et sauvegarde locale persistante", icon: <History size={14} className="text-indigo-700" />, activeColor: "border-indigo-600/30 bg-indigo-50/25" },
|
|
].map((tab) => (
|
|
<button
|
|
key={tab.key}
|
|
onClick={() => {
|
|
setActiveTab(tab.key as any);
|
|
if (tab.key === 'editor' || tab.key === 'agents') {
|
|
triggerSimulation(0);
|
|
}
|
|
}}
|
|
className={`w-full text-left p-3.5 rounded-xl border transition-all duration-300 flex items-start gap-3 cursor-pointer group
|
|
${activeTab === tab.key
|
|
? `${tab.activeColor} border-accent shadow-xs`
|
|
: 'bg-transparent border-transparent hover:border-black/5 hover:bg-stone-50'
|
|
}`}
|
|
>
|
|
<div className={`p-2 rounded-lg bg-white border border-stone-200 shadow-3xs transition-transform group-hover:scale-105`}>
|
|
{tab.icon}
|
|
</div>
|
|
<div className="flex flex-col justify-center">
|
|
<span className={`text-[12px] font-bold tracking-tight ${activeTab === tab.key ? 'text-ink' : 'text-stone-850'}`}>
|
|
{tab.title}
|
|
</span>
|
|
<span className="text-[10.5px] text-stone-505 font-light mt-0.5 leading-snug">
|
|
{tab.desc}
|
|
</span>
|
|
</div>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* CTA action button */}
|
|
<div className="pt-2 space-y-3">
|
|
<button
|
|
onClick={onEnter}
|
|
className="w-full sm:w-auto px-8 py-4.5 bg-ink text-paper text-xs font-bold uppercase tracking-widest rounded-xl hover:opacity-95 shadow-xl shadow-ink/15 flex items-center justify-center gap-3 group cursor-pointer"
|
|
>
|
|
Entrer dans l'application libre
|
|
<ArrowRight size={14} className="group-hover:translate-x-1 transition-transform" />
|
|
</button>
|
|
<div className="flex justify-start items-center gap-2 text-stone-500 text-xs">
|
|
<Lock size={12} className="text-stone-400" />
|
|
<span className="text-[10px] font-mono uppercase tracking-widest font-black text-concrete">Local storage direct · Aucune inscription requise</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right Hero Column: True 1-to-1 Interactive Representation of Memento Workspace */}
|
|
<div className="lg:col-span-7 w-full flex flex-col justify-between">
|
|
<div className="w-full bg-[#1c1c1c] rounded-[24px] border border-ink/40 p-3 shadow-2xl relative overflow-hidden flex flex-col justify-between">
|
|
|
|
{/* Top Bar Navigation Buttons & Markers */}
|
|
<div className="flex items-center justify-between pb-3 border-b border-white/[0.06] text-xs px-2.5">
|
|
<div className="flex items-center gap-2">
|
|
<span className="w-3 h-3 rounded-full bg-red-500/80" />
|
|
<span className="w-3 h-3 rounded-full bg-amber-500/80" />
|
|
<span className="w-3 h-3 rounded-full bg-green-500/80" />
|
|
<span className="text-[10px] font-mono text-concrete uppercase tracking-widest font-bold ml-2">momento-workspace-client</span>
|
|
</div>
|
|
|
|
{activeTab === 'editor' && (
|
|
<div className="flex items-center bg-white/5 border border-white/10 px-2 py-0.5 rounded text-[8.5px] font-mono text-concrete uppercase tracking-wider gap-1.5 select-none">
|
|
<span className="w-1.5 h-1.5 rounded-full bg-amber-600 animate-pulse" />
|
|
Note active : {activeDemoIdx === -1 ? "Recherche perso" : realNotes[activeDemoIdx].title}
|
|
</div>
|
|
)}
|
|
{activeTab === 'graph' && (
|
|
<span className="px-2 py-0.5 rounded bg-purple-500/10 border border-purple-500/20 text-[8.5px] font-mono font-bold text-purple-400">
|
|
KNOWLEDGE MAP DETECTED
|
|
</span>
|
|
)}
|
|
{activeTab === 'agents' && (
|
|
<span className="px-2 py-0.5 rounded bg-blue-500/10 border border-blue-500/20 text-[8.5px] font-mono font-bold text-blue-400">
|
|
6 COGNITIVE AGENTS ON-DUTY
|
|
</span>
|
|
)}
|
|
{activeTab === 'reviews' && (
|
|
<span className="px-2 py-0.5 rounded bg-emerald-500/10 border border-emerald-500/20 text-[8.5px] font-mono font-bold text-emerald-400">
|
|
SPACED REPETITION STUDY
|
|
</span>
|
|
)}
|
|
{activeTab === 'history' && (
|
|
<span className="px-2 py-0.5 rounded bg-indigo-500/10 border border-indigo-500/20 text-[8.5px] font-mono font-bold text-indigo-400">
|
|
VERSION CONTROL SNAPSHOTS
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* Dynamic Interactive Panel Wrapper */}
|
|
<div className="grid grid-cols-12 min-h-[460px] bg-[#EBE9DF]/40 text-ink select-none relative">
|
|
|
|
{/* 1. Common Miniature left control rail */}
|
|
<div className="col-span-1 border-r border-[#1C1C1C]/10 py-5 flex flex-col items-center justify-between bg-[#F1EFEB]">
|
|
<div className="space-y-4.5 flex flex-col items-center">
|
|
<button
|
|
onClick={() => setActiveTab('editor')}
|
|
className={`p-1.8 rounded-lg cursor-pointer transition-colors ${activeTab === 'editor' ? 'text-accent bg-white border border-border shadow-xs' : 'text-stone-400 hover:text-ink'}`}
|
|
title="Éditeur de Notes"
|
|
>
|
|
<BookOpen size={14} />
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('graph')}
|
|
className={`p-1.8 rounded-lg cursor-pointer transition-colors ${activeTab === 'graph' ? 'text-accent bg-white border border-border shadow-xs' : 'text-stone-400 hover:text-ink'}`}
|
|
title="Graphe de connaissances"
|
|
>
|
|
<Network size={14} />
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('agents')}
|
|
className={`p-1.8 rounded-lg cursor-pointer transition-colors ${activeTab === 'agents' ? 'text-accent bg-white border border-border shadow-xs' : 'text-stone-400 hover:text-ink'}`}
|
|
title="Agents d'Enrichissement"
|
|
>
|
|
<CpuIconPlaceholder />
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('reviews')}
|
|
className={`p-1.8 rounded-lg cursor-pointer transition-colors ${activeTab === 'reviews' ? 'text-accent bg-white border border-border shadow-xs' : 'text-stone-400 hover:text-ink'}`}
|
|
title="Deck de Flashcards"
|
|
>
|
|
<CheckSquare size={14} />
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('history')}
|
|
className={`p-1.8 rounded-lg cursor-pointer transition-colors ${activeTab === 'history' ? 'text-accent bg-white border border-border shadow-xs' : 'text-stone-400 hover:text-ink'}`}
|
|
title="Historique Snapshots"
|
|
>
|
|
<History size={14} />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
<Sliders size={14} className="text-stone-400" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* 2. Content view depending on active TAB */}
|
|
<div className="col-span-11 bg-[#FAF9F5] overflow-y-auto max-h-[460px] custom-scrollbar text-left font-sans">
|
|
<AnimatePresence mode="wait">
|
|
|
|
{/* VIEW A: EDITOR & CARNET SYSTEM */}
|
|
{activeTab === 'editor' && (
|
|
<motion.div
|
|
key="editorView"
|
|
initial={{ opacity: 0, y: 5 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0 }}
|
|
className="grid grid-cols-12 min-h-full"
|
|
>
|
|
{/* Nested Folder Panel */}
|
|
<div className="col-span-4 border-r border-[#1C1C1C]/15 bg-[#FDFDFC] p-3 space-y-3">
|
|
<span className="text-[8.5px] font-extrabold uppercase tracking-widest text-concrete font-mono block border-b pb-1">Notes Disponibles</span>
|
|
<div className="space-y-1.5">
|
|
{realNotes.map((note, idx) => (
|
|
<button
|
|
key={note.id}
|
|
onClick={() => triggerSimulation(idx)}
|
|
className={`w-full text-left p-2.5 rounded-lg border text-xs transition-colors cursor-pointer block
|
|
${activeDemoIdx === idx
|
|
? 'bg-[#EAE8DF] border-accent/25'
|
|
: 'border-transparent bg-stone-50 hover:bg-[#EAE8DF]/40'
|
|
}`}
|
|
>
|
|
<span className="text-[8px] font-mono uppercase bg-black/5 px-1 py-0.2 rounded text-stone-500 mb-1 inline-block">{note.carnet}</span>
|
|
<span className="font-bold text-ink block truncate">{note.title}</span>
|
|
</button>
|
|
))}
|
|
<button
|
|
onClick={() => triggerSimulation(0)}
|
|
className="w-full text-center border border-dashed border-accent/30 py-2 rounded-lg text-[9px] font-mono text-accent block hover:bg-accent/5"
|
|
>
|
|
+ Nouveau Document
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Middle Rich Editor Page */}
|
|
<div className="col-span-8 p-5 bg-[#FAF9F5]/70 min-h-full">
|
|
<div className="p-5.5 bg-[#FDFDFD] border border-[#1C1C1C]/5 rounded-xl shadow-xs space-y-4 min-h-[380px] font-sans paper-texture">
|
|
<div className="flex justify-between items-center text-[8.5px] uppercase font-bold tracking-widest font-mono text-[#A47148]">
|
|
<span>{activeDemoIdx === -1 ? "RECHERCHE PERSO" : realNotes[activeDemoIdx].carnet}</span>
|
|
<span className="text-concrete">{activeDemoIdx === -1 ? "MAI 2026" : realNotes[activeDemoIdx].date}</span>
|
|
</div>
|
|
|
|
<h2 className="text-[19px] font-serif font-bold text-ink leading-tight">
|
|
{activeDemoIdx === -1 ? "Votre de Note sémantique" : realNotes[activeDemoIdx].title}
|
|
</h2>
|
|
|
|
<div className="flex gap-1.5 flex-wrap">
|
|
{(activeDemoIdx === -1 ? [{ label: "Structure perso", type: "user" }] : realNotes[activeDemoIdx].tags.map(t => ({ label: t, type: "user" }))).map((tag, i) => (
|
|
<span key={i} className="text-[8px] font-mono font-bold uppercase tracking-widest bg-stone-100 border border-border px-1.5 py-0.5 rounded text-stone-500">
|
|
{tag.label}
|
|
</span>
|
|
))}
|
|
</div>
|
|
|
|
{/* Streamer loader */}
|
|
<div className="space-y-3.5 text-[11px] leading-relaxed text-stone-700">
|
|
<AnimatePresence mode="wait">
|
|
{simulateState === 'searching' && (
|
|
<div className="py-12 space-y-2 text-center">
|
|
<div className="relative inline-flex">
|
|
<span className="flex h-5 w-5 relative">
|
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-accent/40 opacity-75" />
|
|
<span className="relative inline-flex rounded-full h-5 w-5 bg-accent" />
|
|
</span>
|
|
</div>
|
|
<p className="text-[9px] font-mono uppercase tracking-widest text-[#A47148]">Lecture locale...</p>
|
|
</div>
|
|
)}
|
|
|
|
{(simulateState === 'writing' || simulateState === 'complete') && (
|
|
<div className="space-y-3">
|
|
{displayText.split('\n').map((line, idx) => {
|
|
if (line.startsWith('# ')) return null;
|
|
if (line.startsWith('## ')) {
|
|
return <h4 key={idx} className="text-xs font-bold text-ink border-b pb-0.5 mt-3">{line.replace('## ', '')}</h4>;
|
|
}
|
|
if (line.startsWith('$$')) {
|
|
return (
|
|
<div key={idx} className="p-2 bg-[#FAF9F5] text-[#A47148] border rounded-lg text-center font-mono font-semibold select-all leading-none my-1">
|
|
{line.replace(/\$\$/g, '')}
|
|
</div>
|
|
);
|
|
}
|
|
if (line.startsWith('* ')) {
|
|
return (
|
|
<div key={idx} className="flex gap-1.5 pl-1.5 text-stone-600">
|
|
<span className="text-accent">•</span>
|
|
<span>{line.replace('* ', '')}</span>
|
|
</div>
|
|
);
|
|
}
|
|
return <p key={idx} className="text-stone-600 font-light select-text">{line}</p>;
|
|
})}
|
|
</div>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
|
|
{/* VIEW B: MOOD-REINFORCED KNOWLEDGE GRAPH MAP */}
|
|
{activeTab === 'graph' && (
|
|
<motion.div
|
|
key="graphView"
|
|
initial={{ opacity: 0, scale: 0.98 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
className="p-6 space-y-4 min-h-full flex flex-col justify-between"
|
|
>
|
|
<div className="space-y-1">
|
|
<span className="text-[9px] uppercase tracking-[0.2em] font-extrabold text-[#A47148] font-mono block">Cartographie de Votre Deuxième Cerveau</span>
|
|
<p className="text-[11px] text-stone-500 font-light">Double-cliquez n'importe quel nœud pour naviguer dans l'espace ou lier vos notes.</p>
|
|
</div>
|
|
|
|
{/* Real-looking interactive diagram representation */}
|
|
<div className="border border-border bg-[#FDFCFA] rounded-xl flex items-center justify-center p-4 relative overflow-hidden min-h-[300px] shadow-sm select-none">
|
|
|
|
{/* Dot Grid Blueprint SVG background */}
|
|
<svg className="absolute inset-0 w-full h-full pointer-events-none" xmlns="http://www.w3.org/2000/svg">
|
|
<defs>
|
|
<pattern id="dotPattern" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
<circle cx="2" cy="2" r="1" fill="#A47148" opacity="0.12" />
|
|
</pattern>
|
|
</defs>
|
|
<rect width="100%" height="100%" fill="url(#dotPattern)" />
|
|
|
|
{/* Visual connections with gorgeous soft accent glow */}
|
|
<g opacity="0.45">
|
|
<line x1="50%" y1="50%" x2="25%" y2="30%" stroke="#A47148" strokeWidth="1.2" strokeDasharray="3 3" />
|
|
<line x1="50%" y1="50%" x2="75%" y2="28%" stroke="#A47148" strokeWidth="1.2" strokeDasharray="3 3" />
|
|
<line x1="50%" y1="50%" x2="20%" y2="72%" stroke="#1C1C1C" strokeWidth="1.2" />
|
|
<line x1="50%" y1="50%" x2="80%" y2="68%" stroke="#1C1C1C" strokeWidth="1.2" />
|
|
<line x1="50%" y1="50%" x2="50%" y2="20%" stroke="#8B5CF6" strokeWidth="1.5" />
|
|
<line x1="50%" y1="50%" x2="50%" y2="80%" stroke="#10B981" strokeWidth="1.5" />
|
|
</g>
|
|
</svg>
|
|
|
|
{/* central nexus */}
|
|
<div className="w-14 h-14 rounded-full bg-ink text-paper font-serif font-black text-[11px] flex items-center justify-center border-[5px] border-white shadow-lg relative z-20 select-none hover:scale-105 transition-transform duration-300">
|
|
MOMENTO
|
|
</div>
|
|
|
|
{/* Clustered conceptual nodes linked with visual lines */}
|
|
{[
|
|
{ name: "Nombre d'Or", x: -100, y: -65, tag: "Architecture", theme: "text-amber-800 bg-amber-50/95" },
|
|
{ name: "Diffraction lumineuse", x: 105, y: -72, tag: "Optique", theme: "text-violet-850 bg-violet-50/95" },
|
|
{ name: "Bois CLT Lamellé", x: -115, y: 70, tag: "Matériaux", theme: "text-emerald-800 bg-emerald-50/95" },
|
|
{ name: "Transition Formelle", x: 110, y: 60, tag: "Minimalisme", theme: "text-blue-800 bg-blue-50/95" },
|
|
{ name: "Grid System", x: 0, y: -100, tag: "IA Géométrie", theme: "text-stone-800 bg-stone-50/95" },
|
|
{ name: "Éco-Conception", x: 0, y: 100, tag: "Coût Carbone", theme: "text-rose-800 bg-rose-50/95" }
|
|
].map((node, i) => {
|
|
return (
|
|
<div
|
|
key={i}
|
|
style={{ transform: `translate(${node.x}px, ${node.y}px)` }}
|
|
className="absolute cursor-pointer transition-transform hover:scale-105 z-10"
|
|
>
|
|
<div className="px-3 py-1.8 bg-white border border-[#1C1C1C]/10 rounded-xl shadow-xs font-sans text-left space-y-0.5 max-w-[125px]">
|
|
<span className="text-[9px] font-bold text-ink block truncate leading-tight">{node.name}</span>
|
|
<span className={`text-[7px] font-mono tracking-widest uppercase px-1 py-[1px] rounded inline-block font-extrabold ${node.theme}`}>
|
|
{node.tag}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between border-t border-black/[0.04] pt-2.5 text-[9px] font-mono text-concrete uppercase tracking-widest font-bold">
|
|
<span>6 documents connectés</span>
|
|
<span className="text-purple-600">Structure sémantique : Optimale ✓</span>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
|
|
{/* VIEW C: THE 6 INTELLIGENT AGENTS SYSTEM */}
|
|
{activeTab === 'agents' && (
|
|
<motion.div
|
|
key="agentsView"
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
className="grid grid-cols-12 min-h-full"
|
|
>
|
|
{/* Selector items */}
|
|
<div className="col-span-5 border-r border-[#1C1C1C]/10 bg-[#FAF9F6] p-3.5 space-y-3 select-none">
|
|
<span className="text-[8.5px] font-extrabold uppercase tracking-widest text-[#A47148] font-mono block border-b pb-1.5">Système d'Agents (6)</span>
|
|
<div className="space-y-1.5">
|
|
{[
|
|
{ id: "scr", name: "Web Scraper Agent", role: "Enrichit vos notes via analyse d'URL", tag: "SCR", color: "bg-amber-120 text-amber-900 border-amber-200" },
|
|
{ id: "res", name: "Deep Researcher", role: "Excave les bases et revues sur le Web", tag: "RES", color: "bg-teal-100 text-teal-900 border-teal-200" },
|
|
{ id: "sli", name: "Slide Deck Builder", role: "Convertit vos idées en slides articulées", tag: "PPT", color: "bg-blue-100 text-blue-900 border-blue-200" },
|
|
{ id: "mon", name: "Knowledge Monitor", role: "Identifie les lacunes & opportunités de liens", tag: "LNK", color: "bg-purple-100 text-purple-900 border-purple-200" },
|
|
{ id: "dia", name: "Mindmap Architect", role: "Génère des cartes mentales interactives", tag: "MAP", color: "bg-emerald-100 text-emerald-900 border-emerald-200" },
|
|
{ id: "cus", name: "Agent Sur-Mesure", role: "Définissez des consignes et rôles précis", tag: "IA", color: "bg-stone-100 text-stone-900 border-stone-200" }
|
|
].map((a) => (
|
|
<div key={a.id} className="p-2.5 bg-white rounded-xl border border-stone-200 hover:border-accent hover:shadow-2xs transition-all cursor-pointer text-left space-y-1">
|
|
<div className="flex items-center justify-between gap-1">
|
|
<span className="font-extrabold text-[#1c1c1c] text-[10px] leading-tight block truncate">{a.name}</span>
|
|
<span className={`text-[7px] font-mono font-black border px-1 rounded-sm ${a.color}`}>{a.tag}</span>
|
|
</div>
|
|
<span className="text-[9px] text-stone-500 font-light leading-normal block">{a.role}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Active Agent Interactive Chat/RAG sidebar mockup */}
|
|
<div className="col-span-7 bg-[#FDFDFC] flex flex-col justify-between p-4 font-sans">
|
|
<div className="space-y-3.5">
|
|
<div className="flex border-b border-border bg-[#F1EFEB] rounded-lg overflow-hidden shrink-0">
|
|
{([
|
|
{ key: 'explore', label: 'Explore (RAG)' },
|
|
{ key: 'discussion', label: 'Discussion' },
|
|
{ key: 'relations', label: 'Rapports' }
|
|
] as const).map((tab) => (
|
|
<button
|
|
key={tab.key}
|
|
onClick={() => setAiSidebarTab(tab.key)}
|
|
className={`flex-1 py-2 text-[8.5px] uppercase tracking-wider font-extrabold text-stone-500 border-r last:border-r-0 border-border transition-all cursor-pointer text-center
|
|
${aiSidebarTab === tab.key ? 'bg-white text-ink border-b-2 border-b-accent' : 'hover:bg-white/40'}`}
|
|
>
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="space-y-3 min-h-[220px] text-left">
|
|
<AnimatePresence mode="wait">
|
|
{aiSidebarTab === 'explore' && (
|
|
<motion.div key="explore" initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="space-y-3">
|
|
<span className="text-[8.5px] font-mono font-bold uppercase tracking-widest text-[#A47148] block">Analyse RAG passive active :</span>
|
|
<div className="p-2.5 bg-[#FAF9F5] rounded-xl border font-mono text-[8.5px] text-stone-600 space-y-1">
|
|
<span className="block font-extrabold">TERMES DE REQUÊTE :</span>
|
|
<span className="block text-ink font-semibold">"{activeDemoIdx === -1 ? customPrompt || "Géométrie d'or" : realNotes[activeDemoIdx].title}"</span>
|
|
</div>
|
|
<div className="space-y-1.5 pt-1">
|
|
<span className="text-[8.5px] font-bold text-[#8D8D8D] uppercase tracking-widest block pl-0.5">Scraping de sources web et articles :</span>
|
|
<div className="p-2 bg-white border rounded-lg flex items-center justify-between text-[8px] font-mono">
|
|
<span className="text-concrete truncate max-w-[200px]">https://wikipedia.org/wiki/Grid_system_(graphic_design)</span>
|
|
<span className="text-emerald-600 font-extrabold">200 OK</span>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
|
|
{aiSidebarTab === 'discussion' && (
|
|
<motion.div key="discussion" initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="space-y-3 text-[11px] leading-relaxed">
|
|
<div className="p-2.5 bg-slate-50 border rounded-xl text-stone-600">
|
|
<span className="text-[8px] font-mono uppercase text-light block text-stone-400">Consigne utilisateur</span>
|
|
Résume les points géométriques en 2 points clés.
|
|
</div>
|
|
<div className="p-2.5 bg-white border rounded-xl text-ink">
|
|
<span className="text-[8px] font-mono uppercase text-accent font-extrabold block">Modèle de langage (Gemini)</span>
|
|
1. Utilisation du Nombre d'Or pour la logique de trame.<br />
|
|
2. Alignement des forces lumineuses déplaçables.
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
|
|
{aiSidebarTab === 'relations' && (
|
|
<motion.div key="relations" initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="space-y-3">
|
|
<span className="text-[8.5px] font-mono font-bold uppercase tracking-widest text-[#A47148] block">Index Sémantique</span>
|
|
<div className="p-3 bg-white border border-border rounded-xl flex items-center justify-between text-[10px]">
|
|
<span className="font-bold">Score de similarité sémantique</span>
|
|
<span className="font-mono text-accent text-xs font-bold">94% ✓</span>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="p-2.5 bg-[#F1EFEB] border border-border text-[8.5px] font-mono text-concrete flex items-center justify-between rounded-lg">
|
|
<span>SÉCURITÉ CHAT : 100% CRYPTÉ</span>
|
|
<span className="text-accent font-extrabold">PROCESSEUR : BYOK ACTIF</span>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
|
|
{/* VIEW D: ACTIVE RECALL / SPACED REPETITION FLASHCARDS */}
|
|
{activeTab === 'reviews' && (
|
|
<motion.div
|
|
key="reviewsView"
|
|
initial={{ opacity: 0, scale: 0.99 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
className="p-6 space-y-4 min-h-full flex flex-col justify-between text-[#1C1C1C]"
|
|
>
|
|
<div className="space-y-1">
|
|
<span className="text-[9px] uppercase tracking-[0.2em] font-extrabold text-[#A47148] font-mono block">Système d'Étude Active Spaced-Repetition</span>
|
|
<p className="text-[11px] text-stone-500 font-light">L'IA parcourt vos notes pour vous tester et ancrer les concepts dans votre mémoire de travail.</p>
|
|
</div>
|
|
|
|
{/* Visual study card mockup */}
|
|
<div className="bg-white border p-6.5 rounded-xl shadow-xs space-y-4 text-center max-w-md mx-auto w-full min-h-[180px] flex flex-col justify-between relative border-accent/20 paper-texture">
|
|
<div className="space-y-2">
|
|
<span className="text-[8.5px] font-mono uppercase bg-accent/10 text-accent px-2 py-0.5 rounded-full font-bold">Question {flashcardIdx + 1}/2</span>
|
|
<h4 className="text-xs font-serif font-bold text-ink leading-relaxed">
|
|
{simulatedFlashcards[flashcardIdx].question}
|
|
</h4>
|
|
</div>
|
|
|
|
{showFlashcardAnswer ? (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 3 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className="p-3 bg-[#FAF9F5] border border-accent/20 rounded-lg text-left text-[11px] leading-relaxed text-[#A47148] font-light"
|
|
>
|
|
<span className="text-[8.5px] font-mono font-bold uppercase tracking-wider block mb-1">Réponse correcte</span>
|
|
{simulatedFlashcards[flashcardIdx].answer}
|
|
</motion.div>
|
|
) : (
|
|
<button
|
|
onClick={() => setShowFlashcardAnswer(true)}
|
|
className="px-4 py-2 bg-accent/10 hover:bg-accent/20 text-accent transition-colors text-[10px] font-bold uppercase tracking-wider rounded-xl cursor-pointer"
|
|
>
|
|
Afficher la Réponse
|
|
</button>
|
|
)}
|
|
|
|
{showFlashcardAnswer && (
|
|
<div className="flex gap-1 justify-center pt-2.5">
|
|
{[
|
|
{ label: "À revoir", color: "bg-red-500/10 text-red-600 hover:bg-red-500/20" },
|
|
{ label: "Moyen", color: "bg-amber-500/10 text-amber-600 hover:bg-amber-500/20" },
|
|
{ label: "Facile", color: "bg-emerald-500/10 text-emerald-600 hover:bg-emerald-500/20" }
|
|
].map((btn, i) => (
|
|
<button
|
|
key={i}
|
|
onClick={() => {
|
|
setShowFlashcardAnswer(false);
|
|
setFlashcardIdx((prev) => (prev + 1) % 2);
|
|
}}
|
|
className={`px-3 py-1.5 rounded-lg text-[9px] font-mono font-black uppercase transition-colors cursor-pointer ${btn.color}`}
|
|
>
|
|
{btn.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between border-t border-black/[0.04] pt-2 text-[9px] font-mono text-concrete uppercase tracking-widest font-black">
|
|
<span>Étude de Mémoire</span>
|
|
<span className="text-[#A3B18A]">Algorithme SuperMemo actif</span>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
|
|
{/* VIEW E: SNAPSHOTS & VERSIONS HISTORY */}
|
|
{activeTab === 'history' && (
|
|
<motion.div
|
|
key="historyView"
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
className="p-6 space-y-4 min-h-full flex flex-col justify-between"
|
|
>
|
|
<div className="space-y-1">
|
|
<span className="text-[9px] uppercase tracking-[0.2em] font-extrabold text-[#A47148] font-mono block font-sans">Snapshot de Sécurité Temporel</span>
|
|
<p className="text-[11px] text-stone-500 font-light">Explorez et restaurez n'importe quel état de rédaction antérieur. Zéro perte accidentelle.</p>
|
|
</div>
|
|
|
|
{/* Simulated timeline events */}
|
|
<div className="space-y-2 max-w-lg mx-auto w-full text-xs">
|
|
{[
|
|
{ time: "Aujourd'hui, 09:56", event: "Modification de l'Equation", author: "Moi", size: "182 mots", active: true },
|
|
{ time: "Aujourd'hui, 09:21", event: "Analyse d'échantillons CLT par l'Agent Scraper", author: "Agent IA", size: "124 mots" },
|
|
{ time: "Hier, 14:20", event: "Import de grilles orthogonales initiales", author: "Moi", size: "86 mots" },
|
|
{ time: "22 Mai 2026", event: "Création du document d'étude", author: "Système", size: "12 mots" }
|
|
].map((snap, i) => (
|
|
<div
|
|
key={i}
|
|
className={`p-3 bg-[#FDFDFC] border rounded-xl flex items-center justify-between shadow-2xs transition-colors
|
|
${snap.active ? 'border-accent ring-2 ring-accent/10' : 'border-[#1C1C1C]/10 hover:border-accent/40'}`}
|
|
>
|
|
<div className="flex items-center gap-3 text-left">
|
|
<Clock size={14} className="text-[#A47148]" />
|
|
<div>
|
|
<span className="font-bold text-ink block leading-snug">{snap.event}</span>
|
|
<span className="text-[9.5px] text-[#8D8D8D] font-light font-mono block mt-0.5">{snap.time} · Auteur : {snap.author}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
className="text-[8.5px] uppercase tracking-widest font-mono font-black text-accent cursor-pointer bg-[#faf9f5] border p-1.5 rounded-lg hover:bg-accent hover:text-white transition-colors"
|
|
onClick={() => {
|
|
if (i === 1) triggerSimulation(1);
|
|
if (i === 2) triggerSimulation(0);
|
|
}}
|
|
>
|
|
{snap.active ? "Actif ✓" : "Restauration"}
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between border-t border-black/[0.04] pt-2 text-[9px] font-mono text-concrete uppercase tracking-widest font-black">
|
|
<span>État local sauvegardé</span>
|
|
<span className="text-[#A3B18A]">Compression d'historique : Active</span>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
|
|
</AnimatePresence>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{/* Minimalist modern control status bar */}
|
|
<div className="border-t border-black/[0.08] bg-[#F2F1EA] px-5 py-3 rounded-b-[18px] flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 text-left select-none">
|
|
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-[9.5px] font-mono text-stone-600 uppercase tracking-widest">
|
|
<div className="flex items-center gap-1.5 font-bold text-accent">
|
|
<span className="w-1.5 h-1.5 rounded-full bg-accent animate-pulse" />
|
|
<span>ESPACE AUTONOME</span>
|
|
</div>
|
|
<span className="text-stone-300 hidden sm:inline">|</span>
|
|
<span className="font-light">Zéro cloud requis</span>
|
|
<span className="text-stone-300 hidden sm:inline">|</span>
|
|
<span className="font-semibold text-ink">Bases cryptées localement</span>
|
|
</div>
|
|
|
|
<button
|
|
onClick={onEnter}
|
|
className="w-full sm:w-auto px-5 py-2 bg-ink hover:bg-accent text-[#FAF9F6] text-[10px] font-bold uppercase tracking-widest rounded-lg flex items-center justify-center gap-2 transition-all duration-300 shadow-sm hover:translate-x-0.5"
|
|
>
|
|
Ouvrir l'application
|
|
<ArrowRight size={11} className="text-paper" />
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</section>
|
|
|
|
{/* 3. "BYOK" (Bring Your Own Key) & Privacy Showcase section */}
|
|
<section className="py-20 px-6 border-t border-border bg-white text-center">
|
|
<div className="max-w-6xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-12 items-center text-left">
|
|
<div className="space-y-6">
|
|
<span className="text-[10px] font-bold uppercase tracking-[0.3em] text-[#A47148] font-mono block">Respect Souverain des Écrits</span>
|
|
<h2 className="text-3xl font-serif text-[#1C1C1C] tracking-tight leading-tight">Aucun abonnement IA obligatoire grâce au modèle "BYOK".</h2>
|
|
<p className="text-sm font-light text-stone-600 leading-relaxed">
|
|
La plupart des applications cloud d'intelligence artificielle re-facturent de lourdes marges commerciales sur vos écrits. Memento change les règles du jeu :
|
|
</p>
|
|
<div className="space-y-4">
|
|
<div className="flex gap-4">
|
|
<div className="w-10 h-10 bg-accent/5 border border-accent/15 rounded-xl flex items-center justify-center shrink-0">
|
|
<Database size={16} className="text-accent" />
|
|
</div>
|
|
<div>
|
|
<h4 className="text-sm font-bold text-ink leading-snug">Données stockées localement dans votre navigateur</h4>
|
|
<p className="text-[11.5px] text-stone-500 font-light mt-0.5">Zéro base de données tiers n'a accès à vos cours et recherches.</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex gap-4">
|
|
<div className="w-10 h-10 bg-accent/5 border border-accent/15 rounded-xl flex items-center justify-center shrink-0">
|
|
<Terminal size={16} className="text-accent" />
|
|
</div>
|
|
<div>
|
|
<h4 className="text-sm font-bold text-ink leading-snug">Ajoutez votre clé API gratuite ou premium</h4>
|
|
<p className="text-[11.5px] text-stone-500 font-light mt-0.5">Entrez votre propre secret Gemini, OpenAI ou Anthropic pour payer sans commission, exactement selon vos besoins d'écriture.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-ink text-paper rounded-3xl p-8 relative overflow-hidden group">
|
|
<div className="absolute inset-0 bg-accent/10 blur-[60px] pointer-events-none" />
|
|
<div className="relative z-10 font-mono text-[9.5px] text-paper/40 space-y-2 text-left">
|
|
<p className="text-accent">{"{"}</p>
|
|
<p className="pl-4">"momento_client_profile": "offline_first",</p>
|
|
<p className="pl-4">"byok_providers": ["google_gemini", "openai_custom"],</p>
|
|
<p className="pl-4 font-bold border-l-2 border-accent bg-[#2a2a2a] px-2 py-0.5 text-paper">"local_db_encryption": "AES_256_GCM",</p>
|
|
<p className="pl-4">"auto_save_active": true</p>
|
|
<p className="text-accent">{"}"}</p>
|
|
</div>
|
|
|
|
<div className="mt-8 flex items-center justify-between relative z-10 pt-4 border-t border-white/[0.06]">
|
|
<div className="text-left">
|
|
<span className="text-[9px] font-mono text-[#8D8D8D] uppercase block">Méthode d'exécution</span>
|
|
<span className="text-xs font-bold text-paper block">Client-Side Direct Injection</span>
|
|
</div>
|
|
<div className="flex gap-1">
|
|
{[1,2,3].map(i => <div key={i} className="w-1.5 h-1.5 rounded-full bg-accent animate-pulse" />)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* 4. Architectural Pillars section */}
|
|
<section className="py-24 px-6 border-y border-border bg-[#FDFCFA] text-center select-none">
|
|
<div className="max-w-6xl mx-auto space-y-16">
|
|
<div className="max-w-xl mx-auto text-center space-y-3">
|
|
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-[#A47148] font-mono block">Les Atouts Pratiques</span>
|
|
<h2 className="text-3xl font-serif text-[#1C1C1C] tracking-tight leading-tight">Pourquoi utiliser Memento ?</h2>
|
|
<p className="text-xs font-light text-stone-500">Un écosystème conçu de bout en bout pour l'autonomie et la productivité.</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 items-stretch">
|
|
{[
|
|
{
|
|
icon: <Sliders className="text-[#A47148]" />,
|
|
title: "Personnalisation Totale",
|
|
desc: "Réglez vos couleurs d'accentuation, triez vos tags et gérez l'interface pour correspondre à vos habitudes d'études."
|
|
},
|
|
{
|
|
icon: <BrainCircuit className="text-purple-600" />,
|
|
title: "6 Modèles d'Agents",
|
|
desc: "Scrapeurs, réviseurs, générateurs de slides ou mindmaps d'un simple clic pour vous faire gagner des heures."
|
|
},
|
|
{
|
|
icon: <PlusSquare className="text-emerald-600" />,
|
|
title: "Prise en main Libre",
|
|
desc: "Zéro formule de carte bancaire, zéro formulaire interminable. L'application s'initialise instantanément."
|
|
},
|
|
{
|
|
icon: <Lock className="text-indigo-600" />,
|
|
title: "100% Confidentialité",
|
|
desc: "Vos écrits ne quittent jamais votre machine locale. Aucune récolte ou exploitation de données n'est effectuée."
|
|
}
|
|
].map((p, i) => (
|
|
<div key={i} className="p-6 bg-white border border-[#1C1C1C]/10 hover:border-accent hover:shadow-xl transition-all duration-500 rounded-2xl text-left space-y-4 flex flex-col justify-between cursor-pointer">
|
|
<div className="w-10 h-10 bg-[#FAF9F5] border border-border rounded-xl flex items-center justify-center shrink-0">
|
|
{p.icon}
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<h4 className="text-xs font-bold font-sans text-[#1C1C1C] uppercase tracking-wider">{p.title}</h4>
|
|
<p className="text-xs text-stone-500 font-light leading-relaxed">{p.desc}</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* 5. Direct Launch Action Bottom Section */}
|
|
<section className="py-20 text-center bg-[#FAF9F5]/70 select-none">
|
|
<div className="max-w-xl mx-auto space-y-5 px-6">
|
|
<h3 className="text-2xl font-serif text-[#1C1C1C] tracking-tight">Structurer vos notes et vos pensées.</h3>
|
|
<p className="text-xs text-stone-500 font-light">Accédez directement à l'espace de travail fluide de Memento, sans processus contraignant.</p>
|
|
<div className="flex gap-4 justify-center">
|
|
<button
|
|
onClick={onEnter}
|
|
className="px-8 py-4 bg-ink text-paper text-xs font-bold uppercase tracking-widest rounded-xl hover:opacity-90 cursor-pointer shadow-md"
|
|
>
|
|
Lancer l'application
|
|
</button>
|
|
<button
|
|
onClick={onLogin}
|
|
className="px-8 py-4 border border-border bg-white text-xs font-bold uppercase tracking-widest rounded-xl hover:bg-slate-50 cursor-pointer"
|
|
>
|
|
Me Connecter
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Skeuomorphic footer */}
|
|
<footer className="py-12 border-t border-border bg-white text-center text-[10px] uppercase font-bold tracking-widest text-[#8D8D8D] select-none">
|
|
<div className="max-w-6xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-4">
|
|
<div>© 2026 MOMENTO LABS. TOUS DROITS RÉSERVÉS.</div>
|
|
<div className="flex items-center gap-1 text-[9px] text-[#A47148]">
|
|
<span>CONFECTIONNÉ AVEC</span>
|
|
<Heart size={10} className="text-red-500 fill-current animate-pulse" />
|
|
<span>EXCLUSIVEMENT EN FRANCE</span>
|
|
</div>
|
|
<div className="flex gap-8">
|
|
<span>PRODUIT PAR ANTIGRAVITY</span>
|
|
<span>MOTORISÉ PAR GEMINI 3.5 FLASH</span>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// Miniature Icons placeholder to avoid unused variables or broken builds
|
|
const CpuIconPlaceholder = () => (
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<rect x="4" y="4" width="16" height="16" rx="2" ry="2" />
|
|
<rect x="9" y="9" width="6" height="6" />
|
|
<line x1="9" y1="1" x2="9" y2="4" />
|
|
<line x1="15" y1="1" x2="15" y2="4" />
|
|
<line x1="9" y1="20" x2="9" y2="23" />
|
|
<line x1="15" y1="20" x2="15" y2="23" />
|
|
<line x1="20" y1="9" x2="23" y2="9" />
|
|
<line x1="20" y1="15" x2="23" y2="15" />
|
|
<line x1="1" y1="9" x2="4" y2="9" />
|
|
<line x1="1" y1="15" x2="4" y2="15" />
|
|
</svg>
|
|
);
|