add go bench client
This commit is contained in:
251
frontend/js/icon-manager.js
Normal file
251
frontend/js/icon-manager.js
Normal file
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* Icon Manager - Gestion des packs d'icônes
|
||||
* Permet de basculer entre emojis, FontAwesome, et icônes personnalisées
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const ICON_PACKS = {
|
||||
'emoji': {
|
||||
name: 'Emojis Unicode',
|
||||
description: 'Emojis colorés par défaut',
|
||||
icons: {
|
||||
'add': '➕',
|
||||
'edit': '✏️',
|
||||
'delete': '🗑️',
|
||||
'save': '💾',
|
||||
'upload': '📤',
|
||||
'download': '📥',
|
||||
'image': '🖼️',
|
||||
'file': '📄',
|
||||
'pdf': '📕',
|
||||
'link': '🔗',
|
||||
'refresh': '🔄',
|
||||
'search': '🌍',
|
||||
'settings': '⚙️',
|
||||
'close': '❌',
|
||||
'check': '✅',
|
||||
'warning': '⚠️',
|
||||
'info': 'ℹ️',
|
||||
'copy': '📋'
|
||||
}
|
||||
},
|
||||
'fontawesome-solid': {
|
||||
name: 'FontAwesome Solid',
|
||||
description: 'Icônes FontAwesome pleines (bold)',
|
||||
icons: {
|
||||
'add': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/plus.svg" aria-hidden="true"></span>',
|
||||
'edit': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/pen-to-square.svg" aria-hidden="true"></span>',
|
||||
'delete': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/trash-can.svg" aria-hidden="true"></span>',
|
||||
'save': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/floppy-disk.svg" aria-hidden="true"></span>',
|
||||
'upload': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/upload.svg" aria-hidden="true"></span>',
|
||||
'download': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/download.svg" aria-hidden="true"></span>',
|
||||
'image': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/image.svg" aria-hidden="true"></span>',
|
||||
'file': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/file.svg" aria-hidden="true"></span>',
|
||||
'pdf': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/file-pdf.svg" aria-hidden="true"></span>',
|
||||
'link': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/link.svg" aria-hidden="true"></span>',
|
||||
'refresh': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/arrows-rotate.svg" aria-hidden="true"></span>',
|
||||
'search': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/earth-europe.svg" aria-hidden="true"></span>',
|
||||
'settings': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/gear.svg" aria-hidden="true"></span>',
|
||||
'close': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/xmark.svg" aria-hidden="true"></span>',
|
||||
'check': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/check.svg" aria-hidden="true"></span>',
|
||||
'warning': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/triangle-exclamation.svg" aria-hidden="true"></span>',
|
||||
'info': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/circle-info.svg" aria-hidden="true"></span>',
|
||||
'copy': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/copy.svg" aria-hidden="true"></span>'
|
||||
}
|
||||
},
|
||||
'fontawesome-regular': {
|
||||
name: 'FontAwesome Regular',
|
||||
description: 'Icônes FontAwesome fines (outline)',
|
||||
icons: {
|
||||
'add': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/square-plus.svg" aria-hidden="true"></span>',
|
||||
'edit': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/pen-to-square.svg" aria-hidden="true"></span>',
|
||||
'delete': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/trash-can.svg" aria-hidden="true"></span>',
|
||||
'save': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/floppy-disk.svg" aria-hidden="true"></span>',
|
||||
'upload': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/upload.svg" aria-hidden="true"></span>',
|
||||
'download': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/download.svg" aria-hidden="true"></span>',
|
||||
'image': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/image.svg" aria-hidden="true"></span>',
|
||||
'file': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/file.svg" aria-hidden="true"></span>',
|
||||
'pdf': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/file-pdf.svg" aria-hidden="true"></span>',
|
||||
'link': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/link.svg" aria-hidden="true"></span>',
|
||||
'refresh': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/arrows-rotate.svg" aria-hidden="true"></span>',
|
||||
'search': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/earth-europe.svg" aria-hidden="true"></span>',
|
||||
'settings': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/gear.svg" aria-hidden="true"></span>',
|
||||
'close': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/circle-xmark.svg" aria-hidden="true"></span>',
|
||||
'check': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/circle-check.svg" aria-hidden="true"></span>',
|
||||
'warning': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/triangle-exclamation.svg" aria-hidden="true"></span>',
|
||||
'info': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/solid/circle-info.svg" aria-hidden="true"></span>',
|
||||
'copy': '<span class="btn-icon svg-inline" data-svg-src="icons/svg/fa/regular/copy.svg" aria-hidden="true"></span>'
|
||||
}
|
||||
},
|
||||
'icons8': {
|
||||
name: 'Icons8 PNG',
|
||||
description: 'Icônes Icons8 existantes (PNG)',
|
||||
icons: {
|
||||
'add': '<img src="icons/icons8-done-48.png" class="btn-icon" alt="Add">',
|
||||
'edit': '<img src="icons/icons8-edit-pencil-48.png" class="btn-icon" alt="Edit">',
|
||||
'delete': '<img src="icons/icons8-delete-48.png" class="btn-icon" alt="Delete">',
|
||||
'save': '<img src="icons/icons8-save-48.png" class="btn-icon" alt="Save">',
|
||||
'upload': '📤',
|
||||
'download': '📥',
|
||||
'image': '<img src="icons/icons8-picture-48.png" class="btn-icon" alt="Image">',
|
||||
'file': '📄',
|
||||
'pdf': '📕',
|
||||
'link': '🔗',
|
||||
'refresh': '🔄',
|
||||
'search': '🌍',
|
||||
'settings': '<img src="icons/icons8-setting-48.png" class="btn-icon" alt="Settings">',
|
||||
'close': '<img src="icons/icons8-close-48.png" class="btn-icon" alt="Close">',
|
||||
'check': '<img src="icons/icons8-check-mark-48.png" class="btn-icon" alt="Check">',
|
||||
'warning': '⚠️',
|
||||
'info': 'ℹ️',
|
||||
'copy': '📋'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const DEFAULT_PACK = 'emoji';
|
||||
const STORAGE_KEY = 'benchtools_icon_pack';
|
||||
const svgCache = new Map();
|
||||
|
||||
function normalizeSvg(svgText) {
|
||||
let text = svgText;
|
||||
text = text.replace(/fill="(?!none)[^"]*"/g, 'fill="currentColor"');
|
||||
text = text.replace(/stroke="(?!none)[^"]*"/g, 'stroke="currentColor"');
|
||||
return text;
|
||||
}
|
||||
|
||||
function inlineSvgElement(el) {
|
||||
const src = el.getAttribute('data-svg-src');
|
||||
if (!src) return;
|
||||
|
||||
const cached = svgCache.get(src);
|
||||
if (cached) {
|
||||
el.innerHTML = cached;
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(src)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`SVG load failed: ${response.status}`);
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(text => {
|
||||
const normalized = normalizeSvg(text);
|
||||
svgCache.set(src, normalized);
|
||||
el.innerHTML = normalized;
|
||||
})
|
||||
.catch(error => {
|
||||
console.warn('[IconManager] Failed to inline SVG:', src, error);
|
||||
});
|
||||
}
|
||||
|
||||
function inlineSvgIcons(root = document) {
|
||||
const elements = root.querySelectorAll('[data-svg-src]');
|
||||
elements.forEach(el => inlineSvgElement(el));
|
||||
}
|
||||
|
||||
// Icon Manager Object
|
||||
const IconManager = {
|
||||
packs: ICON_PACKS,
|
||||
|
||||
getCurrentPack: function() {
|
||||
return localStorage.getItem(STORAGE_KEY) || DEFAULT_PACK;
|
||||
},
|
||||
|
||||
applyPack: function(packName) {
|
||||
if (!ICON_PACKS[packName]) {
|
||||
console.error(`Icon pack "${packName}" not found`);
|
||||
return false;
|
||||
}
|
||||
|
||||
localStorage.setItem(STORAGE_KEY, packName);
|
||||
|
||||
// Dispatch custom event for icon pack change
|
||||
window.dispatchEvent(new CustomEvent('iconPackChanged', {
|
||||
detail: {
|
||||
pack: packName,
|
||||
packName: ICON_PACKS[packName].name
|
||||
}
|
||||
}));
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
getIcon: function(iconName, fallback = '?') {
|
||||
const currentPack = this.getCurrentPack();
|
||||
const pack = ICON_PACKS[currentPack];
|
||||
|
||||
if (!pack) {
|
||||
console.warn(`Icon pack "${currentPack}" not found`);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return pack.icons[iconName] || fallback;
|
||||
},
|
||||
|
||||
getAllPacks: function() {
|
||||
return Object.keys(ICON_PACKS);
|
||||
},
|
||||
|
||||
getPackInfo: function(packName) {
|
||||
return ICON_PACKS[packName] || null;
|
||||
},
|
||||
|
||||
// Helper pour générer un bouton avec icône
|
||||
createButton: function(iconName, text = '', className = 'btn btn-primary') {
|
||||
const icon = this.getIcon(iconName);
|
||||
const textPart = text ? ` ${text}` : '';
|
||||
return `<button class="${className}">${icon}${textPart}</button>`;
|
||||
},
|
||||
|
||||
// Helper pour mettre à jour tous les boutons de la page
|
||||
updateAllButtons: function() {
|
||||
// Cette fonction sera appelée après changement de pack
|
||||
// Pour mettre à jour dynamiquement tous les boutons
|
||||
const buttons = document.querySelectorAll('[data-icon]');
|
||||
buttons.forEach(btn => {
|
||||
const iconName = btn.getAttribute('data-icon');
|
||||
const iconSpan = btn.querySelector('.btn-icon-wrapper');
|
||||
if (iconSpan && iconName) {
|
||||
iconSpan.innerHTML = this.getIcon(iconName);
|
||||
}
|
||||
});
|
||||
inlineSvgIcons();
|
||||
},
|
||||
|
||||
inlineSvgIcons: function(root = document) {
|
||||
inlineSvgIcons(root);
|
||||
}
|
||||
};
|
||||
|
||||
// Auto-initialize on load
|
||||
function initializeIcons() {
|
||||
IconManager.updateAllButtons();
|
||||
|
||||
// Also call utils.js initializeButtonIcons if available
|
||||
if (window.initializeButtonIcons) {
|
||||
window.initializeButtonIcons();
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initializeIcons);
|
||||
} else {
|
||||
initializeIcons();
|
||||
}
|
||||
|
||||
// Re-initialize when icon pack changes
|
||||
window.addEventListener('iconPackChanged', function() {
|
||||
setTimeout(initializeIcons, 100); // Small delay to ensure DOM is ready
|
||||
});
|
||||
|
||||
// Expose globally
|
||||
window.IconManager = IconManager;
|
||||
|
||||
// Log initialization
|
||||
console.log(`[IconManager] Initialized with pack: ${IconManager.getCurrentPack()}`);
|
||||
})();
|
||||
Reference in New Issue
Block a user