feat: 初始化画个标仓库 - AI驱动设计系统(BYOK模式) - 224源/371504图标+25海报源+130技能

This commit is contained in:
sgp
2026-10-03 21:44:18 +08:00
commit 9e222877ea
497 changed files with 43611 additions and 0 deletions
+457
View File
@@ -0,0 +1,457 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="logo/favicon.svg">
<title>素材库 · 画个标</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; font-size: 14px; color: #1f2937; background: #f3f4f6; min-height: 100vh; }
a { color: #4f46e5; text-decoration: none; }
a:hover { text-decoration: underline; }
.hidden { display: none !important; }
/* ===== 顶栏 ===== */
.topbar { display: flex; align-items: center; justify-content: space-between; padding: 0 20px; height: 54px; background: linear-gradient(90deg, #1e1b4b, #312e81); color: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.15); position: sticky; top: 0; z-index: 20; }
.topbar .brand { display: flex; align-items: center; gap: 10px; }
.topbar .brand .icon { font-size: 20px; }
.topbar .brand .name { font-size: 17px; font-weight: 700; letter-spacing: 1px; }
.topbar .brand .tag { font-size: 11px; color: #c7d2fe; background: rgba(255,255,255,.12); padding: 2px 8px; border-radius: 20px; }
.topbar .nav { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.topbar .nav a { color: #e0e7ff; font-size: 13px; padding: 6px 12px; border: 1px solid rgba(255,255,255,.35); border-radius: 6px; background: rgba(255,255,255,.1); transition: background .15s; }
.topbar .nav a:hover { background: rgba(255,255,255,.22); text-decoration: none; }
.topbar .nav a.active { background: #fff; color: #312e81; font-weight: 700; }
.wrap { max-width: 1180px; margin: 22px auto 60px; padding: 0 16px; }
/* ===== 统计 ===== */
.stats { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; }
.stat-card { flex: 1; min-width: 140px; background: #fff; border: 1px solid #e5e7eb; border-radius: 10px; padding: 12px 16px; box-shadow: 0 1px 3px rgba(0,0,0,.06); }
.stat-card .num { font-size: 24px; font-weight: 800; color: #4f46e5; }
.stat-card .lab { font-size: 12px; color: #6b7280; margin-top: 2px; }
/* ===== 工具栏(Tab + 搜索) ===== */
.toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.tchip { border: 1px solid #e5e7eb; background: #fff; color: #4b5563; padding: 7px 16px; border-radius: 20px; font-size: 13px; cursor: pointer; transition: all .15s; }
.tchip:hover { border-color: #c7d2fe; color: #4338ca; }
.tchip.active { background: #4f46e5; border-color: #4f46e5; color: #fff; }
.search { flex: 1; min-width: 220px; border: 1px solid #e5e7eb; border-radius: 8px; padding: 9px 12px; font-size: 13px; color: #1f2937; outline: none; }
.search:focus { border-color: #4f46e5; }
/* ===== 素材行 ===== */
.row { background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 14px 16px; margin-bottom: 12px; box-shadow: 0 1px 3px rgba(0,0,0,.06); transition: box-shadow .15s; }
.row:hover { box-shadow: 0 4px 14px rgba(79,70,229,.1); }
.row-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.row-name { font-size: 15px; font-weight: 700; }
.row-en { font-size: 11px; color: #9ca3af; }
.row-cat { font-size: 11px; padding: 2px 10px; border-radius: 20px; white-space: nowrap; }
.row-cat.icon { background: #dbeafe; color: #1d4ed8; }
.row-cat.emoji { background: #fef3c7; color: #b45309; }
.row-cat.brand { background: #e0e7ff; color: #4338ca; }
.row-cat.avatar{ background: #fce7f3; color: #be185d; }
.row-cat.palette { background: #dbeafe; color: #1d4ed8; }
.row-cat.font { background: #dcfce7; color: #15803d; }
.row-cat.bg { background: #e0e7ff; color: #4338ca; }
.row-cat.decoration { background: #fef3c7; color: #b45309; }
.row-count { font-size: 11px; color: #6b7280; margin-left: auto; }
.row-desc { font-size: 12px; color: #4b5563; line-height: 1.7; margin-top: 5px; }
.row-meta { font-size: 11px; color: #9ca3af; margin-top: 3px; }
/* ===== 缩略预览 ===== */
.thumbs { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; align-items: center; }
.thumb { width: 44px; height: 44px; border: 1px solid #e5e7eb; border-radius: 8px; background: #f9fafb; display: flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0; }
.thumb svg { width: 26px; height: 26px; }
.thumb.avatar { width: 52px; height: 52px; border-radius: 50%; padding: 4px; }
.thumb.avatar svg { width: 100%; height: 100%; }
.thumb.svg-item { width: 56px; height: 56px; }
.thumb.svg-item svg { width: 100%; height: 100%; }
.swatch { width: 24px; height: 42px; border: 1px solid rgba(0,0,0,.08); border-radius: 5px; flex-shrink: 0; }
.font-sample { font-size: 15px; padding: 4px 10px; border: 1px solid #e5e7eb; border-radius: 8px; background: #f9fafb; color: #1f2937; min-width: 130px; }
.thumb.placeholder { color: #cbd5e1; font-size: 11px; }
/* ===== 更多 ===== */
.more-wrap { margin-top: 10px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.more-btn { border: 1px solid #c7d2fe; background: #eef2ff; color: #4338ca; padding: 5px 14px; border-radius: 16px; font-size: 12px; cursor: pointer; transition: all .15s; }
.more-btn:hover { background: #e0e7ff; }
.more-btn:disabled { opacity: .5; cursor: wait; }
.more-info { font-size: 11px; color: #9ca3af; }
.empty { text-align: center; color: #6b7280; padding: 60px 0; }
</style>
</head>
<body>
<!-- ===== 顶部工具栏 ===== -->
<header class="topbar">
<div class="brand">
<img class="icon" src="logo/logo-mark.svg" alt="画个标" width="20" height="20">
<span class="name">画个标</span>
<span class="tag">素材库</span>
</div>
<nav class="nav">
<a href="index.html" title="LOGO 设计工作台">🎨 LOGO</a>
<a href="avatar.html" title="头像设计工作台">🖼 头像</a>
<a href="poster.html" title="海报设计工作台">📰 海报</a>
<a href="skills.html" title="共享技能中心">🧩 技能中心</a>
<a href="poster-skills.html" title="海报技能中心">🧩 海报技能</a>
<a class="active" href="materials.html" title="素材库:按行预览 LOGO/头像/海报素材">🗃 素材库</a>
<a href="sources.html" title="图标素材中心(来源信息)">📚 素材中心</a>
<a href="poster-sources.html" title="海报素材中心(来源信息)">📚 海报素材</a>
</nav>
</header>
<div class="wrap">
<div class="stats">
<div class="stat-card"><div class="num" id="st-total">-</div><div class="lab">当前分组素材(类)</div></div>
<div class="stat-card"><div class="num" id="st-items">-</div><div class="lab">素材总数(个)</div></div>
</div>
<div class="toolbar">
<div class="tabs" id="tabs"></div>
<input class="search" id="search" placeholder="🔍 搜索素材(名称 / 类别 / 特性描述)">
</div>
<div id="list"></div>
<div class="empty hidden" id="empty">未找到匹配素材,请调整分类或搜索词。</div>
</div>
<script src="js/core/dicebear.js?v=20260822e"></script>
<script src="js/data/builtin-icons.js?v=20260823g"></script>
<script src="js/data/poster-builtin.js?v=20260823e"></script>
<script>
(function () {
'use strict';
/* ============ 工具 ============ */
function esc(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
function loadScript(src) {
return new Promise(function (res, rej) {
var s = document.createElement('script');
s.src = src; s.onload = res; s.onerror = function () { rej(new Error('加载失败 ' + src)); };
document.head.appendChild(s);
});
}
/* 描边型判断 + 渲染属性(与 sources.html 一致) */
var STROKE_SOURCES = new Set(['feather', 'lucide', 'tabler', 'iconoir']);
function isStroke(ic, sid) {
return STROKE_SOURCES.has(sid) || /stroke\s*=|\bstroke-linecap\s*=|\bstroke-linejoin\s*=/.test(ic && ic.svg || '');
}
function iconAttrs(ic, sid) {
if (ic.type && ic.type !== 'icon') return 'fill="inherit" stroke="inherit"';
return isStroke(ic, sid)
? 'fill="none" stroke="#4f46e5" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"'
: 'fill="#4f46e5" stroke="none"';
}
function bodyOf(ic) {
return ic.svg.replace(/fill="currentColor"/g, 'fill="inherit"').replace(/stroke="currentColor"/g, 'stroke="inherit"');
}
/* 从 palette data 递归提取全部 hex */
function collectHex(obj, out) {
if (!obj) return;
if (typeof obj === 'string') { if (/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(obj)) out.push(obj); return; }
if (Array.isArray(obj)) { for (var i = 0; i < obj.length; i++) collectHex(obj[i], out); return; }
for (var k in obj) collectHex(obj[k], out);
}
/* ============ 状态 ============ */
var TAB = 'logo'; // logo / avatar / poster
var kw = '';
var ICON_SRC = []; // LOGO 源(manifest)
var POSTER_SRC = []; // 海报源(manifest)
var BUILTIN = (typeof HGB_BuiltinIcons !== 'undefined') ? HGB_BuiltinIcons : null;
var PBUILTIN = window.HGB_PosterBuiltin || { sources: {} };
var DICE = (typeof HGB_Dicebear !== 'undefined') ? HGB_Dicebear : null;
var loadedCache = {}; // 已加载的数据文件
var fontSeq = 0;
var TYPE_CN = { icon: '单色图标', emoji: '多色表情', brand: '品牌标识' };
var POSTER_TYPE_CN = { palette: '配色', font: '字体', bg: '背景', decoration: '装饰' };
var CAT_CLS = { icon: 'icon', emoji: 'emoji', brand: 'brand', palette: 'palette', font: 'font', bg: 'bg', decoration: 'decoration', avatar: 'avatar' };
/* ============ Manifest 加载 ============ */
function loadIconManifest() {
return fetch('js/data/manifest/icons.json?v=20260823g')
.then(function (r) { return r.json(); })
.then(function (m) { ICON_SRC = m.sources || []; })
.catch(function () { ICON_SRC = window.HGB_IconSources || []; });
}
function loadPosterManifest() {
return fetch('js/data/manifest/posters.json?v=20260823e')
.then(function (r) { return r.json(); })
.then(function (m) { POSTER_SRC = m.sources || []; })
.catch(function () { POSTER_SRC = window.HGB_PosterSources || []; });
}
/* ============ 数据文件懒加载 ============ */
function loadIconData(id) {
if (loadedCache['i_' + id]) return loadedCache['i_' + id];
loadedCache['i_' + id] = loadScript('js/data/sources/' + id + '.js?v=20260823g')
.then(function () { return window['HGB_Source_' + id] || null; });
return loadedCache['i_' + id];
}
function loadPosterData(id) {
if (loadedCache['p_' + id]) return loadedCache['p_' + id];
loadedCache['p_' + id] = loadScript('js/data/posters/' + id + '.js?v=20260823e')
.then(function () { return window['HGB_PosterSource_' + id] || null; });
return loadedCache['p_' + id];
}
/* ============ 渲染 ============ */
var tabs = [
{ id: 'logo', name: '🖼️ LOGO 素材' },
{ id: 'avatar', name: '🧑‍🎨 头像素材' },
{ id: 'poster', name: '🎨 海报素材' }
];
function renderTabs() {
var counts = { logo: ICON_SRC.length, avatar: (DICE ? DICE.STYLES.length : 0), poster: POSTER_SRC.length };
document.getElementById('tabs').innerHTML = tabs.map(function (t) {
return '<button class="tchip ' + (TAB === t.id ? 'active' : '') + '" data-t="' + t.id + '">' + t.name + ' <span style="opacity:.7">' + counts[t.id] + '</span></button>';
}).join('');
document.querySelectorAll('#tabs [data-t]').forEach(function (b) {
b.addEventListener('click', function () { TAB = b.dataset.t; renderTabs(); render(); });
});
}
function renderStats() {
var total = 0, items = 0;
if (TAB === 'logo') {
total = ICON_SRC.length;
items = ICON_SRC.reduce(function (s, x) { return s + ((typeof x.count === 'number') ? x.count : ((BUILTIN && BUILTIN.sources[x.id]) ? BUILTIN.sources[x.id].count : 0)); }, 0);
} else if (TAB === 'avatar') {
total = DICE ? DICE.STYLES.length : 0;
items = total; // 每风格可确定性生成无限头像,按风格数计
} else {
total = POSTER_SRC.length;
items = POSTER_SRC.reduce(function (s, x) { return s + ((typeof x.count === 'number') ? x.count : ((PBUILTIN.sources[x.id] || {}).count || 0)); }, 0);
}
document.getElementById('st-total').textContent = total;
document.getElementById('st-items').textContent = (TAB === 'avatar') ? (total + ' 风格 · 无限生成') : items.toLocaleString();
}
function rowHead(name, en, cat, catCn, count, countText) {
return '<div class="row-top">' +
'<span class="row-name">' + esc(name) + '</span>' +
(en ? '<span class="row-en">' + esc(en) + '</span>' : '') +
'<span class="row-cat ' + (CAT_CLS[cat] || '') + '">' + esc(catCn || cat) + '</span>' +
'<span class="row-count">' + (countText || ('共 ' + count + ' 个')) + '</span>' +
'</div>';
}
/* ---- LOGO 行 ---- */
function iconRow(s) {
var srcData = BUILTIN && BUILTIN.sources[s.id];
var count = (typeof s.count === 'number') ? s.count : (srcData ? srcData.count : '—');
var samples = (srcData && srcData.samples ? srcData.samples.map(function (b) { return { svg: b, type: srcData.type }; }) : []);
var type = s.type || 'icon';
var html = '<div class="row" id="row-i-' + esc(s.id) + '">' +
rowHead(s.nameCn || s.name, s.name, type, TYPE_CN[type] || s.style, count) +
'<div class="row-desc">' + esc(s.desc || '') + '</div>' +
'<div class="row-meta">' + esc(s.style || '') + ' · ' + esc(s.coordText || '') + ' · ' + esc(s.variants || '') + '</div>' +
'<div class="thumbs">' + samples.map(function (ic) {
return '<div class="thumb" title="' + esc((s.nameCn || s.name)) + '"><svg viewBox="0 0 24 24" ' + iconAttrs(ic, s.id) + '>' + bodyOf(ic) + '</svg></div>';
}).join('') + '</div>' +
'<div class="more-wrap"><button class="more-btn" data-act="more" data-id="' + esc(s.id) + '">查看更多(共 ' + count + ' 个)</button><span class="more-info" id="mi-i-' + esc(s.id) + '"></span></div>' +
'</div>';
return html;
}
function iconMore(btn, id, count) {
btn.disabled = true;
loadIconData(id).then(function (def) {
btn.disabled = false;
if (!def || !def.icons || !def.icons.length) { btn.textContent = '暂无更多数据'; return; }
var icons = def.icons;
var shown = parseInt(btn.dataset.shown || '0', 10) || 0;
var LIMIT = 100;
var slice = icons.slice(shown, shown + LIMIT);
var box = btn.closest('.row').querySelector('.thumbs');
box.insertAdjacentHTML('beforeend', slice.map(function (ic) {
return '<div class="thumb" title="' + esc(ic.name || ic.id || '') + '"><svg viewBox="0 0 24 24" ' + iconAttrs(ic, id) + '>' + bodyOf(ic) + '</svg></div>';
}).join(''));
shown += slice.length;
var info = document.getElementById('mi-i-' + id);
if (info) info.textContent = '已显示 ' + shown + ' / 共 ' + icons.length + ' 个';
if (shown < icons.length) { btn.dataset.shown = shown; btn.textContent = '再加载 ' + Math.min(LIMIT, icons.length - shown) + ' 个'; }
else { btn.textContent = '已全部加载'; btn.disabled = true; }
}).catch(function () { btn.disabled = false; btn.textContent = '加载失败,点击重试'; });
}
/* ---- 头像行 ---- */
var AV_SEEDS = ['画个标', 'brand', 'sun', 'star', 'cat', 'wow', 'happy', 'cool', 'blue', 'red', 'green', 'code'];
function avatarRow(styleId) {
var cn = DICE.CN[styleId] || styleId;
var html = '<div class="row" id="row-a-' + esc(styleId) + '">' +
rowHead(cn, styleId, 'avatar', '头像风格', 0, '无限生成') +
'<div class="row-desc">DiceBear 确定性头像生成器:同一 seed 永远生成同一头像,风格可无限产出(' + esc(styleId) + ')。</div>' +
'<div class="row-meta">seed 驱动 · 浏览器本地渲染 · 中性与彩色变体</div>' +
'<div class="thumbs" id="th-a-' + esc(styleId) + '"><div class="thumb placeholder">加载中…</div></div>' +
'<div class="more-wrap"><button class="more-btn" data-act="amore" data-id="' + esc(styleId) + '">查看更多头像</button></div>' +
'</div>';
return html;
}
function avatarPreview(styleId, n) {
var box = document.getElementById('th-a-' + styleId);
if (!box) return;
if (!DICE) { box.innerHTML = '<div class="thumb placeholder">引擎缺失</div>'; return; }
var inner = AV_SEEDS.slice(0, n).map(function (seed) {
var r = DICE.renderAvatar(styleId, seed);
if (!r.svg) return '<div class="thumb placeholder">—</div>';
return '<div class="thumb avatar" title="seed: ' + esc(seed) + '">' + r.svg + '</div>';
}).join('');
box.innerHTML = inner;
}
/* ---- 海报行 ---- */
function posterRow(s) {
var meta = PBUILTIN.sources[s.id] || {};
var count = (typeof s.count === 'number') ? s.count : (meta.count || 0);
var html = '<div class="row" id="row-p-' + esc(s.id) + '">' +
rowHead(s.nameCn || s.name, s.name, s.type, POSTER_TYPE_CN[s.type] || s.type, count) +
'<div class="row-desc">' + esc(s.desc || '') + '</div>' +
'<div class="row-meta">' + esc(s.coordText || '') + ' · ' + esc(s.variants || '') + '</div>' +
'<div class="thumbs" id="th-p-' + esc(s.id) + '"><div class="thumb placeholder">加载中…</div></div>' +
'<div class="more-wrap"><button class="more-btn" data-act="pmore" data-id="' + esc(s.id) + '">查看更多(共 ' + count + ' 个)</button><span class="more-info" id="mi-p-' + esc(s.id) + '"></span></div>' +
'</div>';
return html;
}
function posterPreview(s, limit) {
var box = document.getElementById('th-p-' + s.id);
if (!box) return;
loadPosterData(s.id).then(function (def) {
if (!def || !def.items) { box.innerHTML = '<div class="thumb placeholder">无数据</div>'; return; }
var items = def.items;
if (s.type === 'palette') {
var hexes = [];
items.forEach(function (it) { collectHex(it.data, hexes); });
var shown = hexes.slice(0, limit);
box.innerHTML = shown.map(function (h) { return '<div class="swatch" title="' + esc(h) + '" style="background:' + h + '"></div>'; }).join('');
var info = document.getElementById('mi-p-' + s.id);
if (info) info.textContent = '共 ' + hexes.length + ' 色';
} else if (s.type === 'font') {
box.innerHTML = '';
items.slice(0, limit).forEach(function (it) {
renderFontSample(box, s.id, it);
});
} else { // bg / decoration
var slice = items.slice(0, limit);
box.innerHTML = slice.map(function (it) {
var vb = it.viewBox ? ' viewBox="' + it.viewBox + '"' : ' viewBox="0 0 ' + (it.width || 100) + ' ' + (it.height || 100) + '"';
return '<div class="thumb svg-item" title="' + esc(it.name || it.id || '') + '"><svg' + vb + ' xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet">' + (it.svg || '') + '</svg></div>';
}).join('');
}
}).catch(function () { box.innerHTML = '<div class="thumb placeholder">加载失败</div>'; });
}
function renderFontSample(box, sid, it) {
var name = String(it.name || '字重').replace(/[_-]/g, ' ');
var holder = document.createElement('div');
holder.className = 'font-sample';
holder.textContent = name + ' — 画个标 123 ABC';
box.appendChild(holder);
var fam = 'mlfont' + (fontSeq++);
try {
var ff = new FontFace(fam, 'url(js/data/' + it.file + ')');
ff.load().then(function (f) {
document.fonts.add(f);
holder.style.fontFamily = '"' + fam + '", sans-serif';
}).catch(function () { holder.style.color = '#9ca3af'; });
} catch (e) { holder.style.color = '#9ca3af'; }
}
function posterMore(btn, s) {
btn.disabled = true;
loadPosterData(s.id).then(function (def) {
btn.disabled = false;
if (!def || !def.items) { btn.textContent = '暂无更多数据'; return; }
var items = def.items;
var n;
if (s.type === 'palette') { n = 9999; } // 色块轻量,全显
else if (s.type === 'font') { n = items.length; } // 字重少,全显
else { n = 60; } // SVG 上限 60,避免卡顿
posterPreview(s, n);
var info = document.getElementById('mi-p-' + s.id);
if (info) info.textContent = (s.type === 'palette') ? '全部色板已加载' : ('已显示 ' + Math.min(n, items.length) + ' / 共 ' + items.length + ' 个');
btn.textContent = '已全部加载';
btn.disabled = true;
}).catch(function () { btn.disabled = false; btn.textContent = '加载失败,点击重试'; });
}
/* ============ 主渲染 ============ */
function currentList() {
var kwl = kw.trim().toLowerCase();
if (TAB === 'logo') {
return ICON_SRC.filter(function (s) {
if (!kwl) return true;
return (s.nameCn || '').toLowerCase().includes(kwl) || (s.name || '').toLowerCase().includes(kwl) ||
(s.desc || '').toLowerCase().includes(kwl) || (s.id || '').toLowerCase().includes(kwl);
});
}
if (TAB === 'avatar') {
if (!DICE) return [];
return DICE.STYLES.filter(function (id) {
if (!kwl) return true;
var cn = DICE.CN[id] || '';
return cn.toLowerCase().includes(kwl) || id.toLowerCase().includes(kwl);
});
}
return POSTER_SRC.filter(function (s) {
if (!kwl) return true;
return (s.nameCn || '').toLowerCase().includes(kwl) || (s.name || '').toLowerCase().includes(kwl) ||
(s.desc || '').toLowerCase().includes(kwl) || (s.id || '').toLowerCase().includes(kwl) ||
(POSTER_TYPE_CN[s.type] || '').includes(kwl);
});
}
function render() {
var listEl = document.getElementById('list');
var empty = document.getElementById('empty');
renderStats();
var list = currentList();
if (!list.length) { listEl.innerHTML = ''; empty.classList.remove('hidden'); empty.textContent = '未找到匹配素材,请调整分类或搜索词。'; return; }
empty.classList.add('hidden');
if (TAB === 'logo') {
listEl.innerHTML = list.map(iconRow).join('');
// LOGO 行默认预览来自内置索引,无需异步
} else if (TAB === 'avatar') {
listEl.innerHTML = list.map(avatarRow).join('');
// 并发懒加载全部风格数据后批量渲染前 4 个预览
Promise.all(list.map(function (id) {
return DICE.loadStyle(id).catch(function () { return null; });
})).then(function () {
list.forEach(function (id) { avatarPreview(id, 4); });
});
} else {
listEl.innerHTML = list.map(posterRow).join('');
list.forEach(function (s) { posterPreview(s, 8); });
}
}
/* ============ 事件 ============ */
function onBtn(e) {
var btn = e.target.closest('[data-act]');
if (!btn) return;
var act = btn.dataset.act, id = btn.dataset.id;
if (act === 'more') {
var src = ICON_SRC.find(function (x) { return x.id === id; });
if (src) iconMore(btn, id, src.count);
} else if (act === 'amore') {
avatarPreview(id, 12);
btn.textContent = '已显示 12 个';
btn.disabled = true;
} else if (act === 'pmore') {
var ps = POSTER_SRC.find(function (x) { return x.id === id; });
if (ps) posterMore(btn, ps);
}
}
function init() {
document.getElementById('list').addEventListener('click', onBtn);
document.getElementById('search').addEventListener('input', function (e) { kw = e.target.value; render(); });
renderTabs();
render();
}
Promise.all([loadIconManifest(), loadPosterManifest()]).then(init).catch(init);
})();
</script>
</body>
</html>