AkurAI Build
Menu

Public repository / master

AkurAI-Framework / site/frontend/ai/components/content/linkedin_post.js

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

/**
 * LinkedIn Post — Artifacts / content component.
 * Payload: { name: string, headline?: string, text: string, stats?: { likes?: number, comments?: number } }
 * Renders a LinkedIn-style post card.
 */

function esc(str) {
  return String(str ?? "")
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");
}

function fmt(n) {
  if (n == null) return "0";
  if (n >= 1_000) return (n / 1_000).toFixed(1) + "K";
  return String(n);
}

function initials(name) {
  return (name || "?")
    .split(" ")
    .slice(0, 2)
    .map((w) => w[0] || "")
    .join("")
    .toUpperCase();
}

export const def = {
  name: "linkedin_post",
  category: "Artifacts",
  title: "LinkedIn Post",

  match(payload) {
    return (
      payload !== null &&
      typeof payload === "object" &&
      typeof payload.name === "string" &&
      typeof payload.text === "string"
    );
  },

  render(payload) {
    const { name, headline = "", text, stats = {} } = payload;
    const { likes = 0, comments = 0 } = stats;

    const card = document.createElement("div");
    card.className = "tc-content-lipost";
    card.setAttribute("role", "article");
    card.setAttribute("aria-label", `LinkedIn post by ${name}`);

    card.innerHTML = `
<div class="tc-content-lipost__header">
  <div class="tc-content-lipost__avatar" aria-label="${esc(name)}">${esc(initials(name))}</div>
  <div class="tc-content-lipost__meta">
    <span class="tc-content-lipost__name">${esc(name)}</span>
    ${headline ? `<span class="tc-content-lipost__headline">${esc(headline)}</span>` : ""}
  </div>
  <svg class="tc-content-lipost__logo" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" width="20" height="20">
    <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
  </svg>
</div>
<div class="tc-content-lipost__text">${esc(text)}</div>
<div class="tc-content-lipost__stats">
  <span class="tc-content-lipost__stat">
    <svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16" aria-hidden="true"><path d="M14.5 12c0 1.38-1.12 2.5-2.5 2.5S9.5 13.38 9.5 12s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5z"/><path d="M12 3C7.45 3 3.57 5.68 2 9.5 3.57 13.32 7.45 16 12 16s8.43-2.68 10-6.5C20.43 5.68 16.55 3 12 3zm0 11a4.5 4.5 0 0 1 0-9 4.5 4.5 0 0 1 0 9z"/></svg>
    ${fmt(likes)} reactions
  </span>
  <span class="tc-content-lipost__stat">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" width="16" height="16" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
    ${fmt(comments)} comments
  </span>
</div>
`;
    return card;
  },

  example: {
    name: "Ólafur Búi Ólafsson",
    headline: "Founder at AkurAI · AI solutions for Icelandic businesses",
    text: "Excited to announce: AkurAI Framework now ships a native-ESM AI component library — no React, no bundler, zero deps. Just the browser. 🚀\n\nProduction-grade streaming chat UI, generative tool components, and approvals — all from hand-written ES modules.\n\n#AI #OpenSource #Iceland",
    stats: { likes: 310, comments: 42 },
  },
};