|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const chat = document.getElementById('chat'); |
|
|
const promptEl = document.getElementById('prompt'); |
|
|
const sendBtn = document.getElementById('btnSend'); |
|
|
const statusPill = document.getElementById('statusPill'); |
|
|
const codeEl = document.getElementById('code'); |
|
|
const previewFrame = document.getElementById('previewFrame'); |
|
|
const netStatus = document.getElementById('netStatus'); |
|
|
const mediaOut = document.getElementById('mediaOut'); |
|
|
|
|
|
let onlineBackend = false; |
|
|
|
|
|
function addMsg(role, title, html) { |
|
|
const wrap = document.createElement('div'); |
|
|
wrap.className = "rounded-2xl border border-white/10 bg-white/5 p-4"; |
|
|
wrap.innerHTML = ` |
|
|
<div class="text-xs text-slate-400 mb-2">${title}</div> |
|
|
<div class="text-sm text-slate-200 leading-6">${html}</div> |
|
|
`; |
|
|
chat.appendChild(wrap); |
|
|
chat.scrollTop = chat.scrollHeight; |
|
|
} |
|
|
|
|
|
function setStatus(txt, type="idle") { |
|
|
statusPill.textContent = txt; |
|
|
statusPill.className = "px-2 py-1 rounded-lg border text-xs"; |
|
|
if (type === "ok") statusPill.classList.add("bg-emerald-500/10","border-emerald-400/20","text-emerald-200"); |
|
|
else if (type === "work") statusPill.classList.add("bg-amber-500/10","border-amber-400/20","text-amber-200"); |
|
|
else if (type === "err") statusPill.classList.add("bg-rose-500/10","border-rose-400/20","text-rose-200"); |
|
|
else statusPill.classList.add("bg-white/5","border-white/10","text-slate-200"); |
|
|
} |
|
|
|
|
|
function applyPreview() { |
|
|
previewFrame.srcdoc = codeEl.value; |
|
|
} |
|
|
|
|
|
function switchTab(tab) { |
|
|
document.querySelectorAll('.tabBtn').forEach(b=>{ |
|
|
const active = b.dataset.tab === tab; |
|
|
b.className = "tabBtn px-3 py-1.5 rounded-xl border text-xs " + (active |
|
|
? "bg-indigo-500/20 border-indigo-400/20" |
|
|
: "bg-white/5 border-white/10 hover:bg-white/10"); |
|
|
}); |
|
|
document.getElementById('panel-code').classList.toggle('hidden', tab !== 'code'); |
|
|
document.getElementById('panel-preview').classList.toggle('hidden', tab !== 'preview'); |
|
|
document.getElementById('panel-media').classList.toggle('hidden', tab !== 'media'); |
|
|
} |
|
|
document.querySelectorAll('.tabBtn').forEach(b=>b.addEventListener('click', ()=>switchTab(b.dataset.tab))); |
|
|
|
|
|
document.getElementById('btnApply').addEventListener('click', ()=>{ |
|
|
applyPreview(); |
|
|
switchTab('preview'); |
|
|
}); |
|
|
|
|
|
document.getElementById('btnReloadPreview').addEventListener('click', applyPreview); |
|
|
document.getElementById('btnRefresh').addEventListener('click', applyPreview); |
|
|
|
|
|
document.getElementById('btnCopy').addEventListener('click', async ()=>{ |
|
|
try { await navigator.clipboard.writeText(codeEl.value); } |
|
|
catch {} |
|
|
}); |
|
|
|
|
|
function micStart() { |
|
|
|
|
|
const SR = window.SpeechRecognition || window.webkitSpeechRecognition; |
|
|
if (!SR) { |
|
|
addMsg("sys","Système","Micro indisponible sur ce navigateur. Utilise Chrome Desktop."); |
|
|
return; |
|
|
} |
|
|
const rec = new SR(); |
|
|
rec.lang = "fr-FR"; |
|
|
rec.interimResults = false; |
|
|
rec.maxAlternatives = 1; |
|
|
setStatus("Écoute…","work"); |
|
|
rec.onresult = (e)=>{ |
|
|
const txt = e.results[0][0].transcript; |
|
|
promptEl.value = txt; |
|
|
setStatus("Prête","ok"); |
|
|
}; |
|
|
rec.onerror = ()=>setStatus("Micro erreur","err"); |
|
|
rec.onend = ()=>setStatus("Prête","ok"); |
|
|
rec.start(); |
|
|
} |
|
|
document.getElementById('btnMic').addEventListener('click', micStart); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function agentGenerate(userPrompt) { |
|
|
setStatus("Travail…","work"); |
|
|
addMsg("user","Toi", escapeHtml(userPrompt)); |
|
|
|
|
|
|
|
|
const generated = buildLanding(userPrompt); |
|
|
addMsg("agent","Rosalinda • Plan d'action", |
|
|
` |
|
|
1) Je construis la page (structure + sections).<br> |
|
|
2) Je vérifie la responsivité (desktop/mobile).<br> |
|
|
3) J'envoie le code à droite et j'active la preview.<br> |
|
|
<span class="text-slate-400 text-xs">Mode anti-interruption: si une étape échoue, je relance automatiquement.</span> |
|
|
` |
|
|
); |
|
|
|
|
|
|
|
|
codeEl.value = generated; |
|
|
applyPreview(); |
|
|
setStatus("Terminé","ok"); |
|
|
} |
|
|
|
|
|
function escapeHtml(s) { |
|
|
return s.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">"); |
|
|
} |
|
|
|
|
|
function buildLanding(topic) { |
|
|
const safeTopic = topic && topic.trim() ? topic.trim() : "un projet"; |
|
|
return `<!doctype html> |
|
|
<html lang="fr"> |
|
|
<head> |
|
|
<meta charset="utf-8" /> |
|
|
<meta name="viewport" content="width=device-width,initial-scale=1" /> |
|
|
<title>Landing - ${safeTopic}</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
</head> |
|
|
<body class="min-h-screen bg-[#0b1622] text-slate-100"> |
|
|
<header class="border-b border-white/10 bg-[#09121b]"> |
|
|
<div class="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between"> |
|
|
<div class="flex items-center gap-3"> |
|
|
<div class="w-10 h-10 rounded-2xl bg-white/10 flex items-center justify-center">🐋</div> |
|
|
<div> |
|
|
<div class="font-semibold leading-none">DeepSite</div> |
|
|
<div class="text-xs text-slate-400">Theme rebuild • rapide • propre</div> |
|
|
</div> |
|
|
</div> |
|
|
<a class="px-4 py-2 rounded-xl bg-indigo-500/25 hover:bg-indigo-500/35 border border-indigo-400/20 text-sm" href="#start">Démarrer</a> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
<main class="max-w-6xl mx-auto px-4 py-12"> |
|
|
<div class="grid lg:grid-cols-2 gap-10 items-center"> |
|
|
<div> |
|
|
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-amber-400/20 bg-amber-500/10 text-amber-200 text-xs"> |
|
|
🔥 Nouvelle version |
|
|
</div> |
|
|
<h1 class="mt-4 text-4xl lg:text-6xl font-bold leading-tight"> |
|
|
Construis <span class="text-indigo-300">${safeTopic}</span><br class="hidden lg:block"/> |
|
|
sans lenteur, sans blocage. |
|
|
</h1> |
|
|
<p class="mt-4 text-slate-300 text-base leading-7"> |
|
|
Interface 3 colonnes: navigation à gauche, agent IA au centre, code + preview + médias à droite. |
|
|
Optimisée pour travailler vite et proprement. |
|
|
</p> |
|
|
|
|
|
<div class="mt-6 flex flex-wrap gap-3" id="start"> |
|
|
<button class="px-4 py-2 rounded-xl bg-emerald-500/15 hover:bg-emerald-500/20 border border-emerald-400/20 text-sm"> |
|
|
✅ Générer le code |
|
|
</button> |
|
|
<button class="px-4 py-2 rounded-xl bg-white/5 hover:bg-white/10 border border-white/10 text-sm"> |
|
|
🧩 Ajouter un module |
|
|
</button> |
|
|
<button class="px-4 py-2 rounded-xl bg-white/5 hover:bg-white/10 border border-white/10 text-sm"> |
|
|
🎬 Générer une vidéo (backend local) |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="rounded-3xl border border-white/10 bg-white/5 p-4"> |
|
|
<div class="rounded-2xl bg-[#07111a] border border-white/10 p-4"> |
|
|
<div class="text-xs text-slate-400">Aperçu</div> |
|
|
<div class="mt-2 h-48 rounded-2xl bg-gradient-to-br from-indigo-500/20 to-cyan-400/10 border border-white/10 flex items-center justify-center"> |
|
|
<div class="text-center"> |
|
|
<div class="text-lg font-semibold">Preview prêt ✅</div> |
|
|
<div class="text-xs text-slate-400 mt-1">Responsive • Tailwind • Clean</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="mt-4 grid grid-cols-3 gap-2 text-xs"> |
|
|
<div class="rounded-xl bg-white/5 border border-white/10 p-3">⚡ Rapide</div> |
|
|
<div class="rounded-xl bg-white/5 border border-white/10 p-3">🛡️ Stable</div> |
|
|
<div class="rounded-xl bg-white/5 border border-white/10 p-3">🧠 IA-ready</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<section class="mt-14 grid md:grid-cols-3 gap-4"> |
|
|
<div class="rounded-2xl border border-white/10 bg-white/5 p-5"> |
|
|
<div class="font-semibold">Colonne 1</div> |
|
|
<div class="text-sm text-slate-300 mt-1">Navigation, projets, bibliothèque, paramètres.</div> |
|
|
</div> |
|
|
<div class="rounded-2xl border border-white/10 bg-white/5 p-5"> |
|
|
<div class="font-semibold">Colonne 2</div> |
|
|
<div class="text-sm text-slate-300 mt-1">Agent IA explique, planifie, corrige, n'abandonne pas.</div> |
|
|
</div> |
|
|
<div class="rounded-2xl border border-white/10 bg-white/5 p-5"> |
|
|
<div class="font-semibold">Colonne 3</div> |
|
|
<div class="text-sm text-slate-300 mt-1">Code, preview, images/vidéos via moteur local.</div> |
|
|
</div> |
|
|
</section> |
|
|
</main> |
|
|
|
|
|
<footer class="border-t border-white/10 bg-[#09121b]"> |
|
|
<div class="max-w-6xl mx-auto px-4 py-6 text-xs text-slate-400"> |
|
|
© DeepSite Rebuild • thème pro • prêt pour évolution IA |
|
|
</div> |
|
|
</footer> |
|
|
</body> |
|
|
</html>`; |
|
|
} |
|
|
|
|
|
|
|
|
sendBtn.addEventListener('click', () => { |
|
|
if (promptEl.value.trim()) { |
|
|
agentGenerate(promptEl.value); |
|
|
promptEl.value = ''; |
|
|
} |
|
|
}); |
|
|
|
|
|
promptEl.addEventListener('keypress', (e) => { |
|
|
if (e.key === 'Enter' && promptEl.value.trim()) { |
|
|
agentGenerate(promptEl.value); |
|
|
promptEl.value = ''; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
setStatus("Prête", "ok"); |
|
|
switchTab('code'); |