'use client'; import { useEffect, useState, useCallback } from 'react'; import { useReducedMotion } from 'framer-motion'; import { FileText, FileSpreadsheet, Presentation, FileCheck, Sparkles, ArrowRight, Clock, Users, Flame, Check, ShieldCheck, Save, Undo, Redo, Search, Minus, Square, X, Bold, Italic, Underline, AlignLeft, AlignCenter, List, ListOrdered, Table as TableIcon, ChevronDown, ZoomIn, Printer, Maximize2, } from 'lucide-react'; import { cn } from '@/lib/utils'; /** * Wordly.art — Hero Visual Authentique Office & PDF * * Cette animation recrée fidèlement l'environnement réel d'un logiciel bureautique * (Microsoft Word, Excel, PowerPoint et Adobe PDF) avec : * - Le ruban, la barre de titre, la règle et la barre d'état officielles. * - Une vraie page de document A4 flottante avec du vrai texte lisible (≥ 11px). * - Une onde dorée de numérisation/traduction en temps réel (FR → EN → ES). * - Une stabilité géométrique absolue : zéro décalage, zéro saut de mise en page. */ type OfficeFormat = 'docx' | 'xlsx' | 'pptx' | 'pdf'; interface RecipeData { lang: 'FR' | 'EN' | 'ES'; langName: string; langCodeDoc: string; docTitle: string; docSubtitle: string; category: string; timeLabel: string; servingsLabel: string; heatLabel: string; ingredientsHeading: string; ingredients: Array<{ amount: string; name: string }>; tableTitle: string; tableHeaders: [string, string, string]; tableValues: [string, string, string]; stepsHeading: string; steps: Array<{ num: string; title: string; desc: string }>; excelFormula: string; excelHeaders: [string, string, string, string]; excelRows: Array<[string, string, string, string]>; excelTotalLabel: string; excelTotalVal: string; pptSlideTitle: string; pptCard1Title: string; pptCard1Text: string; pptCard2Title: string; pptCard2Text: string; guaranteeText: string; } const RECIPES: RecipeData[] = [ { lang: 'FR', langName: 'Français (France)', langCodeDoc: 'FR-FR', docTitle: 'Tarte fine aux pommes & cannelle', docSubtitle: 'Recette traditionnelle • Pâtisserie maison de saison', category: 'Pâtisserie artisanale • Recette n°04', timeLabel: '15 min de préparation', servingsLabel: '4 à 6 personnes', heatLabel: 'Four chaud 180°C', ingredientsHeading: 'Ingrédients nécessaires', ingredients: [ { amount: '1 rouleau', name: 'Pâte feuilletée pur beurre dorée' }, { amount: '4 pièces', name: 'Pommes Golden finement tranchées' }, { amount: '25 g', name: 'Beurre doux fondu tiédi' }, { amount: '2 sachets', name: 'Sucre vanillé naturel des îles' }, ], tableTitle: 'Paramètres de cuisson au four', tableHeaders: ['Position four', 'Préparation', 'Cuisson dorée'], tableValues: ['Mi-hauteur 180°C', '15 minutes', '25 minutes'], stepsHeading: 'Instructions de préparation', steps: [ { num: '01', title: 'Préparer la pâte', desc: 'Dérouler la pâte sur la plaque et piquer le fond à la fourchette.', }, { num: '02', title: 'Dresser les pommes', desc: 'Disposer les lamelles de pommes en rosace harmonieuse et serrée.', }, { num: '03', title: 'Enfourner et dorer', desc: 'Badigeonner de beurre fondu puis saupoudrer de sucre vanillé.', }, ], excelFormula: '=SOMME(C3:C6) & " g de garniture"', excelHeaders: ['Ingrédient', 'Quantité', 'Unité', 'Remarque'], excelRows: [ ['Pâte feuilletée', '1', 'rouleau', 'Pur beurre'], ['Pommes Golden', '4', 'pièces', 'Tranches fines'], ['Beurre doux', '25', 'grammes', 'Fondu tiède'], ['Sucre vanillé', '2', 'sachets', 'Arôme naturel'], ], excelTotalLabel: 'Temps de cuisson totale', excelTotalVal: '25 min à 180°C', pptSlideTitle: 'Recette gourmande : Tarte fine aux pommes', pptCard1Title: 'Ingrédients clés', pptCard1Text: 'Pâte feuilletée pur beurre, 4 pommes Golden, beurre doux fondu, sucre vanillé naturel.', pptCard2Title: 'Cuisson & finition', pptCard2Text: 'Disposition en rosace serrée, cuisson 25 min à 180°C jusqu’à dorure parfaite.', guaranteeText: 'Mise en page originale 100% préservée', }, { lang: 'EN', langName: 'English (United States)', langCodeDoc: 'EN-US', docTitle: 'Crisp apple & cinnamon tart', docSubtitle: 'Traditional recipe • Seasonal homemade pastry', category: 'Artisanal pastry • Recipe #04', timeLabel: '15 min preparation time', servingsLabel: '4 to 6 servings', heatLabel: 'Hot oven at 180°C', ingredientsHeading: 'Required ingredients', ingredients: [ { amount: '1 sheet', name: 'Golden all-butter puff pastry sheet' }, { amount: '4 units', name: 'Fresh Golden apples thinly sliced' }, { amount: '25 g', name: 'Melted unsalted sweet butter' }, { amount: '2 packs', name: 'Natural island vanilla sugar dust' }, ], tableTitle: 'Oven baking specifications', tableHeaders: ['Oven position', 'Preparation', 'Golden baking'], tableValues: ['Middle shelf 180°C', '15 minutes', '25 minutes'], stepsHeading: 'Preparation instructions', steps: [ { num: '01', title: 'Prepare the crust', desc: 'Unroll pastry on the tray and prick the base evenly with a fork.', }, { num: '02', title: 'Arrange the fruit', desc: 'Place the apple slices in an elegant, tight spiral pattern.', }, { num: '03', title: 'Bake to golden', desc: 'Brush with melted butter and dust evenly with vanilla sugar.', }, ], excelFormula: '=SUM(C3:C6) & " g filling total"', excelHeaders: ['Ingredient', 'Quantity', 'Unit', 'Note'], excelRows: [ ['Puff pastry', '1', 'sheet', 'All-butter'], ['Golden apples', '4', 'units', 'Thin slices'], ['Unsalted butter', '25', 'grams', 'Melted warm'], ['Vanilla sugar', '2', 'packs', 'Natural flavor'], ], excelTotalLabel: 'Total baking duration', excelTotalVal: '25 min at 180°C', pptSlideTitle: 'Gourmet Recipe: Crisp Apple Tart', pptCard1Title: 'Key Ingredients', pptCard1Text: 'All-butter puff pastry, 4 Golden apples, melted unsalted butter, natural vanilla sugar.', pptCard2Title: 'Baking & Finish', pptCard2Text: 'Arrange in tight spiral, bake 25 min at 180°C until crisp and golden brown.', guaranteeText: 'Original layout 100% preserved', }, { lang: 'ES', langName: 'Español (España)', langCodeDoc: 'ES-ES', docTitle: 'Tarta fina de manzana & canela', docSubtitle: 'Receta tradicional • Repostería casera de otoño', category: 'Repostería artesanal • Receta n°04', timeLabel: '15 min de preparación', servingsLabel: '4 a 6 personas', heatLabel: 'Horno caliente 180°C', ingredientsHeading: 'Ingredientes necesarios', ingredients: [ { amount: '1 lámina', name: 'Masa de hojaldre dorado con mantequilla' }, { amount: '4 piezas', name: 'Manzanas Golden finamente laminadas' }, { amount: '25 g', name: 'Mantequilla dulce derretida templada' }, { amount: '2 sobres', name: 'Azúcar avainillado natural fino' }, ], tableTitle: 'Parámetros de horneado al horno', tableHeaders: ['Posición horno', 'Preparación', 'Horneado dorado'], tableValues: ['Altura media 180°C', '15 minutos', '25 minutes'], stepsHeading: 'Instrucciones de preparación', steps: [ { num: '01', title: 'Preparar la base', desc: 'Extender la masa sobre la bandeja y pinchar la base con tenedor.', }, { num: '02', title: 'Colocar la fruta', desc: 'Disponer las láminas de manzana en una espiral bien apretada.', }, { num: '03', title: 'Hornear y dorar', desc: 'Pincelar con mantequilla y espolvorear el azúcar avainillado.', }, ], excelFormula: '=SUMA(C3:C6) & " g de relleno"', excelHeaders: ['Ingrediente', 'Cantidad', 'Unidad', 'Detalle'], excelRows: [ ['Masa hojaldre', '1', 'lámina', 'Con mantequilla'], ['Manzanas Golden', '4', 'piezas', 'Láminas finas'], ['Mantequilla dulce', '25', 'gramos', 'Derretida tibia'], ['Azúcar vainillado', '2', 'sobres', 'Aroma natural'], ], excelTotalLabel: 'Tiempo de cocción total', excelTotalVal: '25 min a 180°C', pptSlideTitle: 'Receta exquisita: Tarta fina de manzana', pptCard1Title: 'Ingredientes clave', pptCard1Text: 'Masa de hojaldre, 4 manzanas Golden, mantequilla dulce derretida, azúcar avainillado.', pptCard2Title: 'Horneado y acabado', pptCard2Text: 'Disposición en espiral apretada, hornear 25 min a 180°C hasta que esté dorada.', guaranteeText: 'Estructura original 100% preservada', }, ]; const FORMAT_CONFIG: Record< OfficeFormat, { ext: string; label: string; appTitle: string; accentColor: string; headerBg: string; headerText: string; statusBg: string; icon: typeof FileText; defaultFile: string; } > = { docx: { ext: '.DOCX', label: 'Word', appTitle: 'Word', accentColor: '#185ABD', headerBg: 'bg-[#185ABD] dark:bg-[#10438F]', headerText: 'text-white', statusBg: 'bg-[#185ABD] dark:bg-[#10438F]', icon: FileText, defaultFile: 'Recette_Tarte_Pommes.docx', }, xlsx: { ext: '.XLSX', label: 'Excel', appTitle: 'Excel', accentColor: '#107C41', headerBg: 'bg-[#107C41] dark:bg-[#0B5C30]', headerText: 'text-white', statusBg: 'bg-[#107C41] dark:bg-[#0B5C30]', icon: FileSpreadsheet, defaultFile: 'Fiche_Technique_Recette.xlsx', }, pptx: { ext: '.PPTX', label: 'PowerPoint', appTitle: 'PowerPoint', accentColor: '#C43E1C', headerBg: 'bg-[#C43E1C] dark:bg-[#992F13]', headerText: 'text-white', statusBg: 'bg-[#C43E1C] dark:bg-[#992F13]', icon: Presentation, defaultFile: 'Presentation_Recette.pptx', }, pdf: { ext: '.PDF', label: 'PDF Reader', appTitle: 'Adobe Acrobat Reader', accentColor: '#E03E2D', headerBg: 'bg-[#2A2A2A] dark:bg-[#1A1A1A]', headerText: 'text-white', statusBg: 'bg-[#2A2A2A] dark:bg-[#1A1A1A]', icon: FileCheck, defaultFile: 'Document_Recette_Officiel.pdf', }, }; const CYCLE_DURATION_MS = 6200; // ~6.2 secondes par cycle const SCAN_DURATION_MS = 1400; // 1.4s onde dorée /** * Rendu intérieur d'un document Word (.docx) avec vraie mise en page A4 */ function WordDocumentSheet({ data }: { data: RecipeData }) { return (
{/* En-tête avec repères de marge Word */}
Style : Document Word Standard Section 1 • Marges normales (2,5 cm)

