AkurAI Build
Menu

Public repository / master

AkurAI-Framework / site/content/docs/ai-content.md

Latest change 67a966d4abf972b300e8c6c214a30a0279103337 - feat(ai): Artifacts content components + geo map + item carousel (AB3-C) by Ólafur Búi Ólafsson

# AI content components

Six **Artifacts / content** components from the tool-ui port — message drafts, social
post cards, an item carousel, and a geo map. Each is a **native ES module** in
`site/frontend/ai/components/content/` that exports a single `def` object following
the [component contract](#contract). No runtime imports, no build step, zero
dependencies beyond the existing design-system CSS.

---

## Contract

Every component lives at `site/frontend/ai/components/content/<name>.js` and exports:

```js
export const def = {
  name,                         // string — unique kebab-case identifier
  category: "Artifacts",        // fixed
  title,                        // human-readable label
  match(payload),               // returns true when this component owns the payload
  render(payload, ctx),         // returns a DOM node — pure, no side effects outside ctx
  example,                      // a concrete payload object for previews / docs
};
```

**`ctx`** (optional, feature-detected) — the generative-UI runtime context:
- `ctx.onAction(name, data)` — fire a named action back to the runtime.
- `ctx.sendReceipt(obj)` — send a structured receipt back to the assistant as tool output.

All components XSS-safe: user-supplied strings go through `esc()` before touching
`innerHTML`. All components degrade gracefully when `ctx` is absent.

---

## message_draft

An editable draft email card with **Edit** and **Send/Approve** actions.

### Payload

| Field | Type | Required | Description |
|---|---|---|---|
| `body` | string | yes | Message body text. |
| `to` | string | no | Recipient address. |
| `subject` | string | no | Email subject line. |

### Actions (ctx)

| Action | Fired when |
|---|---|
| `draft:edit` | Edit/Done button toggled. Data: `{ editing: boolean }`. |
| `draft:send` | Send button clicked. Data: `{ to, subject, body }`. |

`sendReceipt` is called on Send with `{ type: "message_draft", action: "send", to, subject, body }`.

### Example

```js
import { def } from "/ai/components/content/message_draft.js";
const node = def.render(def.example, ctx);
document.body.appendChild(node);
```

```json
{
  "to": "team@example.com",
  "subject": "Sprint recap",
  "body": "Hi team,\n\nHere's a quick recap of this week's sprint.\n\nBest,\nOli"
}
```

---

## x_post

An **X / Twitter-style post card** — avatar, handle, text, and engagement stats.

### Payload

| Field | Type | Required | Description |
|---|---|---|---|
| `handle` | string | yes | @handle (without `@`). |
| `name` | string | no | Display name (defaults to `handle`). |
| `text` | string | yes | Post body. |
| `avatar` | string | no | Avatar image URL. |
| `stats` | object | no | `{ likes?, reposts?, replies? }` — all numbers. |

### Example

```json
{
  "handle": "olibuijr",
  "name": "Ólafur Búi",
  "text": "Just shipped the AI component library — native ESM, zero deps. 🚀",
  "stats": { "likes": 142, "reposts": 38, "replies": 17 }
}
```

---

## linkedin_post

A **LinkedIn-style post card** — name, optional headline, post text, and reaction/comment counts.

### Payload

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Author display name. |
| `headline` | string | no | Professional headline (role/company). |
| `text` | string | yes | Post body. |
| `stats` | object | no | `{ likes?, comments? }` — all numbers. |

### Example

```json
{
  "name": "Ólafur Búi Ólafsson",
  "headline": "Founder at AkurAI · AI solutions for Icelandic businesses",
  "text": "Excited to announce: AkurAI Framework ships a native-ESM AI component library. No React, no bundler.\n\n#AI #OpenSource",
  "stats": { "likes": 310, "comments": 42 }
}
```

---

## instagram_post

An **Instagram-style media post card** — avatar, image (or SVG placeholder), caption,
and like count.

### Payload

| Field | Type | Required | Description |
|---|---|---|---|
| `user` | string | yes | Username / @handle. |
| `image` | string | no | Image URL. Omit or leave blank for an SVG placeholder — honest, no fake images. |
| `caption` | string | no | Post caption text. |
| `likes` | number | no | Like count. |

### Example

```json
{
  "user": "akurai.is",
  "image": "",
  "caption": "Building AI tools for Icelandic businesses. 🇮🇸",
  "likes": 874
}
```

---

## item_carousel

A **horizontal scroll-snap carousel** with prev/next buttons. Items can be linked or
plain cards. Images are optional (SVG placeholder if absent).

### Payload

| Field | Type | Required | Description |
|---|---|---|---|
| `items` | array | yes | Non-empty list of item objects (see below). |

**Item shape:**

| Field | Type | Required |
|---|---|---|
| `title` | string | yes |
| `image` | string | no — URL |
| `subtitle` | string | no |
| `href` | string | no — must start with `https://` or `/` |

URLs that do not start with `https://` or `/` are silently dropped to prevent injection.

### Example

```json
{
  "items": [
    { "title": "AkurAI Framework", "subtitle": "Native ESM, zero deps", "href": "https://github.com/olibuijr/AkurAI-Framework" },
    { "title": "Streaming Chat", "subtitle": "SSE-based token streaming" },
    { "title": "Tool UI", "subtitle": "30+ generative components" }
  ]
}
```

---

## geo_map

A **lightweight map** with no external library. Always renders a labelled coordinate
panel and an SVG pin canvas. An optional `tileUrl` adds a static tile image grid from
any OSM XYZ-scheme tile server (no key auto-fetching — you supply the URL template).

### Payload

| Field | Type | Required | Description |
|---|---|---|---|
| `lat` | number | yes | Latitude (decimal degrees). |
| `lng` | number | yes | Longitude (decimal degrees). |
| `zoom` | number | no | Zoom level (default 13). Used for tile grid and pin positioning. |
| `markers` | array | no | Additional pins: `[{ lat, lng, label? }]`. |
| `tileUrl` | string | no | Tile URL template, e.g. `"https://yourserver/{z}/{x}/{y}.png"`. Major tile providers (OSM, MapTiler, MapBox) require API keys — this field exists for self-hosted or pre-approved endpoints. Omit to show the honest SVG placeholder. |

### Pin behaviour

The centre coordinate is always pinned. Any `markers` entries get secondary pins.
Pin positions use Web Mercator projection, so they are proportionally accurate on
the SVG canvas and on a real tile overlay.

### Example

```json
{
  "lat": 65.6835,
  "lng": -18.1002,
  "zoom": 13,
  "markers": [{ "lat": 65.684, "lng": -18.098, "label": "AkurAI HQ" }]
}
```

---

## CSS

All component styles live under the `tc-content-*` prefix in `site/frontend/styles.css`
(appended at the end). Components reference only the design-system tokens declared on
`:root` — no hard-coded colours or radii. No other CSS files are touched.