|
@@ -0,0 +1,88 @@
|
|
|
|
|
+#!/usr/bin/env node
|
|
|
|
|
+/**
|
|
|
|
|
+ * Vendors the provider brand marks the editor uses, from simple-icons.
|
|
|
|
|
+ *
|
|
|
|
|
+ * The provider nodes - ten ways of talking to an OpenAI-compatible API - all
|
|
|
|
|
+ * carried the same speech-bubble icon, so a list of them was ten identical
|
|
|
|
|
+ * rows. A brand mark is the one thing that tells them apart at a glance.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Only marks simple-icons actually ships are vendored. It removes logos when a
|
|
|
|
|
+ * trademark holder asks - OpenAI's is already gone - and drawing a replacement
|
|
|
|
|
+ * by hand would mean shipping something that is not the company's mark while
|
|
|
|
|
+ * claiming it is. Providers with no mark get a distinct Lucide icon instead,
|
|
|
|
|
+ * assigned in the node's own @icon.
|
|
|
|
|
+ *
|
|
|
|
|
+ * npm --prefix webui install --no-save simple-icons@16
|
|
|
|
|
+ * node scripts/gen-brand-icons.js
|
|
|
|
|
+ *
|
|
|
|
|
+ * The paths are copied out rather than imported so the editor does not carry
|
|
|
|
|
+ * three and a half thousand icons to show six.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+const fs = require('fs')
|
|
|
|
|
+const path = require('path')
|
|
|
|
|
+
|
|
|
|
|
+const ROOT = path.resolve(__dirname, '..')
|
|
|
|
|
+const OUT = path.join(ROOT, 'webui/src/config/brandIcons.ts')
|
|
|
|
|
+
|
|
|
|
|
+// The name a node writes in @icon -> the simple-icons export.
|
|
|
|
|
+// Left-hand side is ours and stays stable even if a slug changes upstream.
|
|
|
|
|
+const WANTED = {
|
|
|
|
|
+ ollama: 'siOllama',
|
|
|
|
|
+ mistral: 'siMistralai',
|
|
|
|
|
+ perplexity: 'siPerplexity',
|
|
|
|
|
+ deepseek: 'siDeepseek',
|
|
|
|
|
+ openrouter: 'siOpenrouter',
|
|
|
|
|
+ xai: 'siX',
|
|
|
|
|
+ anthropic: 'siAnthropic',
|
|
|
|
|
+ huggingface: 'siHuggingface',
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function main() {
|
|
|
|
|
+ let si
|
|
|
|
|
+ try {
|
|
|
|
|
+ si = require(path.join(ROOT, 'webui/node_modules/simple-icons'))
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('simple-icons is not installed. Run:')
|
|
|
|
|
+ console.error(' npm --prefix webui install --no-save simple-icons@16')
|
|
|
|
|
+ process.exit(2)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const found = []
|
|
|
|
|
+ const missing = []
|
|
|
|
|
+ for (const [name, exportName] of Object.entries(WANTED)) {
|
|
|
|
|
+ const icon = si[exportName]
|
|
|
|
|
+ if (icon && icon.path) found.push([name, icon])
|
|
|
|
|
+ else missing.push([name, exportName])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (missing.length) {
|
|
|
|
|
+ console.warn('Not shipped by simple-icons, so these keep their Lucide icon:')
|
|
|
|
|
+ for (const [name, exportName] of missing) console.warn(` ${name} (${exportName})`)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const body = `// GENERATED by scripts/gen-brand-icons.js - do not edit by hand.
|
|
|
|
|
+//
|
|
|
|
|
+// Provider brand marks, copied from simple-icons so the editor does not have to
|
|
|
|
|
+// carry the whole set. Regenerate with:
|
|
|
|
|
+// npm --prefix webui install --no-save simple-icons@16
|
|
|
|
|
+// node scripts/gen-brand-icons.js
|
|
|
|
|
+//
|
|
|
|
|
+// Each path is a 24x24 viewBox. Drawn in currentColor rather than the brand
|
|
|
|
|
+// colour, so an icon sits in a row with the others instead of shouting over
|
|
|
|
|
+// them, and works in both themes.
|
|
|
|
|
+export interface BrandIcon {
|
|
|
|
|
+ title: string
|
|
|
|
|
+ path: string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export const BRAND_ICONS: Record<string, BrandIcon> = {
|
|
|
|
|
+${found.map(([name, icon]) => ` '${name}': { title: ${JSON.stringify(icon.title)}, path: ${JSON.stringify(icon.path)} },`).join('\n')}
|
|
|
|
|
+}
|
|
|
|
|
+`
|
|
|
|
|
+
|
|
|
|
|
+ fs.writeFileSync(OUT, body)
|
|
|
|
|
+ console.log(`Wrote ${path.relative(ROOT, OUT)}: ${found.length} brand marks`)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+main()
|