gen-tabbar-icons.mjs 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. /**
  2. * 生成 81×81 TabBar PNG 图标(透明底,适合微信小程序)
  3. * 用法:node scripts/gen-tabbar-icons.mjs
  4. */
  5. import fs from 'node:fs'
  6. import path from 'node:path'
  7. import { fileURLToPath } from 'node:url'
  8. import sharp from 'sharp'
  9. const __dirname = path.dirname(fileURLToPath(import.meta.url))
  10. const outDir = path.resolve(__dirname, '../src/static/tabbar')
  11. const GRAY = '#666666'
  12. const PRIMARY = '#00BCD4'
  13. function svgIcon(type, color) {
  14. if (type === 'meal') {
  15. return `<svg width="81" height="81" xmlns="http://www.w3.org/2000/svg">
  16. <path d="M26 22 V48" fill="none" stroke="${color}" stroke-width="4" stroke-linecap="round"/>
  17. <path d="M34 22 V48" fill="none" stroke="${color}" stroke-width="4" stroke-linecap="round"/>
  18. <path d="M26 22 C26 16 34 16 34 22" fill="none" stroke="${color}" stroke-width="4" stroke-linecap="round"/>
  19. <path d="M48 22 V58" fill="none" stroke="${color}" stroke-width="4" stroke-linecap="round"/>
  20. <path d="M48 22 C48 16 56 16 56 22 V34 C56 40 48 40 48 34" fill="none" stroke="${color}" stroke-width="4" stroke-linejoin="round"/>
  21. <ellipse cx="40.5" cy="58" rx="22" ry="6" fill="none" stroke="${color}" stroke-width="3"/>
  22. </svg>`
  23. }
  24. if (type === 'order') {
  25. return `<svg width="81" height="81" xmlns="http://www.w3.org/2000/svg">
  26. <rect x="22" y="18" width="37" height="48" rx="6" fill="none" stroke="${color}" stroke-width="4"/>
  27. <line x1="30" y1="32" x2="51" y2="32" stroke="${color}" stroke-width="3" stroke-linecap="round"/>
  28. <line x1="30" y1="42" x2="51" y2="42" stroke="${color}" stroke-width="3" stroke-linecap="round"/>
  29. <line x1="30" y1="52" x2="44" y2="52" stroke="${color}" stroke-width="3" stroke-linecap="round"/>
  30. </svg>`
  31. }
  32. return `<svg width="81" height="81" xmlns="http://www.w3.org/2000/svg">
  33. <circle cx="40.5" cy="32" r="12" fill="none" stroke="${color}" stroke-width="4"/>
  34. <path d="M20 62 C20 50 58 50 61 62" fill="none" stroke="${color}" stroke-width="4" stroke-linecap="round"/>
  35. </svg>`
  36. }
  37. async function writeIcon(name, type, color) {
  38. const svg = svgIcon(type, color)
  39. const buf = await sharp(Buffer.from(svg)).png().toBuffer()
  40. fs.writeFileSync(path.join(outDir, name), buf)
  41. }
  42. async function main() {
  43. fs.mkdirSync(outDir, { recursive: true })
  44. const items = [
  45. ['meal.png', 'meal', GRAY],
  46. ['meal-active.png', 'meal', PRIMARY],
  47. ['order.png', 'order', GRAY],
  48. ['order-active.png', 'order', PRIMARY],
  49. ['profile.png', 'profile', GRAY],
  50. ['profile-active.png', 'profile', PRIMARY]
  51. ]
  52. for (const [file, type, color] of items) {
  53. await writeIcon(file, type, color)
  54. console.log('wrote', file)
  55. }
  56. }
  57. main().catch(err => {
  58. console.error(err)
  59. process.exit(1)
  60. })