AkurAI Build
Menu

Public repository / 10d19fe0941c186ec244d1f0e2af6b19200dcb0c

AkurAI-Mail / scripts/gen-icons.ts

Latest change 10d19fe0941c186ec244d1f0e2af6b19200dcb0c - OLI-248: pure webmail logic as plain ES modules with JSDoc types; inline icon module by Ólafur Búi Ólafsson

// One-off generator: inline SVG icon data for the icons the mail UI uses, taken from lucide-svelte's shipped components.
const names = "Archive ArrowLeft Bell Bold Bot Check ChevronDown ChevronLeft ChevronRight CircleHelp Clock Clock3 Download FilePen FileText Flag FolderInput Forward Inbox Italic Keyboard Link2 List ListOrdered Mail MessageCircle MoreHorizontal Paperclip PenLine Plus Quote RefreshCcw RefreshCw Reply ReplyAll Search SearchCheck Send ServerCog Settings2 ShieldAlert SlidersHorizontal Star Trash2 TriangleAlert UserPlus WifiOff X".split(" ");
const kebab = (n: string) => n.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Za-z])([0-9])/g, "$1-$2").toLowerCase();
let out = `// icons.js — inline SVG icons for AkurAI Mail (no build step, no runtime dependency).
// Path data from Lucide (https://lucide.dev), ISC License, Copyright (c) Lucide Icons and Contributors;
// icons derived from Feather are MIT, Copyright (c) 2013-present Cole Bemis. Generated by scripts/gen-icons.ts.

const SVG_NS = "http://www.w3.org/2000/svg";

/** @type {Record<string, [string, Record<string, string>][]>} */
export const ICONS = {
`;
for (const n of names) {
  // Icons lucide has renamed since the UI was written keep their old names here.
  const RENAMED: Record<string, string> = { MoreHorizontal: "ellipsis", CircleHelp: "circle-question-mark" };
  const file = `node_modules/lucide-svelte/dist/icons/${RENAMED[n] ?? kebab(n)}.svelte`;
  const src = await Bun.file(file).text();
  const m = /const iconNode = (\[.*\]);/.exec(src);
  if (!m) throw new Error(`no iconNode in ${file}`);
  out += `  ${n}: ${m[1]},\n`;
}
out += `};

/**
 * An inline SVG element for icon \`name\` (a key of ICONS).
 * @param {string} name
 * @param {{ size?: number, strokeWidth?: number, fill?: string, class?: string, label?: string }} [options]
 * @returns {SVGSVGElement}
 */
export function icon(name, { size = 24, strokeWidth = 2, fill = "none", class: className = "", label = "" } = {}) {
  const nodes = ICONS[name];
  if (!nodes) throw new Error(\`unknown icon \${name}\`);
  const svg = document.createElementNS(SVG_NS, "svg");
  const attrs = { xmlns: SVG_NS, width: String(size), height: String(size), viewBox: "0 0 24 24", fill, stroke: "currentColor", "stroke-width": String(strokeWidth), "stroke-linecap": "round", "stroke-linejoin": "round", class: \`icon icon-\${name} \${className}\`.trim() };
  for (const [key, value] of Object.entries(attrs)) svg.setAttribute(key, value);
  if (label) svg.setAttribute("aria-label", label); else svg.setAttribute("aria-hidden", "true");
  for (const [tag, props] of nodes) {
    const child = document.createElementNS(SVG_NS, tag);
    for (const [key, value] of Object.entries(props)) child.setAttribute(key, value);
    svg.appendChild(child);
  }
  return svg;
}
`;
await Bun.write("src/framework/icons.js", out);
console.log("wrote", names.length, "icons");