Files
xiaocai/scripts/generate-icons.js

120 lines
4.3 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.
/**
* 从 Lucide SVG 图标生成高质量 PNG
* 用法: node scripts/generate-icons.js
*/
const sharp = require('sharp')
const fs = require('fs')
const path = require('path')
const ICONS_DIR = path.join(__dirname, '../client/src/static/icons')
const LUCIDE_DIR = path.join(__dirname, '../node_modules/lucide-static/icons')
// 颜色映射hex -> RGB
const COLORS = {
'#2D1B1B': { r: 45, g: 27, b: 27 }, // 暖深棕
'#8B7E7E': { r: 139, g: 126, b: 126 }, // 灰色
'#BFB3B3': { r: 191, g: 179, b: 179 }, // 浅灰
'#E0D6D0': { r: 224, g: 214, b: 208 }, // 极浅灰
'#FF8C69': { r: 255, g: 140, b: 105 }, // 珊瑚橙
'#FF6B6B': { r: 255, g: 107, b: 107 }, // 红色
'#7BC67E': { r: 123, g: 198, b: 126 }, // 绿色
'#FFFFFF': { r: 255, g: 255, b: 255 }, // 白色
}
// 图标配置:{ lucideName, variants: { colorHex: outputName } }
const ICONS = [
// 导航
{ lucide: 'arrow-left', variants: { '#2D1B1B': 'arrow-left-dark', '#8B7E7E': 'arrow-left-gray' } },
{ lucide: 'arrow-right', variants: { '#8B7E7E': 'arrow-right-gray', '#E0D6D0': 'arrow-right-pale' } },
{ lucide: 'chevron-right', variants: { '#BFB3B3': 'chevron-right-light' } },
// 操作
{ lucide: 'plus', variants: { '#FFFFFF': 'plus-white' } },
{ lucide: 'check', variants: { '#FFFFFF': 'check-white' } },
{ lucide: 'edit', variants: { '#8B7E7E': 'edit-gray', '#BFB3B3': 'edit-light' } },
{ lucide: 'trash-2', variants: { '#FF8C69': 'trash-orange', '#FF6B6B': 'trash-red', '#FFFFFF': 'trash-white' } },
{ lucide: 'refresh-cw', variants: { '#8B7E7E': 'refresh-gray', '#FF8C69': 'refresh-orange' } },
// 功能
{ lucide: 'calendar', variants: { '#8B7E7E': 'calendar-gray' } },
{ lucide: 'bell', variants: { '#8B7E7E': 'bell-gray' } },
{ lucide: 'user', variants: { '#8B7E7E': 'user-gray', '#FFFFFF': 'user-white' } },
{ lucide: 'alert-circle', variants: { '#BFB3B3': 'alert-circle-light' } },
// 趋势
{ lucide: 'trending-down', variants: { '#FF6B6B': 'trend-down-red' } },
{ lucide: 'trending-up', variants: { '#7BC67E': 'trend-up-green' } },
]
// TabBar 图标(需要 normal + active 两套)
const TABBAR_ICONS = [
{ lucide: 'home', normal: 'home', active: 'home-active', normalColor: '#BFB3B3', activeColor: '#FF8C69' },
{ lucide: 'bar-chart-2', normal: 'chart', active: 'chart-active', normalColor: '#BFB3B3', activeColor: '#FF8C69' },
{ lucide: 'receipt', normal: 'bill', active: 'bill-active', normalColor: '#BFB3B3', activeColor: '#FF8C69' },
{ lucide: 'user', normal: 'user', active: 'user-active', normalColor: '#BFB3B3', activeColor: '#FF8C69' },
]
const SIZE = 96 // 输出 PNG 尺寸px
async function generateIcon(svgName, outputPath, color) {
const svgPath = path.join(LUCIDE_DIR, `${svgName}.svg`)
if (!fs.existsSync(svgPath)) {
console.warn(`⚠ SVG not found: ${svgName}.svg`)
return false
}
let svgContent = fs.readFileSync(svgPath, 'utf-8')
// 替换 SVG 中的 stroke 颜色
const { r, g, b } = COLORS[color]
svgContent = svgContent.replace(/stroke="[^"]*"/g, `stroke="rgb(${r},${g},${b})"`)
// 也处理可能的 fill
svgContent = svgContent.replace(/fill="none"/g, 'fill="none"')
// 设置输出尺寸
svgContent = svgContent.replace(/width="[^"]*"/, `width="${SIZE}"`)
svgContent = svgContent.replace(/height="[^"]*"/, `height="${SIZE}"`)
await sharp(Buffer.from(svgContent))
.resize(SIZE, SIZE)
.png()
.toFile(outputPath)
return true
}
async function main() {
console.log('🎨 开始生成图标...\n')
let total = 0
let success = 0
// 生成普通图标
for (const icon of ICONS) {
for (const [color, outputName] of Object.entries(icon.variants)) {
const outputPath = path.join(ICONS_DIR, `${outputName}.png`)
total++
if (await generateIcon(icon.lucide, outputPath, color)) {
console.log(`${outputName}.png`)
success++
}
}
}
// 生成 TabBar 图标
for (const icon of TABBAR_ICONS) {
for (const [outputName, color] of [[icon.normal, icon.normalColor], [icon.active, icon.activeColor]]) {
const outputPath = path.join(ICONS_DIR, `${outputName}.png`)
total++
if (await generateIcon(icon.lucide, outputPath, color)) {
console.log(`${outputName}.png (tabbar)`)
success++
}
}
}
console.log(`\n✅ 完成: ${success}/${total} 个图标已生成`)
}
main().catch(console.error)