AkurAI Build
Menu

Public repository / d2de65b4934c81cfa0049cf6b956720e001fe1ec

AkurAI-Framework / site/frontend/ai/components-manifest.js

Latest change d2de65b4934c81cfa0049cf6b956720e001fe1ec - feat(ai): add AI components gallery page (stub manifest + gallery.js + ai-gallery.html) by Ólafur Búi Ólafsson

// STUB — orchestrator overwrites with real component imports from
//        site/frontend/ai/components/<group>/<name>.js
//
// Shape: each entry is a `def` object:
//   export const def = {
//     name:     string,          // kebab-case identifier, unique
//     category: string,          // one of: Progress | Input | Display | Artifacts | Confirmation | Media
//     title:    string,          // human label shown in the gallery
//     match(payload): boolean,   // returns true if this component handles payload
//     render(payload, ctx): HTMLElement,  // returns a mounted DOM element
//     example:  object,          // preset payload; passed to render() in the gallery
//   };
//
// The three inline defs below are real enough to test the gallery build.

const progressBar = {
  name: 'progress-bar',
  category: 'Progress',
  title: 'Progress Bar',
  match(payload) {
    return payload && typeof payload.percent === 'number';
  },
  render(payload) {
    const pct = Math.min(100, Math.max(0, payload.percent ?? 0));
    const wrap = document.createElement('div');
    wrap.style.cssText = 'width:100%;';
    const label = document.createElement('div');
    label.style.cssText = 'display:flex;justify-content:space-between;font-size:13px;color:var(--muted);margin-bottom:6px;';
    label.innerHTML = `<span>${payload.label ?? 'Progress'}</span><span>${pct}%</span>`;
    const track = document.createElement('div');
    track.style.cssText = 'height:8px;border-radius:999px;background:var(--panel-2);overflow:hidden;';
    const fill = document.createElement('div');
    fill.style.cssText = `height:100%;border-radius:999px;background:linear-gradient(90deg,var(--accent),var(--accent-2));width:${pct}%;transition:width .4s ease;`;
    track.appendChild(fill);
    wrap.append(label, track);
    return wrap;
  },
  example: { label: 'Indexing documents', percent: 68 },
};

const optionList = {
  name: 'option-list',
  category: 'Input',
  title: 'Option List',
  match(payload) {
    return payload && Array.isArray(payload.options);
  },
  render(payload, ctx) {
    const wrap = document.createElement('div');
    wrap.style.cssText = 'display:grid;gap:8px;';
    (payload.options ?? []).forEach(opt => {
      const btn = document.createElement('button');
      btn.className = 'btn btn-secondary';
      btn.style.cssText = 'text-align:left;justify-content:flex-start;';
      btn.textContent = opt.label ?? opt;
      btn.addEventListener('click', () => {
        ctx?.onAction?.('select', { option: opt });
        btn.style.background = 'var(--accent)';
        btn.style.color = '#fff';
      });
      wrap.appendChild(btn);
    });
    return wrap;
  },
  example: {
    prompt: 'Which framework feature interests you most?',
    options: [
      { label: 'Native ESM — no bundler', value: 'esm' },
      { label: 'From-scratch SQL engine', value: 'sql' },
      { label: 'Built-in semantic search', value: 'search' },
    ],
  },
};

const statDisplay = {
  name: 'stats-display',
  category: 'Display',
  title: 'Stats Display',
  match(payload) {
    return payload && Array.isArray(payload.stats);
  },
  render(payload) {
    const grid = document.createElement('div');
    grid.style.cssText = 'display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:12px;';
    (payload.stats ?? []).forEach(s => {
      const cell = document.createElement('div');
      cell.className = 'stat';
      cell.innerHTML = `<div class="stat-value">${s.value}</div><div class="stat-label">${s.label}</div>`;
      grid.appendChild(cell);
    });
    return grid;
  },
  example: {
    stats: [
      { label: 'Binary size', value: '2.1 MB' },
      { label: 'Dependencies', value: '0' },
      { label: 'Startup', value: '< 1 ms' },
      { label: 'Queries / s', value: '120 k' },
    ],
  },
};

// STUB — orchestrator overwrites this array with imports of all real component modules.
export const components = [progressBar, optionList, statDisplay];