new interface
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,116 @@
|
|||||||
|
/* DONA_INLINE_INDEX_V2 — rendu natif dans l'index, sans carte opaque. */
|
||||||
|
#donaInlineScene[hidden] { display:none !important; }
|
||||||
|
#donaInlineScene {
|
||||||
|
position:fixed;
|
||||||
|
z-index:55;
|
||||||
|
top:clamp(92px,12vh,150px);
|
||||||
|
right:clamp(18px,4vw,72px);
|
||||||
|
bottom:clamp(108px,13vh,150px);
|
||||||
|
left:clamp(43%,46vw,54%);
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns:0 minmax(0,1fr);
|
||||||
|
color:var(--dona-text, #eff3ff);
|
||||||
|
pointer-events:none;
|
||||||
|
font-family:inherit;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-right {
|
||||||
|
pointer-events:auto;
|
||||||
|
min-width:0;
|
||||||
|
max-width:min(44vw, 760px);
|
||||||
|
overflow:hidden;
|
||||||
|
display:flex;
|
||||||
|
flex-direction:column;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-left { visibility:hidden; }
|
||||||
|
#donaInlineScene .dona-inline-top {
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:space-between;
|
||||||
|
gap:16px;
|
||||||
|
padding-bottom:2px;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-eyebrow {
|
||||||
|
color:#95a9cf;
|
||||||
|
font-weight:700;
|
||||||
|
font-size:11px;
|
||||||
|
letter-spacing:.13em;
|
||||||
|
opacity:.92;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-close {
|
||||||
|
background:rgba(255,255,255,.07);
|
||||||
|
color:#e7efff;
|
||||||
|
border:1px solid rgba(175,202,241,.3);
|
||||||
|
font:inherit;
|
||||||
|
font-size:24px;
|
||||||
|
line-height:1;
|
||||||
|
border-radius:50%;
|
||||||
|
width:36px;
|
||||||
|
height:36px;
|
||||||
|
cursor:pointer;
|
||||||
|
flex-shrink:0;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-close:hover,
|
||||||
|
#donaInlineScene .dona-inline-close:focus-visible {
|
||||||
|
background:rgba(255,255,255,.14);
|
||||||
|
outline-color:#9fcafa;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-heading {
|
||||||
|
font-size:clamp(24px,2.8vw,38px);
|
||||||
|
font-weight:700;
|
||||||
|
line-height:1.22;
|
||||||
|
margin:6px 0 14px;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-heading[hidden] { display:none !important; }
|
||||||
|
#donaInlineScene .dona-inline-content {
|
||||||
|
overflow-y:auto;
|
||||||
|
overscroll-behavior:contain;
|
||||||
|
scrollbar-width:thin;
|
||||||
|
padding:0 12px 18px 0;
|
||||||
|
min-height:0;
|
||||||
|
font-size:clamp(14px,1.04vw,17px);
|
||||||
|
line-height:1.65;
|
||||||
|
white-space:normal;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-paragraph {
|
||||||
|
margin:0 0 13px;
|
||||||
|
white-space:pre-wrap;
|
||||||
|
overflow-wrap:anywhere;
|
||||||
|
color:var(--dona-text-muted, #d0daeb);
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-meta { color:#9fc9ed; margin:0 0 14px; }
|
||||||
|
#donaInlineScene .dona-inline-section { padding:0 0 12px; margin:0; }
|
||||||
|
#donaInlineScene .dona-inline-subheading {
|
||||||
|
font-size:clamp(15px,1.22vw,19px);
|
||||||
|
color:#eef5ff;
|
||||||
|
margin:14px 0 8px;
|
||||||
|
font-weight:650;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-list { margin:0 0 12px; padding-left:1.4em; color:#d0daeb; overflow-wrap:anywhere; }
|
||||||
|
#donaInlineScene .dona-inline-list li { margin:0 0 4px; }
|
||||||
|
#donaInlineScene .dona-inline-more { margin:10px 0; color:#b7d5ff; }
|
||||||
|
#donaInlineScene .dona-inline-more summary { cursor:pointer; }
|
||||||
|
#donaInlineScene code { font-size:.93em; background:rgba(255,255,255,.08); border-radius:4px; padding:1px 4px; }
|
||||||
|
.dona-inline-identity-shift {
|
||||||
|
translate:var(--dona-inline-shift-x,0px) var(--dona-inline-shift-y,0px);
|
||||||
|
scale:var(--dona-inline-scale,1);
|
||||||
|
transition:translate .55s ease, scale .55s ease;
|
||||||
|
transform-origin:center center;
|
||||||
|
will-change:translate, scale;
|
||||||
|
}
|
||||||
|
.dona-inline-suppressed-modal { display:none !important; }
|
||||||
|
body.dona-inline-active #dona-hermes-live-v1 { display:none !important; }
|
||||||
|
@media(max-width:840px) {
|
||||||
|
#donaInlineScene {
|
||||||
|
top:clamp(210px,31vh,370px);
|
||||||
|
left:18px;
|
||||||
|
right:18px;
|
||||||
|
bottom:clamp(95px,11vh,160px);
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
#donaInlineScene .dona-inline-right { max-width:none; }
|
||||||
|
#donaInlineScene .dona-inline-heading { font-size:clamp(21px,4.2vw,30px); }
|
||||||
|
#donaInlineScene .dona-inline-content { font-size:15px; padding-right:6px; }
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion:reduce) {
|
||||||
|
.dona-inline-identity-shift { transition:none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,373 @@
|
|||||||
|
/* DONA_INLINE_INDEX_V2 - Réponses dans l'index, sans modal ni carte opaque.
|
||||||
|
* V2 : orbe/vagues plus petits et à gauche, statut unifié dans la zone existante.
|
||||||
|
*/
|
||||||
|
(() => {
|
||||||
|
'use strict';
|
||||||
|
if (window.__donaInlineIndexV2) return;
|
||||||
|
window.__donaInlineIndexV2 = true;
|
||||||
|
|
||||||
|
const MAX = 24000;
|
||||||
|
const $ = id => document.getElementById(id);
|
||||||
|
const node = (tag, cls, value) => {
|
||||||
|
const n = document.createElement(tag);
|
||||||
|
if (cls) n.className = cls;
|
||||||
|
if (value !== undefined && value !== null) n.textContent = String(value);
|
||||||
|
return n;
|
||||||
|
};
|
||||||
|
const cap = (text, len = MAX) => String(text ?? '').slice(0, len);
|
||||||
|
const state = { kind: '', id: null, text: '', rich: false, recentRich: 0,
|
||||||
|
shifted: null, socket: null, active: false,
|
||||||
|
displayObserver: null, scanTimer: 0,
|
||||||
|
statusNode: null, statusOriginal: '', statusCaptured: false };
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
if ($('donaInlineScene')) return;
|
||||||
|
const scene = node('section', 'dona-inline-scene');
|
||||||
|
scene.id = 'donaInlineScene';
|
||||||
|
scene.hidden = true;
|
||||||
|
scene.setAttribute('aria-label', 'Réponse de Dona dans l’accueil');
|
||||||
|
const side = node('div', 'dona-inline-left');
|
||||||
|
side.append(node('div', 'dona-inline-left-label', 'Dona'));
|
||||||
|
const right = node('article', 'dona-inline-right');
|
||||||
|
const top = node('div', 'dona-inline-top');
|
||||||
|
const eyebrow = node('span', 'dona-inline-eyebrow', 'RÉPONSE · DONA');
|
||||||
|
const close = node('button', 'dona-inline-close', '×');
|
||||||
|
close.type = 'button';
|
||||||
|
close.title = 'Masquer la réponse';
|
||||||
|
close.setAttribute('aria-label', 'Masquer la réponse et revenir à l’accueil');
|
||||||
|
close.addEventListener('click', hide);
|
||||||
|
top.append(eyebrow, close);
|
||||||
|
const heading = node('h2', 'dona-inline-heading');
|
||||||
|
heading.id = 'donaInlineHeading';
|
||||||
|
const content = node('div', 'dona-inline-content');
|
||||||
|
content.id = 'donaInlineContent';
|
||||||
|
content.setAttribute('role', 'region');
|
||||||
|
content.setAttribute('aria-label', 'Contenu de la réponse');
|
||||||
|
right.append(top, heading, content);
|
||||||
|
scene.append(side, right);
|
||||||
|
document.body.append(scene);
|
||||||
|
window.addEventListener('resize', () => { if (state.active) positionIdentity(); }, {passive:true});
|
||||||
|
document.addEventListener('keydown', e => {
|
||||||
|
if (e.key === 'Escape' && state.active && !document.querySelector('[role="dialog"]:not([hidden])')) hide();
|
||||||
|
});
|
||||||
|
attachEvents();
|
||||||
|
observeStandaloneResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHeading(title) {
|
||||||
|
const h = $('donaInlineHeading');
|
||||||
|
if (!h) return;
|
||||||
|
const clean = cap(title || '', 140).trim();
|
||||||
|
h.textContent = clean;
|
||||||
|
h.hidden = !clean;
|
||||||
|
}
|
||||||
|
function statusCandidates() {
|
||||||
|
const selectors = [
|
||||||
|
'#donaStatusText', '#hermesStatus', '#voiceStatus', '#assistantStatus', '#statusText',
|
||||||
|
'.dona-status-text', '.assistant-status', '.status-text', '.voice-status', '.hermes-status',
|
||||||
|
'[data-dona-status]', '[data-hermes-status]', '[data-status-role="assistant"]'
|
||||||
|
];
|
||||||
|
for (const sel of selectors) {
|
||||||
|
const el = document.querySelector(sel);
|
||||||
|
if (el && !el.closest('#donaInlineScene, .dv9-overlay, .d8-overlay') && getComputedStyle(el).display !== 'none') return el;
|
||||||
|
}
|
||||||
|
const all = [...document.querySelectorAll('div,span,p,small,strong')];
|
||||||
|
return all.find(el => {
|
||||||
|
if (el.closest('#donaInlineScene, .dv9-overlay, .d8-overlay')) return false;
|
||||||
|
if (getComputedStyle(el).display === 'none') return false;
|
||||||
|
const t = (el.textContent || '').trim();
|
||||||
|
return /Hermes prépare sa réponse|Dona répond|Dona parle|Réponse reçue|Prête?/i.test(t);
|
||||||
|
}) || null;
|
||||||
|
}
|
||||||
|
function setStatus(text) {
|
||||||
|
const el = statusCandidates();
|
||||||
|
if (!el) return;
|
||||||
|
if (!state.statusCaptured || state.statusNode !== el) {
|
||||||
|
state.statusNode = el;
|
||||||
|
state.statusOriginal = el.textContent || '';
|
||||||
|
state.statusCaptured = true;
|
||||||
|
}
|
||||||
|
el.textContent = String(text || '').trim();
|
||||||
|
}
|
||||||
|
function restoreStatus() {
|
||||||
|
if (state.statusNode && state.statusCaptured) {
|
||||||
|
state.statusNode.textContent = state.statusOriginal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(kind, title) {
|
||||||
|
const scene = $('donaInlineScene');
|
||||||
|
if (!scene) return;
|
||||||
|
scene.hidden = false;
|
||||||
|
state.active = true;
|
||||||
|
state.kind = kind;
|
||||||
|
document.body.classList.add('dona-inline-active');
|
||||||
|
setHeading(title);
|
||||||
|
requestAnimationFrame(positionIdentity);
|
||||||
|
}
|
||||||
|
function clearContent() { $('donaInlineContent').replaceChildren(); }
|
||||||
|
function hide() {
|
||||||
|
state.active = false;
|
||||||
|
$('donaInlineScene').hidden = true;
|
||||||
|
document.body.classList.remove('dona-inline-active');
|
||||||
|
if (state.shifted) {
|
||||||
|
state.shifted.classList.remove('dona-inline-identity-shift');
|
||||||
|
state.shifted.style.removeProperty('--dona-inline-shift-x');
|
||||||
|
state.shifted.style.removeProperty('--dona-inline-shift-y');
|
||||||
|
state.shifted.style.removeProperty('--dona-inline-scale');
|
||||||
|
state.shifted = null;
|
||||||
|
}
|
||||||
|
restoreStatus();
|
||||||
|
for (const el of document.querySelectorAll('.dona-inline-suppressed-modal')) el.classList.remove('dona-inline-suppressed-modal');
|
||||||
|
}
|
||||||
|
|
||||||
|
function identityCandidate() {
|
||||||
|
const root = $('alfredMainV1') || document.body;
|
||||||
|
const preferred = [
|
||||||
|
'#donaWave', '#donaWaves', '#donaOrb', '#alfredOrb', '#alfredWave',
|
||||||
|
'.av-orb-wrap', '.av-orb', '.av-wave-wrap', '.av-waves',
|
||||||
|
'.dona-wave-stage', '.dona-waves', '.dona-orb', '.orb-container',
|
||||||
|
'[data-dona-visualizer]', '[data-dona-orb]', '[data-dona-waves]'
|
||||||
|
];
|
||||||
|
const candidates = preferred.flatMap(sel => [...root.querySelectorAll(sel)]);
|
||||||
|
if (!candidates.length) {
|
||||||
|
const all = [...root.querySelectorAll('[class], [id]')].slice(0, 800);
|
||||||
|
candidates.push(...all.filter(el => {
|
||||||
|
const label = String(el.className?.baseVal || el.className || '') + ' ' + (el.id || '');
|
||||||
|
return /(?:^|[\s_-])(?:dona|alfred|av)?[\s_-]?(?:orb|orbe|waves?|waveform)(?:[\s_-]|$)/i.test(label);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
for (const el of candidates) {
|
||||||
|
if (el.closest('#donaInlineScene, .dv9-overlay, .d8-overlay, #dona-hermes-live-v1')) continue;
|
||||||
|
if (el.matches('button, input, textarea, dialog')) continue;
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
if (rect.width < 50 || rect.height < 20 || rect.width > innerWidth * .98) continue;
|
||||||
|
if (getComputedStyle(el).display === 'none') continue;
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function positionIdentity() {
|
||||||
|
if (!state.active) return;
|
||||||
|
const candidate = identityCandidate();
|
||||||
|
if (!candidate) return;
|
||||||
|
if (state.shifted && state.shifted !== candidate) {
|
||||||
|
state.shifted.classList.remove('dona-inline-identity-shift');
|
||||||
|
state.shifted.style.removeProperty('--dona-inline-shift-x');
|
||||||
|
state.shifted.style.removeProperty('--dona-inline-shift-y');
|
||||||
|
state.shifted.style.removeProperty('--dona-inline-scale');
|
||||||
|
}
|
||||||
|
const label = String(candidate.className?.baseVal || candidate.className || '') + ' ' + (candidate.id || '');
|
||||||
|
const waveLike = /wave|vague/i.test(label);
|
||||||
|
const oldX = parseFloat(candidate.style.getPropertyValue('--dona-inline-shift-x')) || 0;
|
||||||
|
const oldY = parseFloat(candidate.style.getPropertyValue('--dona-inline-shift-y')) || 0;
|
||||||
|
const rect = candidate.getBoundingClientRect();
|
||||||
|
const centreX = rect.left + rect.width / 2 - oldX;
|
||||||
|
const centreY = rect.top + rect.height / 2 - oldY;
|
||||||
|
const portrait = matchMedia('(max-width: 840px)').matches;
|
||||||
|
const desiredX = portrait ? innerWidth * .50 : innerWidth * .18;
|
||||||
|
const desiredY = portrait ? innerHeight * .27 : innerHeight * .50;
|
||||||
|
const x = Math.max(-innerWidth, Math.min(innerWidth, desiredX - centreX));
|
||||||
|
const y = Math.max(-innerHeight, Math.min(innerHeight, desiredY - centreY));
|
||||||
|
const scale = portrait ? (waveLike ? .46 : .34) : (waveLike ? .54 : .32);
|
||||||
|
candidate.style.setProperty('--dona-inline-shift-x', x.toFixed(1) + 'px');
|
||||||
|
candidate.style.setProperty('--dona-inline-shift-y', y.toFixed(1) + 'px');
|
||||||
|
candidate.style.setProperty('--dona-inline-scale', String(scale));
|
||||||
|
candidate.classList.add('dona-inline-identity-shift');
|
||||||
|
state.shifted = candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
function paragraph(text, cls) {
|
||||||
|
const p = node('p', cls || 'dona-inline-paragraph');
|
||||||
|
const chunks = cap(text, 12000).split(/(\*\*[^*]+\*\*|`[^`]+`)/g);
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
if (/^\*\*[^*]+\*\*$/.test(chunk)) p.append(node('strong', '', chunk.slice(2, -2)));
|
||||||
|
else if (/^`[^`]+`$/.test(chunk)) p.append(node('code', '', chunk.slice(1, -1)));
|
||||||
|
else p.append(document.createTextNode(chunk));
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
function appendProse(text) {
|
||||||
|
const container = $('donaInlineContent');
|
||||||
|
const lines = cap(text).replace(/\r/g, '').split(/\n{2,}/);
|
||||||
|
for (const item of lines.slice(0, 90)) {
|
||||||
|
const p = item.trim();
|
||||||
|
if (!p) continue;
|
||||||
|
if (/^#{1,3}\s+/.test(p)) container.append(node('h3', 'dona-inline-subheading', p.replace(/^#{1,3}\s+/, '')));
|
||||||
|
else container.append(paragraph(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function renderText(text, heading = '') {
|
||||||
|
state.rich = false;
|
||||||
|
state.text = cap(text);
|
||||||
|
show('text', heading);
|
||||||
|
clearContent();
|
||||||
|
appendProse(state.text);
|
||||||
|
setStatus('Dona répond…');
|
||||||
|
}
|
||||||
|
function renderStream(event) {
|
||||||
|
if (!event || !event.type || featureOverlayOpen()) return;
|
||||||
|
if (event.type === 'start') {
|
||||||
|
state.id = event.id;
|
||||||
|
state.rich = false;
|
||||||
|
state.text = '';
|
||||||
|
show('stream', '');
|
||||||
|
clearContent();
|
||||||
|
setStatus('Hermes prépare sa réponse…');
|
||||||
|
} else if (state.id && event.id !== state.id) return;
|
||||||
|
else if (event.type === 'delta') {
|
||||||
|
if (state.rich) return;
|
||||||
|
state.text = cap(state.text + String(event.text || ''));
|
||||||
|
show('stream', '');
|
||||||
|
setStatus('Dona répond…');
|
||||||
|
clearContent();
|
||||||
|
appendProse(state.text);
|
||||||
|
} else if (event.type === 'tool') {
|
||||||
|
if (state.rich) return;
|
||||||
|
show('stream', '');
|
||||||
|
setStatus('Hermes prépare sa réponse…');
|
||||||
|
if (!state.text) {
|
||||||
|
clearContent();
|
||||||
|
$('donaInlineContent').append(paragraph('Consultation : ' + cap(event.name, 90)));
|
||||||
|
}
|
||||||
|
} else if (event.type === 'error') {
|
||||||
|
if (!state.rich) {
|
||||||
|
show('stream', '');
|
||||||
|
setStatus('Une erreur est survenue');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function list(title, items, ordered = false) {
|
||||||
|
if (!Array.isArray(items) || !items.length) return;
|
||||||
|
const wrap = node('section', 'dona-inline-section');
|
||||||
|
wrap.append(node('h3', 'dona-inline-subheading', title));
|
||||||
|
const ul = node(ordered ? 'ol' : 'ul', 'dona-inline-list');
|
||||||
|
items.slice(0, 50).forEach(item => ul.append(node('li', '', typeof item === 'string' ? cap(item, 500) : cap(item?.title || item?.name || item?.label || JSON.stringify(item), 500))));
|
||||||
|
wrap.append(ul);
|
||||||
|
$('donaInlineContent').append(wrap);
|
||||||
|
}
|
||||||
|
function featureOverlayOpen() {
|
||||||
|
const ids = ['donaSuiteV9', 'donaDynamicV8'];
|
||||||
|
return ids.some(id => {
|
||||||
|
const el = $(id);
|
||||||
|
return el && !el.hidden && getComputedStyle(el).display !== 'none';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function renderRecipe(recipe) {
|
||||||
|
const name = cap(recipe.title || recipe.name || 'Recette', 160);
|
||||||
|
show('suite', name);
|
||||||
|
setStatus('Dona répond…');
|
||||||
|
clearContent();
|
||||||
|
const d = recipe.duration || recipe.time || recipe.minutes || recipe.duration_min || recipe.duration_minutes;
|
||||||
|
if (d) $('donaInlineContent').append(paragraph('Durée : ' + cap(d, 50) + (typeof d === 'number' ? ' min' : ''), 'dona-inline-meta'));
|
||||||
|
list('Ingrédients', recipe.ingredients);
|
||||||
|
let steps = recipe.steps || recipe.preparation || recipe.instructions || recipe.method;
|
||||||
|
if (typeof steps === 'string') steps = steps.split(/\n+/).filter(Boolean);
|
||||||
|
list('Préparation', steps, true);
|
||||||
|
}
|
||||||
|
function renderSuite(result) {
|
||||||
|
if (!result || typeof result !== 'object' || featureOverlayOpen()) return;
|
||||||
|
state.recentRich = Date.now();
|
||||||
|
state.rich = true;
|
||||||
|
const kind = String(result.kind || '');
|
||||||
|
if (kind === 'recipe') {
|
||||||
|
const recipes = Array.isArray(result.recipes) ? result.recipes : [];
|
||||||
|
if (recipes.length) {
|
||||||
|
renderRecipe(recipes[0]);
|
||||||
|
if (recipes.length > 1) {
|
||||||
|
const summary = node('details', 'dona-inline-more');
|
||||||
|
summary.append(node('summary', '', `Voir ${recipes.length - 1} autre(s) recette(s)`));
|
||||||
|
const ul = node('ul', 'dona-inline-list');
|
||||||
|
recipes.slice(1, 12).forEach(rec => ul.append(node('li', '', cap(rec.title || rec.name || 'Recette', 140))));
|
||||||
|
summary.append(ul); $('donaInlineContent').append(summary);
|
||||||
|
}
|
||||||
|
} else renderText(result.speech || 'Aucune recette trouvée.', result.title || 'Recettes');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
show('suite', result.title || 'Réponse de Dona');
|
||||||
|
setStatus('Dona répond…');
|
||||||
|
clearContent();
|
||||||
|
if (result.speech) appendProse(result.speech);
|
||||||
|
if (kind === 'menu' && result.menu) {
|
||||||
|
const m = result.menu;
|
||||||
|
if (Array.isArray(m)) list('Menus', m);
|
||||||
|
else {
|
||||||
|
list('Menus', m.days || m.meals || m.menu || []);
|
||||||
|
list('Liste de courses', m.shopping_list || m.groceries || []);
|
||||||
|
}
|
||||||
|
} else if (kind === 'briefing' || kind === 'daily') {
|
||||||
|
list('Événements', result.briefing?.events);
|
||||||
|
if (result.briefing?.weather) appendProse(JSON.stringify(result.briefing.weather));
|
||||||
|
} else if (kind === 'documents') list('Documents', result.documents?.found);
|
||||||
|
else if (kind === 'memories') list('Souvenirs', result.memories);
|
||||||
|
else if (kind === 'monitor') list('Supervision', result.monitor?.items || result.monitor?.warnings || []);
|
||||||
|
else if (kind === 'child') list('Questions', result.quiz?.questions || result.quiz || []);
|
||||||
|
else if (kind === 'routine') list('Actions prévues', result.routine?.actions || result.routine || []);
|
||||||
|
}
|
||||||
|
function renderVisual(card) {
|
||||||
|
if (!card || card.schema !== 'dona.visual.v1' || featureOverlayOpen()) return;
|
||||||
|
if (Date.now() - state.recentRich < 1200 && card.type === 'recipe') return;
|
||||||
|
if (card.type === 'recipe') { state.rich = true; renderRecipe(card); }
|
||||||
|
else {
|
||||||
|
state.rich = true;
|
||||||
|
show('visual', card.title || 'Dona');
|
||||||
|
setStatus('Dona répond…');
|
||||||
|
clearContent();
|
||||||
|
if (card.subtitle) appendProse(card.subtitle);
|
||||||
|
list('Informations', card.details);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function renderFinal(data) {
|
||||||
|
if (!data || typeof data !== 'object' || featureOverlayOpen()) return;
|
||||||
|
if (data.type === 'dona_dynamic') return;
|
||||||
|
if (data.type === 'dona_visual_card') return renderVisual(data);
|
||||||
|
if (Date.now() - state.recentRich < 2800) return;
|
||||||
|
const body = data.content && typeof data.content === 'object' ? data.content : data;
|
||||||
|
const text = body.text || body.speech || (typeof body.content === 'string' ? body.content : '');
|
||||||
|
if (typeof text !== 'string' || !text.trim()) return;
|
||||||
|
if (state.active && state.text && text.trim() === state.text.trim()) return;
|
||||||
|
renderText(text, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function observeStandaloneResponse() {
|
||||||
|
if (state.displayObserver) return;
|
||||||
|
function inspect() {
|
||||||
|
for (const el of document.querySelectorAll('[role="dialog"], .dona-response-overlay, .dona-display-overlay, [class*="response-overlay"], [class*="dona-display"], [id*="donaDisplay"], [id*="donaResponse"]')) {
|
||||||
|
if (el.closest('#donaInlineScene') || el.classList.contains('dona-inline-suppressed-modal')) continue;
|
||||||
|
if (el.hidden || getComputedStyle(el).display === 'none') continue;
|
||||||
|
const text = (el.textContent || '').slice(0, 3000);
|
||||||
|
if (!/R[ÉE]PONSE\s*[·•-]\s*DONA/i.test(text) || !/Hermes|réponse complète/i.test(text)) continue;
|
||||||
|
if (!state.active) {
|
||||||
|
const parts = [...el.querySelectorAll('h1,h2,h3,p')].map(e => e.textContent.trim()).filter(Boolean);
|
||||||
|
renderText(parts.join('\n\n').slice(0, MAX), '');
|
||||||
|
}
|
||||||
|
el.classList.add('dona-inline-suppressed-modal');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.displayObserver = new MutationObserver(() => {
|
||||||
|
if (state.scanTimer) return;
|
||||||
|
state.scanTimer = setTimeout(() => { state.scanTimer = 0; inspect(); }, 300);
|
||||||
|
});
|
||||||
|
state.displayObserver.observe(document.body, {childList:true, subtree:true});
|
||||||
|
inspect();
|
||||||
|
}
|
||||||
|
function attachEvents() {
|
||||||
|
const start = Date.now();
|
||||||
|
function connect() {
|
||||||
|
const socket = window.alfredSocket || (typeof window.io === 'function' ? window.io({reconnection:true}) : null);
|
||||||
|
if (!socket) {
|
||||||
|
if (Date.now() - start < 15000) setTimeout(connect, 150);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.socket = socket;
|
||||||
|
socket.on('dona_suite_v9', renderSuite);
|
||||||
|
socket.on('dona_visual_card', renderVisual);
|
||||||
|
socket.on('alfred_render', renderFinal);
|
||||||
|
socket.on('dona_hermes_stream', renderStream);
|
||||||
|
}
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
window.DonaInlineIndexV2 = {hide, showText: renderText};
|
||||||
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', setup, {once:true});
|
||||||
|
else setup();
|
||||||
|
})();
|
||||||
@@ -146,7 +146,7 @@ function init(){
|
|||||||
else if(++attempts>80)clearInterval(interval);
|
else if(++attempts>80)clearInterval(interval);
|
||||||
},150);
|
},150);
|
||||||
const socket=window.alfredSocket;
|
const socket=window.alfredSocket;
|
||||||
socket?.on('dona_suite_v9',result=>render(result,lastPrompt));
|
socket?.on('dona_suite_v9',result=>{if(opened)render(result,lastPrompt);});
|
||||||
}
|
}
|
||||||
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init,{once:true});else init();
|
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init,{once:true});else init();
|
||||||
window.DonaSuiteV9={open,close,render,ask};
|
window.DonaSuiteV9={open,close,render,ask};
|
||||||
|
|||||||
@@ -59,6 +59,8 @@
|
|||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/dona-hermes-stream-v1.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/dona-hermes-stream-v1.css') }}">
|
||||||
<!-- DONA VISUAL CSS V1 -->
|
<!-- DONA VISUAL CSS V1 -->
|
||||||
<link rel="stylesheet" href="/static/css/dona-visuals-v1.css">
|
<link rel="stylesheet" href="/static/css/dona-visuals-v1.css">
|
||||||
|
<!-- DONA_INLINE_INDEX_V1 CSS -->
|
||||||
|
<link rel="stylesheet" href="/static/css/dona-inline-index-v1.css?v=2">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main class="alfred-shell">
|
<main class="alfred-shell">
|
||||||
@@ -270,5 +272,7 @@
|
|||||||
<script defer src="{{ url_for('static', filename='js/dona-hermes-stream-v1.js') }}"></script>
|
<script defer src="{{ url_for('static', filename='js/dona-hermes-stream-v1.js') }}"></script>
|
||||||
<!-- DONA VISUAL JS V1 -->
|
<!-- DONA VISUAL JS V1 -->
|
||||||
<script defer src="/static/js/dona-visuals-v1.js"></script>
|
<script defer src="/static/js/dona-visuals-v1.js"></script>
|
||||||
|
<!-- DONA_INLINE_INDEX_V1 JS -->
|
||||||
|
<script defer src="/static/js/dona-inline-index-v1.js?v=2"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user