Files
drawlogo/_gen_tabbar_preview.js

221 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 临时生成脚本:从图标库提取底部导航 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 + ' 套方案,全部图标命中)');