/**
* OSINT Tools - Shared Icon System
* Uses Lucide icons for consistent monochrome aesthetic
*
* Usage:
*
*
* // In HTML templates:
* ${icon('check')} // Basic icon
* ${icon('alert-triangle', 'warning')} // With status class
* ${statusIcon('ok')} // Semantic status icon
* ${categoryIcon('filing')} // Category icon
*/
(function() {
'use strict';
// Lucide icon SVG paths (subset of most-used icons)
// These are inlined to avoid external dependency and ensure fast loading
const ICONS = {
// Status indicators
'check': '',
'x': '',
'alert-triangle': '',
'alert-circle': '',
'info': '',
// Navigation & Actions
'arrow-right': '',
'arrow-left': '',
'external-link': '',
'link': '',
'search': '',
'filter': '',
'refresh-cw': '',
// Files & Documents
'file': '',
'file-text': '',
'folder': '',
'clipboard': '',
// Finance & Money
'dollar-sign': '',
'credit-card': '',
'trending-up': '',
'trending-down': '',
// People & Organizations
'user': '',
'users': '',
'building': '',
'landmark': '',
// Aviation & Transport
'plane': '',
'plane-landing': '',
// Weather & Environment
'sun': '',
'moon': '',
'cloud': '',
'cloud-rain': '',
'thermometer': '',
'wind': '',
'flame': '',
// Location & Maps
'map': '',
'map-pin': '',
'globe': '',
// Time & Calendar
'clock': '',
'calendar': '',
'history': '',
// Media & Audio
'music': '',
'volume-2': '',
'radio': '',
// Misc
'eye': '',
'eye-off': '',
'bell': '',
'shield': '',
'lock': '',
'database': '',
'activity': '',
'zap': '',
'hash': '',
'tag': '',
'rss': '',
'terminal': '',
'copy': '',
'share': '',
'bookmark': '',
'star': '',
'heart': '',
'message-square': '',
'settings': '',
'home': '',
'menu': '',
'more-horizontal': '',
'chevron-right': '',
'chevron-down': '',
'chevron-up': '',
'plus': '',
'minus': '',
};
// Semantic mappings for common use cases
const STATUS_ICONS = {
'ok': 'check',
'success': 'check',
'healthy': 'check',
'warning': 'alert-triangle',
'caution': 'alert-triangle',
'error': 'x',
'fail': 'x',
'critical': 'alert-circle',
'info': 'info',
};
const CATEGORY_ICONS = {
'filing': 'file-text',
'filings': 'file-text',
'contract': 'clipboard',
'contracts': 'clipboard',
'donor': 'dollar-sign',
'donors': 'dollar-sign',
'money': 'dollar-sign',
'finance': 'trending-up',
'person': 'user',
'people': 'users',
'organization': 'building',
'org': 'building',
'government': 'landmark',
'gov': 'landmark',
'flight': 'plane',
'aircraft': 'plane',
'aviation': 'plane',
'military': 'shield',
'weather': 'cloud',
'geo': 'globe',
'map': 'map',
'location': 'map-pin',
'alert': 'bell',
'security': 'shield',
'news': 'rss',
'change': 'refresh-cw',
'search': 'search',
'link': 'external-link',
'time': 'clock',
'calendar': 'calendar',
'history': 'history',
'audio': 'volume-2',
'music': 'music',
'data': 'database',
'activity': 'activity',
'trending': 'trending-up',
'tag': 'tag',
'bookmark': 'bookmark',
'star': 'star',
'home': 'home',
'settings': 'settings',
};
const SEVERITY_ICONS = {
'high': 'alert-circle',
'medium': 'alert-triangle',
'low': 'info',
};
/**
* Generate SVG icon markup
* @param {string} name - Icon name from ICONS
* @param {string} [className] - Optional CSS class
* @param {number} [size] - Icon size in pixels (default: 16)
* @returns {string} SVG markup
*/
function icon(name, className, size) {
const path = ICONS[name];
if (!path) {
console.warn(`[icons] Unknown icon: ${name}`);
return `[${name}]`;
}
size = size || 16;
const classes = ['icon', className].filter(Boolean).join(' ');
return ``;
}
/**
* Get icon for a status type
* @param {string} status - Status type (ok, warning, error, etc.)
* @param {number} [size] - Icon size
* @returns {string} SVG markup with appropriate class
*/
function statusIcon(status, size) {
const iconName = STATUS_ICONS[status.toLowerCase()] || 'info';
const className = `status-${status.toLowerCase()}`;
return icon(iconName, className, size);
}
/**
* Get icon for a category
* @param {string} category - Category name
* @param {number} [size] - Icon size
* @returns {string} SVG markup
*/
function categoryIcon(category, size) {
const iconName = CATEGORY_ICONS[category.toLowerCase()] || 'file';
return icon(iconName, 'category-icon', size);
}
/**
* Get icon for severity level
* @param {string} severity - Severity level (high, medium, low)
* @param {number} [size] - Icon size
* @returns {string} SVG markup with severity class
*/
function severityIcon(severity, size) {
const iconName = SEVERITY_ICONS[severity.toLowerCase()] || 'info';
const className = `severity-${severity.toLowerCase()}`;
return icon(iconName, className, size);
}
/**
* Create an icon with label
* @param {string} iconName - Icon name
* @param {string} label - Text label
* @param {string} [className] - Optional CSS class
* @returns {string} HTML markup
*/
function iconLabel(iconName, label, className) {
return `${icon(iconName)} ${label}`;
}
/**
* List all available icons (for debugging)
* @returns {string[]} Array of icon names
*/
function listIcons() {
return Object.keys(ICONS).sort();
}
// Export to window for use in HTML templates
window.icon = icon;
window.statusIcon = statusIcon;
window.categoryIcon = categoryIcon;
window.severityIcon = severityIcon;
window.iconLabel = iconLabel;
window.listIcons = listIcons;
// Also export the mappings for reference
window.ICON_MAPPINGS = {
status: STATUS_ICONS,
category: CATEGORY_ICONS,
severity: SEVERITY_ICONS,
};
/**
* Auto-replace elements with actual icons
* Supports: data-icon, data-status, data-category, data-severity
* Optional: data-size for custom size
*/
function initIcons() {
// Basic icons:
document.querySelectorAll('[data-icon]').forEach(el => {
const name = el.getAttribute('data-icon');
const size = el.getAttribute('data-size') || 14;
const cls = el.className || '';
el.outerHTML = icon(name, cls, parseInt(size));
});
// Status icons:
document.querySelectorAll('[data-status]').forEach(el => {
const status = el.getAttribute('data-status');
const size = el.getAttribute('data-size') || 14;
el.outerHTML = statusIcon(status, parseInt(size));
});
// Category icons:
document.querySelectorAll('[data-category]').forEach(el => {
const category = el.getAttribute('data-category');
const size = el.getAttribute('data-size') || 14;
el.outerHTML = categoryIcon(category, parseInt(size));
});
// Severity icons:
document.querySelectorAll('[data-severity]').forEach(el => {
const severity = el.getAttribute('data-severity');
const size = el.getAttribute('data-size') || 14;
el.outerHTML = severityIcon(severity, parseInt(size));
});
}
// Auto-init on DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initIcons);
} else {
initIcons();
}
window.initIcons = initIcons;
})();