/** * 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 `${path}`; } /** * 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; })();