// public/js/icon-picker.js (function () { let ALL_ICONS = []; let _targetInput = null; // ── Init: inject modal + fetch icons ────────────────────────────────────── function init() { _injectModal(); _fetchIcons(); _bindSearch(); } function _injectModal() { if (document.getElementById('iconPickerModal')) return; // tránh inject 2 lần document.body.insertAdjacentHTML('beforeend', ` `); } async function _fetchIcons() { try { const res = await fetch('/js/fa-icons.json'); if (!res.ok) throw new Error('HTTP ' + res.status); const json = await res.json(); const POPULAR_ORDER = [ // Education 'fa-solid fa-graduation-cap', 'fa-solid fa-book', 'fa-solid fa-book-open', 'fa-solid fa-chalkboard-teacher', 'fa-solid fa-school', 'fa-solid fa-university', 'fa-solid fa-pencil', 'fa-solid fa-certificate', 'fa-solid fa-award', 'fa-solid fa-medal', // Finance 'fa-solid fa-piggy-bank', 'fa-solid fa-dollar-sign', 'fa-solid fa-credit-card', 'fa-solid fa-wallet', 'fa-solid fa-hand-holding-dollar', 'fa-solid fa-coins', 'fa-solid fa-chart-line', 'fa-solid fa-receipt', 'fa-solid fa-building-columns', 'fa-solid fa-landmark', // Social / Contact 'fa-solid fa-users', 'fa-solid fa-user-group', 'fa-solid fa-handshake', 'fa-solid fa-comments', 'fa-solid fa-phone', 'fa-solid fa-envelope', 'fa-solid fa-globe', 'fa-solid fa-location-dot', 'fa-solid fa-building', 'fa-solid fa-headset', // Social Media 'fa-brands fa-facebook', 'fa-brands fa-instagram', 'fa-brands fa-youtube', 'fa-brands fa-linkedin', 'fa-brands fa-twitter', 'fa-brands fa-tiktok', 'fa-brands fa-whatsapp', 'fa-brands fa-telegram', ]; ALL_ICONS = Object.entries(json).flatMap(([name, meta]) => (meta.styles || []) .filter(s => ['solid', 'regular', 'brands'].includes(s)) .map(style => ({ value: `fa-${style} fa-${name}`, label: meta.label || name, })) ); ALL_ICONS.sort((a, b) => { const ai = POPULAR_ORDER.indexOf(a.value); const bi = POPULAR_ORDER.indexOf(b.value); if (ai === -1 && bi === -1) return 0; if (ai === -1) return 1; if (bi === -1) return -1; return ai - bi; }); console.log('[IconPicker] loaded:', ALL_ICONS.length, 'icons'); } catch (err) { console.error('[IconPicker] fetch failed:', err); } } function _bindSearch() { document.addEventListener('input', function (e) { if (e.target.id !== 'iconSearchInput') return; const q = e.target.value.toLowerCase().trim(); const filtered = q ? ALL_ICONS.filter(i => i.label.toLowerCase().includes(q) || i.value.includes(q)) : ALL_ICONS; console.log('[IconPicker] search:', q, '→', filtered.length); _renderGrid(filtered); }); } // ── Public: open picker ─────────────────────────────────────────────────── function open(inputEl) { _targetInput = inputEl; document.getElementById('iconSearchInput').value = ''; if (!ALL_ICONS.length) { _setStatus('Loading icons...'); _renderGrid([]); } else { _setStatus(''); _renderGrid(ALL_ICONS); } const modal = new bootstrap.Modal(document.getElementById('iconPickerModal')); modal.show(); document.getElementById('iconPickerModal').addEventListener('shown.bs.modal', function handler() { document.getElementById('iconSearchInput').focus(); this.removeEventListener('shown.bs.modal', handler); }); } function _renderGrid(icons) { const grid = document.getElementById('iconGrid'); grid.style.visibility = 'hidden'; if (!icons.length) { grid.innerHTML = '

No icons found.

'; return; } _setStatus(`Showing ${Math.min(icons.length, 200)} / ${icons.length}`); grid.innerHTML = icons.slice(0, 200).map(icon => ` `).join(''); document.fonts.ready.then(() => { grid.style.visibility = 'visible'; }); } function iconPickerInput(cssClass, currentValue) { return ( '
' + '' + (currentValue ? '' : '') + '' + '' + '
' ); } function pick(value) { if (!_targetInput) return; _targetInput.value = value; // Update preview nếu có const previewCell = _targetInput.closest('.input-group')?.querySelector('.icon-preview-cell'); if (previewCell) previewCell.innerHTML = ``; bootstrap.Modal.getInstance(document.getElementById('iconPickerModal')).hide(); console.log('[IconPicker] picked:', value); } function _setStatus(msg) { const el = document.getElementById('iconPickerStatus'); if (el) el.textContent = msg; } function _esc(val) { return String(val || '').replace(/"/g, '"').replace(//g, '>'); } // ── Expose global ───────────────────────────────────────────────────────── window.IconPicker = { init, open, pick }; window.IconPicker = { init, open, pick, inputHtml: iconPickerInput }; window.IconPicker.pick = pick; window.IconPickerPick = pick; })();