feat: 初始化画个标仓库 - AI驱动设计系统(BYOK模式) - 224源/371504图标+25海报源+130技能
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
// 临时生成脚本:从图标库提取底部导航 5 个菜单图标,生成双态对比预览页(勿提交)
|
||||
const fs = require('fs');
|
||||
const path = 'js/data/sources/';
|
||||
global.window = {};
|
||||
|
||||
const RED = '#C8102E';
|
||||
const GRAY = '#999999';
|
||||
|
||||
function load(sid) {
|
||||
eval(fs.readFileSync(path + sid + '.js', 'utf8'));
|
||||
return window['HGB_Source_' + sid];
|
||||
}
|
||||
function findIcon(data, ref) {
|
||||
const namePart = ref.includes(':') ? ref.split(':')[1] : ref;
|
||||
return (data.icons || []).find(i => i.id === ref || i.name === namePart) || null;
|
||||
}
|
||||
|
||||
// style: native(自带currentColor) / fill(根fill) / stroke(根stroke)
|
||||
const SOURCES = {
|
||||
fluent: { style: 'native', vb: 24 },
|
||||
'material-symbols': { style: 'native', vb: 24 },
|
||||
remix: { style: 'fill', vb: 24 },
|
||||
lucide: { style: 'stroke', vb: 24 },
|
||||
ionicons: { style: 'fill', vb: 512 },
|
||||
mingcute: { style: 'native', vb: 24 }
|
||||
};
|
||||
|
||||
function renderSVG(ic, src, color) {
|
||||
const { style, vb } = src;
|
||||
let attrs = 'xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + vb + ' ' + vb + '"';
|
||||
if (style === 'stroke') attrs += ' fill="none" stroke="' + color + '" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"';
|
||||
else if (style === 'fill') attrs += ' fill="' + color + '"';
|
||||
return '<svg ' + attrs + '>' + ic.svg + '</svg>';
|
||||
}
|
||||
|
||||
const SOLUTIONS = [
|
||||
{
|
||||
key: 'A', title: 'Fluent 微软圆润', desc: '微软现代风格,描边/实心双态,与现款同源;「发房」= 房子+加号',
|
||||
source: 'fluent', pub: 'fluent:home-add-24-filled',
|
||||
items: [
|
||||
{ label: '首页', n: 'fluent:home-24-regular', a: 'fluent:home-24-filled' },
|
||||
{ label: '租房', n: 'fluent:search-24-regular', a: 'fluent:search-24-filled' },
|
||||
{ label: '消息', n: 'fluent:chat-24-regular', a: 'fluent:chat-24-filled' },
|
||||
{ label: '我的', n: 'fluent:person-24-regular', a: 'fluent:person-24-filled' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'B', title: 'Material Symbols 谷歌圆角', desc: 'Material Design 风格,圆角厚重,实心为主;「发房」= 房子+加号',
|
||||
source: 'material-symbols', pub: 'material-symbols:add-home-rounded',
|
||||
items: [
|
||||
{ label: '首页', n: 'material-symbols:home-outline-rounded', a: 'material-symbols:home-rounded' },
|
||||
{ label: '租房', n: 'material-symbols:search-outline-rounded', a: 'material-symbols:search-rounded' },
|
||||
{ label: '消息', n: 'material-symbols:chat-outline-rounded', a: 'material-symbols:chat-rounded' },
|
||||
{ label: '我的', n: 'material-symbols:person-outline-rounded', a: 'material-symbols:person-rounded' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'C', title: 'Remix 锐克思', desc: '国内产品最常见图标库,线条/实心双态;「发房」= 铅笔编辑',
|
||||
source: 'remix', pub: 'remix:edit-2-fill',
|
||||
items: [
|
||||
{ label: '首页', n: 'remix:home-5-line', a: 'remix:home-5-fill' },
|
||||
{ label: '租房', n: 'remix:search-line', a: 'remix:search-fill' },
|
||||
{ label: '消息', n: 'remix:message-3-line', a: 'remix:message-3-fill' },
|
||||
{ label: '我的', n: 'remix:user-3-line', a: 'remix:user-3-fill' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'D', title: 'Lucide 轻细线条', desc: '精致细线条风格,克制优雅;「发房」= 房子+加号(线条)',
|
||||
source: 'lucide', pub: 'lucide:house-plus',
|
||||
items: [
|
||||
{ label: '首页', n: 'lucide:house', a: 'lucide:house' },
|
||||
{ label: '租房', n: 'lucide:search', a: 'lucide:search' },
|
||||
{ label: '消息', n: 'lucide:message-square', a: 'lucide:message-square' },
|
||||
{ label: '我的', n: 'lucide:user', a: 'lucide:user' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'E', title: 'Ionicons iOS 经典', desc: 'iOS 系统同源图标,实心/描边双态;「发房」= 铅笔',
|
||||
source: 'ionicons', pub: 'ionicons:create',
|
||||
items: [
|
||||
{ label: '首页', n: 'ionicons:home-outline', a: 'ionicons:home' },
|
||||
{ label: '租房', n: 'ionicons:search-outline', a: 'ionicons:search' },
|
||||
{ label: '消息', n: 'ionicons:chatbox-ellipses-outline', a: 'ionicons:chatbox-ellipses' },
|
||||
{ label: '我的', n: 'ionicons:person-outline', a: 'ionicons:person' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'F', title: 'Mingcute 圆润可爱', desc: '圆头线条/实心双态,造型年轻活泼;「发房」= 铅笔编辑',
|
||||
source: 'mingcute', pub: 'mingcute:edit-2-fill',
|
||||
items: [
|
||||
{ label: '首页', n: 'mingcute:home-1-line', a: 'mingcute:home-1-fill' },
|
||||
{ label: '租房', n: 'mingcute:search-2-line', a: 'mingcute:search-2-fill' },
|
||||
{ label: '消息', n: 'mingcute:chat-1-line', a: 'mingcute:chat-1-fill' },
|
||||
{ label: '我的', n: 'mingcute:user-3-line', a: 'mingcute:user-3-fill' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// 预加载所有源
|
||||
const dataCache = {};
|
||||
for (const sid of Object.keys(SOURCES)) {
|
||||
try { dataCache[sid] = load(sid); } catch (e) { console.error('加载失败 ' + sid); process.exit(1); }
|
||||
}
|
||||
|
||||
// 发房按钮:红色渐变圆钮 + 匹配图标(白色)
|
||||
function pubBtn(sol) {
|
||||
const src = SOURCES[sol.source];
|
||||
const ic = findIcon(dataCache[sol.source], sol.pub);
|
||||
if (!ic) { missList.push(sol.pub); return '<div class="plus"><span>+</span></div>'; }
|
||||
return '<div class="plus">' + renderSVG(ic, src, '#ffffff') + '</div>';
|
||||
}
|
||||
|
||||
let cards = '';
|
||||
const missList = [];
|
||||
for (const sol of SOLUTIONS) {
|
||||
const src = SOURCES[sol.source];
|
||||
const res = [];
|
||||
for (const it of sol.items) {
|
||||
const nIc = findIcon(dataCache[sol.source], it.n);
|
||||
const aIc = findIcon(dataCache[sol.source], it.a);
|
||||
if (!nIc) missList.push(it.n);
|
||||
if (!aIc) missList.push(it.a);
|
||||
res.push({
|
||||
label: it.label,
|
||||
normal: nIc ? renderSVG(nIc, src, GRAY) : '',
|
||||
active: aIc ? renderSVG(aIc, src, RED) : ''
|
||||
});
|
||||
}
|
||||
const plus = pubBtn(sol);
|
||||
|
||||
// 常规态 TabBar mock
|
||||
const arrNormal = [res[0], res[1], null, res[2], res[3]];
|
||||
const barActive = `<div class="tabbar">` +
|
||||
arrNormal.map((r, i) => r ? `<div class="tabitem${i === 0 ? ' active' : ''}"><div class="ic">${i === 0 ? r.active : r.normal}</div><div class="lb">${r.label}</div></div>` : `<div class="tabitem"><div class="ic">${plus}</div><div class="lb">发房</div></div>`)
|
||||
.join('') + `</div>`;
|
||||
const barNormalFull = `<div class="tabbar">` +
|
||||
arrNormal.map(r => r ? `<div class="tabitem"><div class="ic">${r.normal}</div><div class="lb">${r.label}</div></div>` : `<div class="tabitem"><div class="ic">${plus}</div><div class="lb">发房</div></div>`)
|
||||
.join('') + `</div>`;
|
||||
|
||||
const ids = [...sol.items.map(it => it.n), ...sol.items.map(it => it.a)].join('、');
|
||||
cards += `
|
||||
<div class="card">
|
||||
<div class="card-head">
|
||||
<div class="card-title"><span class="tag">方案 ${sol.key}</span>${sol.title}</div>
|
||||
<div class="card-desc">${sol.desc}</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mock-wrap">
|
||||
<div class="mock-col">
|
||||
<div class="mock-title">常规态</div>
|
||||
<div class="phone">${barNormalFull}</div>
|
||||
</div>
|
||||
<div class="mock-col">
|
||||
<div class="mock-title">选中态(首页高亮)</div>
|
||||
<div class="phone">${barActive}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="state-strip">
|
||||
${res.map(r => `<div class="state-cell">
|
||||
<div class="state-ic">${r.normal}</div><div class="state-lb">${r.label}·未选</div>
|
||||
<div class="state-ic active">${r.active}</div><div class="state-lb active">${r.label}·选中</div>
|
||||
</div>`).join('')}
|
||||
</div>
|
||||
<div class="ids">图标:<code>${ids}</code></div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const html = `<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>小虎租房 · 底部导航图标方案</title>
|
||||
<style>
|
||||
* { margin:0; padding:0; box-sizing:border-box; }
|
||||
body { font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif; background:#f5f5f7; color:#333; padding:36px 28px 80px; }
|
||||
h1 { font-size:24px; margin-bottom:6px; }
|
||||
.sub { color:#888; font-size:13px; margin-bottom:32px; }
|
||||
.card { background:#fff; border-radius:16px; padding:24px 28px; margin-bottom:24px; box-shadow:0 1px 4px rgba(0,0,0,.06); }
|
||||
.card-head { margin-bottom:18px; }
|
||||
.card-title { font-size:18px; font-weight:700; display:flex; align-items:center; gap:10px; }
|
||||
.tag { display:inline-block; background:#C8102E; color:#fff; font-size:12px; font-weight:600; border-radius:6px; padding:2px 8px; }
|
||||
.card-desc { font-size:13px; color:#888; margin-top:8px; }
|
||||
.card-body { display:flex; flex-wrap:wrap; gap:28px; align-items:flex-start; }
|
||||
.mock-wrap { display:flex; gap:20px; }
|
||||
.mock-col { text-align:center; }
|
||||
.mock-title { font-size:12px; color:#999; margin-bottom:10px; }
|
||||
.phone { width:300px; border-radius:20px; border:6px solid #222; background:#fff; overflow:hidden; }
|
||||
.phone::before { content:""; display:block; height:8px; }
|
||||
.tabbar { display:flex; height:54px; background:#fff; border-top:1px solid #f0f0f0; }
|
||||
.tabitem { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px; }
|
||||
.tabitem .ic { width:24px; height:24px; color:#999; }
|
||||
.tabitem .ic svg { width:24px; height:24px; display:block; }
|
||||
.tabitem .lb { font-size:10px; color:#999; line-height:14px; }
|
||||
.tabitem.active .ic { color:#C8102E; }
|
||||
.tabitem.active .lb { color:#C8102E; }
|
||||
.plus { width:26px; height:26px; border-radius:50%; background:linear-gradient(135deg,#e8433d,#C8102E); box-shadow:0 1px 3px rgba(200,16,46,.3); display:flex; align-items:center; justify-content:center; color:#fff; }
|
||||
.plus svg { width:18px; height:18px; display:block; }
|
||||
.state-strip { display:flex; gap:18px; flex-wrap:wrap; }
|
||||
.state-cell { display:flex; flex-direction:column; align-items:center; gap:6px; background:#fafafa; border:1px solid #f0f0f0; border-radius:12px; padding:12px 10px; min-width:76px; }
|
||||
.state-ic { width:26px; height:26px; color:#999; }
|
||||
.state-ic svg { width:26px; height:26px; display:block; }
|
||||
.state-ic.active { color:#C8102E; }
|
||||
.state-lb { font-size:10px; color:#aaa; }
|
||||
.state-lb.active { color:#C8102E; }
|
||||
.ids { width:100%; font-size:11px; color:#999; margin-top:6px; word-break:break-all; }
|
||||
.ids code { font-family:ui-monospace,Consolas,monospace; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>小虎租房 · 底部导航图标方案</h1>
|
||||
<div class="sub">数据来自「画个标」内置图标库 · 共 6 套方案 · 未选中 #999999 / 选中 ${RED}(品牌红)·「发房」红色圆钮内置匹配图标(房子+加号/铅笔编辑)</div>
|
||||
${cards}
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
fs.writeFileSync('D:/SGP_KF3/ruyizu_web/docs/tabbar-icons-preview.html', html, 'utf8');
|
||||
if (missList.length) console.log('缺失图标: ' + missList.join(', '));
|
||||
else console.log('OK,已生成 docs/tabbar-icons-preview.html(' + SOLUTIONS.length + ' 套方案,全部图标命中)');
|
||||
Reference in New Issue
Block a user