Spaces:
Running
Running
| // State management | |
| const state = { | |
| activeTab: 'chat', | |
| messages: [ | |
| { | |
| role: 'assistant', | |
| content: "Salut ! 👋 Je suis Rosalinda, votre AI senior full-stack.\n\nJe peux générer des interfaces web professionnelles :\n• Pricing pages SaaS\n• Landing pages startup\n• Dashboard analytics\n• Boutiques e-commerce\n• Scripts vidéo pro\n\nCliquez sur un bouton rapide ou décrivez ce que vous voulez générer." | |
| } | |
| ], | |
| generatedCode: { html: '', css: '', js: '' }, | |
| loading: false, | |
| theme: 'brand-blue', | |
| industry: 'app-hosting', | |
| activeQuickGen: null | |
| }; | |
| // DOM elements | |
| const elements = { | |
| chatPanel: document.getElementById('chat-panel'), | |
| codePanel: document.getElementById('code-panel'), | |
| jsonPanel: document.getElementById('json-panel'), | |
| chatTab: document.getElementById('chat-tab'), | |
| codeTab: document.getElementById('code-tab'), | |
| jsonTab: document.getElementById('json-tab'), | |
| messagesContainer: document.getElementById('messages-container'), | |
| messageInput: document.getElementById('message-input'), | |
| sendButton: document.getElementById('send-button'), | |
| quickGenButtons: document.getElementById('quick-gen-buttons'), | |
| themeSelect: document.getElementById('theme-select'), | |
| industrySelect: document.getElementById('industry-select'), | |
| htmlCode: document.getElementById('html-code'), | |
| cssCode: document.getElementById('css-code'), | |
| jsCode: document.getElementById('js-code'), | |
| jsonOutput: document.getElementById('json-output'), | |
| copyButton: document.getElementById('copy-button'), | |
| downloadButton: document.getElementById('download-button'), | |
| refreshButton: document.getElementById('refresh-button'), | |
| previewIframe: document.getElementById('preview-iframe') | |
| }; | |
| // Quick generation buttons data | |
| const quickGenButtons = [ | |
| { id: 'pricing', icon: 'tag', label: 'Pricing SaaS', prompt: 'Génère une page de pricing SaaS moderne avec 3 plans (Starter, Pro, Enterprise), responsive et avec des animations' }, | |
| { id: 'landing', icon: 'rocket', label: 'Landing Pro', prompt: 'Crée une landing page startup moderne avec hero section, features, testimonials et CTA' }, | |
| { id: 'dashboard', icon: 'bar-chart-2', label: 'Dashboard Pro', prompt: 'Génère un dashboard analytics avec sidebar, graphiques, cards de métriques et table de données' }, | |
| { id: 'boutique', icon: 'shopping-cart', label: 'Boutique Pro', prompt: 'Crée une boutique e-commerce avec grille de produits, filtres et panier' }, | |
| { id: 'script', icon: 'film', label: 'Script Vidéo', prompt: 'Génère un script vidéo professionnel avec structure Hook/Body/CTA et timestamps' }, | |
| ]; | |
| // Initialize the app | |
| function init() { | |
| renderQuickGenButtons(); | |
| setupEventListeners(); | |
| renderMessages(); | |
| updatePreview(); | |
| } | |
| // Render quick generation buttons | |
| function renderQuickGenButtons() { | |
| elements.quickGenButtons.innerHTML = quickGenButtons.map(btn => ` | |
| <button | |
| data-id="${btn.id}" | |
| class="w-full text-left px-4 py-3 rounded-lg mb-2 transition-all hover:bg-indigo-500 bg-indigo-600/50 quick-gen-btn" | |
| > | |
| <i data-feather="${btn.icon}" class="mr-2"></i> | |
| ${btn.label} | |
| </button> | |
| `).join(''); | |
| feather.replace(); | |
| } | |
| // Setup event listeners | |
| function setupEventListeners() { | |
| // Tab switching | |
| elements.chatTab.addEventListener('click', () => switchTab('chat')); | |
| elements.codeTab.addEventListener('click', () => switchTab('code')); | |
| elements.jsonTab.addEventListener('click', () => switchTab('json')); | |
| // Message sending | |
| elements.sendButton.addEventListener('click', sendMessage); | |
| elements.messageInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') sendMessage(); | |
| }); | |
| // Quick generation buttons | |
| document.querySelectorAll('.quick-gen-btn').forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| const buttonId = btn.getAttribute('data-id'); | |
| const buttonData = quickGenButtons.find(b => b.id === buttonId); | |
| if (buttonData) { | |
| state.activeQuickGen = buttonId; | |
| generateCode(buttonData.prompt); | |
| setTimeout(() => { | |
| state.activeQuickGen = null; | |
| // Update button styles | |
| document.querySelectorAll('.quick-gen-btn').forEach(b => { | |
| b.classList.remove('bg-white', 'text-indigo-600', 'shadow-lg'); | |
| b.classList.add('hover:bg-indigo-500', 'bg-indigo-600/50'); | |
| }); | |
| }, 2000); | |
| // Update clicked button style | |
| btn.classList.remove('hover:bg-indigo-500', 'bg-indigo-600/50'); | |
| btn.classList.add('bg-white', 'text-indigo-600', 'shadow-lg'); | |
| } | |
| }); | |
| }); | |
| // Configuration changes | |
| elements.themeSelect.addEventListener('change', (e) => { | |
| state.theme = e.target.value; | |
| }); | |
| elements.industrySelect.addEventListener('change', (e) => { | |
| state.industry = e.target.value; | |
| }); | |
| // Code actions | |
| elements.copyButton.addEventListener('click', copyCode); | |
| elements.downloadButton.addEventListener('click', downloadCode); | |
| elements.refreshButton.addEventListener('click', updatePreview); | |
| } | |
| // Switch between tabs | |
| function switchTab(tab) { | |
| state.activeTab = tab; | |
| // Update tab styles | |
| elements.chatTab.classList.remove('border-indigo-600', 'text-indigo-600'); | |
| elements.codeTab.classList.remove('border-indigo-600', 'text-indigo-600'); | |
| elements.jsonTab.classList.remove('border-indigo-600', 'text-indigo-600'); | |
| elements.chatTab.classList.add('border-transparent', 'text-gray-600', 'hover:text-gray-900'); | |
| elements.codeTab.classList.add('border-transparent', 'text-gray-600', 'hover:text-gray-900'); | |
| elements.jsonTab.classList.add('border-transparent', 'text-gray-600', 'hover:text-gray-900'); | |
| // Show active tab | |
| if (tab === 'chat') { | |
| elements.chatTab.classList.add('border-indigo-600', 'text-indigo-600'); | |
| elements.chatTab.classList.remove('border-transparent', 'text-gray-600', 'hover:text-gray-900'); | |
| elements.chatPanel.classList.remove('hidden'); | |
| elements.codePanel.classList.add('hidden'); | |
| elements.jsonPanel.classList.add('hidden'); | |
| } else if (tab === 'code') { | |
| elements.codeTab.classList.add('border-indigo-600', 'text-indigo-600'); | |
| elements.codeTab.classList.remove('border-transparent', 'text-gray-600', 'hover:text-gray-900'); | |
| elements.chatPanel.classList.add('hidden'); | |
| elements.codePanel.classList.remove('hidden'); | |
| elements.jsonPanel.classList.add('hidden'); | |
| } else if (tab === 'json') { | |
| elements.jsonTab.classList.add('border-indigo-600', 'text-indigo-600'); | |
| elements.jsonTab.classList.remove('border-transparent', 'text-gray-600', 'hover:text-gray-900'); | |
| elements.chatPanel.classList.add('hidden'); | |
| elements.codePanel.classList.add('hidden'); | |
| elements.jsonPanel.classList.remove('hidden'); | |
| } | |
| } | |
| // Send message handler | |
| function sendMessage() { | |
| const message = elements.messageInput.value.trim(); | |
| if (message && !state.loading) { | |
| generateCode(message); | |
| elements.messageInput.value = ''; | |
| } | |
| } | |
| // Generate code based on prompt | |
| function generateCode(prompt) { | |
| state.loading = true; | |
| state.messages.push({ role: 'user', content: prompt }); | |
| renderMessages(); | |
| // Show loading indicator | |
| const loadingElement = document.createElement('div'); | |
| loadingElement.className = 'flex justify-start'; | |
| loadingElement.innerHTML = ` | |
| <div class="bg-gray-100 rounded-2xl px-4 py-3"> | |
| <div class="loading-dots"> | |
| <div class="loading-dot"></div> | |
| <div class="loading-dot"></div> | |
| <div class="loading-dot"></div> | |
| </div> | |
| </div> | |
| `; | |
| elements.messagesContainer.appendChild(loadingElement); | |
| elements.messagesContainer.scrollTop = elements.messagesContainer.scrollHeight; | |
| // Simulate API call with timeout | |
| setTimeout(() => { | |
| let html = '', css = '', js = ''; | |
| if (prompt.toLowerCase().includes('pricing')) { | |
| html = `<div class="pricing-container"> | |
| <h1>Choisissez votre plan</h1> | |
| <div class="pricing-grid"> | |
| <div class="pricing-card"> | |
| <h3>Starter</h3> | |
| <div class="price">29€<span>/mois</span></div> | |
| <ul> | |
| <li>✓ 5 projets</li> | |
| <li>✓ Génération illimitée</li> | |
| <li>✓ Support email</li> | |
| </ul> | |
| <button class="cta-btn">Commencer</button> | |
| </div> | |
| <div class="pricing-card featured"> | |
| <div class="badge">Populaire</div> | |
| <h3>Pro</h3> | |
| <div class="price">79€<span>/mois</span></div> | |
| <ul> | |
| <li>✓ Projets illimités</li> | |
| <li>✓ Génération illimitée</li> | |
| <li>✓ Support prioritaire</li> | |
| <li>✓ Export avancé</li> | |
| </ul> | |
| <button class="cta-btn">Commencer</button> | |
| </div> | |
| <div class="pricing-card"> | |
| <h3>Enterprise</h3> | |
| <div class="price">199€<span>/mois</span></div> | |
| <ul> | |
| <li>✓ Tout de Pro</li> | |
| <li>✓ API dédiée</li> | |
| <li>✓ Compte manager</li> | |
| <li>✓ SLA garanti</li> | |
| </ul> | |
| <button class="cta-btn">Nous contacter</button> | |
| </div> | |
| </div> | |
| </div>`; | |
| css = `* { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; padding: 40px 20px; } | |
| .pricing-container { max-width: 1200px; margin: 0 auto; } | |
| h1 { text-align: center; color: white; font-size: 3rem; margin-bottom: 50px; } | |
| .pricing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 30px; } | |
| .pricing-card { background: white; border-radius: 20px; padding: 40px; position: relative; transition: transform 0.3s ease; } | |
| .pricing-card:hover { transform: translateY(-10px); box-shadow: 0 20px 40px rgba(0,0,0,0.2); } | |
| .pricing-card.featured { border: 3px solid #667eea; } | |
| .badge { position: absolute; top: -15px; right: 30px; background: #667eea; color: white; padding: 5px 20px; border-radius: 20px; font-size: 0.9rem; } | |
| h3 { font-size: 1.8rem; color: #333; margin-bottom: 20px; } | |
| .price { font-size: 3rem; color: #667eea; font-weight: bold; margin-bottom: 30px; } | |
| .price span { font-size: 1.2rem; color: #999; } | |
| ul { list-style: none; margin-bottom: 30px; } | |
| li { padding: 10px 0; color: #666; font-size: 1.1rem; } | |
| .cta-btn { width: 100%; padding: 15px; background: #667eea; color: white; border: none; border-radius: 10px; font-size: 1.1rem; cursor: pointer; transition: background 0.3s; } | |
| .cta-btn:hover { background: #5568d3; } | |
| @media (max-width: 768px) { h1 { font-size: 2rem; } .pricing-grid { grid-template-columns: 1fr; } }`; | |
| js = `document.querySelectorAll('.cta-btn').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| alert('Redirection vers le paiement...'); | |
| }); | |
| });`; | |
| } else if (prompt.toLowerCase().includes('landing')) { | |
| html = `<div class="landing-page"> | |
| <nav class="navbar"> | |
| <div class="logo">🚀 Startup Pro</div> | |
| <div class="nav-links"> | |
| <a href="#features">Features</a> | |
| <a href="#pricing">Pricing</a> | |
| <button class="nav-cta">Commencer</button> | |
| </div> | |
| </nav> | |
| <section class="hero"> | |
| <h1>Créez votre succès digital</h1> | |
| <p>La plateforme tout-en-un pour lancer votre startup en quelques clics</p> | |
| <button class="hero-cta">Essayer gratuitement</button> | |
| </section> | |
| <section class="features" id="features"> | |
| <h2>Pourquoi nous choisir ?</h2> | |
| <div class="features-grid"> | |
| <div class="feature"> | |
| <div class="icon">⚡</div> | |
| <h3>Rapide</h3> | |
| <p>Lancez votre projet en moins de 24h</p> | |
| </div> | |
| <div class="feature"> | |
| <div class="icon">🎨</div> | |
| <h3>Design moderne</h3> | |
| <p>Templates professionnels prêts à l'emploi</p> | |
| </div> | |
| <div class="feature"> | |
| <div class="icon">🔒</div> | |
| <h3>Sécurisé</h3> | |
| <p>Vos données protégées 24/7</p> | |
| </div> | |
| </div> | |
| </section> | |
| </div>`; | |
| css = `* { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } | |
| .navbar { display: flex; justify-content: space-between; align-items: center; padding: 20px 50px; background: white; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } | |
| .logo { font-size: 1.5rem; font-weight: bold; } | |
| .nav-links { display: flex; gap: 30px; align-items: center; } | |
| .nav-links a { text-decoration: none; color: #333; } | |
| .nav-cta { padding: 10px 25px; background: #4F46E5; color: white; border: none; border-radius: 8px; cursor: pointer; } | |
| .hero { text-align: center; padding: 100px 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } | |
| .hero h1 { font-size: 3.5rem; margin-bottom: 20px; } | |
| .hero p { font-size: 1.3rem; margin-bottom: 40px; opacity: 0.9; } | |
| .hero-cta { padding: 15px 40px; background: white; color: #667eea; border: none; border-radius: 10px; font-size: 1.2rem; cursor: pointer; font-weight: bold; } | |
| .features { padding: 80px 50px; } | |
| .features h2 { text-align: center; font-size: 2.5rem; margin-bottom: 60px; } | |
| .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 40px; max-width: 1200px; margin: 0 auto; } | |
| .feature { text-align: center; padding: 30px; } | |
| .icon { font-size: 4rem; margin-bottom: 20px; } | |
| .feature h3 { font-size: 1.5rem; margin-bottom: 15px; color: #333; } | |
| .feature p { color: #666; line-height: 1.6; } | |
| @media (max-width: 768px) { .navbar { flex-direction: column; gap: 20px; } .hero h1 { font-size: 2rem; } }`; | |
| js = `document.querySelector('.hero-cta').addEventListener('click', () => { | |
| alert('Bienvenue ! Commençons votre aventure 🚀'); | |
| });`; | |
| } else if (prompt.toLowerCase().includes('dashboard')) { | |
| html = `<div class="dashboard"> | |
| <aside class="sidebar"> | |
| <div class="logo">📊 Dashboard</div> | |
| <nav> | |
| <a href="#" class="active">Vue d'ensemble</a> | |
| <a href="#">Analytics</a> | |
| <a href="#">Rapports</a> | |
| <a href="#">Paramètres</a> | |
| </nav> | |
| </aside> | |
| <main class="main-content"> | |
| <header> | |
| <h1>Vue d'ensemble</h1> | |
| <div class="user-menu">👤 Admin</div> | |
| </header> | |
| <div class="metrics"> | |
| <div class="metric-card"> | |
| <div class="metric-label">Revenus</div> | |
| <div class="metric-value">45,231€</div> | |
| <div class="metric-change positive">+20.1%</div> | |
| </div> | |
| <div class="metric-card"> | |
| <div class="metric-label">Utilisateurs</div> | |
| <div class="metric-value">2,350</div> | |
| <div class="metric-change positive">+15.3%</div> | |
| </div> | |
| <div class="metric-card"> | |
| <div class="metric-label">Conversions</div> | |
| <div class="metric-value">12.5%</div> | |
| <div class="metric-change negative">-3.2%</div> | |
| </div> | |
| </div> | |
| <div class="chart-container"> | |
| <h3>Statistiques mensuelles</h3> | |
| <div class="chart">📈 Graphique ici</div> | |
| </div> | |
| </main> | |
| </div>`; | |
| css = `* { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #f5f5f5; } | |
| .dashboard { display: flex; height: 100vh; } | |
| .sidebar { width: 250px; background: #1e293b; color: white; padding: 30px 20px; } | |
| .logo { font-size: 1.5rem; font-weight: bold; margin-bottom: 40px; } | |
| .sidebar nav { display: flex; flex-direction: column; gap: 10px; } | |
| .sidebar a { color: rgba(255,255,255,0.7); text-decoration: none; padding: 12px 15px; border-radius: 8px; transition: all 0.3s; } | |
| .sidebar a:hover, .sidebar a.active { background: #334155; color: white; } | |
| .main-content { flex: 1; padding: 30px; overflow-y: auto; } | |
| header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; } | |
| h1 { font-size: 2rem; color: #333; } | |
| .user-menu { padding: 10px 20px; background: white; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } | |
| .metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 30px; } | |
| .metric-card { background: white; padding: 25px; border-radius: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } | |
| .metric-label { color: #666; font-size: 0.9rem; margin-bottom: 10px; } | |
| .metric-value { font-size: 2rem; font-weight: bold; color: #333; margin-bottom: 10px; } | |
| .metric-change { font-size: 0.9rem; } | |
| .positive { color: #10b981; } | |
| .negative { color: #ef4444; } | |
| .chart-container { background: white; padding: 30px; border-radius: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } | |
| .chart { height: 300px; background: #f9fafb; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 2rem; margin-top: 20px; }`; | |
| js = `console.log('Dashboard chargé avec succès');`; | |
| } else if (prompt.toLowerCase().includes('boutique') || prompt.toLowerCase().includes('e-commerce')) { | |
| html = `<div class="shop"> | |
| <nav class="shop-nav"> | |
| <div class="logo">🛍️ Ma Boutique</div> | |
| <div class="nav-right"> | |
| <input type="search" placeholder="Rechercher..." class="search"> | |
| <div class="cart">🛒 Panier (0)</div> | |
| </div> | |
| </nav> | |
| <div class="shop-container"> | |
| <aside class="filters"> | |
| <h3>Filtres</h3> | |
| <div class="filter-group"> | |
| <h4>Catégories</h4> | |
| <label><input type="checkbox"> Électronique</label> | |
| <label><input type="checkbox"> Mode</label> | |
| <label><input type="checkbox"> Maison</label> | |
| </div> | |
| <div class="filter-group"> | |
| <h4>Prix</h4> | |
| <label><input type="checkbox"> 0€ - 50€</label> | |
| <label><input type="checkbox"> 50€ - 100€</label> | |
| <label><input type="checkbox"> 100€+</label> | |
| </div> | |
| </aside> | |
| <main class="products"> | |
| <h2>Nos produits</h2> | |
| <div class="product-grid"> | |
| <div class="product-card"> | |
| <div class="product-image">📱</div> | |
| <h3>Smartphone Pro</h3> | |
| <p class="price">599€</p> | |
| <button class="add-cart">Ajouter au panier</button> | |
| </div> | |
| <div class="product-card"> | |
| <div class="product-image">💻</div> | |
| <h3>Laptop Ultra</h3> | |
| <p class="price">1299€</p> | |
| <button class="add-cart">Ajouter au panier</button> | |
| </div> | |
| <div class="product-card"> | |
| <div class="product-image">🎧</div> | |
| <h3>Casque Premium</h3> | |
| <p class="price">249€</p> | |
| <button class="add-cart">Ajouter au panier</button> | |
| </div> | |
| <div class="product-card"> | |
| <div class="product-image">⌚</div> | |
| <h3>Smartwatch</h3> | |
| <p class="price">399€</p> | |
| <button class="add-cart">Ajouter au panier</button> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| </div>`; | |
| css = `* { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #f9fafb; } | |
| .shop-nav { display: flex; justify-content: space-between; align-items: center; padding: 20px 40px; background: white; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } | |
| .logo { font-size: 1.5rem; font-weight: bold; } | |
| .nav-right { display: flex; gap: 20px; align-items: center; } | |
| .search { padding: 10px 20px; border: 1px solid #ddd; border-radius: 8px; width: 300px; } | |
| .cart { padding: 10px 20px; background: #4F46E5; color: white; border-radius: 8px; cursor: pointer; } | |
| .shop-container { display: flex; gap: 30px; padding: 40px; max-width: 1400px; margin: 0 auto; } | |
| .filters { width: 250px; background: white; padding: 25px; border-radius: 12px; height: fit-content; } | |
| .filters h3 { margin-bottom: 20px; } | |
| .filter-group { margin-bottom: 25px; } | |
| .filter-group h4 { margin-bottom: 10px; color: #666; font-size: 0.9rem; } | |
| .filter-group label { display: block; margin-bottom: 8px; cursor: pointer; } | |
| .products { flex: 1; } | |
| .products h2 { margin-bottom: 30px; font-size: 2rem; } | |
| .product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 25px; } | |
| .product-card { background: white; border-radius: 12px; padding: 20px; text-align: center; transition: transform 0.3s; cursor: pointer; } | |
| .product-card:hover { transform: translateY(-5px); box-shadow: 0 10px 25px rgba(0,0,0,0.1); } | |
| .product-image { font-size: 5rem; margin-bottom: 15px; } | |
| .product-card h3 { font-size: 1.2rem; margin-bottom: 10px; } | |
| .price { font-size: 1.5rem; color: #4F46E5; font-weight: bold; margin-bottom: 15px; } | |
| .add-cart { width: 100%; padding: 12px; background: #4F46E5; color: white; border: none; border-radius: 8px; cursor: pointer; transition: background 0.3s; } | |
| .add-cart:hover { background: #4338ca; }`; | |
| js = `let cartCount = 0; | |
| document.querySelectorAll('.add-cart').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| cartCount++; | |
| document.querySelector('.cart').textContent = \`🛒 Panier (\${cartCount})\`; | |
| this.textContent = '✓ Ajouté'; | |
| setTimeout(() => this.textContent = 'Ajouter au panier', 1500); | |
| }); | |
| });`; | |
| } else { | |
| // Default code | |
| html = `<div class="container"> | |
| <h1>Code généré avec succès!</h1> | |
| <p>Votre demande: "${prompt}"</p> | |
| <p>Utilisez les boutons rapides pour générer des templates spécifiques.</p> | |
| </div>`; | |
| css = `body { font-family: sans-serif; background: #f5f5f5; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; } | |
| .container { background: white; padding: 40px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); text-align: center; max-width: 600px; } | |
| h1 { color: #4F46E5; margin-bottom: 20px; } | |
| p { color: #666; line-height: 1.6; }`; | |
| js = `console.log('Code généré');`; | |
| } | |
| state.generatedCode = { html, css, js }; | |
| state.messages.push({ | |
| role: 'assistant', | |
| content: `✨ Code généré avec succès ! Consultez l'onglet "Code" pour voir le résultat complet.` | |
| }); | |
| state.loading = false; | |
| // Update UI | |
| renderMessages(); | |
| updateCodeDisplay(); | |
| updatePreview(); | |
| switchTab('code'); | |
| }, 1500); | |
| } | |
| // Render messages in chat | |
| function renderMessages() { | |
| elements.messagesContainer.innerHTML = state.messages.map(msg => ` | |
| <div class="flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}"> | |
| <div class="max-w-2xl rounded-2xl px-4 py-3 ${ | |
| msg.role === 'user' | |
| ? 'bg-indigo-600 text-white' | |
| : 'bg-gray-100 text-gray-900' | |
| }"> | |
| ${msg.role === 'assistant' && msg === state.messages[0] ? ` | |
| <div class="flex items-center gap-2 mb-2"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white font-bold"> | |
| R | |
| </div> | |
| <span class="font-semibold">Rosalinda</span> | |
| </div> | |
| ` : ''} | |
| <div class="whitespace-pre-wrap">${msg.content}</div> | |
| </div> | |
| </div> | |
| `).join(''); | |
| // Scroll to bottom | |
| elements.messagesContainer.scrollTop = elements.messagesContainer.scrollHeight; | |
| } | |
| // Update code display in code panel | |
| function updateCodeDisplay() { | |
| elements.htmlCode.textContent = state.generatedCode.html || '// No HTML generated yet'; | |
| elements.cssCode.textContent = state.generatedCode.css || '// No CSS generated yet'; | |
| elements.jsCode.textContent = state.generatedCode.js || '// No JavaScript generated yet'; | |
| // Update JSON panel | |
| elements.jsonOutput.textContent = JSON.stringify({ | |
| theme: state.theme, | |
| industry: state.industry, | |
| generated: { | |
| html: state.generatedCode.html.length > 0, | |
| css: state.generatedCode.css.length > 0, | |
| js: state.generatedCode.js.length > 0 | |
| }, | |
| timestamp: new Date().toISOString() | |
| }, null, 2); | |
| } | |
| // Update preview iframe | |
| function updatePreview() { | |
| if (elements.previewIframe && state.generatedCode.html) { | |
| const doc = elements.previewIframe.contentDocument; | |
| const fullCode = ` | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <style>${state.generatedCode.css}</style> | |
| </head> | |
| <body> | |
| ${state.generatedCode.html} | |
| <script>${state.generatedCode.js}</script> | |
| </body> | |
| </html> | |
| `; | |
| doc.open(); | |
| doc.write(fullCode); | |
| doc.close(); | |
| } | |
| } | |
| // Copy code to clipboard | |
| function copyCode() { | |
| const fullCode = `<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <style>${state.generatedCode.css}</style> | |
| </head> | |
| <body> | |
| ${state.generatedCode.html} | |
| <script>${state.generatedCode.js}</script> | |
| </body> | |
| </html>`; | |
| navigator.clipboard.writeText(fullCode) | |
| .then(() => alert('Code copié dans le presse-papier !')) | |
| .catch(err => console.error('Failed to copy: ', err)); | |
| } | |
| // Download code as HTML file | |
| function downloadCode() { | |
| const fullCode = `<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <style>${state.generatedCode.css}</style> | |
| </head> | |
| <body> | |
| ${state.generatedCode.html} | |
| <script>${state.generatedCode.js}</script> | |
| </body> | |
| </html>`; | |
| const blob = new Blob([fullCode], { type: 'text/html' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'code-genere.html'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |
| // Initialize the app when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', init); |