feat: auto-map all 3098 simple-icons via import * and word-boundary detection

Replace hand-curated named imports with `import * as si from 'simple-icons'`.
BRANDS keeps only entries requiring custom aliases, absent icons, or colour
overrides. AUTO_SI covers all remaining simple-icons (title >= 4 chars) with
pre-compiled word-boundary regexes to avoid substring false positives.

detectBrands() now runs two passes:
1. BRANDS — curated aliases (pve → Proxmox, unifi → Ubiquiti, k3s → k8s…)
2. AUTO_SI — automatic match on any icon title as a whole word

Bundle: +5 MB minified / +2 MB gzip (acceptable for a self-hosted tool).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-22 09:09:33 +02:00
parent fd289cc00f
commit 5001ce192d
+163 -265
View File
@@ -1,44 +1,7 @@
import {
siProxmox, siDocker,
siSynology, siTruenas,
siSchneiderelectric,
siUbiquiti, siMikrotik, siCisco, siTplink, siAsus, siNetgear, siPfsense, siOpnsense, siOpenwrt,
siFortinet,
siApache, siNginx, siTraefikproxy, siApacheguacamole,
siAuthelia, siKeycloak, siAuthentik, siOkta, siAuth0,
siOrange, siOvh,
siBitwarden, siVaultwarden, si1password, siKeepassxc, siVault,
siMariadb,
siKubernetes,
siPrometheus, siGrafana, siDatadog, siNetdata, siCheckmk, siIcinga, siInfluxdb, siVictoriametrics,
siOpsgenie, siPagerduty,
siElastic, siKibana, siLogstash, siSplunk, siGraylog, siJaeger, siOpentelemetry,
siApple,
siDebian, siUbuntu, siFirefox,
siCentos, siRedhat, siFedora, siAlpinelinux, siArchlinux, siOpensuse, siFreebsd,
siAlmalinux, siRockylinux, siNixos, siGentoo, siVoidlinux, siSlackware,
siSuse, siManjaro, siLinuxmint, siZorin, siPopos, siDeepin, siElementary,
siMxlinux, siSolus, siEndeavouros, siArtixlinux, siAsahilinux,
siKubuntu, siLubuntu, siXubuntu, siUbuntumate,
siBsd, siOpenbsd, siNetbsd,
siKalilinux, siParrotsecurity, siTails, siQubesos, siReactos,
siMacos, siIos, siLinux,
siAndroid,
siAnsible,
siDell, siHp,
siRaspberrypi, siArduino,
siNextcloud, siPaperlessngx, siUptimekuma, siMaterialformkdocs,
siWordpress, siGhost, siGrav, siJekyll, siHugo, siHexo, siDrupal, siJoomla, siTypo3, siOctobercms, siTextpattern,
siMatomo, siPlausibleanalytics,
siSamsung, siLg, siSony, siPanasonic, siSharp, siToshiba, siVestel,
siChromecast, siAppletv, siAmazonfiretv, siRoku, siKodi,
siJellyfin, siHomeassistant, siPhilipshue, siXiaomi,
siRadarr, siSonarr, siTransmission,
siExcalidraw,
siKde,
} from 'simple-icons'
import * as si from 'simple-icons'
// ── Icônes personnalisées (absentes de simple-icons) ────────────────────────
// Icônes personnalisées (absentes de simple-icons) — même format { title, hex, path }.
const ICON_FREE = {
title: 'Free',
hex: 'CD1126',
@@ -75,7 +38,6 @@ const ICON_MAIL = {
path: 'M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z',
}
// UPS custom icons (absents de simple-icons)
const ICON_EATON = {
title: 'Eaton',
hex: 'E22000',
@@ -94,7 +56,6 @@ const ICON_VERTIV = {
path: 'M20 3H4v4h16V3zm0 5H4v4h16V8zm0 5H4v4h16v-4zM6 5h2v2H6zm0 5h2v2H6zm0 5h2v2H6z',
}
// Monitoring custom icons (absents de simple-icons)
const ICON_ZABBIX = {
title: 'Zabbix',
hex: 'D40000',
@@ -125,251 +86,165 @@ const ICON_WINDOWS = {
path: 'M0 3.449L9.75 2.1v9.451H0m10.949-9.602L24 0v11.4h-13.051M0 12.6h9.75v9.451L0 20.699M10.949 12.6H24V24l-13.051-1.8',
}
// Ordre : du plus spécifique au plus générique pour éviter les faux positifs.
// ── BRANDS : alias custom, icônes absentes de simple-icons, couleurs override ─
// Les ~3000 autres icônes simple-icons sont couvertes automatiquement via AUTO_SI.
const BRANDS = [
// Hyperviseurs / virtualisation
{ kw: ['proxmox', 'pve'], icon: siProxmox },
{ kw: ['docker'], icon: siDocker },
// NAS
{ kw: ['synology', 'dsm'], icon: siSynology },
{ kw: ['truenas', 'freenas'], icon: siTruenas },
// Onduleurs (UPS)
{ kw: ['apc', 'schneider electric', 'symmetra', 'smart-ups', 'easy ups', 'galaxy ups'], icon: siSchneiderelectric },
{ kw: ['eaton', 'powerware', 'eaton ups'], icon: ICON_EATON },
{ kw: ['riello', 'riello ups'], icon: ICON_RIELLO },
{ kw: ['vertiv', 'liebert', 'avocent', 'geist'], icon: ICON_VERTIV },
// Virtualisation / NAS
{ kw: ['proxmox', 'pve'], icon: si.siProxmox },
{ kw: ['truenas', 'freenas'], icon: si.siTruenas },
// Onduleurs
{ kw: ['apc', 'schneider electric', 'symmetra', 'smart-ups', 'easy ups', 'galaxy ups'], icon: si.siSchneiderelectric },
{ kw: ['eaton', 'powerware', 'eaton ups'], icon: ICON_EATON },
{ kw: ['riello', 'riello ups'], icon: ICON_RIELLO },
{ kw: ['vertiv', 'liebert', 'avocent', 'geist'], icon: ICON_VERTIV },
// Réseau
{ kw: ['ubiquiti', 'unifi', 'usg', 'udm'], icon: siUbiquiti },
{ kw: ['mikrotik', 'routeros'], icon: siMikrotik },
{ kw: ['cisco'], icon: siCisco },
{ kw: ['tp-link', 'tplink', 'tp link'], icon: siTplink },
{ kw: ['asus'], icon: siAsus },
{ kw: ['netgear'], icon: siNetgear },
{ kw: ['pfsense'], icon: siPfsense },
{ kw: ['opnsense'], icon: siOpnsense },
{ kw: ['openwrt'], icon: siOpenwrt },
// Sécurité réseau
{ kw: ['fortinet', 'fortigate', 'fortios', 'fortimanager', 'fortiauthenticator'], icon: siFortinet },
{ kw: ['ubiquiti', 'unifi', 'usg', 'udm'], icon: si.siUbiquiti },
{ kw: ['mikrotik', 'routeros'], icon: si.siMikrotik },
{ kw: ['tp-link', 'tplink', 'tp link'], icon: si.siTplink },
{ kw: ['fortinet', 'fortigate', 'fortios', 'fortimanager', 'fortiauthenticator'], icon: si.siFortinet },
// FAI français
{ kw: ['orange', 'sosh', 'livebox'], icon: siOrange },
{ kw: ['ovh', 'ovhcloud', 'kimsufi', 'soyoustart'], icon: siOvh },
{ kw: ['freebox', 'free mobile', 'free telecom', 'iliad'], icon: ICON_FREE },
{ kw: ['bouygues', 'bbox'], icon: ICON_BOUYGUES },
{ kw: ['sfr', 'red by sfr', 'sfr box'], icon: ICON_SFR },
// Serveurs web / proxy
{ kw: ['apache', 'apache2', 'httpd'], icon: siApache },
{ kw: ['nginx'], icon: siNginx },
{ kw: ['traefik'], icon: siTraefikproxy },
{ kw: ['guacamole'], icon: siApacheguacamole },
// Bastions / jump hosts
{ kw: ['bastion', 'jumphost', 'jump host', 'jump server', 'teleport', 'bastillion'], icon: ICON_BASTION },
// Auth / SSO / IDP
{ kw: ['authelia'], icon: siAuthelia },
{ kw: ['keycloak'], icon: siKeycloak },
{ kw: ['authentik'], icon: siAuthentik },
{ kw: ['okta'], icon: siOkta },
{ kw: ['auth0'], icon: siAuth0 },
// Coffres-forts de mots de passe
{ kw: ['vaultwarden'], icon: siVaultwarden },
{ kw: ['bitwarden'], icon: siBitwarden },
{ kw: ['1password', 'onepassword'], icon: si1password },
{ kw: ['keepass', 'keepassxc'], icon: siKeepassxc },
{ kw: ['hashicorp vault', 'hashicorp'], icon: siVault },
// Archivage
{ kw: ['archive', 'archiver', 'archivage', 'archivar', 'archivebox'], icon: ICON_ARCHIVE },
// Messagerie
{ kw: ['orange', 'sosh', 'livebox'], icon: si.siOrange },
{ kw: ['ovh', 'ovhcloud', 'kimsufi', 'soyoustart'], icon: si.siOvh },
{ kw: ['freebox', 'free mobile', 'free telecom', 'iliad'], icon: ICON_FREE },
{ kw: ['bouygues', 'bbox'], icon: ICON_BOUYGUES },
{ kw: ['sfr', 'red by sfr', 'sfr box'], icon: ICON_SFR },
// Web / proxy (titre simple-icons differ de l'alias courant)
{ kw: ['traefik'], icon: si.siTraefikproxy },
{ kw: ['guacamole'], icon: si.siApacheguacamole },
// Bastion / jump host
{ kw: ['bastion', 'jumphost', 'jump host', 'jump server', 'teleport', 'bastillion'], icon: ICON_BASTION },
// Messagerie / archivage
{ kw: ['mail', 'smtp', 'imap', 'postfix', 'dovecot', 'mailcow', 'mailu', 'roundcube'], icon: ICON_MAIL },
// Bases de données
{ kw: ['mariadb', 'maria db'], icon: siMariadb },
{ kw: ['archive', 'archiver', 'archivage', 'archivar', 'archivebox'], icon: ICON_ARCHIVE },
// Passwords
{ kw: ['1password', 'onepassword'], icon: si.si1password },
{ kw: ['keepass', 'keepassxc'], icon: si.siKeepassxc },
{ kw: ['hashicorp vault', 'hashicorp'], icon: si.siVault },
// Orchestration
{ kw: ['kubernetes', 'k8s', 'kubectl', 'k3s'], icon: siKubernetes },
// Monitoring / Observabilité
{ kw: ['zabbix'], icon: ICON_ZABBIX },
{ kw: ['centreon'], icon: ICON_CENTREON },
{ kw: ['nagios', 'nagiosxi', 'nagios xi'], icon: ICON_NAGIOS },
{ kw: ['prtg', 'paessler'], icon: ICON_PRTG },
{ kw: ['prometheus'], icon: siPrometheus },
{ kw: ['grafana'], icon: siGrafana },
{ kw: ['datadog'], icon: siDatadog },
{ kw: ['netdata'], icon: siNetdata },
{ kw: ['checkmk', 'check_mk'], icon: siCheckmk },
{ kw: ['icinga', 'icinga2'], icon: { ...siIcinga, hex: '3F5FBA' } },
{ kw: ['influxdb', 'influx db'], icon: siInfluxdb },
{ kw: ['victoriametrics', 'victoria metrics'], icon: siVictoriametrics },
{ kw: ['kubernetes', 'k8s', 'kubectl', 'k3s'], icon: si.siKubernetes },
// Monitoring (icônes custom)
{ kw: ['zabbix'], icon: ICON_ZABBIX },
{ kw: ['centreon'], icon: ICON_CENTREON },
{ kw: ['nagios', 'nagiosxi', 'nagios xi'], icon: ICON_NAGIOS },
{ kw: ['prtg', 'paessler'], icon: ICON_PRTG },
// Monitoring (couleurs override)
{ kw: ['icinga', 'icinga2'], icon: { ...si.siIcinga, hex: '3F5FBA' } },
{ kw: ['opsgenie'], icon: { ...si.siOpsgenie, hex: '2684FF' } },
{ kw: ['victoria metrics', 'victoriametrics'], icon: si.siVictoriametrics },
// Logs / traces (alias + couleurs override)
{ kw: ['elastic', 'elasticsearch', 'elastic stack', 'elk'], icon: si.siElastic },
{ kw: ['splunk'], icon: { ...si.siSplunk, hex: '65A637' } },
{ kw: ['opentelemetry', 'otel'], icon: { ...si.siOpentelemetry, hex: '425CC7' } },
// Apple (couleur override + aliases)
{ kw: ['apple', 'iphone', 'ipad', 'ipados', 'macbook', 'imac', 'mac mini', 'mac pro', 'mac studio', 'macos', 'mac os', 'icloud', 'airpods', 'airdrop'], icon: { ...si.siApple, hex: '555555' } },
// Windows (icône custom)
{ kw: ['windows', 'win10', 'win11', 'winserver', 'windows server'], icon: ICON_WINDOWS },
// Serveurs (aliases)
{ kw: ['dell', 'idrac', 'poweredge'], icon: si.siDell },
{ kw: ['hp', 'hpe', 'proliant', 'ilo', 'hewlett'], icon: si.siHp },
// SBC
{ kw: ['raspberry', 'raspberrypi', 'rpi', 'raspi'], icon: si.siRaspberrypi },
// Bureau (titre trop court pour l'auto-détection)
{ kw: ['kde', 'plasma'], icon: si.siKde },
// Self-hosted (aliases utiles)
{ kw: ['paperless', 'paperless-ng', 'paperless-ngx'], icon: si.siPaperlessngx },
{ kw: ['uptime-kuma', 'uptimekuma', 'uptime kuma'], icon: si.siUptimekuma },
{ kw: ['mkdocs', 'material for mkdocs'], icon: si.siMaterialformkdocs },
// TV / Domotique
{ kw: ['samsung', 'tizen'], icon: si.siSamsung },
{ kw: ['lg', 'webos'], icon: si.siLg },
{ kw: ['sony', 'bravia'], icon: { ...si.siSony, hex: '1A1A1A' } },
{ kw: ['chromecast', 'google tv'], icon: si.siChromecast },
{ kw: ['android tv', 'androidtv'], icon: si.siAndroid },
{ kw: ['fire tv', 'firetv', 'amazon fire'], icon: si.siAmazonfiretv },
{ kw: ['philips hue', 'hue bridge', 'hue hub'], icon: si.siPhilipshue },
{ kw: ['homeassistant', 'home assistant', 'hassio', 'hass'], icon: si.siHomeassistant },
{ kw: ['xiaomi', 'mi home', 'yeelight'], icon: si.siXiaomi },
// Alerting
{ kw: ['opsgenie'], icon: { ...siOpsgenie, hex: '2684FF' } },
{ kw: ['pagerduty', 'pager duty'], icon: siPagerduty },
// Logs / Traces
{ kw: ['elasticsearch', 'elastic stack', 'elk'], icon: siElastic },
{ kw: ['kibana'], icon: siKibana },
{ kw: ['logstash'], icon: siLogstash },
{ kw: ['splunk'], icon: { ...siSplunk, hex: '65A637' } },
{ kw: ['graylog'], icon: siGraylog },
{ kw: ['jaeger'], icon: siJaeger },
{ kw: ['opentelemetry', 'otel'], icon: { ...siOpentelemetry, hex: '425CC7' } },
// Écosystème Apple
{ kw: ['apple', 'iphone', 'ipad', 'ipados', 'macbook', 'imac', 'mac mini', 'mac pro', 'mac studio', 'macos', 'mac os', 'ios', 'icloud', 'airpods', 'airdrop'], icon: { ...siApple, hex: '555555' } },
// OS / distros
{ kw: ['windows', 'win10', 'win11', 'winserver', 'windows server'], icon: ICON_WINDOWS },
{ kw: ['debian'], icon: siDebian },
{ kw: ['ubuntu'], icon: siUbuntu },
// Navigateurs
{ kw: ['firefox'], icon: siFirefox },
// Automatisation
{ kw: ['ansible'], icon: siAnsible },
// Serveurs
{ kw: ['dell', 'idrac', 'poweredge'], icon: siDell },
{ kw: ['proliant', 'ilo', 'hewlett'], icon: siHp },
// SBC / DIY
{ kw: ['raspberry', 'raspberrypi', 'rpi', 'raspi'], icon: siRaspberrypi },
{ kw: ['arduino'], icon: siArduino },
// Environnements de bureau
{ kw: ['kde', 'plasma', 'kde desktop'], icon: siKde },
// Outils
{ kw: ['excalidraw'], icon: siExcalidraw },
// Productivité / self-hosted
{ kw: ['nextcloud'], icon: siNextcloud },
{ kw: ['paperless', 'paperless-ng', 'paperless-ngx'], icon: siPaperlessngx },
{ kw: ['uptime-kuma', 'uptimekuma', 'uptime kuma'], icon: siUptimekuma },
{ kw: ['mkdocs', 'material for mkdocs'], icon: siMaterialformkdocs },
// CMS / Blog
{ kw: ['wordpress'], icon: siWordpress },
{ kw: ['ghost'], icon: siGhost },
{ kw: ['grav'], icon: siGrav },
{ kw: ['jekyll'], icon: siJekyll },
{ kw: ['hugo'], icon: siHugo },
{ kw: ['hexo'], icon: siHexo },
{ kw: ['drupal'], icon: siDrupal },
{ kw: ['joomla'], icon: siJoomla },
{ kw: ['typo3'], icon: siTypo3 },
{ kw: ['octobercms', 'october cms'], icon: siOctobercms },
{ kw: ['textpattern'], icon: siTextpattern },
// Analytique
{ kw: ['matomo'], icon: siMatomo },
{ kw: ['plausible'], icon: siPlausibleanalytics },
// TV connectées — fabricants
{ kw: ['samsung', 'tizen', 'samsung tv'], icon: siSamsung },
{ kw: ['lg', 'webos', 'lg tv'], icon: siLg },
{ kw: ['sony', 'bravia'], icon: { ...siSony, hex: '1A1A1A' } },
{ kw: ['panasonic'], icon: siPanasonic },
{ kw: ['sharp'], icon: siSharp },
{ kw: ['toshiba'], icon: siToshiba },
{ kw: ['vestel'], icon: siVestel },
// TV connectées — boîtiers / écosystèmes
{ kw: ['chromecast', 'google tv'], icon: siChromecast },
{ kw: ['android tv', 'androidtv'], icon: siAndroid },
{ kw: ['apple tv', 'appletv'], icon: siAppletv },
{ kw: ['fire tv', 'firetv', 'amazon fire'], icon: siAmazonfiretv },
{ kw: ['roku'], icon: siRoku },
{ kw: ['kodi'], icon: siKodi },
// Médias / torrent
{ kw: ['radarr'], icon: siRadarr },
{ kw: ['sonarr'], icon: siSonarr },
{ kw: ['transmission'], icon: siTransmission },
// Médias / domotique
{ kw: ['jellyfin'], icon: siJellyfin },
{ kw: ['homeassistant', 'home assistant', 'hassio', 'hass'], icon: siHomeassistant },
{ kw: ['philips hue', 'hue bridge', 'hue hub'], icon: siPhilipshue },
{ kw: ['xiaomi', 'mi home', 'yeelight'], icon: siXiaomi },
{ kw: ['pagerduty', 'pager duty'], icon: si.siPagerduty },
]
// Slugs couverts par BRANDS → exclus de l'auto-détection pour éviter les doublons
const _BRANDS_SLUGS = new Set(
BRANDS.flatMap(b => (b.icon && b.icon.slug) ? [b.icon.slug] : [])
)
// Toutes les icônes simple-icons (title >= 4 chars) non couvertes par BRANDS.
// Regex pré-compilée avec frontières de mots pour éviter les faux positifs
// (ex. "known" ne doit pas matcher dans "unknown").
const AUTO_SI = Object.values(si)
.filter(icon => icon.title.length >= 4 && !_BRANDS_SLUGS.has(icon.slug))
.map(icon => {
const escaped = icon.title.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
return { icon, re: new RegExp('(?<![a-z0-9])' + escaped + '(?![a-z0-9])') }
})
export const OS_LIST = [
// Infrastructure
{ value: 'proxmox', label: 'Proxmox VE', kw: ['proxmox', 'pve'], icon: siProxmox },
{ value: 'truenas', label: 'TrueNAS', kw: ['truenas', 'freenas'], icon: siTruenas },
{ value: 'synology', label: 'Synology DSM', kw: ['synology', 'dsm'], icon: siSynology },
{ value: 'proxmox', label: 'Proxmox VE', kw: ['proxmox', 'pve'], icon: si.siProxmox },
{ value: 'truenas', label: 'TrueNAS', kw: ['truenas', 'freenas'], icon: si.siTruenas },
{ value: 'synology', label: 'Synology DSM', kw: ['synology', 'dsm'], icon: si.siSynology },
// Réseau / pare-feu
{ value: 'openwrt', label: 'OpenWrt', kw: ['openwrt'], icon: siOpenwrt },
{ value: 'pfsense', label: 'pfSense', kw: ['pfsense'], icon: siPfsense },
{ value: 'opnsense', label: 'OPNsense', kw: ['opnsense'], icon: siOpnsense },
{ value: 'openwrt', label: 'OpenWrt', kw: ['openwrt'], icon: si.siOpenwrt },
{ value: 'pfsense', label: 'pfSense', kw: ['pfsense'], icon: si.siPfsense },
{ value: 'opnsense', label: 'OPNsense', kw: ['opnsense'], icon: si.siOpnsense },
// SBC
{ value: 'raspbian', label: 'Raspberry Pi OS', kw: ['raspbian', 'raspberry pi os', 'pi os'], icon: siRaspberrypi },
{ value: 'raspbian', label: 'Raspberry Pi OS', kw: ['raspbian', 'raspberry pi os', 'pi os'], icon: si.siRaspberrypi },
// Debian / Ubuntu
{ value: 'ubuntu', label: 'Ubuntu', kw: ['ubuntu'], icon: siUbuntu },
{ value: 'kubuntu', label: 'Kubuntu', kw: ['kubuntu'], icon: siKubuntu },
{ value: 'lubuntu', label: 'Lubuntu', kw: ['lubuntu'], icon: siLubuntu },
{ value: 'xubuntu', label: 'Xubuntu', kw: ['xubuntu'], icon: siXubuntu },
{ value: 'ubuntumate', label: 'Ubuntu MATE', kw: ['ubuntu mate', 'ubuntumate'], icon: siUbuntumate },
{ value: 'debian', label: 'Debian', kw: ['debian'], icon: siDebian },
{ value: 'ubuntu', label: 'Ubuntu', kw: ['ubuntu'], icon: si.siUbuntu },
{ value: 'kubuntu', label: 'Kubuntu', kw: ['kubuntu'], icon: si.siKubuntu },
{ value: 'lubuntu', label: 'Lubuntu', kw: ['lubuntu'], icon: si.siLubuntu },
{ value: 'xubuntu', label: 'Xubuntu', kw: ['xubuntu'], icon: si.siXubuntu },
{ value: 'ubuntumate', label: 'Ubuntu MATE', kw: ['ubuntu mate', 'ubuntumate'], icon: si.siUbuntumate },
{ value: 'debian', label: 'Debian', kw: ['debian'], icon: si.siDebian },
// Red Hat / CentOS
{ value: 'redhat', label: 'Red Hat', kw: ['red hat', 'redhat', 'rhel'], icon: siRedhat },
{ value: 'centos', label: 'CentOS', kw: ['centos'], icon: siCentos },
{ value: 'almalinux', label: 'AlmaLinux', kw: ['almalinux', 'alma linux'], icon: { ...siAlmalinux, hex: '4d4d4d' } },
{ value: 'rockylinux', label: 'Rocky Linux', kw: ['rockylinux', 'rocky linux', 'rocky'], icon: siRockylinux },
{ value: 'fedora', label: 'Fedora', kw: ['fedora'], icon: siFedora },
{ value: 'redhat', label: 'Red Hat', kw: ['red hat', 'redhat', 'rhel'], icon: si.siRedhat },
{ value: 'centos', label: 'CentOS', kw: ['centos'], icon: si.siCentos },
{ value: 'almalinux', label: 'AlmaLinux', kw: ['almalinux', 'alma linux'], icon: { ...si.siAlmalinux, hex: '4d4d4d' } },
{ value: 'rockylinux', label: 'Rocky Linux', kw: ['rockylinux', 'rocky linux', 'rocky'], icon: si.siRockylinux },
{ value: 'fedora', label: 'Fedora', kw: ['fedora'], icon: si.siFedora },
// SUSE
{ value: 'opensuse', label: 'openSUSE', kw: ['opensuse', 'open suse'], icon: siOpensuse },
{ value: 'suse', label: 'SUSE Linux Enterprise', kw: ['sles', 'suse linux enterprise'], icon: { ...siSuse, hex: '73BA25' } },
{ value: 'opensuse', label: 'openSUSE', kw: ['opensuse', 'open suse'], icon: si.siOpensuse },
{ value: 'suse', label: 'SUSE Linux Enterprise', kw: ['sles', 'suse linux enterprise'], icon: { ...si.siSuse, hex: '73BA25' } },
// Arch
{ value: 'arch', label: 'Arch Linux', kw: ['arch linux', 'archlinux'], icon: siArchlinux },
{ value: 'manjaro', label: 'Manjaro', kw: ['manjaro'], icon: siManjaro },
{ value: 'endeavouros', label: 'EndeavourOS', kw: ['endeavouros', 'endeavour os'], icon: siEndeavouros },
{ value: 'artixlinux', label: 'Artix Linux', kw: ['artixlinux', 'artix linux', 'artix'], icon: siArtixlinux },
{ value: 'arch', label: 'Arch Linux', kw: ['arch linux', 'archlinux'], icon: si.siArchlinux },
{ value: 'manjaro', label: 'Manjaro', kw: ['manjaro'], icon: si.siManjaro },
{ value: 'endeavouros', label: 'EndeavourOS', kw: ['endeavouros', 'endeavour os'], icon: si.siEndeavouros },
{ value: 'artixlinux', label: 'Artix Linux', kw: ['artixlinux', 'artix linux', 'artix'], icon: si.siArtixlinux },
// Alpine
{ value: 'alpine', label: 'Alpine Linux', kw: ['alpine linux', 'alpine'], icon: siAlpinelinux },
{ value: 'alpine', label: 'Alpine Linux', kw: ['alpine linux', 'alpine'], icon: si.siAlpinelinux },
// Divers
{ value: 'nixos', label: 'NixOS', kw: ['nixos', 'nix os'], icon: siNixos },
{ value: 'gentoo', label: 'Gentoo', kw: ['gentoo'], icon: siGentoo },
{ value: 'voidlinux', label: 'Void Linux', kw: ['voidlinux', 'void linux'], icon: siVoidlinux },
{ value: 'slackware', label: 'Slackware', kw: ['slackware'], icon: { ...siSlackware, hex: '4d4d4d' } },
{ value: 'asahilinux', label: 'Asahi Linux', kw: ['asahi linux', 'asahi'], icon: siAsahilinux },
{ value: 'nixos', label: 'NixOS', kw: ['nixos', 'nix os'], icon: si.siNixos },
{ value: 'gentoo', label: 'Gentoo', kw: ['gentoo'], icon: si.siGentoo },
{ value: 'voidlinux', label: 'Void Linux', kw: ['voidlinux', 'void linux'], icon: si.siVoidlinux },
{ value: 'slackware', label: 'Slackware', kw: ['slackware'], icon: { ...si.siSlackware, hex: '4d4d4d' } },
{ value: 'asahilinux', label: 'Asahi Linux', kw: ['asahi linux', 'asahi'], icon: si.siAsahilinux },
// Bureau
{ value: 'linuxmint', label: 'Linux Mint', kw: ['linux mint', 'linuxmint'], icon: siLinuxmint },
{ value: 'popos', label: 'Pop!_OS', kw: ["pop!_os", 'popos', 'pop os'], icon: siPopos },
{ value: 'zorin', label: 'Zorin OS', kw: ['zorin'], icon: siZorin },
{ value: 'elementary', label: 'elementary OS', kw: ['elementary os', 'elementaryos'], icon: siElementary },
{ value: 'deepin', label: 'deepin', kw: ['deepin'], icon: siDeepin },
{ value: 'mxlinux', label: 'MX Linux', kw: ['mx linux', 'mxlinux'], icon: { ...siMxlinux, hex: '4d4d4d' } },
{ value: 'solus', label: 'Solus', kw: ['solus'], icon: siSolus },
{ value: 'linuxmint', label: 'Linux Mint', kw: ['linux mint', 'linuxmint'], icon: si.siLinuxmint },
{ value: 'popos', label: 'Pop!_OS', kw: ["pop!_os", 'popos', 'pop os'], icon: si.siPopos },
{ value: 'zorin', label: 'Zorin OS', kw: ['zorin'], icon: si.siZorin },
{ value: 'elementary', label: 'elementary OS', kw: ['elementary os', 'elementaryos'], icon: si.siElementary },
{ value: 'deepin', label: 'deepin', kw: ['deepin'], icon: si.siDeepin },
{ value: 'mxlinux', label: 'MX Linux', kw: ['mx linux', 'mxlinux'], icon: { ...si.siMxlinux, hex: '4d4d4d' } },
{ value: 'solus', label: 'Solus', kw: ['solus'], icon: si.siSolus },
// BSD
{ value: 'freebsd', label: 'FreeBSD', kw: ['freebsd', 'free bsd'], icon: siFreebsd },
{ value: 'openbsd', label: 'OpenBSD', kw: ['openbsd'], icon: siOpenbsd },
{ value: 'netbsd', label: 'NetBSD', kw: ['netbsd'], icon: siNetbsd },
{ value: 'freebsd', label: 'FreeBSD', kw: ['freebsd', 'free bsd'], icon: si.siFreebsd },
{ value: 'openbsd', label: 'OpenBSD', kw: ['openbsd'], icon: si.siOpenbsd },
{ value: 'netbsd', label: 'NetBSD', kw: ['netbsd'], icon: si.siNetbsd },
// Sécurité
{ value: 'kali', label: 'Kali Linux', kw: ['kali linux', 'kalilinux'], icon: siKalilinux },
{ value: 'parrot', label: 'Parrot Security', kw: ['parrot security', 'parrotsec', 'parrot os'], icon: siParrotsecurity },
{ value: 'tails', label: 'Tails', kw: ['tails os', 'tails linux'], icon: siTails },
{ value: 'qubes', label: 'Qubes OS', kw: ['qubes os', 'qubesos'], icon: siQubesos },
{ value: 'kali', label: 'Kali Linux', kw: ['kali linux', 'kalilinux'], icon: si.siKalilinux },
{ value: 'parrot', label: 'Parrot Security', kw: ['parrot security', 'parrotsec', 'parrot os'], icon: si.siParrotsecurity },
{ value: 'tails', label: 'Tails', kw: ['tails os', 'tails linux'], icon: si.siTails },
{ value: 'qubes', label: 'Qubes OS', kw: ['qubes os', 'qubesos'], icon: si.siQubesos },
// Windows / macOS / mobile
{ value: 'windows', label: 'Windows', kw: ['windows', 'win10', 'win11', 'winserver', 'windows server'], icon: ICON_WINDOWS },
{ value: 'macos', label: 'macOS', kw: ['macos', 'mac os'], icon: { ...siMacos, hex: '555555' } },
{ value: 'ios', label: 'iOS / iPadOS', kw: ['ios', 'ipados'], icon: { ...siIos, hex: '555555' } },
{ value: 'android', label: 'Android', kw: ['android'], icon: siAndroid },
{ value: 'windows', label: 'Windows', kw: ['windows', 'win10', 'win11', 'winserver', 'windows server'], icon: ICON_WINDOWS },
{ value: 'macos', label: 'macOS', kw: ['macos', 'mac os'], icon: { ...si.siMacos, hex: '555555' } },
{ value: 'ios', label: 'iOS / iPadOS', kw: ['ios', 'ipados'], icon: { ...si.siIos, hex: '555555' } },
{ value: 'android', label: 'Android', kw: ['android'], icon: si.siAndroid },
// Autres
{ value: 'reactos', label: 'ReactOS', kw: ['reactos'], icon: siReactos },
{ value: 'linux', label: 'Linux (générique)', kw: ['linux'], icon: siLinux },
{ value: 'bsd', label: 'BSD (générique)', kw: ['bsd'], icon: siBsd },
{ value: 'reactos', label: 'ReactOS', kw: ['reactos'], icon: si.siReactos },
{ value: 'linux', label: 'Linux (générique)', kw: ['linux'], icon: si.siLinux },
{ value: 'bsd', label: 'BSD (générique)', kw: ['bsd'], icon: si.siBsd },
]
export function osIcon(value) {
@@ -385,5 +260,28 @@ export function detectOs(name, description) {
export function detectBrands(name, description) {
const text = ((name || '') + ' ' + (description || '')).toLowerCase()
if (!text.trim()) return []
return BRANDS.filter(b => b.kw.some(kw => text.includes(kw))).map(b => b.icon)
const seen = new Set()
const results = []
// Pass 1 : BRANDS — aliases custom, icônes personnalisées, couleurs overridées
for (const b of BRANDS) {
if (b.kw.some(kw => text.includes(kw))) {
const key = b.icon.slug ?? b.icon.title
if (!seen.has(key)) {
seen.add(key)
results.push(b.icon)
}
}
}
// Pass 2 : auto-détection sur l'ensemble des icônes simple-icons (frontières de mots)
for (const { icon, re } of AUTO_SI) {
if (!seen.has(icon.slug) && re.test(text)) {
seen.add(icon.slug)
results.push(icon)
}
}
return results
}