Files
2026-10-30 22:10:03 +01:00

65 lines
3.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Espace enfant : dialogue texte uniquement. Aucun WebSocket/audio/MCP. */
(() => {
'use strict';
const $ = id => document.getElementById(id);
const session = JSON.parse($('dona-child-session').textContent);
const messages = $('child-messages');
const form = $('child-form');
const input = $('child-input');
const send = $('child-send');
let busy = false;
function bubble(text, role, loading=false) {
const article=document.createElement('article');article.className='chat-turn '+role+(loading?' loading':'');
if (role==='scratch') {
const pic=document.createElement('img');pic.src='/static/img/scratch-cat-user.png';pic.alt='Le chat Scratch';pic.className='chat-avatar scratch-avatar';article.append(pic);
} else {
const avatar=document.createElement('div');avatar.className='user-avatar';avatar.textContent='🙂';avatar.setAttribute('aria-hidden','true');article.append(avatar);
}
const copy=document.createElement('div');copy.className='turn-copy';
const speaker=document.createElement('span');speaker.className='speaker';speaker.textContent=role==='scratch'?'Scratch':'Moi';
const textBox=document.createElement('div');textBox.className='chat-bubble';textBox.textContent=text;
copy.append(speaker,textBox);article.append(copy);messages.append(article);
messages.scrollTop=messages.scrollHeight;
return article;
}
async function post(url,data) {
const r=await fetch(url,{method:'POST',credentials:'same-origin',headers:{
'Content-Type':'application/json','X-Dona-Enfant':'1'
},body:JSON.stringify(data)});
let payload={};try{payload=await r.json();}catch(_){}
if(!r.ok)throw new Error(payload.error||'Connexion impossible');
return payload;
}
form.addEventListener('submit',async event=>{
event.preventDefault();
if(busy)return;
const text=input.value.trim();if(!text)return;
busy=true;send.disabled=true;input.disabled=true;
input.value='';bubble(text,'you');
const pending=bubble('Scratch réfléchit…','scratch',true);
try {
const result=await post('/api/enfant/message',{session,message:text});
pending.querySelector('.chat-bubble').textContent=result.reply||'Je n’ai pas compris, on réessaie ?';
pending.classList.remove('loading');
} catch(err) {
pending.querySelector('.chat-bubble').textContent=err.message;
pending.classList.remove('loading');
} finally {
busy=false;send.disabled=false;input.disabled=false;input.focus();
messages.scrollTop=messages.scrollHeight;
}
});
input.addEventListener('keydown',event=>{
if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();form.requestSubmit();}
});
$('child-clear').addEventListener('click',async()=>{
if(busy)return;
try {
await post('/api/enfant/clear',{session});
messages.replaceChildren();
bubble('Coucou ! 😺 On commence une nouvelle histoire ?','scratch');
} catch(err){bubble(err.message,'scratch');}
input.focus();
});
})();