gen-brand-icons.js 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #!/usr/bin/env node
  2. /**
  3. * Vendors the provider brand marks the editor uses, from simple-icons.
  4. *
  5. * The provider nodes - ten ways of talking to an OpenAI-compatible API - all
  6. * carried the same speech-bubble icon, so a list of them was ten identical
  7. * rows. A brand mark is the one thing that tells them apart at a glance.
  8. *
  9. * Only marks simple-icons actually ships are vendored. It removes logos when a
  10. * trademark holder asks - OpenAI's is already gone - and drawing a replacement
  11. * by hand would mean shipping something that is not the company's mark while
  12. * claiming it is. Providers with no mark get a distinct Lucide icon instead,
  13. * assigned in the node's own @icon.
  14. *
  15. * npm --prefix webui install --no-save simple-icons@16
  16. * node scripts/gen-brand-icons.js
  17. *
  18. * The paths are copied out rather than imported so the editor does not carry
  19. * three and a half thousand icons to show six.
  20. */
  21. const fs = require('fs')
  22. const path = require('path')
  23. const ROOT = path.resolve(__dirname, '..')
  24. const OUT = path.join(ROOT, 'webui/src/config/brandIcons.ts')
  25. // The name a node writes in @icon -> the simple-icons export.
  26. // Left-hand side is ours and stays stable even if a slug changes upstream.
  27. const WANTED = {
  28. ollama: 'siOllama',
  29. mistral: 'siMistralai',
  30. perplexity: 'siPerplexity',
  31. deepseek: 'siDeepseek',
  32. openrouter: 'siOpenrouter',
  33. xai: 'siX',
  34. anthropic: 'siAnthropic',
  35. huggingface: 'siHuggingface',
  36. }
  37. function main() {
  38. let si
  39. try {
  40. si = require(path.join(ROOT, 'webui/node_modules/simple-icons'))
  41. } catch (e) {
  42. console.error('simple-icons is not installed. Run:')
  43. console.error(' npm --prefix webui install --no-save simple-icons@16')
  44. process.exit(2)
  45. }
  46. const found = []
  47. const missing = []
  48. for (const [name, exportName] of Object.entries(WANTED)) {
  49. const icon = si[exportName]
  50. if (icon && icon.path) found.push([name, icon])
  51. else missing.push([name, exportName])
  52. }
  53. if (missing.length) {
  54. console.warn('Not shipped by simple-icons, so these keep their Lucide icon:')
  55. for (const [name, exportName] of missing) console.warn(` ${name} (${exportName})`)
  56. }
  57. const body = `// GENERATED by scripts/gen-brand-icons.js - do not edit by hand.
  58. //
  59. // Provider brand marks, copied from simple-icons so the editor does not have to
  60. // carry the whole set. Regenerate with:
  61. // npm --prefix webui install --no-save simple-icons@16
  62. // node scripts/gen-brand-icons.js
  63. //
  64. // Each path is a 24x24 viewBox. Drawn in currentColor rather than the brand
  65. // colour, so an icon sits in a row with the others instead of shouting over
  66. // them, and works in both themes.
  67. export interface BrandIcon {
  68. title: string
  69. path: string
  70. }
  71. export const BRAND_ICONS: Record<string, BrandIcon> = {
  72. ${found.map(([name, icon]) => ` '${name}': { title: ${JSON.stringify(icon.title)}, path: ${JSON.stringify(icon.path)} },`).join('\n')}
  73. }
  74. `
  75. fs.writeFileSync(OUT, body)
  76. console.log(`Wrote ${path.relative(ROOT, OUT)}: ${found.length} brand marks`)
  77. }
  78. main()