Files
vna_system/vna_system/web_ui/static/js/modules/icons.js
2025-10-20 16:33:50 +03:00

272 lines
9.7 KiB
JavaScript

const SVG_NS = 'http://www.w3.org/2000/svg';
const ICONS = {
activity: {
viewBox: '0 0 24 24',
elements: [
{ type: 'polyline', attrs: { points: '22 12 18 12 15 21 9 3 6 12 2 12' } }
]
},
'bar-chart-3': {
viewBox: '0 0 24 24',
elements: [
{ type: 'path', attrs: { d: 'M3 3v18h18' } },
{ type: 'line', attrs: { x1: 9, y1: 9, x2: 9, y2: 21 } },
{ type: 'line', attrs: { x1: 13, y1: 6, x2: 13, y2: 21 } },
{ type: 'line', attrs: { x1: 17, y1: 12, x2: 17, y2: 21 } }
]
},
settings: {
viewBox: '0 0 24 24',
elements: [
{
type: 'path',
attrs: {
d: 'M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z'
}
},
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 3.25 } }
]
},
play: {
viewBox: '0 0 24 24',
elements: [
{ type: 'polygon', attrs: { points: '9 5 19 12 9 19 9 5' } }
]
},
square: {
viewBox: '0 0 24 24',
elements: [
{ type: 'rect', attrs: { x: 5, y: 5, width: 14, height: 14, rx: 2 } }
]
},
zap: {
viewBox: '0 0 24 24',
elements: [
{ type: 'path', attrs: { d: 'M13 2 3 14h7l-1 8 10-12h-7l1-8z' } }
]
},
check: {
viewBox: '0 0 24 24',
elements: [
{ type: 'polyline', attrs: { points: '4 12 10 18 20 6' } }
]
},
'check-circle': {
viewBox: '0 0 24 24',
elements: [
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 9 } },
{ type: 'polyline', attrs: { points: '8 12 11 15 16 9' } }
]
},
save: {
viewBox: '0 0 24 24',
elements: [
{ type: 'rect', attrs: { x: 5, y: 3, width: 14, height: 18, rx: 2 } },
{ type: 'line', attrs: { x1: 5, y1: 9, x2: 19, y2: 9 } },
{ type: 'rect', attrs: { x: 9, y: 13, width: 6, height: 4, rx: 1 } }
]
},
target: {
viewBox: '0 0 24 24',
elements: [
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 1.5 } },
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 5 } },
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 9 } }
]
},
'download-cloud': {
viewBox: '0 0 24 24',
elements: [
{ type: 'path', attrs: { d: 'M6 19h11a4 4 0 0 0 .4-8A6 6 0 0 0 6 7a5 5 0 0 0-.5 10z' } },
{ type: 'line', attrs: { x1: 12, y1: 11, x2: 12, y2: 17 } },
{ type: 'polyline', attrs: { points: '9 14 12 17 15 14' } }
]
},
x: {
viewBox: '0 0 24 24',
elements: [
{ type: 'line', attrs: { x1: 18, y1: 6, x2: 6, y2: 18 } },
{ type: 'line', attrs: { x1: 6, y1: 6, x2: 18, y2: 18 } }
]
},
'trash-2': {
viewBox: '0 0 24 24',
elements: [
{ type: 'polyline', attrs: { points: '3 6 5 6 21 6' } },
{ type: 'path', attrs: { d: 'M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6' } },
{ type: 'line', attrs: { x1: 10, y1: 11, x2: 10, y2: 17 } },
{ type: 'line', attrs: { x1: 14, y1: 11, x2: 14, y2: 17 } },
{ type: 'path', attrs: { d: 'M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2' } }
]
},
expand: {
viewBox: '0 0 24 24',
elements: [
{ type: 'polyline', attrs: { points: '15 3 21 3 21 9' } },
{ type: 'polyline', attrs: { points: '9 21 3 21 3 15' } },
{ type: 'line', attrs: { x1: 21, y1: 3, x2: 14, y2: 10 } },
{ type: 'line', attrs: { x1: 3, y1: 21, x2: 10, y2: 14 } }
]
},
download: {
viewBox: '0 0 24 24',
elements: [
{ type: 'line', attrs: { x1: 12, y1: 3, x2: 12, y2: 17 } },
{ type: 'polyline', attrs: { points: '6 13 12 19 18 13' } },
{ type: 'line', attrs: { x1: 5, y1: 21, x2: 19, y2: 21 } }
]
},
upload: {
viewBox: '0 0 24 24',
elements: [
{ type: 'line', attrs: { x1: 12, y1: 21, x2: 12, y2: 7 } },
{ type: 'polyline', attrs: { points: '6 11 12 5 18 11' } },
{ type: 'line', attrs: { x1: 5, y1: 5, x2: 19, y2: 5 } }
]
},
'alert-triangle': {
viewBox: '0 0 24 24',
elements: [
{ type: 'path', attrs: { d: 'M10.5 3.5L2.2 18a2 2 0 0 0 1.8 3h16a2 2 0 0 0 1.8-3L13.5 3.5a2 2 0 0 0-3 0z' } },
{ type: 'line', attrs: { x1: 12, y1: 9, x2: 12, y2: 13.5 } },
{ type: 'circle', attrs: { cx: 12, cy: 17, r: 0.75 } }
]
},
'eye-off': {
viewBox: '0 0 24 24',
elements: [
{ type: 'path', attrs: { d: 'M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12z' } },
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 3 } },
{ type: 'line', attrs: { x1: 4, y1: 4, x2: 20, y2: 20 } }
]
},
'alert-circle': {
viewBox: '0 0 24 24',
elements: [
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 10 } },
{ type: 'line', attrs: { x1: 12, y1: 7, x2: 12, y2: 13 } },
{ type: 'circle', attrs: { cx: 12, cy: 17, r: 1 } }
]
},
loader: {
viewBox: '0 0 24 24',
elements: [
{ type: 'path', attrs: { d: 'M21 12a9 9 0 1 1-9-9' } }
]
},
info: {
viewBox: '0 0 24 24',
elements: [
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 9 } },
{ type: 'line', attrs: { x1: 12, y1: 8, x2: 12, y2: 12 } },
{ type: 'circle', attrs: { cx: 12, cy: 16, r: 0.75 } }
]
},
clock: {
viewBox: '0 0 24 24',
elements: [
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 9 } },
{ type: 'line', attrs: { x1: 12, y1: 7, x2: 12, y2: 12 } },
{ type: 'line', attrs: { x1: 12, y1: 12, x2: 16, y2: 14 } }
]
},
radio: {
viewBox: '0 0 24 24',
elements: [
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 2 } },
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 6 } },
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 10 } }
]
},
database: {
viewBox: '0 0 24 24',
elements: [
{ type: 'ellipse', attrs: { cx: 12, cy: 5, rx: 9, ry: 3 } },
{ type: 'path', attrs: { d: 'M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5' } },
{ type: 'path', attrs: { d: 'M3 12c0 1.66 4 3 9 3s9-1.34 9-3' } }
]
},
plus: {
viewBox: '0 0 24 24',
elements: [
{ type: 'line', attrs: { x1: 12, y1: 5, x2: 12, y2: 19 } },
{ type: 'line', attrs: { x1: 5, y1: 12, x2: 19, y2: 12 } }
]
}
};
const DEFAULT_ICON = {
viewBox: '0 0 24 24',
elements: [
{ type: 'circle', attrs: { cx: 12, cy: 12, r: 9 } },
{ type: 'line', attrs: { x1: 12, y1: 8, x2: 12, y2: 12 } },
{ type: 'circle', attrs: { cx: 12, cy: 16, r: 0.5 } }
]
};
function createSvgElement(definition) {
const element = document.createElementNS(SVG_NS, definition.type);
Object.entries(definition.attrs || {}).forEach(([key, value]) => {
element.setAttribute(key, value);
});
return element;
}
function buildIcon(name, options = {}) {
const definition = ICONS[name] || DEFAULT_ICON;
const svg = document.createElementNS(SVG_NS, 'svg');
svg.setAttribute('viewBox', definition.viewBox || '0 0 24 24');
const size = options.size || 24;
svg.setAttribute('width', size);
svg.setAttribute('height', size);
svg.setAttribute('fill', 'none');
svg.setAttribute('stroke', 'currentColor');
svg.setAttribute('stroke-width', options.strokeWidth || 1.5);
svg.setAttribute('stroke-linecap', 'round');
svg.setAttribute('stroke-linejoin', 'round');
svg.setAttribute('aria-hidden', 'true');
svg.setAttribute('focusable', 'false');
(definition.elements || []).forEach(elementDef => {
svg.appendChild(createSvgElement(elementDef));
});
return svg;
}
export function renderIcons(root = document) {
if (!root) {
return;
}
const candidates = root.querySelectorAll('[data-icon]:not([data-icon-rendered]), [data-lucide]:not([data-icon-rendered])');
candidates.forEach(node => {
const iconName = node.getAttribute('data-icon') || node.getAttribute('data-lucide') || '';
const sizeAttr = node.getAttribute('data-icon-size');
const strokeAttr = node.getAttribute('data-icon-stroke');
const svg = buildIcon(iconName.trim().toLowerCase(), {
size: sizeAttr ? Number(sizeAttr) : undefined,
strokeWidth: strokeAttr ? Number(strokeAttr) : undefined
});
// Transfer non-icon attributes
node.getAttributeNames()
.filter(attr => !['data-icon', 'data-lucide', 'data-icon-size', 'data-icon-stroke', 'data-icon-rendered', 'class'].includes(attr))
.forEach(attr => {
svg.setAttribute(attr, node.getAttribute(attr));
});
svg.classList.add('icon');
node.classList.forEach(className => svg.classList.add(className));
node.replaceWith(svg);
});
}
export function getAvailableIcons() {
return Object.keys(ICONS);
}