{data.docTitle}

{data.category}

{data.docSubtitle}

{/* Métadonnées */}
{data.timeLabel}
{data.servingsLabel}
{data.heatLabel}
{/* Corps 2 colonnes */}
{/* Colonne Ingrédients + Tableau Word */}

{data.ingredientsHeading}

    {data.ingredients.map((item, idx) => (
  • {item.name} {item.amount}
  • ))}
{/* Vrai Tableau Word avec bordures officielles */}
{data.tableTitle}
{data.tableHeaders.map((header, hIdx) => (
{header}
{data.tableValues[hIdx]}
))}
{/* Colonne Instructions numérotées Word */}

{data.stepsHeading}

{data.steps.map((st, sIdx) => (
{st.num}
{st.title}
{st.desc}
))}
{/* Pied de page Word */}
{data.guaranteeText}
Wordly Engine • Microsoft Word XML
); } /** * Rendu intérieur d'une feuille Excel (.xlsx) avec vraie grille de cellules */ function ExcelDocumentSheet({ data }: { data: RecipeData }) { return (
{/* Barre de formule Excel */}
A1:D8 fx {data.excelFormula}
{/* Grille Excel avec entêtes de colonnes A, B, C, D */}
{/* Ligne des colonnes A B C D */}
#
A ({data.excelHeaders[0]})
B ({data.excelHeaders[1]})
C ({data.excelHeaders[2]})
D ({data.excelHeaders[3]})
{/* Ligne 1 : Titre fusionné */}
1
{data.docTitle}
{/* Lignes de données Excel */} {data.excelRows.map((row, rIdx) => (
{rIdx + 2}
{row[0]}
{row[1]}
{row[2]}
{row[3]}
))} {/* Ligne de total / formule */}
7
{data.excelTotalLabel}
{data.excelTotalVal}
{/* Onglets de classeur Excel en bas */}
Feuil1_Recette
Feuil2_Calculs
Formules & Cellules 100% intactes
); } /** * Rendu intérieur d'une diapositive PowerPoint (.pptx) */ function PptxDocumentSheet({ data }: { data: RecipeData }) { return (
{/* Diapositive 16:9 avec cartouche PowerPoint */}
Diapositive 1 / 1 {data.pptSlideTitle}
Thème Officiel 16:9
{/* Cartes de contenu de présentation */}
{data.pptCard1Title}

{data.pptCard1Text}

{data.pptCard2Title}

{data.pptCard2Text}

Blocs textes & vecteurs PowerPoint préservés Affichage Normal • 100%
); } /** * Rendu intérieur d'un document PDF vectoriel officiel */ function PdfDocumentSheet({ data }: { data: RecipeData }) { return (
{/* Barre d'outils Acrobat */}
PDF/A-1b Page 1 / 1
100% Vectoriel
{/* Page PDF avec repères de coupe */}

{data.docTitle}

DOCUMENT CERTIFIÉ

{data.docSubtitle} — {data.timeLabel} • {data.servingsLabel} • {data.heatLabel}.

{data.ingredientsHeading} {data.ingredients.slice(0, 3).map((ing, i) => (
{ing.name} {ing.amount}
))}
{data.stepsHeading} {data.steps.slice(0, 2).map((st, i) => (
{st.num}. {st.desc}
))}
Adobe PostScript • Calque vectoriel préservé 100% Fidélité PDF
); } /** * Composant principal de démonstration */ export function HeroVisual() { const prefersReduced = useReducedMotion(); const [format, setFormat] = useState('docx'); const [langIndex, setLangIndex] = useState(0); const [prevLangIndex, setPrevLangIndex] = useState(0); const [isTranslating, setIsTranslating] = useState(false); const [scanProgress, setScanProgress] = useState(0); const cfg = FORMAT_CONFIG[format]; const currentRecipe = RECIPES[langIndex]; const prevRecipe = RECIPES[prevLangIndex]; // Déclencher une traduction manuelle ou automatique const triggerTranslation = useCallback((targetLangIndex: number) => { if (targetLangIndex === langIndex || isTranslating) return; setPrevLangIndex(langIndex); setLangIndex(targetLangIndex); setIsTranslating(true); setScanProgress(0); const startTime = performance.now(); const animateScan = (currentTime: number) => { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / SCAN_DURATION_MS, 1); setScanProgress(progress * 100); if (progress < 1) { requestAnimationFrame(animateScan); } else { setIsTranslating(false); setPrevLangIndex(targetLangIndex); } }; requestAnimationFrame(animateScan); }, [langIndex, isTranslating]); // Boucle de rotation automatique des langues (toutes les ~6.2 secondes) useEffect(() => { if (prefersReduced) return; const interval = setInterval(() => { setLangIndex((current) => { const next = (current + 1) % RECIPES.length; setPrevLangIndex(current); setIsTranslating(true); setScanProgress(0); const startTime = performance.now(); const animateScan = (currentTime: number) => { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / SCAN_DURATION_MS, 1); setScanProgress(progress * 100); if (progress < 1) { requestAnimationFrame(animateScan); } else { setIsTranslating(false); setPrevLangIndex(next); } }; requestAnimationFrame(animateScan); return next; }); }, CYCLE_DURATION_MS); return () => clearInterval(interval); }, [prefersReduced]); // Sélecteur de rendu selon le format actif const renderSheet = (data: RecipeData) => { switch (format) { case 'xlsx': return ; case 'pptx': return ; case 'pdf': return ; case 'docx': default: return ; } }; return (
{/* Halo d'ambiance doré sous la fenêtre */}
{/* Pastille Flottante 1 (Gauche) */}
SmartArt & Formules
100% Intacts et recalculés
{/* Pastille Flottante 2 (Droite) */}
Rétention Zéro
Données supprimées après export
{/* Conteneur de fenêtre logicielle Office / PDF ultra-réaliste */}
{/* ============================================================ */} {/* 1. BARRE DE TITRE OFFICIELLE DU LOGICIEL (Word/Excel/PPT/PDF) */} {/* ============================================================ */}
{/* Gauche : Icônes d'accès rapide (Enregistrer, Annuler, Rétablir) */}
{cfg.defaultFile} — {cfg.appTitle}
{/* Centre : Recherche Office */}
Rechercher ou demander de l'aide (Alt+Q)
{/* Droite : Boutons de fenêtre Windows / Mac */}
{/* ============================================================ */} {/* 2. RUBAN OFFICE / SÉLECTEUR DE FORMAT RÉEL */} {/* ============================================================ */}
{/* Onglets des 4 formats bureautiques supportés */}
{(['docx', 'xlsx', 'pptx', 'pdf'] as const).map((fmtKey) => { const item = FORMAT_CONFIG[fmtKey]; const isSelected = format === fmtKey; const Icon = item.icon; return ( ); })}
{/* Outils du ruban (Police, Gras, Italique, Alignement) */}
{format === 'docx' ? 'Calibri' : format === 'xlsx' ? 'Segoe UI' : 'Arial'}
{/* Sélecteur de langue en direct */}
Langue :
{RECIPES.map((r, rIdx) => { const isActive = rIdx === langIndex; return ( ); })}
{/* ============================================================ */} {/* 3. RÈGLE GRADUÉE WORD (Visible en mode .docx) */} {/* ============================================================ */} {format === 'docx' && (
◄ 0 2 4 6 8 10 12 14 16 cm ►
)} {/* ============================================================ */} {/* 4. PLAN DE TRAVAIL & DOCUMENT A4 FLOTTANT */} {/* ============================================================ */}
{/* Feuille de document flottante avec ombre de papier réelle */}
{/* Conteneur Superposé Grid garantissant 0px de décalage */}
{/* Couche 1 : Document de base (Langue précédente ou active) */}
{renderSheet(isTranslating ? prevRecipe : currentRecipe)}
{/* Couche 2 : Document traduit révélé par découpe (Clip-path) */} {isTranslating && !prefersReduced && (
{renderSheet(currentRecipe)}
)} {/* ============================================================ */} {/* 5. ONDE DORÉE DE NUMÉRISATION / TRADUCTION */} {/* ============================================================ */} {isTranslating && !prefersReduced && (
{/* Halo lumineux doré au-dessus */}
{/* Ligne laser dorée principale */}
{/* Badge central d'indication de traduction */}
Traduction en direct : {prevRecipe.lang} → {currentRecipe.lang}
)}
{/* ============================================================ */} {/* 6. BARRE D'ÉTAT OFFICIELLE EN BAS (Statistiques & Langue) */} {/* ============================================================ */}
{/* Statistiques documentaires officielles */}
Page 1 sur 1 | 184 mots | {currentRecipe.langName}
{/* Sceau de conformité Wordly.art */}
Mise en page 100% inviolée : 0 pixel de décalage
{/* Indicateur de Zoom */}
Mode Page 100%
); }