/**
* src/static/js/icons.js — v1.5.0 Phase 1
*
* Local inline Lucide SVG icons (ISC license, https://lucide.dev/license).
* 49 icons covering the v1.5.0 IA redesign + v1.4.6.11 emoji → SVG migration.
*
* Usage:
* import { icon } from './icons.js';
* container.innerHTML = `${icon('home', {size: 20})} Home`;
* button.innerHTML = icon('save', {size: 16, aria: 'Save'}); // role=img +
Save
*
* All icons share Lucide canonical wrapper:
*
*
* Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather
* (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022.
* Permission to use, copy, modify, and/or distribute this software for any purpose with or
* without fee is hereby granted, provided that the above copyright notice and this permission
* notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. ISC License — https://lucide.dev/license
*/
/* eslint-disable */
const escapeAttr = (s) => String(s)
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(//g, '>');
const ICONS = {
// Navigation / Layout
'home': '',
'menu': '',
'chevron-down': '',
'chevron-right': '',
'x': '',
// Network / Communication
'wifi': '',
'ethernet-port': '',
'globe': '',
'radio-tower': '',
'radio': '',
'flag': '',
'server': '',
'link': '',
'cable': '',
'route': '',
'smartphone': '',
'plug-zap': '',
// Data
'bar-chart-3': '',
'clipboard-list': '',
'list': '',
'share-2': '',
'file-text': '',
'folder': '',
'package': '',
'box': '',
'puzzle': '',
// Actions
'save': '',
'download': '',
'upload': '',
'trash-2': '',
'refresh-cw': '',
'radar': '',
// Status
'check-circle-2': '',
'x-circle': '',
'alert-triangle': '',
'activity': '',
'hourglass': '',
// Tool/Config
'wrench': '',
'settings': '',
'sliders-horizontal': '',
'gauge': '',
'factory': '',
'building-2': '',
// Security / Vision
'eye': '',
'eye-off': '',
'lock': '',
// Theme
'moon': '',
'sun': '',
// System
'terminal-square': '',
'cpu': '',
'monitor': '',
'book-open': '',
};
/**
* Render an inline SVG icon.
*
* @param {string} name ICONS key
* @param {Object} [opts]
* @param {number} [opts.size=16]
* @param {string} [opts.class=""]
* @param {string} [opts.aria] if set → role="img" + ; else aria-hidden="true"
* @returns {string} SVG HTML string, or '' if name unknown
*/
export function icon(name, opts = {}) {
const body = ICONS[name];
if (!body) {
if (typeof console !== 'undefined') console.warn('[icon] unknown:', name);
return '';
}
const size = Number(opts.size) || 16;
// XSS-safe: strip dangerous chars from class option
const cls = (typeof opts.class === 'string' ? opts.class : '').replace(/[<>"']/g, '');
let ariaAttrs, titleElement;
if (opts.aria) {
ariaAttrs = `role=\"img\"`;
titleElement = `${escapeAttr(opts.aria)}`;
} else {
ariaAttrs = `aria-hidden=\"true\"`;
titleElement = '';
}
return ``;
}
/** All ICONS keys (for testing/introspection). */
export const ICON_NAMES = Object.keys(ICONS);