Menu
Public repository / 439f0dcabf5cdf2b120c7724be895cf1df30507f
AkurAI-Framework / site/frontend/ai/components/progress/plan.js
Latest change d49e9bb8beb5dc669fe029e034a13342d358a4f3 - feat(ai): tool-ui Progress + Confirmation components (AB4-B) by Ólafur Búi Ólafsson
// Plan component — tool-ui Progress category.
// Payload: { title?, steps: [{ label, status: 'pending'|'active'|'done'|'failed' }] }
const ICONS = { done: '✓', active: '▶', pending: '○', failed: '✗' };
const STATUS_CLASS = { done: 'is-done', active: 'is-current', pending: '', failed: 'tc-progress-failed' };
export const def = {
name: 'plan',
category: 'Progress',
title: 'Plan',
match(payload) {
return Array.isArray(payload?.steps);
},
render(payload) {
const root = document.createElement('div');
root.className = 'card tc-progress-plan';
if (payload.title) {
const h = document.createElement('h3');
h.textContent = payload.title;
root.appendChild(h);
}
const list = document.createElement('ul');
list.className = 'tc-progress-checklist';
list.style.cssText = 'list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:8px;';
for (const step of payload.steps) {
const status = step.status ?? 'pending';
const li = document.createElement('li');
li.style.cssText = 'display:flex;align-items:center;gap:10px;font-size:14px;';
const icon = document.createElement('span');
icon.setAttribute('aria-hidden', 'true');
icon.style.cssText = 'display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;font-size:12px;font-weight:700;flex-shrink:0;';
if (status === 'done') {
icon.style.background = 'color-mix(in srgb, var(--ok) 20%, var(--panel))';
icon.style.color = 'var(--ok)';
icon.style.border = '1.5px solid var(--ok)';
} else if (status === 'active') {
icon.style.background = 'color-mix(in srgb, var(--accent) 22%, var(--panel))';
icon.style.color = 'var(--fg)';
icon.style.border = '1.5px solid var(--accent)';
icon.style.boxShadow = '0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent)';
} else if (status === 'failed') {
icon.style.background = 'color-mix(in srgb, var(--danger) 18%, var(--panel))';
icon.style.color = 'var(--danger)';
icon.style.border = '1.5px solid var(--danger)';
} else {
icon.style.background = 'var(--panel-2)';
icon.style.color = 'var(--muted)';
icon.style.border = '1.5px solid var(--border-2)';
}
icon.textContent = ICONS[status] ?? '○';
const label = document.createElement('span');
label.textContent = step.label ?? '';
if (status === 'done') label.style.color = 'var(--muted)';
else if (status === 'active') label.style.fontWeight = '600';
else if (status === 'failed') label.style.color = 'var(--danger)';
else label.style.color = 'var(--muted)';
li.appendChild(icon);
li.appendChild(label);
const cls = STATUS_CLASS[status];
if (cls) li.className = cls;
list.appendChild(li);
}
root.appendChild(list);
return root;
},
example: {
title: 'Deploy pipeline',
steps: [
{ label: 'Build binary', status: 'done' },
{ label: 'Run tests', status: 'done' },
{ label: 'Upload artifact', status: 'active' },
{ label: 'Restart service', status: 'pending' },
{ label: 'Smoke check', status: 'pending' },
],
},
};