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
2431 lines
155 KiB
TypeScript
2431 lines
155 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
||
import { motion, AnimatePresence } from 'motion/react';
|
||
import {
|
||
BrainCircuit,
|
||
Search,
|
||
MessageSquare,
|
||
Zap,
|
||
Cpu,
|
||
Workflow,
|
||
Globe,
|
||
Shield,
|
||
ArrowRight,
|
||
Sparkles,
|
||
Layers,
|
||
Box,
|
||
FileText,
|
||
Activity,
|
||
ArrowRightLeft,
|
||
Check,
|
||
Languages,
|
||
History,
|
||
Network,
|
||
Clock,
|
||
BookOpen,
|
||
Sliders,
|
||
CheckSquare,
|
||
Lock,
|
||
Compass,
|
||
HelpCircle
|
||
} from 'lucide-react';
|
||
|
||
// Define the shape of our localized dictionary keys
|
||
interface LangDict {
|
||
nav_features: string;
|
||
nav_agents: string;
|
||
nav_brainstorm: string;
|
||
nav_pricing: string;
|
||
nav_architecture: string;
|
||
nav_login: string;
|
||
nav_start: string;
|
||
|
||
hero_badge: string;
|
||
hero_title_1: string;
|
||
hero_title_italic: string;
|
||
hero_desc: string;
|
||
hero_cta_start: string;
|
||
hero_cta_features: string;
|
||
|
||
floating_card_1: string;
|
||
floating_card_1_text: string;
|
||
floating_card_2: string;
|
||
floating_card_2_text: string;
|
||
floating_card_2_desc: string;
|
||
|
||
features_badge: string;
|
||
features_title_1: string;
|
||
features_title_2: string;
|
||
features_subtitle: string;
|
||
|
||
f1_title: string;
|
||
f1_desc: string;
|
||
f2_title: string;
|
||
f2_desc: string;
|
||
f3_title: string;
|
||
f3_desc: string;
|
||
|
||
agents_badge: string;
|
||
agents_title: string;
|
||
agents_subtitle: string;
|
||
|
||
agent_scraper_desc: string;
|
||
agent_researcher_desc: string;
|
||
agent_slide_desc: string;
|
||
agent_monitor_desc: string;
|
||
agent_diagram_desc: string;
|
||
agent_custom_desc: string;
|
||
|
||
brain_badge: string;
|
||
brain_title: string;
|
||
brain_item1_title: string;
|
||
brain_item1_desc: string;
|
||
brain_item2_title: string;
|
||
brain_item2_desc: string;
|
||
brain_item3_title: string;
|
||
brain_item3_desc: string;
|
||
|
||
brain_node1_title: string;
|
||
brain_node1_text: string;
|
||
brain_node2_title: string;
|
||
brain_node2_text: string;
|
||
|
||
tech_badge: string;
|
||
tech_title: string;
|
||
tech_tier1_label: string;
|
||
tech_tier1_desc: string;
|
||
tech_tier2_label: string;
|
||
tech_tier2_desc: string;
|
||
tech_tier3_label: string;
|
||
tech_tier3_desc: string;
|
||
|
||
price_badge: string;
|
||
price_title: string;
|
||
price_desc: string;
|
||
price_monthly: string;
|
||
price_annual: string;
|
||
price_popular: string;
|
||
price_free_name: string;
|
||
price_free_price: string;
|
||
price_free_desc: string;
|
||
price_pro_name: string;
|
||
price_pro_price: string;
|
||
price_pro_desc: string;
|
||
price_biz_name: string;
|
||
price_biz_price: string;
|
||
price_biz_desc: string;
|
||
price_ent_name: string;
|
||
price_ent_price: string;
|
||
price_ent_desc: string;
|
||
price_period_month: string;
|
||
price_period_annual: string;
|
||
price_cta_start: string;
|
||
price_cta_pro: string;
|
||
price_cta_biz: string;
|
||
price_cta_ent: string;
|
||
|
||
price_free_features: string[];
|
||
price_pro_features: string[];
|
||
price_biz_features: string[];
|
||
price_ent_features: string[];
|
||
|
||
byok_badge: string;
|
||
byok_title: string;
|
||
byok_desc: string;
|
||
byok_col1_title: string;
|
||
byok_col1_desc: string;
|
||
byok_col2_title: string;
|
||
byok_col2_desc: string;
|
||
byok_config_title: string;
|
||
|
||
final_cta_title: string;
|
||
final_cta_title_italic: string;
|
||
final_cta_desc: string;
|
||
final_cta_button: string;
|
||
|
||
eco_badge: string;
|
||
eco_title_1: string;
|
||
eco_title_2: string;
|
||
eco_desc: string;
|
||
eco_button: string;
|
||
eco_original: string;
|
||
eco_translated: string;
|
||
eco_status: string;
|
||
|
||
footer_desc: string;
|
||
footer_col1_title: string;
|
||
footer_col2_title: string;
|
||
footer_col3_title: string;
|
||
|
||
workspace_title_editor: string;
|
||
workspace_title_graph: string;
|
||
workspace_title_agents: string;
|
||
workspace_title_reviews: string;
|
||
workspace_title_history: string;
|
||
workspace_notes_available: string;
|
||
workspace_new_doc: string;
|
||
workspace_local_reading: string;
|
||
workspace_graph_map_title: string;
|
||
workspace_graph_map_desc: string;
|
||
workspace_graph_connected: string;
|
||
workspace_graph_status: string;
|
||
workspace_agents_title: string;
|
||
workspace_active_prompt: string;
|
||
workspace_rag_active: string;
|
||
workspace_consigne: string;
|
||
workspace_secure_chat: string;
|
||
workspace_processor: string;
|
||
workspace_recall_title: string;
|
||
workspace_recall_desc: string;
|
||
workspace_show_answer: string;
|
||
workspace_correct_answer: string;
|
||
workspace_study_memory: string;
|
||
workspace_snapshot_title: string;
|
||
workspace_snapshot_desc: string;
|
||
workspace_restore: string;
|
||
workspace_state_saved: string;
|
||
}
|
||
|
||
const FR: LangDict = {
|
||
nav_features: "Fonctionnalités",
|
||
nav_agents: "Agents IA",
|
||
nav_brainstorm: "Brainstorm",
|
||
nav_pricing: "Tarification",
|
||
nav_architecture: "Architecture",
|
||
nav_login: "Se connecter",
|
||
nav_start: "Commencez",
|
||
|
||
hero_badge: "Augmenté par l'Intelligence Artificielle",
|
||
hero_title_1: "Votre second cerveau,",
|
||
hero_title_italic: "enfin amplifié.",
|
||
hero_desc: "Memento n'est pas qu'une simple application de notes. C'est un écosystème intelligent qui connecte, analyse et développe vos idées en temps réel grâce à 6 types d'agents IA et une recherche sémantique de pointe.",
|
||
hero_cta_start: "S'inscrire maintenant",
|
||
hero_cta_features: "Voir les fonctionnalités",
|
||
|
||
floating_card_1: "Memory Echo",
|
||
floating_card_1_text: '\"Connexion détectée avec votre projet de design durable de Mars 2024...\"',
|
||
floating_card_2: "Brainstorm Live",
|
||
floating_card_2_text: "+12 idées générées",
|
||
floating_card_2_desc: "Utilisateurs actifs en simultané",
|
||
|
||
features_badge: "Capacités IA",
|
||
features_title_1: "Une intelligence fluide,",
|
||
features_title_2: "intégrée à chaque mot.",
|
||
features_subtitle: "Memento orchestre vos idées grâce à une architecture multi-fournisseurs.",
|
||
|
||
f1_title: "Recherche Sémantique",
|
||
f1_desc: "Ne cherchez plus par mots-clés. Trouvez par concept. Notre moteur hybride Vector + FTS comprend l'intention derrière vos notes.",
|
||
f2_title: "Chat RAG Contextuel",
|
||
f2_desc: "Discutez avec votre savoir. Nos agents lisent vos notes, explorent le web et analysent vos documents pour répondre avec précision.",
|
||
f3_title: "Écriture Augmentée",
|
||
f3_desc: "Reformulation, suggestions de titres, tagging automatique et résumés. L'IA travaille en arrière-plan pour structurer votre pensée.",
|
||
|
||
agents_badge: "Agents Spécialisés",
|
||
agents_title: "Déléguez le travail complexe.",
|
||
agents_subtitle: "6 types d'agents IA autonomes pour automatiser vos recherches, vos résumés et vos présentations.",
|
||
|
||
agent_scraper_desc: "Scrape des URLs, parse les flux RSS et synthétise l'info avec placement d'images intelligent.",
|
||
agent_researcher_desc: "Génère des requêtes complexes, explore les sources web et rédige des notes de recherche structurées.",
|
||
agent_slide_desc: "Transforme vos notes en présentations PowerPoint professionnelles ou Slides HTML Interactives.",
|
||
agent_monitor_desc: "Analyse continuellement vos carnets pour détecter les tendances et les nouveaux insights.",
|
||
agent_diagram_desc: "Convertit vos idées en diagrammes Excalidraw fluides (Mindmaps, Flowcharts) avec auto-layout.",
|
||
agent_custom_desc: "Définissez vos propres agents avec des rôles et des sources de données spécifiques.",
|
||
|
||
brain_badge: "Vagues de Pensée",
|
||
brain_title: "Brainstorming radial en temps réel.",
|
||
brain_item1_title: "Génération par Vagues",
|
||
brain_item1_desc: "Variations, Analogies, puis Disruptions. L'IA pousse votre concept initial dans ses retranchements.",
|
||
brain_item2_title: "Collaboration Native",
|
||
brain_item2_desc: "Curseurs fantômes IA, avatars synchronisés et déplacement de nœuds en temps réel.",
|
||
brain_item3_title: "Export Sémantique",
|
||
brain_item3_desc: "Convertissez tout votre brainstorm en notes structurées d'un seul clic.",
|
||
|
||
brain_node1_title: "DISRUPTION",
|
||
brain_node1_text: "Architecture Modulaire 2.0",
|
||
brain_node2_title: "ANALOGIE",
|
||
brain_node2_text: "Le cycle des marées",
|
||
|
||
tech_badge: "Architecture & Fournisseurs",
|
||
tech_title: "Connectez votre propre intelligence.",
|
||
tech_tier1_label: "Tags",
|
||
tech_tier1_desc: "Indépendamment configurable avec n'importe quel modèle.",
|
||
tech_tier2_label: "Embeddings",
|
||
tech_tier2_desc: "Indépendamment configurable avec n'importe quel modèle.",
|
||
tech_tier3_label: "Chat RAG",
|
||
tech_tier3_desc: "Indépendamment configurable avec n'importe quel modèle.",
|
||
|
||
price_badge: "Plans & Tarification",
|
||
price_title: "Choisissez votre niveau d'amplification.",
|
||
price_desc: "Des options flexibles pour les esprits créatifs, de l'usage individuel aux grandes organisations.",
|
||
price_monthly: "Mensuel",
|
||
price_annual: "Annuel",
|
||
price_popular: "Le plus populaire",
|
||
price_free_name: "Basic",
|
||
price_free_price: "Gratuit",
|
||
price_free_desc: "Pour découvrir la magie de Memento.",
|
||
price_pro_name: "Pro",
|
||
price_pro_price: "9,90€",
|
||
price_pro_desc: "Pour les consultants et créateurs exigeants.",
|
||
price_biz_name: "Business",
|
||
price_biz_price: "29,90€",
|
||
price_biz_desc: "Pour les équipes et chefs de produit.",
|
||
price_ent_name: "Enterprise",
|
||
price_ent_price: "49,90€",
|
||
price_ent_desc: "Mémoire organisationnelle sécurisée.",
|
||
price_period_month: "/mois",
|
||
price_period_annual: "/mois, facturé annuellement",
|
||
price_cta_start: "Commencer",
|
||
price_cta_pro: "Passer Pro",
|
||
price_cta_biz: "Choisir Business",
|
||
price_cta_ent: "Contacter Ventes",
|
||
|
||
price_free_features: ["100 Notes max", "3 Carnets", "50 crédits IA (Lifetime)", "Recherche sémantique", "Historique 7 jours"],
|
||
price_pro_features: ["Notes illimitées", "BYOK (OpenAI/Anthropic)", "200 recherches sémantiques", "Agents (12 runs/mois)", "Historique 30 jours", "Support Email"],
|
||
price_biz_features: ["10 Collaborateurs inclus", "BYOK (13 fournisseurs)", "1000 recherches sémantiques", "Agents (60 runs/mois)", "Brainstorm illimité", "Accès API"],
|
||
price_ent_features: ["Tout Business", "Agents illimités", "SSO / SAML", "Audit Logs & SLA", "Support Dédié", "Onboarding Live"],
|
||
|
||
byok_badge: "Technologie Cloud Ouverte",
|
||
byok_title: "La stratégie BYOK",
|
||
byok_desc: "Vous possédez déjà des clés API OpenAI, Anthropic ou Google ? Connectez-les directement à Memento. Utilisez l'IA sans limites de crédits imposées, en payant uniquement ce que vous consommez chez votre fournisseur favori.",
|
||
byok_col1_title: "Pas de lock-in",
|
||
byok_col1_desc: "Changez de fournisseur en 1 clic.",
|
||
byok_col2_title: "Coûts optimisés",
|
||
byok_col2_desc: "Payez le prix direct API.",
|
||
byok_config_title: "Config Multi-Fournisseurs",
|
||
|
||
final_cta_title: "Prêt à libérer votre",
|
||
final_cta_title_italic: "plein potentiel ?",
|
||
final_cta_desc: "Rejoignez des milliers de chercheurs, designers et penseurs qui utilisent déjà Memento pour construire leur futur.",
|
||
final_cta_button: "Lancer Memento",
|
||
|
||
eco_badge: "Écosystème Memento",
|
||
eco_title_1: "Traduisez vos documents.",
|
||
eco_title_2: "Formatage préservé.",
|
||
eco_desc: "Le seul traducteur qui préserve les graphiques, tables des matières, formes et en-têtes — exactement tels qu'ils étaient. Prolongez l'intelligence de vos notes à l'international.",
|
||
eco_button: "Découvrir le traducteur",
|
||
eco_original: "original.pdf",
|
||
eco_translated: "translated.pdf",
|
||
eco_status: "Structure Intacte ✓",
|
||
|
||
footer_desc: "Le second cerveau amplifié par l'IA. Pensé pour les esprits créatifs.",
|
||
footer_col1_title: "Product",
|
||
footer_col2_title: "Community",
|
||
footer_col3_title: "Legal",
|
||
|
||
workspace_title_editor: "Éditeur de Notes",
|
||
workspace_title_graph: "Graphe Spatial",
|
||
workspace_title_agents: "Enrichissement IA",
|
||
workspace_title_reviews: "Révisions Actives",
|
||
workspace_title_history: "Snapshots Temporels",
|
||
workspace_notes_available: "Documents Locaux",
|
||
workspace_new_doc: "+ Créer Note",
|
||
workspace_local_reading: "Lecture du stockage local...",
|
||
workspace_graph_map_title: "Cartographie Interactive de Formes",
|
||
workspace_graph_map_desc: "Vos écrits se connectent automatiquement selon leur signification profonde.",
|
||
workspace_graph_connected: "6 notes interconnectées",
|
||
workspace_graph_status: "Structure Sémantique : Optimale ✓",
|
||
workspace_agents_title: "Système Cognitif d'Agents",
|
||
workspace_active_prompt: "TERMES ACTIFS DE RECHERCHE :",
|
||
workspace_rag_active: "RAG sémantique actif :",
|
||
workspace_consigne: "Consigne d'exploration :",
|
||
workspace_secure_chat: "SÉCURITÉ : CRYPTAGE SYSTÉMATIQUE",
|
||
workspace_processor: "SYSTÈME : BYOK ACTIF",
|
||
workspace_recall_title: "Répétition Espacée active",
|
||
workspace_recall_desc: "Algorithme actif convertissant automatiquement vos documents en cartes mémoires réactives.",
|
||
workspace_show_answer: "Afficher la réponse",
|
||
workspace_correct_answer: "Réponse attendue :",
|
||
workspace_study_memory: "Algorithme SuperMemo actif (SM2)",
|
||
workspace_snapshot_title: "Versionning & Sauvegardes",
|
||
workspace_snapshot_desc: "Enregistrement continu. Restaurez n'importe quel état textuel à la seconde près.",
|
||
workspace_restore: "Restaurer",
|
||
workspace_state_saved: "Sauvegarde locale : Active"
|
||
};
|
||
|
||
const EN: LangDict = {
|
||
nav_features: "Features",
|
||
nav_agents: "AI Agents",
|
||
nav_brainstorm: "Brainstorm",
|
||
nav_pricing: "Pricing",
|
||
nav_architecture: "Architecture",
|
||
nav_login: "Login",
|
||
nav_start: "Get Started",
|
||
|
||
hero_badge: "Amplified by Artificial Intelligence",
|
||
hero_title_1: "Your second brain,",
|
||
hero_title_italic: "finally amplified.",
|
||
hero_desc: "Memento is not just a typical note-taking tool. It is an intelligent ecosystem that connects, analyzes, and scales your thoughts in real time with 6 autonomous AI agents and vector semantic search.",
|
||
hero_cta_start: "Sign Up Now",
|
||
hero_cta_features: "View Features",
|
||
|
||
floating_card_1: "Memory Echo",
|
||
floating_card_1_text: '"Connection detected with your sustainable design project from March 2024..."',
|
||
floating_card_2: "Brainstorm Live",
|
||
floating_card_2_text: "+12 ideas generated",
|
||
floating_card_2_desc: "Simultaneous active users",
|
||
|
||
features_badge: "AI Capabilities",
|
||
features_title_1: "Fluid intelligence,",
|
||
features_title_2: "integrated into every word.",
|
||
features_subtitle: "Memento orchestrates your thoughts through a multi-provider landscape.",
|
||
|
||
f1_title: "Semantic Search",
|
||
f1_desc: "Stop searching by keywords. Retrieve by concept. Our hybrid Vector + FTS engine understands the core semantic context behind your logs.",
|
||
f2_title: "Contextual RAG Chat",
|
||
f2_desc: "Converse with your knowledge database. Our autonomous agents digest your notes, scan the web, and construct precise, cited answers.",
|
||
f3_title: "Augmented Writing",
|
||
f3_desc: "Rephrasing, title suggestions, automatic taxonomy tagging, and summaries. The AI acts passively in the background.",
|
||
|
||
agents_badge: "Autonomous Agents",
|
||
agents_title: "Delegate complex workflows.",
|
||
agents_subtitle: "6 specialized AI agents to automate your reference parsing, summaries, and instant pitch creation.",
|
||
|
||
agent_scraper_desc: "Scrapes assets and URLs, parses RSS feeds, and builds elegant visual summary cards with smart image placement.",
|
||
agent_researcher_desc: "Formulates deep search queries, surveys global web databases, and writes structured synthesis research drafts.",
|
||
agent_slide_desc: "Converts your raw notebooks into clean, structured PowerPoint templates or interactive HTML slide components.",
|
||
agent_monitor_desc: "Scans your folders persistently to capture structural changes, semantic triggers, and new dynamic patterns.",
|
||
agent_diagram_desc: "Extracts ideas into geometric flowcharts or Excalidraw-like mindmaps with perfect automatic layouts.",
|
||
agent_custom_desc: "Easily set custom system prompts, custom agents, distinct operational scopes, and data access limits.",
|
||
|
||
brain_badge: "Insight Waves",
|
||
brain_title: "Radial brainstorming in real time.",
|
||
brain_item1_title: "Multi-Wave Expansion",
|
||
brain_item1_desc: "Generates variations, analogies, and subsequent disruptions. The model challenges your initial hypothesis systematically.",
|
||
brain_item2_title: "Cooperative Canvas",
|
||
brain_item2_desc: "Live multi-user cursor tracking, active AI avatars, and smooth real-time node resizing and arrangement.",
|
||
brain_item3_title: "Semantic Export",
|
||
brain_item3_desc: "Seamlessly translate an entire radial brainstorm draft into typed markdown and structures with a single click.",
|
||
|
||
brain_node1_title: "DISRUPTION",
|
||
brain_node1_text: "Modular Architecture 2.0",
|
||
brain_node2_title: "ANALOGY",
|
||
brain_node2_text: "The tide cycle",
|
||
|
||
tech_badge: "Open Providers",
|
||
tech_title: "Bring your own model.",
|
||
tech_tier1_label: "Custom Tags",
|
||
tech_tier1_desc: "Each option is independently configurable with any LLM.",
|
||
tech_tier2_label: "Vector Embeddings",
|
||
tech_tier2_desc: "Each option is independently configurable with any LLM.",
|
||
tech_tier3_label: "Semantic RAG Engine",
|
||
tech_tier3_desc: "Each option is independently configurable with any LLM.",
|
||
|
||
price_badge: "Flexible Tiers",
|
||
price_title: "Select your cognitive scale.",
|
||
price_desc: "Scalable options for creative builders, starting from solo thinkers up to large modern agencies.",
|
||
price_monthly: "Monthly",
|
||
price_annual: "Annual",
|
||
price_popular: "Most Popular",
|
||
price_free_name: "Basic",
|
||
price_free_price: "Free",
|
||
price_free_desc: "Get started with the foundational magic of Memento.",
|
||
price_pro_name: "Pro",
|
||
price_pro_price: "$9.90",
|
||
price_pro_desc: "For consultants, writers, and advanced researchers.",
|
||
price_biz_name: "Business",
|
||
price_biz_price: "$29.90",
|
||
price_biz_desc: "For corporate groups, publishers, and product managers.",
|
||
price_ent_name: "Enterprise",
|
||
price_ent_price: "$49.90",
|
||
price_ent_desc: "Secured enterprise organizational memory layers.",
|
||
price_period_month: "/month",
|
||
price_period_annual: "/month, billed annually",
|
||
price_cta_start: "Get Started",
|
||
price_cta_pro: "Upgrade to Pro",
|
||
price_cta_biz: "Choose Business",
|
||
price_cta_ent: "Contact Sales",
|
||
|
||
price_free_features: ["100 Notes max", "3 Notebooks", "50 IA credits (Lifetime)", "Semantic search included", "7-day history backup"],
|
||
price_pro_features: ["Unlimited Notes", "BYOK (OpenAI/Anthropic)", "200 semantic lookups", "Agents (12 runs/month)", "30-day timeline rollback", "Premium Support"],
|
||
price_biz_features: ["10 Seats included", "BYOK (13 active models)", "1000 semantic lookups", "Agents (60 runs/month)", "Unlimited Brainstorm", "Full custom APIs Access"],
|
||
price_ent_features: ["Everything in Business", "Unlimited Agent runtimes", "Identity SSO & SAML logs", "Integrity Logs & local SLA", "Dedicated team channel", "Live technical onboarding"],
|
||
|
||
byok_badge: "Open Technology",
|
||
byok_title: "The BYOK Strategy",
|
||
byok_desc: "Already have OpenAI, Anthropic, or Google API credentials? Connect them directly to save subscription costs. Run models without arbitrary platform caps, paying only for raw API usage.",
|
||
byok_col1_title: "No lock-in",
|
||
byok_col1_desc: "Swap models or endpoints instantly with a single toggle.",
|
||
byok_col2_title: "Cost reduction",
|
||
byok_col2_desc: "Pay standard direct wholesale prices.",
|
||
byok_config_title: "Multi-Provider Schema",
|
||
|
||
final_cta_title: "Ready to expand your",
|
||
final_cta_title_italic: "second organic brain?",
|
||
final_cta_desc: "Join thousands of academics, product architects, and minimalist designers scaling their insights with Memento.",
|
||
final_cta_button: "Launch Memento",
|
||
|
||
eco_badge: "Memento Ecosystem",
|
||
eco_title_1: "Local document translation.",
|
||
eco_title_2: "Format intact.",
|
||
eco_desc: "The only translator preserving graphs, nested hierarchies, vectors, alignments, and titles exactly as you drew them. Take your local notes globally.",
|
||
eco_button: "Explore Translator",
|
||
eco_original: "original.pdf",
|
||
eco_translated: "translated.pdf",
|
||
eco_status: "Structure Preserved ✓",
|
||
|
||
footer_desc: "The ultimate AI-empowered second brain. Designed for mindful thinkers.",
|
||
footer_col1_title: "Product",
|
||
footer_col2_title: "Community",
|
||
footer_col3_title: "Legal",
|
||
|
||
workspace_title_editor: "Note Editor",
|
||
workspace_title_graph: "Knowledge Graph",
|
||
workspace_title_agents: "AI Enrichment",
|
||
workspace_title_reviews: "Active Recall",
|
||
workspace_title_history: "Time Snapshots",
|
||
workspace_notes_available: "Local Documents",
|
||
workspace_new_doc: "+ Create Note",
|
||
workspace_local_reading: "Reading local storage...",
|
||
workspace_graph_map_title: "Interactive Space Mapping",
|
||
workspace_graph_map_desc: "Your nodes attach automatically as semantic similarity is detected.",
|
||
workspace_graph_connected: "6 interconnected links",
|
||
workspace_graph_status: "Semantic Structure: Optimal ✓",
|
||
workspace_agents_title: "Cognitive Agents System",
|
||
workspace_active_prompt: "ACTIVE EXPLORATION TERMS:",
|
||
workspace_rag_active: "Semantic RAG active:",
|
||
workspace_consigne: "User instructions:",
|
||
workspace_secure_chat: "SECURITY: LOCAL SYMMETRIC ENCRYPTION",
|
||
workspace_processor: "PROCESSOR: BYOK COMPLIANT",
|
||
workspace_recall_title: "Active Spaced-Repetition Recall",
|
||
workspace_recall_desc: "Active recall algorithm that converts your writings into responsive flashcards dynamically.",
|
||
workspace_show_answer: "Show Answer",
|
||
workspace_correct_answer: "Correct answer:",
|
||
workspace_study_memory: "Active SuperMemo (SM2) engine",
|
||
workspace_snapshot_title: "Timeline Snapshots & Backups",
|
||
workspace_snapshot_desc: "Continuous backup checkpoints. Revert any document to an earlier state instantly.",
|
||
workspace_restore: "Revert",
|
||
workspace_state_saved: "Continuous local backup: Active"
|
||
};
|
||
|
||
const JA: LangDict = {
|
||
nav_features: "機能紹介",
|
||
nav_agents: "自律エージェント",
|
||
nav_brainstorm: "ブレスト",
|
||
nav_pricing: "料金プラン",
|
||
nav_architecture: "システム構成",
|
||
nav_login: "ログイン",
|
||
nav_start: "新規登録",
|
||
|
||
hero_badge: "人工知能による拡張済システム",
|
||
hero_title_1: "あなたの第二の脳を、",
|
||
hero_title_italic: "ついに具現化する。",
|
||
hero_desc: "Memento(モメント)は単なるメモ帳ではありません。6体の専門AIエージェント、ハイブリッドベクトル検索を搭載し、リアルタイムで知識の接続、整理、展開を実行する知能エコシステムです。",
|
||
hero_cta_start: "無料で体験する",
|
||
hero_cta_features: "機能一覧を見る",
|
||
|
||
floating_card_1: "メモリ・エコー",
|
||
floating_card_1_text: "「2024年3月のサスタナブルデザインの草稿と関連性を感知しました...」",
|
||
floating_card_2: "ライブ・ブレスト",
|
||
floating_card_2_text: "+12件のアイデア創出",
|
||
floating_card_2_desc: "同時編集中のアクティブユーザー",
|
||
|
||
features_badge: "先進AI性能",
|
||
features_title_1: "記述に完全に融合する、",
|
||
features_title_2: "インテリジェンス。",
|
||
features_subtitle: "Mementoは、複数のLLMプロバイダを容易に構成可能な適応性を備えています。",
|
||
|
||
f1_title: "セマンティック意味検索",
|
||
f1_desc: "単なるキーワード検索はもう不要。記述された文脈、概念そのものを捉えて、過去の関連メモを一瞬で検索します。",
|
||
f2_title: "コンテキスト適合RAG対話",
|
||
f2_desc: "自らのナレッジベースに直接質問。AIエージェントがメモの内容、Web、ドキュメントを統合して高精度な回答を構築します。",
|
||
f3_title: "筆記自動拡張",
|
||
f3_desc: "言い換え提案、タイトル自動補完、自動メタタグ分類、要約作成。AIがバックグラウンドで思考を強力に支援します。",
|
||
|
||
agents_badge: "自律AIエージェント",
|
||
agents_title: "面倒な調査、作成を委託。",
|
||
agents_subtitle: "Web調査、プレゼン資料構成、自動要約など、6種類の特化型エージェントに自律実行させることが可能です。",
|
||
|
||
agent_scraper_desc: "URLを解析し、RSSフィードから最新ニュースを要約。イメージ画像の最適な配置まで自律実行します。",
|
||
agent_researcher_desc: "深層検索クエリを作成し、グローバルWeb上のリソースから構造化されたリサーチ報告書を下書きします。",
|
||
agent_slide_desc: "作成したメモやアウトラインから、PowerPointプレゼン用プロット、またはHTMLのスライドを一括生成します。",
|
||
agent_monitor_desc: "ノートブックを常時モニタリング。新しいトレンドの予兆や興味深い相関関係を可視化します。",
|
||
agent_diagram_desc: "アイデアをExcalidraw形式のフローチャートやマインドマップ、関連図に美しく自動レイアウトします。",
|
||
agent_custom_desc: "独自の役割定義(プロンプト)、稼働スコープ、データアクセス制限をカスタマイズして動作させることができます。",
|
||
|
||
brain_badge: "思考の拡散",
|
||
brain_title: "リアルタイムなマインドマッピング。",
|
||
brain_item1_title: "多重ウェーブ連想",
|
||
brain_item1_desc: "「類似」「応用」「破壊」という異なる深度でAIがアイデアを分析し、最初の着想を多角的に突き詰めます。",
|
||
brain_item2_title: "コラボレーション機能",
|
||
brain_item2_desc: "リアルタイムでのポインター追跡、AIアバターとの同時ブレスト、円滑なノード拡大・自動整列システム。",
|
||
brain_item3_title: "構造化エクスポート",
|
||
brain_item3_desc: "ブレストキャンバス上に並んだ多数 Hideアイデア群を、構造化されたMarkdown形式へ1タップで変換します。",
|
||
|
||
brain_node1_title: "破壊的アイデア",
|
||
brain_node1_text: "モジュール式アーキテクチャ 2.0",
|
||
brain_node2_title: "自然の相似比",
|
||
brain_node2_text: "潮汐の周期モデル",
|
||
|
||
tech_badge: "マルチ・プロバイダ対応",
|
||
tech_title: "自分自身のAPIキーを連携。",
|
||
tech_tier1_label: "メタ分類",
|
||
tech_tier1_desc: "利用したいモデル、設定のすべてを個別に自由にバインドしてコントロールできます。",
|
||
tech_tier2_label: "意味ベクトル化",
|
||
tech_tier2_desc: "利用したいモデル、設定のすべてを個別に自由にバインドしてコントロールできます。",
|
||
tech_tier3_label: "意味的RAG",
|
||
tech_tier3_desc: "利用したいモデル、設定 ofすべてを個別に自由にバインドしてコントロールできます。",
|
||
|
||
price_badge: "料金・プラン",
|
||
price_title: "求める思考スケールに応じて選択。",
|
||
price_desc: "個人での思考整理、創作活動からチーム、グローバル企業での知能共有まで対応するプラン設計。",
|
||
price_monthly: "月払い",
|
||
price_annual: "年払い (お得値)",
|
||
price_popular: "人気プラン",
|
||
price_free_name: "ベーシック",
|
||
price_free_price: "無料",
|
||
price_free_desc: "Mementoの見事な基礎機能をすぐにお試しいただけます。",
|
||
price_pro_name: "プロ",
|
||
price_pro_price: "¥1,480",
|
||
price_pro_desc: "ライター、学習者、研究者、コンサルタントの方へ最適。",
|
||
price_biz_name: "ビジネス",
|
||
price_biz_price: "¥4,480",
|
||
price_biz_desc: "複数のコラボレーター連携やマインドマップ、高度API利用が必要なチームへ。",
|
||
price_ent_name: "エンタープライズ",
|
||
price_ent_price: "お問い合わせ",
|
||
price_ent_desc: "セキュアな組織知識データレイク、S/MIME、SSO、個別SLA管理。",
|
||
price_period_month: "/月",
|
||
price_period_annual: "/月 (年一括のご請求)",
|
||
price_cta_start: "今すぐ開始",
|
||
price_cta_pro: "プロへアップグレード",
|
||
price_cta_biz: "ビジネス選択",
|
||
price_cta_ent: "営業にお問い合わせ",
|
||
|
||
price_free_features: ["最大100ノート", "3つのノートブック制限", "50回の初期AIクレジット", "セマンティック意味検索", "7日間の履歴自動バックアップ"],
|
||
price_pro_features: ["作成メモ数無制限", "独自のAPIキー連携 (BYOK)", "200回のセマンティック意味検索", "AIエージェント (月12回起動)", "30日分の編集履歴ロールバック", "優先的な技術サポート"],
|
||
price_biz_features: ["最大10人のコラボレーター連携", "13種のLLMモデル切替", "1000回の意味検索/月", "AIエージェント (月60回起動)", "ブレスト回数に制限なし", "完全なAPI接続アクセス"],
|
||
price_ent_features: ["ビジネスプランの全機能", "AIエージェント起動無制限", "SAML/SSO シングルサインオン", "アクセス監査ログ & 専用SLA対応", "24時間年中無休の個別サポート", "オンボーディング技術教育支援"],
|
||
|
||
byok_badge: "オープン構想",
|
||
byok_title: "APIキー持ち込み(BYOK)",
|
||
byok_desc: "OpenAI、Anthropic、Googleなどの既存APIキーをお持ちですか?Mementoに直接バインドすれば、従量課金のみで任意の極限モデルを完全に制限なしで無制限にご利用いただけます。",
|
||
byok_col1_title: "ロックイン縛りゼロ",
|
||
byok_col1_desc: "好みのプロバイダやエンジンへ一瞬でコンフィグを切り替えられます。",
|
||
byok_col2_title: "中抜きマージン排除",
|
||
byok_col2_desc: "プロバイダ公式APIの卸売価格そのままの最低価格で使用できます。",
|
||
byok_config_title: "構成プロバイダ詳細",
|
||
|
||
final_cta_title: "あなたの第二の有機的な脳を",
|
||
final_cta_title_italic: "今すぐ起動させましょう。",
|
||
final_cta_desc: "最先端デザインと人工知能を極限まで融合させたMemento。すでに数千人のアカデミアやデザイナーが思考のスケールを始めています。",
|
||
final_cta_button: "Mementoを起動する",
|
||
|
||
eco_badge: "Mementoエコシステム",
|
||
eco_title_1: "ドキュメントローカル翻訳。",
|
||
eco_title_2: "完璧な構造維持。",
|
||
eco_desc: "グラフ、入れ子、アライメント、レイアウト、タイトル座標のすべてを完璧に保持したまま、言語領域を変換します。アイデアを瞬時にグローバルへ。",
|
||
eco_button: "翻訳機を起動する",
|
||
eco_original: "original.pdf",
|
||
eco_translated: "translated.pdf",
|
||
eco_status: "構造の一貫性を確認済 ✓",
|
||
|
||
footer_desc: "インテリジェントに調律された、あなたの第二の脳。豊かな思考者に捧ぐ。",
|
||
footer_col1_title: "製品",
|
||
footer_col2_title: "公式コミュニティ",
|
||
footer_col3_title: "規約・リーガル",
|
||
|
||
workspace_title_editor: "エディター",
|
||
workspace_title_graph: "知識グラフ",
|
||
workspace_title_agents: "AI拡張機能",
|
||
workspace_title_reviews: "間隔反復学習",
|
||
workspace_title_history: "履歴復元",
|
||
workspace_notes_available: "手稿・ノート一覧",
|
||
workspace_new_doc: "+ メモ新規作成",
|
||
workspace_local_reading: "ローカルDBを読み込み中...",
|
||
workspace_graph_map_title: "インタラクティブ概念座標",
|
||
workspace_graph_map_desc: "異なるメモ間の意味的類似度に基づいて、自動でリンク線が投影されます。",
|
||
workspace_graph_connected: "6件の関連リンク",
|
||
workspace_graph_status: "意味構造:最高ランク ✓",
|
||
workspace_agents_title: "自律型エージェント(4)",
|
||
workspace_active_prompt: "探査キーワード :",
|
||
workspace_rag_active: "RAGセマンティクス機能中 :",
|
||
workspace_consigne: "ユーザー指示要約 :",
|
||
workspace_secure_chat: "暗号化:ローカル内対称鍵で安全に保管",
|
||
workspace_processor: "システム:モデルキー持込対応",
|
||
workspace_recall_title: "効率的な間隔反復フラッシュカード",
|
||
workspace_recall_desc: "蓄積されたナレッジから自動テストを生成。定着を科学的にサポート。",
|
||
workspace_show_answer: "解答を表示する",
|
||
workspace_correct_answer: "正解の解説 :",
|
||
workspace_study_memory: "SuperMemo (SM2) アルゴリズム有効",
|
||
workspace_snapshot_title: "履歴バージョン管理",
|
||
workspace_snapshot_desc: "すべての編集イベントが秒単位で自動保存されます。いつでも過去の状態へ復元可能。",
|
||
workspace_restore: "適用する",
|
||
workspace_state_saved: "手稿保護:ローカル常時保管中"
|
||
};
|
||
|
||
interface LandingPageProps {
|
||
onEnter: () => void;
|
||
onLogin: () => void;
|
||
onRegister: () => void;
|
||
onSwitchVersion: (v: 'v1' | 'v2' | 'v3') => void;
|
||
}
|
||
|
||
export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRegister, onSwitchVersion }) => {
|
||
const [billingInterval, setBillingInterval] = useState<'monthly' | 'annual'>('monthly');
|
||
const [lang, setLang] = useState<'fr' | 'en' | 'ja'>('fr');
|
||
const [showI18nKeys, setShowI18nKeys] = useState<boolean>(false);
|
||
|
||
const [activeTab, setActiveTab] = useState<'editor' | 'graph' | 'agents' | 'reviews' | 'history'>('editor');
|
||
const [activeDemoIdx, setActiveDemoIdx] = useState<number>(0);
|
||
const [simulateState, setSimulateState] = useState<'searching' | 'writing' | 'idle' | 'complete'>('idle');
|
||
const [displayText, setDisplayText] = useState<string>('');
|
||
const [aiSidebarTab, setAiSidebarTab] = useState<'explore' | 'discussion' | 'relations'>('explore');
|
||
const [customPrompt, setCustomPrompt] = useState<string>('');
|
||
const [showFlashcardAnswer, setShowFlashcardAnswer] = useState<boolean>(false);
|
||
const [flashcardIdx, setFlashcardIdx] = useState<number>(0);
|
||
|
||
const [editorMode, setEditorMode] = useState<'wysiwyg' | 'markdown' | 'html'>('wysiwyg');
|
||
const [zoomedBlockId, setZoomedBlockId] = useState<string | null>(null);
|
||
const [dbViewMode, setDbViewMode] = useState<'table' | 'card'>('card');
|
||
const [newAuthorName, setNewAuthorName] = useState("");
|
||
const [newBookTitle, setNewBookTitle] = useState("");
|
||
const [dbAuthors, setDbAuthors] = useState([
|
||
{ id: 'a1', name: "Jules Verne", works: ["Twenty Thousand Leagues Under The Sea"], count: 1 },
|
||
{ id: 'a2', name: "Liu Cixin", works: ["The Three-Body Problem", "The Wandering Earth"], count: 2 }
|
||
]);
|
||
const [dbBooks, setDbBooks] = useState([
|
||
{ id: 'b1', title: "Twenty Thousand Leagues Under The Sea", author: "Jules Verne", cover: "https://images.unsplash.com/photo-1543002588-bfa74002ed7e?auto=format&fit=crop&q=80&w=200&h=300", tag: "Science fiction" },
|
||
{ id: 'b2', title: "The Three-Body Problem", author: "Liu Cixin", cover: "https://images.unsplash.com/photo-1512820790803-83ca734da794?auto=format&fit=crop&q=80&w=200&h=300", tag: "Science fiction" },
|
||
{ id: 'b3', title: "The Wandering Earth", author: "Liu Cixin", cover: "https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&q=80&w=200&h=300", tag: "Science fiction" }
|
||
]);
|
||
|
||
const realNotes = [
|
||
{
|
||
id: 'n1',
|
||
title: "H2 Relation and Rollup",
|
||
carnet: "Database & Books",
|
||
date: "26 Oct 2024",
|
||
tags: ["Relational", "Rollup", "Blocks"],
|
||
content: `# H2 Relation and Rollup\n\nCe document démontre la puissance du modèle relationnel de Memento.\n\n## 1. Modèle Relationnel\nVous pouvez lier des auteurs à leurs œuvres pour comptabiliser dynamiquement les entrées grâce à notre système de Rollups sémantiques.`,
|
||
stats: { words: 124, lines: 18, equations: 1, graphs: 4, images: 3 }
|
||
},
|
||
{
|
||
id: 'n2',
|
||
title: "Block-Style Math & Formulas",
|
||
carnet: "Mathematical & Geometrical",
|
||
date: "24 Oct 2024",
|
||
tags: ["LaTeX", "Gantt", "Flowcharts"],
|
||
content: `# Block-Style Math & Formulas\n\nMemento supporte les équations complexes de type LaTeX et les diagrammes sémantiques directement intégrés sous forme de blocs.\n\n$$\\Phi = \\frac{1 + \\sqrt{5}}{2}$$\n\n$$\\Delta Carbon = E_{béton} - E_{CLT} = 410 \\text{ kg } CO_2/m^3$$`,
|
||
stats: { words: 91, lines: 12, equations: 2, graphs: 4, images: 1 }
|
||
},
|
||
{
|
||
id: 'n3',
|
||
title: "Large Document Virtualization",
|
||
carnet: "Performance Model",
|
||
date: "22 Oct 2024",
|
||
tags: ["Virtualization", "Zoom-In"],
|
||
content: `# Large Document Virtualization\n\nLe moteur de rendu WYSIWYG traite de longs documents (jusqu'à 1 000 000 de mots) sans aucune baisse de performance grâce au chargement différé des blocs de contenu.\n\n## Zoom-In de bloc\nIsoler et grossir un bloc spécifique pour vous concentrer sur la rédaction.`,
|
||
stats: { words: 1542, lines: 80, equations: 0, graphs: 0, images: 0 }
|
||
}
|
||
];
|
||
|
||
const simulatedFlashcards = [
|
||
{
|
||
id: 'f1',
|
||
question: lang === 'fr'
|
||
? "Quel rôle joue le Nombre d'Or (1.618) dans les structures d'architecture ?"
|
||
: lang === 'ja'
|
||
? "建築構造において黄金比(1.618)はどのような役割を果たしますか?"
|
||
: "What role does the Golden Ratio (1.618) play in architectural structures?",
|
||
answer: lang === 'fr'
|
||
? "Il sert à définir des proportions optimales de fenêtrage et de colonnes, créant une harmonie visuelle naturelle pour le cortex occipital."
|
||
: lang === 'ja'
|
||
? "サッシや柱の最適な比率を決定することで、後頭葉に自然な視覚的調和をもたらします。"
|
||
: "It serves to define optimal proportions of windowing and columns, creating a natural visual harmony for the occipital cortex."
|
||
},
|
||
{
|
||
id: 'f2',
|
||
question: lang === 'fr'
|
||
? "Pourquoi privilégier le bois CLT (lamellé-croisé) au béton armé ?"
|
||
: lang === 'ja'
|
||
? "なぜ鉄筋コンクリートよりもCLT木材を優先するのですか?"
|
||
: "Why prioritize CLT (cross-laminated timber) over reinforced concrete?",
|
||
answer: lang === 'fr'
|
||
? "Pour son stockage actif de CO2 à long terme, sa légèreté combinée à sa résistance sismique et coupe-feu naturelle."
|
||
: lang === 'ja'
|
||
? "長期的な炭素固定、軽量性と耐震性、そして優れた天然の防火性能を併せ持つためです。"
|
||
: "For its active long-term CO2 sequestration, lightweight properties combined with superior seismic and natural fire resistance."
|
||
}
|
||
];
|
||
|
||
const triggerSimulation = (index: number, overrideText?: string) => {
|
||
setActiveDemoIdx(index);
|
||
setSimulateState('searching');
|
||
setDisplayText('');
|
||
setShowFlashcardAnswer(false);
|
||
|
||
if (index === 0) setAiSidebarTab('explore');
|
||
if (index === 1) setAiSidebarTab('relations');
|
||
if (index === 2) setAiSidebarTab('discussion');
|
||
|
||
const sourceText = overrideText || (index === -1 ? "" : realNotes[index].content);
|
||
|
||
const length = sourceText.length;
|
||
let curr = 0;
|
||
|
||
setTimeout(() => {
|
||
setSimulateState('writing');
|
||
const timer = setInterval(() => {
|
||
curr += 18;
|
||
if (curr >= length) {
|
||
setDisplayText(sourceText);
|
||
setSimulateState('complete');
|
||
clearInterval(timer);
|
||
} else {
|
||
setDisplayText(sourceText.substring(0, curr));
|
||
}
|
||
}, 15);
|
||
}, 800);
|
||
};
|
||
|
||
const handleCustomSubmit = (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
if (!customPrompt.trim()) return;
|
||
|
||
const summaryContent = `# Synthèse : ${customPrompt}\n\nRecherche sémantique connectée.\n\n$$\\Phi = \\lim_{n \\to \\infty} \\frac{F_{n+1}}{F_n}$$\n\n* Intégration d'éléments croisés complets.\n* Index de concordance optimale validé.`;
|
||
triggerSimulation(-1, summaryContent);
|
||
};
|
||
|
||
const handleAddDbEntry = (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
if (!newAuthorName.trim() || !newBookTitle.trim()) return;
|
||
|
||
const authorExists = dbAuthors.some(a => a.name.toLowerCase() === newAuthorName.toLowerCase());
|
||
if (!authorExists) {
|
||
setDbAuthors(prev => [...prev, {
|
||
id: 'a_' + Date.now(),
|
||
name: newAuthorName,
|
||
works: [newBookTitle],
|
||
count: 1
|
||
}]);
|
||
} else {
|
||
setDbAuthors(prev => prev.map(a => {
|
||
if (a.name.toLowerCase() === newAuthorName.toLowerCase()) {
|
||
return { ...a, works: [...a.works, newBookTitle] };
|
||
}
|
||
return a;
|
||
}));
|
||
}
|
||
|
||
setDbBooks(prev => [...prev, {
|
||
id: 'b_' + Date.now(),
|
||
title: newBookTitle,
|
||
author: newAuthorName,
|
||
cover: "https://images.unsplash.com/photo-1544947950-fa07a98d237f?auto=format&fit=crop&q=80&w=200&h=300",
|
||
tag: "Science fiction"
|
||
}]);
|
||
|
||
setNewAuthorName("");
|
||
setNewBookTitle("");
|
||
};
|
||
|
||
useEffect(() => {
|
||
triggerSimulation(0);
|
||
}, []);
|
||
|
||
const dicts = { fr: FR, en: EN, ja: JA };
|
||
const currentDict = dicts[lang];
|
||
|
||
// Helper function to translate string keys with styled brackets mode support
|
||
const t = (key: keyof LangDict, isPlain: boolean = false) => {
|
||
if (showI18nKeys) {
|
||
if (isPlain) return `{{${key}}}`;
|
||
return (
|
||
<span
|
||
className="inline-flex items-center bg-amber-500/10 text-amber-700 border border-amber-500/20 px-1.5 py-0.5 rounded font-mono text-[9px] font-black select-all leading-normal mx-0.5"
|
||
title={`i18n key: ${key}`}
|
||
>
|
||
{`{${key}}`}
|
||
</span>
|
||
);
|
||
}
|
||
const val = currentDict[key];
|
||
return typeof val === 'string' ? val : '';
|
||
};
|
||
|
||
const tArray = (key: 'price_free_features' | 'price_pro_features' | 'price_biz_features' | 'price_ent_features'): string[] => {
|
||
if (showI18nKeys) {
|
||
return Array(5).fill(`{${key}}`);
|
||
}
|
||
return currentDict[key];
|
||
};
|
||
|
||
return (
|
||
<div className="min-h-screen bg-paper text-ink font-sans selection:bg-ochre/30 selection:text-ink">
|
||
{/* Navigation */}
|
||
<nav className="fixed top-0 left-0 right-0 z-[100] bg-paper/80 backdrop-blur-md border-b border-border px-8 py-4 flex items-center justify-between">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 bg-ink flex items-center justify-center rounded-xl shadow-lg rotate-3 group hover:rotate-0 transition-transform cursor-pointer">
|
||
<span className="text-paper font-serif text-2xl font-bold">M</span>
|
||
</div>
|
||
<span className="font-serif text-2xl font-medium tracking-tight">Memento</span>
|
||
</div>
|
||
|
||
<div className="hidden lg:flex items-center gap-10">
|
||
<a href="#features" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('nav_features')}</a>
|
||
<a href="#agents" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('nav_agents')}</a>
|
||
<a href="#brainstorm" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('nav_brainstorm')}</a>
|
||
<a href="#pricing" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('nav_pricing')}</a>
|
||
<a href="#tech" className="text-[11px] font-bold uppercase tracking-widest text-concrete hover:text-ink transition-colors">{t('nav_architecture')}</a>
|
||
</div>
|
||
|
||
{/* Dynamic Controls System: Version switches, Language bar, and Raw translation key indicator */}
|
||
<div className="flex items-center gap-3">
|
||
{/* Elegant language switcher */}
|
||
<div className="bg-slate-100 p-0.5 rounded-lg flex items-center gap-0.5 border border-border/80">
|
||
{(['fr', 'en', 'ja'] as const).map((l) => (
|
||
<button
|
||
key={l}
|
||
onClick={() => setLang(l)}
|
||
className={`px-2 py-1 text-[10px] font-bold rounded-md transition-all uppercase cursor-pointer ${lang === l ? 'bg-white text-ink shadow-2xs font-extrabold' : 'text-concrete hover:text-ink'}`}
|
||
>
|
||
{l}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* Raw translation key indicator switch */}
|
||
<button
|
||
onClick={() => setShowI18nKeys(!showI18nKeys)}
|
||
className={`px-2.5 py-1 rounded-md border text-[9px] font-mono tracking-wider font-extrabold flex items-center gap-1.5 transition-all cursor-pointer shadow-3xs
|
||
${showI18nKeys
|
||
? 'bg-amber-100 text-amber-900 border-amber-305'
|
||
: 'bg-white text-stone-500 border-stone-200 hover:bg-stone-50'}`}
|
||
>
|
||
<Languages size={11} className={showI18nKeys ? "animate-spin" : ""} />
|
||
<span className="hidden md:inline">{showI18nKeys ? "🔑 Clés" : "Afficher i18n"}</span>
|
||
</button>
|
||
|
||
{/* Elegant Version landing switcher pill */}
|
||
<div className="bg-slate-100 p-0.5 rounded-full flex items-center gap-0.5 border border-border/80">
|
||
<button
|
||
onClick={() => onSwitchVersion('v1')}
|
||
className="px-3 py-1 text-[9px] uppercase tracking-widest font-extrabold rounded-full bg-ink text-paper shadow-sm"
|
||
title="Classique V1 bilingue"
|
||
>
|
||
V1
|
||
</button>
|
||
<button
|
||
onClick={() => onSwitchVersion('v2')}
|
||
className="px-3 py-1 text-[9px] uppercase tracking-widest font-bold rounded-full text-concrete hover:text-ink transition-all"
|
||
title="Aperçu Interactif V2"
|
||
>
|
||
V2
|
||
</button>
|
||
<button
|
||
onClick={() => onSwitchVersion('v3')}
|
||
className="px-3 py-1 text-[9px] uppercase tracking-widest font-bold rounded-full text-concrete hover:text-ink transition-all"
|
||
title="Bilingue V3"
|
||
>
|
||
V3 ✨
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex items-center gap-4">
|
||
<button
|
||
onClick={onLogin}
|
||
className="hidden md:block px-6 py-2.5 text-concrete hover:text-ink text-[11px] font-bold uppercase tracking-widest transition-colors"
|
||
>
|
||
{t('nav_login')}
|
||
</button>
|
||
<button
|
||
onClick={onRegister}
|
||
className="px-6 py-2.5 bg-ink text-paper rounded-full text-[11px] font-bold uppercase tracking-widest hover:opacity-90 transition-all flex items-center gap-2 group shadow-xl shadow-ink/10"
|
||
>
|
||
{t('nav_start')}
|
||
<ArrowRight size={14} className="group-hover:translate-x-1 transition-transform" />
|
||
</button>
|
||
</div>
|
||
</nav>
|
||
|
||
{/* Hero Section */}
|
||
<section className="relative pt-40 pb-32 px-8 overflow-hidden">
|
||
{/* Background Decorative Elements */}
|
||
<div className="absolute top-0 right-0 w-[800px] h-[800px] bg-ochre/5 rounded-full blur-[120px] -translate-y-1/2 translate-x-1/4 -z-10" />
|
||
<div className="absolute bottom-0 left-0 w-[600px] h-[600px] bg-accent/5 rounded-full blur-[100px] translate-y-1/2 -translate-x-1/4 -z-10" />
|
||
|
||
<div className="max-w-6xl mx-auto text-center">
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 30 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.8, ease: [0.23, 1, 0.32, 1] }}
|
||
>
|
||
<div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-ochre/10 border border-ochre/20 text-ochre text-[10px] font-bold uppercase tracking-[0.2em] mb-8">
|
||
<Sparkles size={12} />
|
||
{t('hero_badge')}
|
||
</div>
|
||
<h1 className="text-5xl md:text-7xl font-serif font-medium tracking-tight text-ink mb-8 leading-[1.15]">
|
||
{t('hero_title_1')} <br />
|
||
<span className="italic">{t('hero_title_italic')}</span>
|
||
</h1>
|
||
<p className="max-w-2xl mx-auto text-base md:text-lg text-concrete font-light leading-relaxed mb-12">
|
||
{t('hero_desc')}
|
||
</p>
|
||
|
||
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||
<button
|
||
onClick={onRegister}
|
||
className="px-10 py-5 bg-ink text-paper rounded-2xl text-sm font-bold uppercase tracking-[0.2em] hover:opacity-95 transition-all shadow-2xl shadow-ink/20 flex items-center gap-4 group"
|
||
>
|
||
{t('hero_cta_start')}
|
||
<ArrowRight size={18} className="group-hover:translate-x-1 transition-transform" />
|
||
</button>
|
||
<a href="#features" className="px-10 py-5 border border-border rounded-2xl text-sm font-bold uppercase tracking-[0.2em] hover:bg-slate-50 transition-all">
|
||
{t('hero_cta_features')}
|
||
</a>
|
||
</div>
|
||
</motion.div>
|
||
|
||
{/* Integrated Dynamic Workspace Player - Savior of V1! */}
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 80 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 1, delay: 0.2, ease: [0.23, 1, 0.32, 1] }}
|
||
className="mt-24 w-full text-left"
|
||
>
|
||
<div className="w-full bg-[#1c1c1c] rounded-[24px] border border-ink/40 p-3.5 shadow-2xl relative overflow-hidden flex flex-col justify-between">
|
||
|
||
{/* Top Bar Indicators */}
|
||
<div className="flex items-center justify-between pb-3.5 border-b border-white/[0.05] text-[10px] px-2">
|
||
<div className="flex items-center gap-2">
|
||
<span className="w-2.5 h-2.5 rounded-full bg-red-400" />
|
||
<span className="w-2.5 h-2.5 rounded-full bg-amber-400" />
|
||
<span className="w-2.5 h-2.5 rounded-full bg-emerald-400" />
|
||
<span className="font-mono text-stone-500 uppercase tracking-widest font-bold ml-1.5">MOMENTO-SANDBOX-LAYER</span>
|
||
</div>
|
||
|
||
<div className="flex items-center gap-1 bg-white/5 border border-white/10 px-2 py-0.5 rounded text-[8.5px] font-mono text-stone-400 uppercase tracking-widest">
|
||
<span className="w-1 h-1 rounded-full bg-amber-600 animate-pulse" />
|
||
{t('workspace_notes_available')} : {activeDemoIdx === -1 ? `Custom` : `${activeDemoIdx + 1}/3`}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Central Player Frame */}
|
||
<div className="grid grid-cols-12 min-h-[460px] bg-[#EAE8E0]/30 select-none relative">
|
||
|
||
{/* Left Active Controls 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-2 rounded-lg cursor-pointer transition-colors ${activeTab === 'editor' ? 'text-[#A47148] bg-white border border-stone-200 shadow-3xs' : 'text-stone-400 hover:text-ink'}`}
|
||
title={t('workspace_title_editor', true)}
|
||
>
|
||
<BookOpen size={14} />
|
||
</button>
|
||
<button
|
||
onClick={() => setActiveTab('graph')}
|
||
className={`p-2 rounded-lg cursor-pointer transition-colors ${activeTab === 'graph' ? 'text-[#A47148] bg-white border border-stone-200 shadow-3xs' : 'text-stone-400 hover:text-ink'}`}
|
||
title={t('workspace_title_graph', true)}
|
||
>
|
||
<Network size={14} />
|
||
</button>
|
||
<button
|
||
onClick={() => setActiveTab('agents')}
|
||
className={`p-2 rounded-lg cursor-pointer transition-colors ${activeTab === 'agents' ? 'text-[#A47148] bg-white border border-stone-200 shadow-3xs' : 'text-stone-400 hover:text-ink'}`}
|
||
title={t('workspace_title_agents', true)}
|
||
>
|
||
<Cpu size={14} />
|
||
</button>
|
||
<button
|
||
onClick={() => setActiveTab('reviews')}
|
||
className={`p-2 rounded-lg cursor-pointer transition-colors ${activeTab === 'reviews' ? 'text-[#A47148] bg-white border border-stone-200 shadow-3xs' : 'text-stone-400 hover:text-ink'}`}
|
||
title={t('workspace_title_reviews', true)}
|
||
>
|
||
<CheckSquare size={14} />
|
||
</button>
|
||
<button
|
||
onClick={() => setActiveTab('history')}
|
||
className={`p-2 rounded-lg cursor-pointer transition-colors ${activeTab === 'history' ? 'text-[#A47148] bg-white border border-stone-200 shadow-3xs' : 'text-stone-400 hover:text-ink'}`}
|
||
title={t('workspace_title_history', true)}
|
||
>
|
||
<History size={14} />
|
||
</button>
|
||
</div>
|
||
<div className="space-y-4">
|
||
<Sliders size={14} className="text-stone-400" />
|
||
</div>
|
||
</div>
|
||
|
||
{/* Main Tab Screen Area */}
|
||
<div className="col-span-11 bg-[#FAF9F5] overflow-y-auto max-h-[460px] text-left">
|
||
<AnimatePresence mode="wait">
|
||
|
||
{/* 1. EDITOR SCREEN */}
|
||
{activeTab === 'editor' && (
|
||
<motion.div
|
||
key="editor"
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
exit={{ opacity: 0 }}
|
||
className="grid grid-cols-12 min-h-full"
|
||
>
|
||
{/* Notes selector drawer */}
|
||
<div className="col-span-4 border-r border-black/[0.08] bg-[#FDFDFC] p-3 space-y-3.5">
|
||
<span className="text-[8.5px] font-black uppercase tracking-widest text-[#A47148] font-mono block border-b pb-1">
|
||
{t('workspace_notes_available')}
|
||
</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-[#A47148]/20'
|
||
: 'border-transparent bg-stone-50 hover:bg-[#EAE8DF]/40'
|
||
}`}
|
||
>
|
||
<span className="text-[7.5px] 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-extrabold text-[#1c1c1c] block truncate leading-tight">{note.title}</span>
|
||
</button>
|
||
))}
|
||
<button
|
||
onClick={() => triggerSimulation(0)}
|
||
className="w-full text-center border border-dashed border-accent/25 py-2 rounded-lg text-[9px] font-mono text-accent block hover:bg-accent/5 cursor-pointer"
|
||
>
|
||
{t('workspace_new_doc')}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Note workspace page content */}
|
||
<div className="col-span-8 p-3.5 bg-[#FAF9F5]/80 min-h-full">
|
||
|
||
{/* Rich Editor Mode Switcher Panel */}
|
||
<div className="flex bg-[#F1EFEB] border border-stone-250 p-1 rounded-lg items-center justify-between mb-3 text-[9px] font-mono tracking-wide">
|
||
<span className="text-[#A47148] font-bold uppercase pl-1.5">{lang === 'fr' ? "Rendu d'Édition" : lang === 'ja' ? "書き込み・表示形式" : "Editor Rendering Modality"} :</span>
|
||
<div className="flex gap-1">
|
||
{[
|
||
{ mode: 'wysiwyg', label: lang === 'fr' ? 'Block WYSIWYG (Préféré)' : lang === 'ja' ? 'WYSIWYGブロック' : 'Block WYSIWYG' },
|
||
{ mode: 'markdown', label: 'Raw Markdown' },
|
||
{ mode: 'html', label: 'HTML Map' }
|
||
].map((m) => (
|
||
<button
|
||
key={m.mode}
|
||
onClick={() => setEditorMode(m.mode as any)}
|
||
className={`px-2 py-1 rounded cursor-pointer transition-all ${editorMode === m.mode ? 'bg-white text-ink shadow-3xs font-black' : 'text-stone-500 hover:text-ink hover:bg-white/40'}`}
|
||
>
|
||
{m.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-4.5 bg-white border border-black/5 rounded-xl shadow-xs space-y-4 min-h-[400px] font-sans paper-texture relative">
|
||
{/* Breadcrumbs / Document Info */}
|
||
<div className="flex justify-between items-center text-[8.5px] uppercase font-bold tracking-widest font-mono text-[#A47148]">
|
||
<span>{activeDemoIdx === -1 ? "SYNTHÈSE" : realNotes[activeDemoIdx].carnet}</span>
|
||
<span className="text-stone-400">{activeDemoIdx === -1 ? "ACTIF" : realNotes[activeDemoIdx].date}</span>
|
||
</div>
|
||
|
||
<h2 className="text-lg font-serif font-bold text-[#1c1c1c] leading-tight flex items-center gap-1.5">
|
||
{activeDemoIdx === -1 ? (lang === 'fr' ? "Synthèse de recherche" : lang === 'ja' ? "研究合成メモ" : "Research Synthesis") : realNotes[activeDemoIdx].title}
|
||
{zoomedBlockId && (
|
||
<span className="text-[9px] bg-accent/20 text-accent font-mono py-0.5 px-2 rounded-full uppercase tracking-widest animate-pulse">Zoomed Focus</span>
|
||
)}
|
||
</h2>
|
||
|
||
<div className="flex gap-1 flex-wrap items-center justify-between">
|
||
<div className="flex gap-1">
|
||
{(activeDemoIdx === -1 ? ["Custom"] : realNotes[activeDemoIdx].tags).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-400">
|
||
{tag}
|
||
</span>
|
||
))}
|
||
</div>
|
||
<span className="text-[8px] font-mono text-stone-400">
|
||
{realNotes[activeDemoIdx].stats.words} {lang === 'fr' ? "mots" : lang === 'ja' ? "語" : "words"} · {realNotes[activeDemoIdx].stats.lines} {lang === 'fr' ? "blocs" : lang === 'ja' ? "ブロック" : "blocks"}
|
||
</span>
|
||
</div>
|
||
|
||
<div className="space-y-4 text-[10.5px] text-stone-650 leading-relaxed font-light">
|
||
<AnimatePresence mode="wait">
|
||
{simulateState === 'searching' && (
|
||
<div className="py-12 space-y-2 text-center">
|
||
<div className="relative inline-flex">
|
||
<span className="flex h-4 w-4 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-4 w-4 bg-accent" />
|
||
</span>
|
||
</div>
|
||
<p className="text-[8.5px] font-mono uppercase tracking-widest text-[#A47148]">
|
||
{t('workspace_local_reading')}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{(simulateState === 'writing' || simulateState === 'complete') && (
|
||
<div className="space-y-4">
|
||
|
||
{/* A. WYSIWYG BLOCK MODE */}
|
||
{editorMode === 'wysiwyg' && (
|
||
<div className="space-y-3.5">
|
||
|
||
{/* Zoomed Block Mode Warning Indicator */}
|
||
{zoomedBlockId && (
|
||
<div className="bg-amber-500/10 border border-amber-500/20 p-2.5 rounded-lg flex items-center justify-between">
|
||
<span className="text-[9px] font-mono text-amber-800 font-semibold uppercase">
|
||
🔎 {lang === 'fr' ? "Sous-bloc isolé en édition zoomée" : lang === 'ja' ? "分離した1ブロックを全画面ズーム編集中" : "1 block isolated under deep zoom-in focus"}
|
||
</span>
|
||
<button
|
||
onClick={() => setZoomedBlockId(null)}
|
||
className="text-[8px] uppercase tracking-wider font-bold bg-white px-2 py-0.5 rounded shadow-3xs hover:bg-[#FAF9F5] text-ink cursor-pointer border"
|
||
>
|
||
{lang === 'fr' ? "← Voir tout" : lang === 'ja' ? "← 全て表示" : "← View all"}
|
||
</button>
|
||
</div>
|
||
)}
|
||
|
||
{/* NOTE 1: H2 RELATION AND ROLLUP */}
|
||
{activeDemoIdx === 0 && (
|
||
<div className="space-y-4">
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b_desc') && (
|
||
<div className="relative group p-2 rounded-lg hover:bg-stone-50 transition-colors border border-transparent hover:border-black/[0.04]">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b_desc' ? null : 'b_desc')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
<p className="text-stone-605 select-text font-light text-[10.5px]">
|
||
{lang === 'fr'
|
||
? "Ce document démontre le lien sémantique dynamique entre différentes entités de bases de données grâce à un système de métadonnées et de rollups de type \"Count All\" (comptage de relations)."
|
||
: lang === 'ja'
|
||
? "本資料では、スキーマ定義されたデータベース群が、関連づけ(Relation)と、何件あるかの集計(Rollup - Count All機能)によって有機的につながる様子を再現しています。"
|
||
: "This document demonstrates the dynamic semantic connection between different database entities thanks to metadata structures and 'Count All' relational rollups."}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b_database') && (
|
||
<div className="relative group p-3 bg-stone-50 border border-black/[0.08] rounded-xl space-y-3.5 my-3">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b_database' ? null : 'b_database')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
|
||
{/* Notion-style database inner switcher header */}
|
||
<div className="flex items-center justify-between border-b pb-2">
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-sm">📚</span>
|
||
<span className="font-extrabold text-[#1c1c1c] text-[11px] uppercase tracking-wide">
|
||
{lang === 'fr' ? "Base d'Auteurs & Œuvres" : lang === 'ja' ? "著者・作品関係データベース" : "Authors & Publications Relation"}
|
||
</span>
|
||
</div>
|
||
<div className="bg-stone-200/60 p-0.5 rounded flex gap-0.5 text-[8.5px] font-bold">
|
||
<button
|
||
onClick={() => setDbViewMode('table')}
|
||
className={`px-2 py-0.5 rounded cursor-pointer ${dbViewMode === 'table' ? 'bg-white text-ink shadow-3xs' : 'text-stone-550'}`}
|
||
>
|
||
{lang === 'fr' ? "Tableau" : lang === 'ja' ? "テーブル" : "Table"}
|
||
</button>
|
||
<button
|
||
onClick={() => setDbViewMode('card')}
|
||
className={`px-2 py-0.5 rounded cursor-pointer ${dbViewMode === 'card' ? 'bg-white text-ink shadow-3xs' : 'text-stone-550'}`}
|
||
>
|
||
{lang === 'fr' ? "Fiches" : lang === 'ja' ? "カード" : "Card"}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* TABLE MODE VIEW */}
|
||
{dbViewMode === 'table' ? (
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-left text-[9.5px] font-mono border-collapse">
|
||
<thead>
|
||
<tr className="border-b border-stone-250 text-stone-500 font-bold uppercase tracking-wider bg-stone-105">
|
||
<th className="py-1.5 px-2">🔑 Author / Auteur</th>
|
||
<th className="py-1.5 px-2">↗ Works / Œuvres</th>
|
||
<th className="py-1.5 px-2 text-right">⧉ Works count (Rollup)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{dbAuthors.map((auth) => {
|
||
const authorBooks = dbBooks.filter(b => b.author.toLowerCase() === auth.name.toLowerCase());
|
||
const worksStr = authorBooks.map(b => b.title).join(', ') || 'No linked works';
|
||
return (
|
||
<tr key={auth.id} className="border-b border-stone-200 hover:bg-stone-100/50">
|
||
<td className="py-2 px-2 font-bold text-ink">{auth.name}</td>
|
||
<td className="py-2 px-2 text-stone-600 truncate max-w-[180px] font-sans italic">{worksStr}</td>
|
||
<td className="py-2 px-2 text-right font-black text-accent bg-accent/5">{authorBooks.length}</td>
|
||
</tr>
|
||
);
|
||
})}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
) : (
|
||
/* CARD MODE VIEW */
|
||
<div className="grid grid-cols-3 gap-2.5">
|
||
{dbBooks.map((book) => (
|
||
<div key={book.id} className="bg-white rounded-lg border border-black/5 overflow-hidden flex flex-col justify-between shadow-3xs group/book hover:border-accent transition-colors">
|
||
<div className="h-20 bg-stone-100 relative overflow-hidden flex items-center justify-center">
|
||
<img
|
||
src={book.cover}
|
||
alt={book.title}
|
||
referrerPolicy="no-referrer"
|
||
className="w-full h-full object-cover saturate-[0.8] brightness-[0.95]"
|
||
/>
|
||
<div className="absolute inset-0 bg-black/10 transition-colors group-hover/book:bg-transparent" />
|
||
</div>
|
||
<div className="p-2 space-y-1 text-[9px] text-left">
|
||
<p className="font-extrabold text-ink leading-tight truncate" title={book.title}>{book.title}</p>
|
||
<div className="flex flex-col gap-0.5 pt-0.5">
|
||
<span className="text-[7.5px] font-mono uppercase bg-purple-500/10 text-purple-700 px-1 py-[1px] rounded inline-block font-extrabold truncate w-fit">
|
||
{book.author}
|
||
</span>
|
||
<span className="text-[7.5px] font-mono uppercase bg-emerald-500/10 text-emerald-700 px-1 py-[1px] rounded inline-block font-bold">
|
||
{book.tag}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
<div className="border border-dashed border-stone-300 rounded-lg flex flex-col items-center justify-center p-3 text-stone-400 font-mono text-[8px] hover:bg-stone-100 transition-colors">
|
||
<span>➕ Card Entry</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Dynamic simulation insertion form! */}
|
||
<form onSubmit={handleAddDbEntry} className="pt-2 border-t border-black/[0.05] flex flex-wrap gap-2 items-center">
|
||
<span className="text-[8.5px] font-sans font-bold text-[#A47148] uppercase tracking-wide w-full sm:w-auto">
|
||
{lang === 'fr' ? "Ajouter un livre :" : lang === 'ja' ? "作品インライン登録 :" : "Link novel inline:"}
|
||
</span>
|
||
<input
|
||
type="text"
|
||
value={newAuthorName}
|
||
onChange={(e) => setNewAuthorName(e.target.value)}
|
||
placeholder={lang === 'fr' ? "Auteur (ex: Asimov)" : lang === 'ja' ? "著者 (例: アイザック・アシモフ)" : "Author Name"}
|
||
className="bg-white text-[9px] border px-2 py-1 rounded text-ink font-mono focus:border-accent outline-none flex-1 min-w-[100px]"
|
||
/>
|
||
<input
|
||
type="text"
|
||
value={newBookTitle}
|
||
onChange={(e) => setNewBookTitle(e.target.value)}
|
||
placeholder={lang === 'fr' ? "Titre (ex: Fondation)" : lang === 'ja' ? "作品名 (例: ファウンデーション)" : "Novel Title"}
|
||
className="bg-white text-[9px] border px-2 py-1 rounded text-ink font-mono focus:border-accent outline-none flex-1 min-w-[110px]"
|
||
/>
|
||
<button
|
||
type="submit"
|
||
className="bg-ink hover:bg-accent text-white font-bold p-1 rounded font-mono text-[9px] uppercase tracking-wider cursor-pointer transition-colors px-2.5"
|
||
>
|
||
+ Push Row
|
||
</button>
|
||
</form>
|
||
|
||
<p className="text-[8px] text-stone-400 font-mono leading-relaxed pt-1.5 border-t border-dashed">
|
||
{lang === 'fr'
|
||
? "In the Author database, the Works count is summarized and statistics are made on its Works, and the statistics method is Count all."
|
||
: lang === 'ja'
|
||
? "In the Author database, the Works count is summarized and statistics are made on its Works, and the statistics method is Count all."
|
||
: "In the Author database, the Works count is summarized and statistics are made on its Works, and the statistics method is Count all."}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b_templates') && (
|
||
<div className="relative group p-2.5 rounded-lg border border-transparent hover:border-black/[0.04] hover:bg-stone-50 transition-colors space-y-2">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b_templates' ? null : 'b_templates')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
<h3 className="text-sm font-serif font-black text-ink">{lang === 'fr' ? "Gabarits de données" : lang === 'ja' ? "テンプレート構文" : "Template Syntax"}</h3>
|
||
<p className="text-stone-600">
|
||
{lang === 'fr'
|
||
? "Les gabarits peuvent accéder, calculer et résoudre des données croisées d'un même lot via des formules dynamiques :"
|
||
: lang === 'ja'
|
||
? "テンプレートは、同一項目の関連データをアクセス・計算、独自にレンダリングする記法を導入可能です。"
|
||
: "Templates can access, calculate and render the values of other fields in the same piece of data through the syntax introduced in Template snippet:"}
|
||
</p>
|
||
<div className="space-y-1.5 pl-2 border-l-2 border-accent pl-3 text-[9.5px]">
|
||
<div className="flex gap-1.5 items-center">
|
||
<span className="text-accent font-black">•</span>
|
||
<span>{lang === 'fr' ? "Utilisez " : lang === 'ja' ? "使用法 " : "Use "}<code className="bg-stone-100 px-1 py-0.5 text-[#A47148] font-mono rounded font-bold">.action{`{ .field }`}</code> {lang === 'fr' ? "pour accéder aux propriétés globales." : lang === 'ja' ? "でビュー情報表示。" : "to access view properties."}</span>
|
||
</div>
|
||
<div className="flex gap-1.5 items-center">
|
||
<span className="text-accent font-black">•</span>
|
||
<span>{lang === 'fr' ? "Utilisez " : lang === 'ja' ? "使用法 " : "Use "}<code className="bg-stone-100 px-1 py-0.5 text-[#A47148] font-mono rounded font-bold">.action{`{ index . "custom-xxx" }`}</code> {lang === 'fr' ? "pour le ciblage de bloc sémantique." : lang === 'ja' ? "でカスタムメタデータ展開。" : "to access content block custom attributes."}</span>
|
||
</div>
|
||
<div className="flex gap-1.5 items-center">
|
||
<span className="text-accent font-black">•</span>
|
||
<span>{lang === 'fr' ? "Gabarit résolu de démonstration : " : lang === 'ja' ? "計算評価シミュレーション : " : "Evaluated bills mockup snippet: "}</span>
|
||
<span className="bg-[#FAF9F5] px-2 py-0.5 rounded border border-stone-250 font-mono font-bold text-accent">
|
||
.action{`{ compute sum of Books }`} = <span className="underline">{dbBooks.length} items</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
</div>
|
||
)}
|
||
|
||
{/* NOTE 2: BLOCK-STYLE MATH & FORMULAS */}
|
||
{activeDemoIdx === 1 && (
|
||
<div className="space-y-4">
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b2_mathdesc') && (
|
||
<div className="relative group p-2 rounded-lg hover:bg-stone-50 transition-colors border border-transparent hover:border-black/[0.04]">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b2_mathdesc' ? null : 'b2_mathdesc')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
<p className="text-stone-605">
|
||
{lang === 'fr'
|
||
? "Memento intègre des équations mathématiques pures et des diagrammes sémantiques ou Gantt de manière entièrement nativisée sous forme de blocs WYSIWYG."
|
||
: lang === 'ja'
|
||
? "Mementoは本格的なLaTeX数式および概念関係フローチャートをWYSIWYGブロックとして極めて滑らかに表示・調整可能です。"
|
||
: "Memento integrates highly stylized Mathematical LaTeX formulas and semantic/Gantt flowcharts directly as interactive WYSIWYG blocks."}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b2_equations') && (
|
||
<div className="relative group p-3 bg-[#FAF9F5]/50 border rounded-xl space-y-3">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b2_equations' ? null : 'b2_equations')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
<div className="flex items-center gap-1.5 border-b pb-1.5">
|
||
<span className="text-xs">📐</span>
|
||
<span className="font-mono text-[9px] uppercase font-bold text-stone-500">{lang === 'fr' ? "Module d'Équations Mathématiques" : lang === 'ja' ? "インラインLaTeXレンダラー" : "Mathematical Formulas Equation Block"}</span>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 gap-3">
|
||
<div className="space-y-1">
|
||
<span className="text-[8px] uppercase tracking-wider font-bold text-stone-400 block ml-0.5">LaTex code inputs:</span>
|
||
<div className="bg-zinc-900 text-stone-300 p-2 rounded-lg font-mono text-[9px] space-y-1 select-all">
|
||
<div>{"$$\\Phi = \\frac{1 + \\sqrt{5}}{2}$$"}</div>
|
||
<div className="text-emerald-400">{"$$\\Delta Carbon = E - H = 410$$"}</div>
|
||
</div>
|
||
</div>
|
||
<div className="space-y-1 text-center">
|
||
<span className="text-[8px] uppercase tracking-wider font-bold text-[#A47148] block">Live Math rendering:</span>
|
||
<div className="bg-white border p-3 rounded-lg flex flex-col items-center justify-center h-[56px] space-y-1">
|
||
<span className="text-xs font-serif italic font-bold select-all text-ink">Φ = 1.61803398...</span>
|
||
<span className="text-[8px] text-stone-405 font-mono">Rollup Equation Evaluated ✓</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b2_flowchart') && (
|
||
<div className="relative group p-3 bg-white border rounded-xl space-y-2.5">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b2_flowchart' ? null : 'b2_flowchart')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
<div className="flex items-center gap-1.5 border-b pb-1">
|
||
<span className="text-xs">📊</span>
|
||
<span className="font-mono text-[9px] uppercase font-bold text-stone-500">{lang === 'fr' ? "Diagramme Temporel / Gantt de Projet" : lang === 'ja' ? "ガントチャート・タイムラインブロック" : "Flowchart & Project Gantt Block"}</span>
|
||
</div>
|
||
|
||
{/* Mini vector flowchart */}
|
||
<div className="p-3 bg-stone-50 rounded-lg space-y-2">
|
||
{[
|
||
{ task: "Research & Relations", progress: "100%", width: "w-full", color: "bg-emerald-500", date: "Oct 1 - Oct 5" },
|
||
{ task: "SuperMemo Sync Engine", progress: "80%", width: "w-4/5", color: "bg-accent", date: "Oct 6 - Oct 12" },
|
||
{ task: "Multi-Million Word DB", progress: "40%", width: "w-2/5", color: "bg-amber-500", date: "Oct 13 - Dec 1" },
|
||
].map((bar, i) => (
|
||
<div key={i} className="flex items-center justify-between text-[8px] font-mono">
|
||
<span className="w-1/3 truncate text-stone-600 font-medium">{bar.task}</span>
|
||
<div className="w-1/2 bg-stone-200 h-2.5 rounded relative overflow-hidden">
|
||
<div className={`${bar.width} ${bar.color} h-full rounded transition-all duration-1000`} />
|
||
</div>
|
||
<span className="w-1/6 text-right text-[#A47148] font-bold">{bar.date}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
</div>
|
||
)}
|
||
|
||
{/* NOTE 3: LARGE DOCUMENT VIRTUALIZATION */}
|
||
{activeDemoIdx === 2 && (
|
||
<div className="space-y-4">
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b3_intro') && (
|
||
<div className="relative group p-2 rounded-lg hover:bg-stone-50 transition-colors border border-transparent hover:border-black/[0.04]">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b3_intro' ? null : 'b3_intro')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
<p className="text-stone-605">
|
||
{lang === 'fr'
|
||
? "Le noyau de Memento est conçu pour gérer d'immenses documents textuels (plus d'un million de mots) avec une latence quasi nulle en virtualisant les sous-structures."
|
||
: lang === 'ja'
|
||
? "Mementoの超高速仮想ドキュメントレンダリングは、合計100万語を越える膨大な書籍や論文データベースでも、表示遅延なく高速に動作・ブロック分割制御可能です。"
|
||
: "Its lightweight framework allows seamlessly displaying and editing files sizing up to 1,000,000 words without single-frame drops thanks to block virtualization."}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b3_stat') && (
|
||
<div className="relative group p-3 bg-[#FAF9F5] rounded-xl border flex items-center justify-between">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b3_stat' ? null : 'b3_stat')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
<div className="flex items-center gap-3">
|
||
<span className="text-xl">⚡</span>
|
||
<div>
|
||
<span className="font-extrabold text-[#1c1c1c] font-mono text-[9px] block uppercase tracking-wide">
|
||
{lang === 'fr' ? "Statistiques de Virtualisation" : lang === 'ja' ? "メモリ仮想ブロック稼働状態" : "Million-Word Scale Buffer Monitor"}
|
||
</span>
|
||
<span className="text-[8px] text-stone-400 font-mono">RAM overhead: 0.12 MB / Render: 12ms (SuperMemo SM2 active in background)</span>
|
||
</div>
|
||
</div>
|
||
<span className="font-mono text-xs bg-emerald-500/10 border border-emerald-500/30 text-emerald-700 px-2 py-1 rounded font-black font-extrabold shadow-3xs">
|
||
1,542,391 words
|
||
</span>
|
||
</div>
|
||
)}
|
||
|
||
{(!zoomedBlockId || zoomedBlockId === 'b3_zoomin_demo') && (
|
||
<div className="relative group p-3 bg-white border border-stone-200 rounded-xl space-y-2">
|
||
<button
|
||
onClick={() => setZoomedBlockId(zoomedBlockId === 'b3_zoomin_demo' ? null : 'b3_zoomin_demo')}
|
||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity text-[8px] font-mono px-1.5 py-0.5 bg-white border rounded text-[#A47148] hover:bg-stone-100 cursor-pointer"
|
||
title="Zoom-in"
|
||
>
|
||
🔎 {zoomedBlockId ? "Unzoom" : "Focus"}
|
||
</button>
|
||
<div className="flex items-center gap-1 border-b pb-1">
|
||
<span className="text-xs">🔎</span>
|
||
<span className="font-mono text-[9px] uppercase font-bold text-stone-500">{lang === 'fr' ? "Démonstration Interactive Zoom-In" : lang === 'ja' ? "ブロック・フォーカスズーム実演" : "Block Zoom-In Interactive Focus Demonstration"}</span>
|
||
</div>
|
||
<p className="text-[#A47148] text-[9.5px] font-light italic leading-relaxed">
|
||
{lang === 'fr'
|
||
? "Survolez n'importe quel bloc ci-dessus ou cliquez sur la loupe 🔎 pour faire l'expérience du Zoom-In de bloc, permettant d'isoler un unique paragraphe pour une rédaction concentrée."
|
||
: lang === 'ja'
|
||
? "上記の段落にホバーするか、虫眼鏡 🔎 をクリックして「ブロックのズームイン(Zoom-In Focus)」をテストできます。1つの項目のみに集中環境を作成します。"
|
||
: "Hover over any paragraph block in this editor mockup or click the magnifying glass icon 🔎 to test 'Block zoom-in', creating an isolated and completely noise-free environment."}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
</div>
|
||
)}
|
||
|
||
</div>
|
||
)}
|
||
|
||
{/* B. RAW MARKDOWN VIEW */}
|
||
{editorMode === 'markdown' && (
|
||
<div className="space-y-3 font-mono text-[9.5px]">
|
||
<div className="bg-zinc-850 text-[#F1EFEB] border p-3 rounded-lg overflow-x-auto relative select-all leading-normal whitespace-pre">
|
||
<div className="absolute right-2 top-2 text-[7.5px] uppercase bg-black/40 text-stone-400 px-1 py-0.2 rounded font-bold font-mono">
|
||
Markdown
|
||
</div>
|
||
{activeDemoIdx === 0 && (
|
||
`# H2 Relation and Rollup\n\nCe document démontre la puissance du modèle relationnel de Memento.\n\n## 1. Modèle Relationnel\nLier des auteurs à leurs œuvres pour comptabiliser dynamiquement.\n\n[DATABASE id="authors-works" view="table"]\n\n## Template\nTemplates can access values via syntax: .action { .field }`
|
||
)}
|
||
{activeDemoIdx === 1 && (
|
||
`# Block-Style Math & Formulas\n\nMemento supporte LaTeX.\n\n$$ \\Phi = \\frac{1 + \\sqrt{5}}{2} $$\n\n$$ \\Delta Carbon = E_béton - E_CLT = 410 $$`
|
||
)}
|
||
{activeDemoIdx === 2 && (
|
||
`# Large Document Virtualization\n\nLe moteur supporte de longs documents.\n\n## Zoom-In de bloc\nIsoler un bloc spécifique pour se concentrer.`
|
||
)}
|
||
{activeDemoIdx === -1 && (
|
||
`# Synthèse : ${customPrompt}\n\nRecherche sémantique connectée.`
|
||
)}
|
||
</div>
|
||
<span className="text-[8px] text-stone-400 font-mono block italic">
|
||
* {lang === 'fr' ? "Le Markdown nécessite de se souvenir de la syntaxe. Le WYSIWYG est nettement plus pertinent et fluide !" : lang === 'ja' ? "マークダウン記法の暗記は思考を遮ります。WYSIWYGのほうが直感的で生産的です。" : "Markdown blocks require manual parsing overhead, which is why Block WYSIWYG is much more convenient."}
|
||
</span>
|
||
</div>
|
||
)}
|
||
|
||
{/* C. HTML DOM VIEW MAP */}
|
||
{editorMode === 'html' && (
|
||
<div className="space-y-2.5 font-mono text-[9px]">
|
||
<div className="bg-slate-50 border p-3 rounded-lg text-emerald-800 space-y-2 select-all leading-snug">
|
||
<div>{`<!-- Memento Symmetrical DOM Tree map -->`}</div>
|
||
<div>{`<div class="note-container font-serif" id="momento-doc-${activeDemoIdx}">`}</div>
|
||
<div className="pl-3">{`<h2 class="title text-lg border-b">${activeDemoIdx === -1 ? "Synthèse" : realNotes[activeDemoIdx].title}</h2>`}</div>
|
||
<div className="pl-3">{`<div class="section-meta flex text-[8px] uppercase">`}</div>
|
||
<div className="pl-6">{`<span class="tag bg-stone-100">${activeDemoIdx === -1 ? "Custom" : realNotes[activeDemoIdx].tags[0]}</span>`}</div>
|
||
<div className="pl-3">{`</div>`}</div>
|
||
<div className="pl-3">{`<div class="blocks-stack space-y-4">`}</div>
|
||
<div className="pl-6 text-purple-700">{`<p class="block-paragraph" data-block-id="p1">... [text content] ...</p>`}</div>
|
||
{activeDemoIdx === 0 && (
|
||
<div className="pl-6 text-amber-900">{`<div class="block-database" data-relation="authors" data-rollup="count"> ... </div>`}</div>
|
||
)}
|
||
<div className="pl-3">{`</div>`}</div>
|
||
<div>{`</div>`}</div>
|
||
</div>
|
||
<span className="text-[8px] text-stone-400 font-mono block italic">
|
||
* {lang === 'fr' ? "La vue HTML brute est illisible pour un redacteur. La vue d'arborescence structure par contre idéalement le document." : lang === 'ja' ? "HTMLコードは人間の執筆には不向きです。WYSIWYGがDOM構造をカプセル化します。" : "HTML raw outputs are messy, making WYSIWYG encapsulate DOM rendering perfectly."}
|
||
</span>
|
||
</div>
|
||
)}
|
||
|
||
</div>
|
||
)}
|
||
</AnimatePresence>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
)}
|
||
|
||
{/* 2. SPATIAL GRAPH SCREEN */}
|
||
{activeTab === 'graph' && (
|
||
<motion.div
|
||
key="graph"
|
||
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-0.5">
|
||
<span className="text-[9px] uppercase tracking-[0.2em] font-extrabold text-[#A47148] font-mono block">
|
||
{t('workspace_graph_map_title')}
|
||
</span>
|
||
<p className="text-[10.5px] text-stone-500 font-light">{t('workspace_graph_map_desc')}</p>
|
||
</div>
|
||
|
||
{/* Blueprint grid layout */}
|
||
<div className="border border-black/[0.08] bg-[#FDFCFA] rounded-xl flex items-center justify-center p-4 relative overflow-hidden min-h-[300px] shadow-sm">
|
||
<svg className="absolute inset-0 w-full h-full pointer-events-none" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<pattern id="dotPatternV3" 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(#dotPatternV3)" />
|
||
|
||
<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>
|
||
|
||
{/* Center node */}
|
||
<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 hover:scale-105 transition-transform duration-300">
|
||
MOMENTO
|
||
</div>
|
||
|
||
{/* Surrounding linked concepts */}
|
||
{[
|
||
{ name: lang === 'fr' ? "Nombre d'Or" : lang === 'ja' ? "黄金比率" : "Golden ratio", x: -95, y: -65, tag: lang === 'fr' ? "Architecture" : lang === 'ja' ? "建築幾何学" : "Architecture", theme: "text-amber-800 bg-amber-50/95" },
|
||
{ name: lang === 'fr' ? "Diffraction lumineuse" : lang === 'ja' ? "光の回折" : "Light diffraction", x: 105, y: -72, tag: lang === 'fr' ? "Optique" : lang === 'ja' ? "光学" : "Optics", theme: "text-violet-850 bg-violet-50/95" },
|
||
{ name: lang === 'fr' ? "Bois CLT Lamellé" : lang === 'ja' ? "CLT 木材" : "CLT Timber", x: -115, y: 70, tag: lang === 'fr' ? "Matériaux" : lang === 'ja' ? "エコ材料" : "Materials", theme: "text-emerald-800 bg-emerald-50/95" },
|
||
{ name: lang === 'fr' ? "Transition Formelle" : lang === 'ja' ? "形式変換" : "Format Transition", x: 110, y: 60, tag: lang === 'fr' ? "Minimalisme" : lang === 'ja' ? "ミニマリズム" : "Minimalism", theme: "text-blue-800 bg-blue-50/95" },
|
||
{ name: "Grid System", x: 0, y: -100, tag: lang === 'fr' ? "IA Métrique" : lang === 'ja' ? "AI評価指標" : "AI Metric", theme: "text-stone-800 bg-stone-50/95" },
|
||
{ name: lang === 'fr' ? "Éco-Conception" : lang === 'ja' ? "エコ設計" : "Eco-design", x: 0, y: 100, tag: lang === 'fr' ? "Carbone" : lang === 'ja' ? "カーボン量" : "Carbon", theme: "text-rose-800 bg-rose-50/95" }
|
||
].map((node, idx) => (
|
||
<div
|
||
key={idx}
|
||
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.5 bg-white border border-black/[0.08] rounded-xl shadow-3xs 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 text-[9px] font-mono text-stone-500 uppercase tracking-widest font-bold">
|
||
<span>{t('workspace_graph_connected')}</span>
|
||
<span className="text-purple-600">{t('workspace_graph_status')}</span>
|
||
</div>
|
||
</motion.div>
|
||
)}
|
||
|
||
{/* 3. COGNITIVE AGENTS SCREEN */}
|
||
{activeTab === 'agents' && (
|
||
<motion.div
|
||
key="agents"
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
exit={{ opacity: 0 }}
|
||
className="grid grid-cols-12 min-h-full"
|
||
>
|
||
{/* System models list */}
|
||
<div className="col-span-5 border-r border-[#1C1C1C]/10 bg-[#FAF9F6] p-3 space-y-3">
|
||
<span className="text-[8.5px] font-black uppercase tracking-widest text-[#A47148] font-mono block border-b pb-1.5">
|
||
{t('workspace_agents_title')}
|
||
</span>
|
||
<div className="space-y-1.5">
|
||
{[
|
||
{ id: "scr", name: lang === 'fr' ? "Web Scraper" : lang === 'ja' ? "Webスクレイパー" : "Web Scraper", role: lang === 'fr' ? "Parse et simplifie les URLs" : lang === 'ja' ? "URLコンテンツの解析と要約" : "Parse and simplify URLs", tag: "SCR", color: "bg-amber-100 text-amber-900 border-amber-200" },
|
||
{ id: "res", name: lang === 'fr' ? "Deep Researcher" : lang === 'ja' ? "ディープ・リサーチャー" : "Deep Researcher", role: lang === 'fr' ? "Recherche exhaustive internet" : lang === 'ja' ? "Web情報を徹底探索調査" : "Exhaustive web research", tag: "RES", color: "bg-teal-100 text-teal-900 border-teal-200" },
|
||
{ id: "sli", name: lang === 'fr' ? "Slide Builder" : lang === 'ja' ? "スライドビルダー" : "Slide Builder", role: lang === 'fr' ? "Formate en deck PowerPoint" : lang === 'ja' ? "ワンタップでPPTに自動成形" : "Format into raw PPT decks", tag: "PPT", color: "bg-blue-100 text-blue-900 border-blue-200" },
|
||
{ id: "mon", name: lang === 'fr' ? "Knowledge Monitor" : lang === 'ja' ? "ナレッジ・モニター" : "Knowledge Monitor", role: lang === 'fr' ? "Trouve les redondances" : lang === 'ja' ? "同一ノートの重複・接点検知" : "Detect nested redundancies", tag: "LNK", color: "bg-purple-100 text-purple-900 border-purple-200" }
|
||
].map((a) => (
|
||
<div key={a.id} className="p-2.5 bg-white rounded-xl border border-stone-200 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-[7.5px] font-mono font-black border px-1 rounded-sm ${a.color}`}>{a.tag}</span>
|
||
</div>
|
||
<span className="text-[8.5px] text-stone-505 font-light leading-snug block">{a.role}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Interactive prompt chat system */}
|
||
<div className="col-span-7 bg-[#FDFDFC] flex flex-col justify-between p-4 font-sans">
|
||
<div className="space-y-3.5 text-left">
|
||
<div className="flex border-b border-border bg-[#F1EFEB] rounded-lg overflow-hidden shrink-0">
|
||
{([
|
||
{ key: 'explore', label: lang === 'fr' ? 'Explore (RAG)' : lang === 'ja' ? '探索 (RAG)' : 'Explore (RAG)' },
|
||
{ key: 'discussion', label: lang === 'fr' ? 'Discussion' : lang === 'ja' ? 'チャット対話' : 'Discussion' },
|
||
{ key: 'relations', label: lang === 'fr' ? 'Rapports' : lang === 'ja' ? '関連文書' : 'Matches' }
|
||
] as const).map((tab) => (
|
||
<button
|
||
key={tab.key}
|
||
onClick={() => setAiSidebarTab(tab.key)}
|
||
className={`flex-1 py-1.5 text-[8.5px] uppercase tracking-wider font-extrabold text-[#A47148] transition-all cursor-pointer text-center
|
||
${aiSidebarTab === tab.key ? 'bg-white text-ink font-black border-r border-[#1C1C1C]/10' : 'hover:bg-white/40'}`}
|
||
>
|
||
{tab.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
<div className="space-y-3 min-h-[220px]">
|
||
<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">
|
||
{t('workspace_active_prompt')}
|
||
</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">{t('workspace_rag_active')}</span>
|
||
<span className="block text-ink font-semibold">"{activeDemoIdx === -1 ? customPrompt || "Custom Search" : realNotes[activeDemoIdx].title}"</span>
|
||
</div>
|
||
<form onSubmit={handleCustomSubmit} className="space-y-1.5 pt-1">
|
||
<span className="text-[8.5px] font-bold text-stone-500 uppercase tracking-widest block pl-0.5">
|
||
{lang === 'fr' ? "Synthétiser un sujet personnalisé :" : lang === 'ja' ? "カスタムテーマを選択して要約 :" : "Synthesize custom topic:"}
|
||
</span>
|
||
<div className="flex gap-1">
|
||
<input
|
||
type="text"
|
||
value={customPrompt}
|
||
onChange={(e) => setCustomPrompt(e.target.value)}
|
||
placeholder={lang === 'fr' ? "Ex: Couleur dans l'architecture Bauhaus" : lang === 'ja' ? "例: バウハウスの色彩秩序理論" : "E.g., Bauhaus architectural color scale"}
|
||
className="flex-1 bg-white border border-stone-200 rounded-lg px-2.5 py-1.5 text-[10px] outline-none font-mono focus:border-accent"
|
||
/>
|
||
<button
|
||
type="submit"
|
||
className="p-1.5 bg-ink text-white rounded-lg text-[9px] font-bold uppercase tracking-wider cursor-pointer hover:opacity-90"
|
||
>
|
||
Go
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</motion.div>
|
||
)}
|
||
|
||
{aiSidebarTab === 'discussion' && (
|
||
<motion.div key="discussion" initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="space-y-3 text-[10px] leading-relaxed">
|
||
<div className="p-2 bg-slate-50 border rounded-xl text-stone-605">
|
||
<span className="text-[8px] font-mono uppercase text-stone-400 block">{t('workspace_consigne')}</span>
|
||
{lang === 'fr' ? "Structure minimaliste de la diffraction active." : lang === 'ja' ? "アクティブ回折のミニマル構造의設計案" : "Minimalist structure of active diffraction."}
|
||
</div>
|
||
<div className="p-2 bg-white border border-black/5 rounded-xl text-ink">
|
||
<span className="text-[8px] font-mono uppercase text-accent font-extrabold block">Gemini local model</span>
|
||
{lang === 'fr' ? "Transparence induite par le verre feuilleté déclinable, limitant les structures." : lang === 'ja' ? "合わせガラスにより透明性を最大限に引き出し、支柱などの構造材を最小限に抑制します。" : "Transparency induced by laminated declinable glass, reducing supporting structures."}
|
||
</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">
|
||
{lang === 'fr' ? "Correspondances d'index :" : lang === 'ja' ? "インデックス整合率検出 :" : "Semantic index matches:"}
|
||
</span>
|
||
<div className="p-3 bg-white border rounded-xl flex items-center justify-between text-[10px]">
|
||
<span className="font-bold text-[#1c1c1c]">{lang === 'fr' ? "Grille d'Éco-Conception CLT" : lang === 'ja' ? "木造CLTグリッドモジュール" : "Sustainable CLT Space Grid"}</span>
|
||
<span className="font-mono text-accent text-[11px] font-bold">89% match ✓</span>
|
||
</div>
|
||
</motion.div>
|
||
)}
|
||
</AnimatePresence>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-2.5 bg-[#F1EFEB] border border-border text-[8px] font-mono text-stone-500 flex items-center justify-between rounded-lg">
|
||
<span>{t('workspace_secure_chat')}</span>
|
||
<span className="text-accent font-extrabold">{t('workspace_processor')}</span>
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
)}
|
||
|
||
{/* 4. SPACED REPETITION STUDY CARD SCREEN */}
|
||
{activeTab === 'reviews' && (
|
||
<motion.div
|
||
key="reviews"
|
||
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-0.5">
|
||
<span className="text-[9px] uppercase tracking-[0.2em] font-extrabold text-[#A47148] font-mono block">
|
||
{t('workspace_recall_title')}
|
||
</span>
|
||
<p className="text-[10.5px] text-stone-505 font-light">{t('workspace_recall_desc')}</p>
|
||
</div>
|
||
|
||
{/* Interactive flipped card structure */}
|
||
<div className="bg-white border border-black/[0.08] p-5 rounded-xl shadow-xs space-y-4 text-center max-w-sm mx-auto w-full min-h-[180px] flex flex-col justify-between paper-texture">
|
||
<div className="space-y-2">
|
||
<span className="text-[8px] font-mono uppercase bg-accent/10 text-accent px-2 py-0.5 rounded-full font-bold">
|
||
{lang === 'fr' ? `Carte mémoire révision ` : lang === 'ja' ? `暗記カード ` : `Concept review `} {flashcardIdx + 1}/2
|
||
</span>
|
||
<h4 className="text-xs font-serif font-black text-ink leading-relaxed">
|
||
{simulatedFlashcards[flashcardIdx].question}
|
||
</h4>
|
||
</div>
|
||
|
||
{showFlashcardAnswer ? (
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 4 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
className="p-2.5 bg-[#FAF9F5] border border-accent/20 rounded-lg text-left text-[10.5px] leading-relaxed text-stone-650"
|
||
>
|
||
<span className="text-[8px] font-mono font-black uppercase text-[#A47148] block mb-1">{t('workspace_correct_answer')}</span>
|
||
{simulatedFlashcards[flashcardIdx].answer}
|
||
</motion.div>
|
||
) : (
|
||
<button
|
||
onClick={() => setShowFlashcardAnswer(true)}
|
||
className="px-4 py-2 bg-accent hover:bg-accent/90 text-white transition-all text-[9.5px] font-bold uppercase tracking-wider rounded-xl cursor-pointer"
|
||
>
|
||
{t('workspace_show_answer')}
|
||
</button>
|
||
)}
|
||
|
||
{showFlashcardAnswer && (
|
||
<div className="flex gap-1 justify-center pt-2">
|
||
{[
|
||
{ label: lang === 'fr' ? "Revoir" : lang === 'ja' ? "やり直し" : "Again", color: "bg-red-500/10 text-red-600 hover:bg-red-500/20" },
|
||
{ label: lang === 'fr' ? "Ok" : lang === 'ja' ? "了解" : "Good", color: "bg-amber-500/10 text-amber-600 hover:bg-amber-500/20" },
|
||
{ label: lang === 'fr' ? "Parfait" : lang === 'ja' ? "完璧" : "Easy", color: "bg-emerald-500/10 text-emerald-600 hover:bg-emerald-500/20" }
|
||
].map((btn, idx) => (
|
||
<button
|
||
key={idx}
|
||
onClick={() => {
|
||
setShowFlashcardAnswer(false);
|
||
setFlashcardIdx((prev) => (prev + 1) % 2);
|
||
}}
|
||
className={`px-3 py-1 text-[8.5px] font-mono font-black uppercase transition-colors cursor-pointer rounded-md ${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-[#A47148] uppercase tracking-widest font-black">
|
||
<span>Spaced recall study active</span>
|
||
<span>{t('workspace_study_memory')}</span>
|
||
</div>
|
||
</motion.div>
|
||
)}
|
||
|
||
{/* 5. BACKUPS & TEMPORAL HISTORY SNAPSHOTS SCREEN */}
|
||
{activeTab === 'history' && (
|
||
<motion.div
|
||
key="history"
|
||
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-0.5">
|
||
<span className="text-[9px] uppercase tracking-[0.2em] font-extrabold text-[#A47148] font-mono block">
|
||
{t('workspace_snapshot_title')}
|
||
</span>
|
||
<p className="text-[10.5px] text-stone-500 font-light">{t('workspace_snapshot_desc')}</p>
|
||
</div>
|
||
|
||
{/* List timelines */}
|
||
<div className="space-y-2 max-w-lg mx-auto w-full text-xs">
|
||
{[
|
||
{
|
||
time: lang === 'fr' ? "Aujourd'hui, 09:56" : lang === 'ja' ? "今日, 09:56" : "Today, 09:56",
|
||
event: lang === 'fr' ? "Modification de l'Équation" : lang === 'ja' ? "数式マトリクスの編集" : "Equation structure modified",
|
||
size: lang === 'fr' ? "182 mots" : lang === 'ja' ? "182語" : "182 words",
|
||
active: true
|
||
},
|
||
{
|
||
time: lang === 'fr' ? "Aujourd'hui, 09:21" : lang === 'ja' ? "今日, 09:21" : "Today, 09:21",
|
||
event: lang === 'fr' ? "Import de l'Agent Scraper" : lang === 'ja' ? "スクレイパー起動ログ" : "Scraper Agent Log Import",
|
||
size: lang === 'fr' ? "124 mots" : lang === 'ja' ? "124語" : "124 words"
|
||
},
|
||
{
|
||
time: lang === 'fr' ? "Hier, 14:20" : lang === 'ja' ? "昨日, 14:20" : "Yesterday, 14:20",
|
||
event: lang === 'fr' ? "Création initiale de la trame" : lang === 'ja' ? "初期枠組みの構築" : "Initial model setup",
|
||
size: lang === 'fr' ? "86 mots" : lang === 'ja' ? "86語" : "86 words"
|
||
}
|
||
].map((snap, i) => (
|
||
<div
|
||
key={i}
|
||
className={`p-3 bg-white border rounded-xl flex items-center justify-between shadow-3xs transition-colors
|
||
${snap.active ? 'border-accent ring-2 ring-accent/10' : 'border-black/[0.08] hover:border-accent/40'}`}
|
||
>
|
||
<div className="flex items-center gap-2.5 text-left">
|
||
<Clock size={13} className="text-[#A47148]" />
|
||
<div>
|
||
<span className="font-bold text-ink block leading-snug">{snap.event}</span>
|
||
<span className="text-[9px] text-stone-500 font-mono block mt-0.5">{snap.time} · {snap.size}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<button
|
||
className="text-[8px] uppercase tracking-widest font-mono font-black text-accent cursor-pointer bg-stone-50 border border-stone-200 p-1 rounded-md hover:bg-accent hover:text-white transition-colors"
|
||
onClick={() => {
|
||
if (i === 1) triggerSimulation(1);
|
||
if (i === 2) triggerSimulation(0);
|
||
}}
|
||
>
|
||
{snap.active ? (lang === 'fr' ? "Actif" : lang === 'ja' ? "適用中" : "Active") : t('workspace_restore', true)}
|
||
</button>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="flex items-center justify-between border-t border-black/[0.04] pt-2 text-[9px] font-mono text-stone-500 uppercase tracking-widest font-bold">
|
||
<span>{t('workspace_state_saved')}</span>
|
||
<span className="text-[#A3B18A]">{lang === 'fr' ? "Secteurs locaux protégés pour de bon" : lang === 'ja' ? "ローカル保護領域:正常" : "Continuous sector write: OK"}</span>
|
||
</div>
|
||
</motion.div>
|
||
)}
|
||
|
||
</AnimatePresence>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{/* Console status footer */}
|
||
<div className="border-t border-white/[0.06] bg-[#F1EFEB] px-5 py-3 rounded-b-[18px] flex flex-col sm:flex-row items-center justify-between gap-3 text-left">
|
||
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-[9.5px] font-mono text-stone-500 uppercase tracking-widest">
|
||
<div className="flex items-center gap-1.5 font-bold text-[#A47148]">
|
||
<span className="w-1.5 h-1.5 rounded bg-accent animate-pulse" />
|
||
<span>SECURE KERNEL</span>
|
||
</div>
|
||
<span>|</span>
|
||
<span>{lang === 'fr' ? "Totalement chiffré" : lang === 'ja' ? "完全暗号化ローカル保管" : "AES-256 local encrypted"}</span>
|
||
<span>|</span>
|
||
<span className="font-semibold text-ink">{lang === 'fr' ? "STOCKAGE PRIVÉ ACTIF" : lang === 'ja' ? "セキュア物理保存" : "ACTIVE EXCLUSIVE COLD STORAGE"}</span>
|
||
</div>
|
||
|
||
<button
|
||
onClick={onEnter}
|
||
className="px-5 py-2 bg-ink text-paper hover:bg-[#A47148] text-[9.5px] font-bold uppercase tracking-widest rounded transition-all duration-300 shadow-sm cursor-pointer"
|
||
>
|
||
{t('nav_start', true)}
|
||
</button>
|
||
</div>
|
||
|
||
</div>
|
||
</motion.div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Features Grid */}
|
||
<section id="features" className="py-32 px-8 bg-paper">
|
||
<div className="max-w-6xl mx-auto">
|
||
<div className="mb-24 flex flex-col md:flex-row md:items-end justify-between gap-8 text-left">
|
||
<div className="max-w-2xl">
|
||
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('features_badge')}</span>
|
||
<h2 className="text-4xl md:text-5xl font-serif tracking-tight text-ink">
|
||
{t('features_title_1')} <br />{t('features_title_2')}
|
||
</h2>
|
||
</div>
|
||
<div className="text-concrete font-light text-sm md:text-base">
|
||
{t('features_subtitle')}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-12 text-left">
|
||
{[
|
||
{
|
||
icon: <Search className="text-accent" />,
|
||
title: t('f1_title'),
|
||
desc: t('f1_desc')
|
||
},
|
||
{
|
||
icon: <MessageSquare className="text-ochre" />,
|
||
title: t('f2_title'),
|
||
desc: t('f2_desc')
|
||
},
|
||
{
|
||
icon: <Zap className="text-ink" />,
|
||
title: t('f3_title'),
|
||
desc: t('f3_desc')
|
||
}
|
||
].map((feature, i) => (
|
||
<div key={i} className="group">
|
||
<div className="w-14 h-14 bg-slate-50 border border-border rounded-2xl flex items-center justify-center mb-8 group-hover:bg-ink group-hover:text-paper transition-all duration-300">
|
||
{feature.icon}
|
||
</div>
|
||
<h3 className="text-xl font-serif font-medium mb-4">{feature.title}</h3>
|
||
<div className="text-sm text-concrete leading-relaxed font-light">{feature.desc}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Agent Showcase */}
|
||
<section id="agents" className="py-32 px-8 bg-ink text-paper overflow-hidden relative text-left">
|
||
<div className="absolute top-0 right-0 w-[1000px] h-[1000px] bg-accent/10 rounded-full blur-[150px] -translate-y-1/2 translate-x-1/2" />
|
||
|
||
<div className="max-w-6xl mx-auto relative z-10">
|
||
<div className="text-center mb-24">
|
||
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('agents_badge')}</span>
|
||
<h2 className="text-4xl md:text-6xl font-serif tracking-tight mb-8">{t('agents_title')}</h2>
|
||
<p className="text-paper/60 max-w-xl mx-auto font-light text-sm md:text-base">{t('agents_subtitle')}</p>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||
{[
|
||
{ type: "Scraper", icon: <Globe size={24} />, desc: t('agent_scraper_desc') },
|
||
{ type: "Researcher", icon: <Search size={24} />, desc: t('agent_researcher_desc') },
|
||
{ type: "Slide Gen", icon: <Layers size={24} />, desc: t('agent_slide_desc') },
|
||
{ type: "Monitor", icon: <Activity size={24} />, desc: t('agent_monitor_desc') },
|
||
{ type: "Diagram Gen", icon: <Box size={24} />, desc: t('agent_diagram_desc') },
|
||
{ type: "Custom", icon: <Workflow size={24} />, desc: t('agent_custom_desc') }
|
||
].map((agent, i) => (
|
||
<div key={i} className="p-8 rounded-3xl bg-white/5 border border-white/10 hover:bg-white/10 transition-all cursor-default group">
|
||
<div className="text-ochre mb-6 transition-transform group-hover:scale-110 duration-300">
|
||
{agent.icon}
|
||
</div>
|
||
<h4 className="text-xl font-serif font-medium mb-4">{agent.type}</h4>
|
||
<div className="text-sm text-paper/50 leading-relaxed font-light">{agent.desc}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Brainstorm Section */}
|
||
<section id="brainstorm" className="py-32 px-8 bg-paper text-left">
|
||
<div className="max-w-6xl mx-auto flex flex-col md:flex-row items-center gap-24">
|
||
<div className="flex-1">
|
||
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('brain_badge')}</span>
|
||
<h2 className="text-4xl md:text-5xl font-serif tracking-tight text-ink mb-8 leading-tight">{t('brain_title')}</h2>
|
||
<div className="space-y-8">
|
||
{[
|
||
{ title: t('brain_item1_title'), desc: t('brain_item1_desc') },
|
||
{ title: t('brain_item2_title'), desc: t('brain_item2_desc') },
|
||
{ title: t('brain_item3_title'), desc: t('brain_item3_desc') }
|
||
].map((item, i) => (
|
||
<div key={i} className="flex gap-6">
|
||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-ochre/10 text-ochre flex items-center justify-center font-bold text-xs">
|
||
{i+1}
|
||
</div>
|
||
<div>
|
||
<h5 className="font-bold text-sm mb-1">{item.title}</h5>
|
||
<div className="text-sm text-concrete font-light leading-relaxed">{item.desc}</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div className="flex-1 relative">
|
||
<div className="w-[350px] h-[350px] md:w-[450px] md:h-[450px] border-2 border-dashed border-border rounded-full flex items-center justify-center relative animate-spin-slow">
|
||
<div className="absolute top-0 right-1/2 translate-x-1/2 -translate-y-1/2 w-4 h-4 bg-ink rounded-full" />
|
||
<div className="absolute bottom-0 right-1/2 translate-x-1/2 translate-y-1/2 w-4 h-4 bg-ochre rounded-full" />
|
||
<div className="w-[250px] h-[250px] md:w-[300px] md:h-[300px] border-2 border-dashed border-border rounded-full flex items-center justify-center">
|
||
<div className="w-[120px] h-[120px] md:w-[150px] md:h-[150px] border-2 border-dashed border-border rounded-full flex items-center justify-center">
|
||
<div className="w-12 h-12 bg-ink rounded-xl shadow-2xl flex items-center justify-center text-paper font-serif text-xl">M</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Floating nodes */}
|
||
<div className="absolute top-10 right-0 p-4 bg-white border border-border rounded-xl shadow-xl animate-float">
|
||
<div className="text-[10px] font-bold text-[#A47148]">{t('brain_node1_title')}</div>
|
||
<div className="text-xs font-serif italic text-ink">{t('brain_node1_text')}</div>
|
||
</div>
|
||
<div className="absolute bottom-20 -left-5 p-4 bg-white border border-border rounded-xl shadow-xl animate-bounce-slow">
|
||
<div className="text-[10px] font-bold text-accent">{t('brain_node2_title')}</div>
|
||
<div className="text-xs font-serif italic text-ink">{t('brain_node2_text')}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Tech Section */}
|
||
<section id="tech" className="py-32 px-8 bg-slate-50 border-y border-border text-center">
|
||
<div className="max-w-6xl mx-auto text-center">
|
||
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('tech_badge')}</span>
|
||
<h2 className="text-3xl md:text-4xl font-serif tracking-tight mb-16">{t('tech_title')}</h2>
|
||
|
||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-8 grayscale opacity-55 hover:grayscale-0 hover:opacity-100 transition-all duration-700">
|
||
{['OpenAI', 'Google', 'Anthropic', 'DeepSeek', 'Mistral', 'Meta', 'Ollama', 'Groq', 'X.AI', 'Custom'].map((brand, i) => (
|
||
<div key={i} className="flex flex-col items-center gap-3">
|
||
<div className="w-12 h-12 bg-white rounded-xl border border-border flex items-center justify-center text-xs font-black tracking-tighter">
|
||
{brand.slice(0,2).toUpperCase()}
|
||
</div>
|
||
<span className="text-[10px] font-bold uppercase tracking-widest">{brand}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="mt-24 max-w-2xl mx-auto p-1 bg-white rounded-3xl border border-border shadow-3xs flex flex-col md:flex-row gap-0.5 text-left">
|
||
{[
|
||
{ label: t('tech_tier1_label'), desc: t('tech_tier1_desc'), color: 'bg-accent' },
|
||
{ label: t('tech_tier2_label'), desc: t('tech_tier2_desc'), color: 'bg-ochre' },
|
||
{ label: t('tech_tier3_label'), desc: t('tech_tier3_desc'), color: 'bg-ink' }
|
||
].map((tier, i) => (
|
||
<div key={i} className="flex-1 p-6">
|
||
<div className={`w-1.5 h-1.5 rounded-full ${tier.color} mb-4`} />
|
||
<h6 className="text-[10px] font-bold uppercase tracking-widest text-concrete mb-2">{tier.label}</h6>
|
||
<div className="text-xs font-light text-concrete leading-relaxed">{tier.desc}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Pricing Section */}
|
||
<section id="pricing" className="py-32 px-8 bg-paper text-center">
|
||
<div className="max-w-7xl mx-auto">
|
||
<div className="text-center mb-12">
|
||
<span className="text-[11px] font-bold uppercase tracking-[0.3em] text-ochre mb-4 block">{t('price_badge')}</span>
|
||
<h2 className="text-4xl md:text-5xl font-serif tracking-tight text-ink mb-6">{t('price_title')}</h2>
|
||
<p className="text-concrete font-light max-w-xl mx-auto mb-12 text-sm md:text-base">{t('price_desc')}</p>
|
||
|
||
{/* Billing Toggle */}
|
||
<div className="flex items-center justify-center gap-10 mb-8">
|
||
<button
|
||
onClick={() => setBillingInterval('monthly')}
|
||
className={`group relative py-2 px-1 transition-all ${billingInterval === 'monthly' ? 'text-ink' : 'text-concrete/40 hover:text-concrete'}`}
|
||
>
|
||
<span className="text-xs font-black uppercase tracking-[0.2em]">{t('price_monthly')}</span>
|
||
{billingInterval === 'monthly' && (
|
||
<motion.div
|
||
layoutId="interval-active-v1"
|
||
className="absolute -inset-x-2 -inset-y-0.5 border border-ochre/60"
|
||
transition={{ type: 'spring', bounce: 0.2, duration: 0.6 }}
|
||
/>
|
||
)}
|
||
</button>
|
||
|
||
<div className="relative">
|
||
<button
|
||
onClick={() => setBillingInterval('annual')}
|
||
className={`group relative py-2 px-1 transition-all ${billingInterval === 'annual' ? 'text-ink' : 'text-concrete/40 hover:text-concrete'}`}
|
||
>
|
||
<span className="text-xs font-black uppercase tracking-[0.2em]">{t('price_annual')}</span>
|
||
{billingInterval === 'annual' && (
|
||
<motion.div
|
||
layoutId="interval-active-v1"
|
||
className="absolute -inset-x-2 -inset-y-0.5 border border-ochre/60"
|
||
transition={{ type: 'spring', bounce: 0.2, duration: 0.6 }}
|
||
/>
|
||
)}
|
||
</button>
|
||
<div className="absolute -top-6 left-1/2 -translate-x-1/2 whitespace-nowrap">
|
||
<span className="text-[9px] font-bold text-ochre uppercase tracking-widest italic animate-pulse">(-20%)</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 items-stretch text-left">
|
||
{[
|
||
{
|
||
name: t('price_free_name'),
|
||
price: t('price_free_price'),
|
||
desc: t('price_free_desc'),
|
||
features: tArray('price_free_features'),
|
||
cta: t('price_cta_start'),
|
||
popular: false
|
||
},
|
||
{
|
||
name: t('price_pro_name'),
|
||
price: lang === 'ja' ? '¥1,480' : planIsAnnual => planIsAnnual ? "7,90€" : "9,90€", // handle localized currencies seamlessly
|
||
period: billingInterval === 'monthly' ? t('price_period_month') : t('price_period_annual'),
|
||
desc: t('price_pro_desc'),
|
||
features: tArray('price_pro_features'),
|
||
cta: t('price_cta_pro'),
|
||
popular: true
|
||
},
|
||
{
|
||
name: t('price_biz_name'),
|
||
price: lang === 'ja' ? '¥4,480' : planIsAnnual => planIsAnnual ? "23,90€" : "29,90€",
|
||
period: billingInterval === 'monthly' ? t('price_period_month') : t('price_period_annual'),
|
||
desc: t('price_biz_desc'),
|
||
features: tArray('price_biz_features'),
|
||
cta: t('price_cta_biz'),
|
||
popular: false
|
||
},
|
||
{
|
||
name: t('price_ent_name'),
|
||
price: lang === 'ja' ? '要相談' : '49,90€',
|
||
period: billingInterval === 'monthly' ? t('price_period_month') : t('price_period_annual'),
|
||
desc: t('price_ent_desc'),
|
||
features: tArray('price_ent_features'),
|
||
cta: t('price_cta_ent'),
|
||
popular: false
|
||
}
|
||
].map((plan, i) => {
|
||
const displayPrice = typeof plan.price === 'function' ? plan.price(billingInterval === 'annual') : plan.price;
|
||
return (
|
||
<div
|
||
key={i}
|
||
className={`relative p-8 rounded-[32px] border flex flex-col transition-all duration-300 hover:shadow-2xl hover:shadow-ink/5 ${plan.popular ? 'bg-ink text-paper border-ink ring-4 ring-ochre/20' : 'bg-white border-border text-ink'}`}
|
||
>
|
||
{plan.popular && (
|
||
<div className="absolute -top-4 left-1/2 -translate-x-1/2 px-4 py-1 bg-ochre text-ink text-[10px] font-bold uppercase tracking-widest rounded-full">
|
||
{t('price_popular')}
|
||
</div>
|
||
)}
|
||
<div className="mb-8">
|
||
<h4 className="text-[11px] font-bold uppercase tracking-widest mb-2 opacity-60">{plan.name}</h4>
|
||
<div className="flex items-baseline gap-1 mb-4">
|
||
<span className="text-3xl font-serif font-medium">{displayPrice}</span>
|
||
<span className="text-xs opacity-60">{'period' in plan ? plan.period : ''}</span>
|
||
</div>
|
||
<p className="text-sm font-light leading-relaxed opacity-80">{plan.desc}</p>
|
||
</div>
|
||
|
||
<div className="flex-1 space-y-4 mb-10">
|
||
{plan.features.map((feature, j) => (
|
||
<div key={j} className="flex items-start gap-3">
|
||
<div className={`mt-1 rounded-full p-0.5 ${plan.popular ? 'bg-ochre text-ink' : 'bg-accent/10 text-accent'}`}>
|
||
<Shield size={10} fill="currentColor" />
|
||
</div>
|
||
<span className="text-xs font-light">{feature}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<button
|
||
onClick={onEnter}
|
||
className={`w-full py-4 rounded-2xl text-xs font-bold uppercase tracking-widest transition-all ${plan.popular ? 'bg-ochre text-ink hover:opacity-90' : 'bg-ink text-paper hover:bg-ink/90 link-underlined'}`}
|
||
>
|
||
{plan.cta}
|
||
</button>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{/* BYOK Section */}
|
||
<div className="mt-20 p-6 md:p-12 bg-slate-50 border border-border rounded-[40px] flex flex-col lg:flex-row items-center gap-12 text-left">
|
||
<div className="flex-1">
|
||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-accent/10 text-accent text-[9px] font-bold uppercase tracking-widest mb-6">
|
||
<Cpu size={12} />
|
||
{t('byok_badge')}
|
||
</div>
|
||
<h3 className="text-2xl md:text-3xl font-serif font-medium mb-4">{t('byok_title')}</h3>
|
||
<p className="text-concrete font-light leading-relaxed mb-6 text-sm text-justify">
|
||
{t('byok_desc')}
|
||
</p>
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="p-4 bg-white rounded-2xl border border-border">
|
||
<h5 className="text-[10px] font-bold uppercase tracking-widest mb-2">{t('byok_col1_title')}</h5>
|
||
<p className="text-[10px] text-concrete font-light leading-relaxed">{t('byok_col1_desc')}</p>
|
||
</div>
|
||
<div className="p-4 bg-white rounded-2xl border border-border">
|
||
<h5 className="text-[10px] font-bold uppercase tracking-widest mb-2">{t('byok_col2_title')}</h5>
|
||
<p className="text-[10px] text-concrete font-light leading-relaxed">{t('byok_col2_desc')}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="w-full lg:w-[400px] bg-ink rounded-3xl p-8 relative overflow-hidden group">
|
||
<div className="absolute inset-0 bg-accent/10 blur-[50px] group-hover:bg-ochre/10 transition-colors" />
|
||
<div className="relative z-10 font-mono text-[10px] text-paper/40 space-y-2">
|
||
<p className="text-ochre">{"{"}</p>
|
||
<p className="pl-4">"provider": "anthropic",</p>
|
||
<p className="pl-4">"model": "claude-3-opus",</p>
|
||
<p className="pl-4 border-l border-accent/30 bg-accent/5">"apiKey": "sk-ant-at03-..."</p>
|
||
<p className="pl-4">"useSystemKey": false</p>
|
||
<p className="text-ochre">{"}"}</p>
|
||
</div>
|
||
<div className="mt-8 flex items-center justify-between relative z-10">
|
||
<span className="text-[10px] font-bold text-paper uppercase tracking-widest">{t('byok_config_title')}</span>
|
||
<div className="flex gap-1">
|
||
{[1,2,3].map(i => <div key={i} className="w-1 h-1 rounded-full bg-paper/20" />)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Ecosystem Section / Cross-promotion */}
|
||
<section className="py-24 px-8 border-t border-border bg-slate-50/50 text-left animate-fade-in">
|
||
<div className="max-w-6xl mx-auto">
|
||
<div className="flex flex-col md:flex-row items-center gap-16">
|
||
<div className="flex-1 space-y-8">
|
||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-accent/10 text-accent text-[9px] font-bold uppercase tracking-widest">
|
||
<Globe size={12} />
|
||
{t('eco_badge')}
|
||
</div>
|
||
<h3 className="text-3xl md:text-4xl font-serif font-medium leading-tight text-ink">
|
||
{t('eco_title_1')}<br />
|
||
<span className="text-accent italic">{t('eco_title_2')}</span>
|
||
</h3>
|
||
<p className="text-base text-concrete font-light leading-relaxed text-justify">
|
||
{t('eco_desc')}
|
||
</p>
|
||
<button
|
||
onClick={onEnter}
|
||
className="px-8 py-4 border-2 border-accent text-accent rounded-2xl text-sm font-bold uppercase tracking-widest hover:bg-accent hover:text-white transition-all cursor-pointer"
|
||
>
|
||
{t('eco_button')}
|
||
</button>
|
||
</div>
|
||
|
||
<div className="w-full md:w-1/2 relative group">
|
||
<div className="absolute inset-0 bg-accent/5 blur-3xl -z-10 group-hover:bg-accent/10 transition-colors" />
|
||
<div className="bg-white border border-border p-8 rounded-[32px] shadow-2xl relative overflow-hidden">
|
||
<div className="flex items-center justify-between mb-8 pb-4 border-b border-border/40">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 bg-accent/10 rounded-xl flex items-center justify-center text-accent">
|
||
<FileText size={20} />
|
||
</div>
|
||
<div className="text-[10px] uppercase font-bold tracking-widest text-ink">{t('eco_original')}</div>
|
||
</div>
|
||
<ArrowRightLeft size={16} className="text-concrete" />
|
||
<div className="flex items-center gap-3">
|
||
<div className="text-[10px] uppercase font-bold tracking-widest text-ink">{t('eco_translated')}</div>
|
||
<div className="w-10 h-10 bg-green-50 rounded-xl flex items-center justify-center text-green-600">
|
||
<Check size={20} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Abstract document structure representation */}
|
||
<div className="space-y-4">
|
||
<div className="h-4 bg-slate-100 rounded-full w-3/4" />
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="aspect-video bg-accent/5 rounded-xl border border-dashed border-accent/20" />
|
||
<div className="space-y-3">
|
||
<div className="h-3 bg-slate-100 rounded-full w-full" />
|
||
<div className="h-3 bg-slate-100 rounded-full w-5/6" />
|
||
<div className="h-3 bg-slate-100 rounded-full w-4/6" />
|
||
</div>
|
||
</div>
|
||
<div className="h-20 bg-slate-50 border border-border/40 rounded-xl p-3">
|
||
<div className="h-2 bg-slate-200 rounded-full w-1/2 mb-2" />
|
||
<div className="grid grid-cols-4 gap-2">
|
||
{[1,2,3,4].map(i => <div key={i} className="h-8 bg-white border border-border/20 rounded shadow-sm" />)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="absolute bottom-4 right-8 text-[8px] font-bold text-accent italic uppercase tracking-tighter">
|
||
{t('eco_status')}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Final CTA */}
|
||
<section className="py-40 px-8 text-center bg-paper relative overflow-hidden">
|
||
<div className="max-w-3xl mx-auto relative z-10">
|
||
<h2 className="text-4xl md:text-6xl font-serif tracking-tight mb-8 leading-tight">
|
||
{t('final_cta_title')} <br />
|
||
<span className="italic">{t('final_cta_title_italic')}</span>
|
||
</h2>
|
||
<p className="text-base text-concrete font-light mb-12">{t('final_cta_desc')}</p>
|
||
<button
|
||
onClick={onEnter}
|
||
className="px-16 py-6 bg-ink text-paper rounded-[32px] text-base font-bold uppercase tracking-[0.2em] hover:scale-105 transition-all shadow-[0_30px_60px_-15px_rgba(0,0,0,0.3)] cursor-pointer"
|
||
>
|
||
{t('final_cta_button')}
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Footer */}
|
||
<footer className="py-20 px-8 border-t border-border bg-paper text-left">
|
||
<div className="max-w-6xl mx-auto flex flex-col md:flex-row justify-between gap-12">
|
||
<div className="space-y-6">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-8 h-8 bg-ink flex items-center justify-center rounded-lg">
|
||
<span className="text-paper font-serif text-lg font-bold">M</span>
|
||
</div>
|
||
<span className="font-serif text-xl font-medium tracking-tight">Memento</span>
|
||
</div>
|
||
<p className="text-sm text-concrete font-light max-w-xs leading-relaxed">{t('footer_desc')}</p>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 md:grid-cols-3 gap-16">
|
||
<div className="space-y-4">
|
||
<h6 className="text-[10px] font-bold uppercase tracking-widest text-ink">{t('footer_col1_title')}</h6>
|
||
<ul className="space-y-2 text-sm text-concrete font-light">
|
||
<li><a href="#" className="hover:text-ink transition-colors">Changelog</a></li>
|
||
<li><a href="#" className="hover:text-ink transition-colors">Documentation</a></li>
|
||
<li><a href="#" className="hover:text-ink transition-colors">Roadmap</a></li>
|
||
</ul>
|
||
</div>
|
||
<div className="space-y-4">
|
||
<h6 className="text-[10px] font-bold uppercase tracking-widest text-ink">{t('footer_col2_title')}</h6>
|
||
<ul className="space-y-2 text-sm text-concrete font-light">
|
||
<li><a href="#" className="hover:text-ink transition-colors">Discord</a></li>
|
||
<li><a href="#" className="hover:text-ink transition-colors">Twitter / X</a></li>
|
||
<li><a href="#" className="hover:text-ink transition-colors">LinkedIn</a></li>
|
||
</ul>
|
||
</div>
|
||
<div className="space-y-4">
|
||
<h6 className="text-[10px] font-bold uppercase tracking-widest text-ink">{t('footer_col3_title')}</h6>
|
||
<ul className="space-y-2 text-sm text-concrete font-light">
|
||
<li><a href="#" className="hover:text-ink transition-colors">Privacy Policy</a></li>
|
||
<li><a href="#" className="hover:text-ink transition-colors">Terms of Service</a></li>
|
||
<li><a href="#" className="hover:text-ink transition-colors">Cookie Policy</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="max-w-6xl mx-auto mt-20 pt-10 border-t border-border flex flex-col md:flex-row justify-between items-center gap-4 text-[10px] uppercase font-bold tracking-widest text-concrete">
|
||
<div>© 2026 MOMENTO LABS. ALL RIGHTS RESERVED.</div>
|
||
<div className="flex gap-8">
|
||
<span>DESIGNED BY ANTIGRAVITY</span>
|
||
<span>POWERED BY GEMINI 1.5 FLASH</span>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
);
|
||
};
|