// Renders the Digital Apprentice step cards into the shared stream (#log). // Consecutive steps of the same action collapse into one card. Cards render // INCREMENTALLY (append new, patch changed) so each entry animation fires once — // the staggered "steps slowly show up" reveal. A connector rail links the // check-circles down the left edge for a terminal/console feel. import { escapeHtml } from "./util.js"; const steps = []; const CARDS = { warmup: { title: "Waking the models", lead: "" }, recall: { title: "Memory", lead: "Checked your past jobs for anything similar." }, document: { title: "Document Capture", lead: "Read the handed-over document." }, perceive: { title: "Site Analysis", lead: "Reviewed the job and noted what's needed." }, price: { title: "Market Pricing", lead: "Pulled current prices for each part." }, add_priced_item: { title: "Market Pricing", lead: "Pulled current prices for each part." }, finish: { title: "Estimate Assembled", lead: "" }, assemble: { title: "Estimate Assembled", lead: "" }, }; function group(list) { const cards = []; for (const s of list) { const last = cards[cards.length - 1]; if (last && last.action === s.action) { last.details.push(s.detail); last.status = s.status; } else { cards.push({ action: s.action, status: s.status, details: [s.detail] }); } } return cards; } function cardInner(c) { const working = c.status === "active"; const marker = working ? '
' : 'check_circle'; const meta = CARDS[c.action] || { title: c.action, lead: "" }; const lead = meta.lead ? `

${meta.lead}

` : ""; const items = c.details.length > 1 || meta.lead ? `` : `

${escapeHtml(c.details[0])}

`; return `
${marker}

${meta.title}

${lead}${items}
`; } function host(el) { let h = el.querySelector(".steps"); if (!h) { const div = document.createElement("div"); div.className = "steps"; el.prepend(div); h = div; } return h; } export function resetTrace(el) { steps.length = 0; el.innerHTML = '

Waiting for a job to forge…

'; } export function addStep(el, step) { steps.push(step); const cards = group(steps); const h = host(el); const empty = h.querySelector(".step-empty"); if (empty) empty.remove(); const existing = h.querySelectorAll(":scope > .step-card"); cards.forEach((c, i) => { if (existing[i]) { const node = existing[i]; const wasWorking = node.classList.contains("working"); node.innerHTML = cardInner(c); node.classList.toggle("working", c.status === "active"); if (wasWorking && c.status !== "active") node.classList.add("just-done"); } else { const node = document.createElement("div"); node.className = "step-card enter" + (c.status === "active" ? " working" : ""); node.style.setProperty("--enter-delay", `${Math.min(i, 6) * 60}ms`); node.innerHTML = cardInner(c); h.appendChild(node); node.addEventListener("animationend", () => node.classList.remove("enter"), { once: true }); } }); el.scrollTo({ top: el.scrollHeight, behavior: "smooth" }); }