// 临时脚本:按品牌意象关键词从图标数据文件提取候选(画个标 logo 测试用) const fs = require('fs'); const path = require('path'); const vm = require('vm'); const ROOT = process.cwd(); const OUT = '_design-test'; fs.mkdirSync(OUT, { recursive: true }); const manifest = JSON.parse(fs.readFileSync('js/data/manifest/icons.json', 'utf8')); const srcMap = {}; manifest.sources.forEach(s => { srcMap[s.id] = s; }); // 候选源:线条主库 + 实心/多色特色 const TARGETS = ['feather', 'lucide', 'tabler', 'bootstrap', 'remix', 'heroicons', 'iconoir', 'phosphor', 'fluent', 'fluent-mdl2']; // 品牌意象词表:画个标 = 画(绘) + 标(标志) const THEMES = { design: ['pen', 'pencil', 'palette', 'brush', 'paint', 'edit', 'ruler', 'compass', 'layout', 'draft', 'design', 'sketch', 'ink'], brand: ['flag', 'tag', 'badge', 'bookmark', 'award', 'crown', 'star', 'sparkle', 'label', 'logo', 'target', 'certificate'], symbol: ['hexagon', 'diamond', 'triangle', 'shield', 'anchor', 'gem', 'bolt', 'zap', 'infinity', 'sun', 'moon', 'leaf', 'flower'], tech: ['rocket', 'cpu', 'cloud', 'code', 'terminal', 'wifi', 'database', 'globe'], commerce: ['bag', 'cart', 'coin', 'wallet', 'briefcase', 'chart', 'store', 'gift'], misc: ['key', 'lock', 'mail', 'phone', 'calendar', 'clock', 'home', 'book', 'heart', 'camera', 'map', 'plane'] }; function loadSource(sid) { const file = path.join(ROOT, 'js/data/sources', sid + '.js'); if (!fs.existsSync(file)) return null; const code = fs.readFileSync(file, 'utf8'); const sb = {}; sb.window = sb; sb.self = sb; sb.globalThis = sb; vm.runInNewContext(code, sb, { filename: sid + '.js' }); const src = sb.window['HGB_Source_' + sid]; return src ? src.icons : null; } const out = []; const seen = new Set(); for (const sid of TARGETS) { const cfg = srcMap[sid]; if (!cfg) continue; const icons = loadSource(sid); if (!icons) { console.log('SKIP(无数据文件): ' + sid); continue; } for (const [theme, kws] of Object.entries(THEMES)) { for (const kw of kws) { let hits = icons.filter(ic => (ic.name || '').toLowerCase().includes(kw) && !seen.has(sid + ':' + ic.id)); hits = hits.slice(0, 1); // 每源每词取 1 个,控制候选量 for (const h of hits) { seen.add(sid + ':' + h.id); out.push({ theme, source: sid, id: h.id, name: h.name, categoryCn: h.categoryCn || '', type: h.type || cfg.type, svg: h.svg, license: cfg.license, licenseNote: cfg.licenseNote, coordText: cfg.coordText, style: cfg.style || '' }); } } } console.log(` 加载 ${sid}(${cfg.count} 图标)→ 命中 ${out.filter(o => o.source === sid).length}`); } fs.writeFileSync(path.join(OUT, 'candidates.json'), JSON.stringify(out, null, 1), 'utf8'); console.log(`\n候选池共 ${out.length} 个图标 → ${OUT}/candidates.json`); const byTheme = {}; out.forEach(o => { byTheme[o.theme] = (byTheme[o.theme] || 0) + 1; }); console.log('按主题分布:' + JSON.stringify(byTheme));