// public/views/icon_picker.js — inline picker with Type + Brand tabs. import { el, mount, clear } from '../dom.js'; import { api } from '../api.js'; import { resolveIcon } from './icon_util.js'; // onPick(ref) called with 'set::' or 'brand:'. Returns an element. export function iconPicker(currentRef, onPick) { const box = el('div', { class: 'icon-picker' }); const tabs = el('div', { class: 'ip-tabs' }); const body = el('div', { class: 'ip-body' }); const typeTab = el('button', { class: 'ip-tab active' }, 'Type'); const brandTab = el('button', { class: 'ip-tab' }, 'Brand'); typeTab.onclick = () => { typeTab.classList.add('active'); brandTab.classList.remove('active'); showType(); }; brandTab.onclick = () => { brandTab.classList.add('active'); typeTab.classList.remove('active'); showBrand(); }; async function showType() { clear(body); body.append(el('div', { class: 'muted' }, 'Loading…')); let list = []; try { list = await api.get('/api/icon-sets'); } catch { /* ignore */ } clear(body); for (const s of list) { const grid = el('div', { class: 'ip-grid' }, s.icons.map(file => { const name = file.replace(/\.[a-z]+$/, ''); const ref = `set:${s.set}:${name}`; const b = el('button', { class: 'ip-icon', title: name }, el('img', { src: `/api/icon-sets/${s.set}/${file}` })); b.onclick = () => onPick(ref); return b; })); body.append(el('div', { class: 'ip-set' }, el('div', { class: 'ip-set-hd' }, s.set + (s.readonly ? '' : ' ·')), grid)); } } function showBrand() { clear(body); const inp = el('input', { class: 'dv-edit-name', placeholder: 'brand slug e.g. apple, google-nest' }); const prev = el('div', { class: 'ip-grid' }); inp.oninput = () => { const slug = inp.value.trim().toLowerCase().replace(/[^a-z0-9-]/g, ''); clear(prev); if (!slug) return; const b = el('button', { class: 'ip-icon' }, el('img', { src: `/api/icons/${slug}.png` })); b.onclick = () => onPick(`brand:${slug}`); prev.append(b); }; body.append(inp, prev); } mount(tabs, typeTab, brandTab); mount(box, tabs, body); showType(); return box; }