Remplacer les icônes SVG par défaut de Discourse par des icônes personnalisées dans un thème

Vous pouvez remplacer les icônes SVG par défaut de Discourse individuellement ou dans leur ensemble par vos propres SVG personnalisés et les remplacer dans un thème ou un composant de thème.

Étape 1 - Créer une feuille de sprites SVG

Pour commencer, vous devez créer une feuille de sprites SVG. Celle-ci peut contenir n’importe quoi, d’une seule icône SVG personnalisée supplémentaire à un ensemble complet de remplacement de centaines.

La feuille de sprites doit être enregistrée en tant que fichier SVG. En principe, vous imbriquez le contenu de la balise <svg> du fichier d’icône SVG d’origine dans des balises <symbol> et leur donnez un identifiant agréable.

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="my-theme-icon-1">
    <!--
      Code à l'intérieur de la balise <svg> du fichier d'icône SVG source
      c'est typiquement tout ce qui se trouve entre les balises <svg>
      (mais pas la balise SVG elle-même, qui est remplacée par <symbol> ci-dessus)
      Vous pouvez transférer n'importe quel attribut (c'est-à-dire ViewBox="0 0 0 0") à la balise <symbol>
      -->
  </symbol>

  <symbol id="my-theme-icon-2">
    <!-- Code SVG ici. Ajoutez plus de blocs <symbol> si nécessaire.
      -->
  </symbol>
</svg>
  • Assurez-vous d’ajouter un ID personnalisé à chaque symbole dans la feuille de sprites. Il est probablement utile pour votre santé mentale de préfixer vos ID avec le nom de votre thème my-theme-icon.

  • Pour que la couleur de l’icône soit dynamique comme les icônes existantes, définissez le remplissage sur currentColor plutôt qu’une couleur codée en dur (comme #333)

  • Pour mettre à l’échelle ou centrer correctement votre icône, utilisez un attribut viewBox sur la balise <symbol>. Consultez How to Scale SVG | CSS-Tricks pour plus d’informations.

  • Faites attention aux collisions de style dans vos SVG. Par exemple, les SVG auront souvent un style en ligne tel que .st0{fill:#FF0000;} défini. Si vous avez plusieurs SVG utilisant les mêmes classes, cela peut causer des problèmes (pour résoudre ces problèmes, modifiez les classes pour qu’elles soient uniques à chaque icône).

  • Si vous avez beaucoup d’icônes, il existe des moyens d’automatiser cela. https://www.npmjs.com/package/svg-sprite-generator est un outil simple en ligne de commande pour combiner des SVG en une feuille de sprites.

Exemple - feuille de sprites d’icône personnalisée unique

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="bat-icon" viewBox="6 6 36 36">
    <path
      fill="currentColor"
      d="M24,18.2c0.7,0,0.9,0.2,0.9,0.2l0.4-1.7c0,0,0.4,1.5,0.4,2.8c0.2,1.1,2.2,0.4,3.9,0C31.4,19.1,32,16,32,16h16c0,0-9.4,3.5-7,10c0,0-14.8-2-17,7l0,0c-2.2-9-17-7-17-7c2.4-6.5-7-10-7-10h16c0,0,0.6,3.1,2.3,3.5c1.7,0.4,3.9,1.1,3.9,0c0.2-1.1,0.4-2.8,0.4-2.8l0.4,1.7C23.1,18.4,23.4,18.2,24,18.2L24,18.2L24,18.2z"
    />
  </symbol>
</svg>

Étape 2 - Ajouter la feuille de sprites à votre thème

Une fois votre feuille de sprites créée, vous devez ajouter le fichier SVG à votre composant/thème. C’est facile via l’interface utilisateur, ou vous pouvez le coder en dur dans un composant/thème.

:information_source: Une fois qu’il est téléchargé sur n’importe quel composant/thème installé, il est disponible sur toute votre instance en utilisant l’ID dans la balise <symbol>.

Via l’interface utilisateur

Accédez à la section Téléchargements des paramètres du thème/composant et ajoutez votre fichier sprite avec un nom de variable SCSS de icons-sprite:

Coder en dur dans un thème / composant

Ajoutez le fichier de feuille de sprites au dossier /assets du thème. Ensuite, mettez à jour votre fichier assets.json dans le dossier racine.
Pour un sprite SVG nommé my-icons.svg, votre about.json doit inclure ceci :

"assets": {
  "icons-sprite": "/assets/my-icons.svg"
}

Étape 3 (facultatif) - Remplacer les icônes par défaut

Maintenant que votre feuille de sprites est définie, vous pouvez indiquer à Discourse de remplacer les icônes. Voici comment le faire à partir d’un api-initializer :

// {theme}/javascripts/discourse/api-initializers/init-theme.gjs

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
  api.replaceIcon("bars", "my-theme-icon-bars");
  api.replaceIcon("link", "my-theme-icon-link");
  // etc.
});

Le premier ID, bars, est l’ID d’icône par défaut dans Discourse et le second est l’ID de votre icône de remplacement. Le moyen le plus simple de trouver l’ID de l’une de nos icônes est d’inspecter l’icône dans votre navigateur.

Ici, le nom de l’icône suit le préfixe d-icon-. Donc, dans cet exemple, c’est d-unliked

La plupart de nos icônes suivent les noms d’icônes de https://fontawesome.com/, mais il y a des exceptions (c’est pourquoi vérifier l’ID dans votre inspecteur est la méthode la plus fiable). Vous pouvez voir toutes les exceptions dans le bloc const REPLACEMENTS ici sur github.

C’est tout. Vous pouvez maintenant styliser Discourse avec vos propres icônes personnalisées !


Ce document est contrôlé par version - suggérez des modifications sur github.

57 « J'aime »

Comment cibler une icône spécifique dans un élément spécifique ? Dans mon cas, j’aimerais remplacer l’icône Docs dans le menu de la barre latérale par une autre icône FA.

1 « J'aime »

Je le cacherais avec CSS et j’ajouterais un nouveau bouton pour cela.

Commun / CSS

.sidebar-section-wrapper {
  li[data-list-item-name=docs] {
    display: none !important;
  }
}

Ajoutez un nouveau bouton dans Plus > Personnaliser cette section

4 « J'aime »

Cela ne fonctionne pas. J’ai essayé de faire :

<script type="text/discourse-plugin" version="0.8">
    api.replaceIcon("shield-halved", "hat-wizard");
</script>

d’ici, mais cela ne semble pas fonctionner. Je pense que la méthode de la balise script est cassée, car ceci ne fonctionne pas avec le lien de prévisualisation. Honnêtement, je ne suis pas sûr.

1 « J'aime »

ça marche pour moi :woman_shrugging:t2:

le mettez-vous dans l’onglet head ? j’ai aussi remplacé le robot dans mon en-tête :

vous devrez peut-être ajouter l’icône au paramètre SVG icon subset de l’administrateur.

2 « J'aime »

[citation=“Lilly, post:40, topic:115736”]
êtes-vous en train de le mettre dans l’onglet d’en-tête ?
[/citation]

Oui, l’onglet d’en-tête. Et l’onglet d’entête (header), puisque le guide dit ça.

[citation=“Lilly, post:40, topic:115736”]
SVG icon subset
[/citation]
C’est fait. Ça marche maintenant. Merci !

1 « J'aime »

@NateDhaliwal Pourriez-vous m’envoyer un message privé s’il vous plaît ? J’ai besoin d’aide pour quelque chose et je ne vois pas d’option de chat sur votre profil. Merci !

1 « J'aime »
Pour le menu de gauche, nous redéfinissons l'arrière-plan de l'élément avec la classe prefix-span dans la catégorie Audi */
.navigation-category [data-category-id="6"] .prefix-span {
  background: url("https://raw.githubusercontent.com/tima4502/car-icons/bb0d0fae3e5b66c512a27a130b219ec0ee342ada/audi.svg") center/contain no-repeat !important;

lorsque je clique sur la page principale, l’icône carrée réapparaît ! Pouvez-vous me dire ce que je fais de mal ? et sur la page de catégorie elle-même, cela fonctionne.

Bonjour, quelqu’un pourrait-il clarifier la relation entre un nom de thème/composant, un nom de fichier, un nom de variable SCSS et l’ID du symbole… ?

J’essaie de remplacer l’icône de modérateur shield-halved par la nôtre, mais les instructions sont un peu confuses.

Dans l’étape 2 :

  • La capture d’écran “Via l’interface utilisateur” montre un nom de fichier baticonsprite.svg avec un nom de variable SCSS icons-sprite.
  • Mais ensuite, dans “Codage en dur dans un thème”, il vous est demandé de le coder en dur dans un thème/composant.
  • Mais comment ? Je ne vois pas de fichier assets.json dans l’éditeur. Si j’exporte le composant, je vois un about.json, qui montre le sprite que j’ai téléchargé via l’interface utilisateur.
  • Mais cet exemple montre également un nom de fichier différent /assets/my-icons.svg — est-ce censé être le même fichier que baticonsprite.svg ?
  • S’agit-il de deux façons alternatives de faire la même chose, et vous n’avez besoin d’en faire qu’une OU l’autre, pas les deux… ?

Dans l’étape 3 :

  • Mais alors maintenant, dans api.replaceIcon(), le deuxième paramètre n’utilise aucun des ID précédents, ni icons-sprite, ni bat-icon, ni baticonsprite.svg, ni my-icons.svg. Au lieu de cela, nous obtenons un tout nouvel my-theme-icon-bars… confus.
  • Le préfixe my-theme est-il requis, et si oui, d’où vient cette chaîne “nom du thème” ? Est-ce censé être my-theme-bat-icon ? Et qu’en est-il si c’est un composant, pas un thème ?
  • Et pour la partie icon-bars, est-ce censé être :
    • L’ID du symbole du XML de la spritesheet SVG
    • Le nom du fichier du fichier SVG
    • Le nom de la variable SCSS que vous lui donnez
    • Une combinaison des éléments ci-dessus (comme icons-sprite-bat-icon) ?

Et où placez-vous réellement l’appel api.replaceIcon() ? Est-il acceptable de le placer dans l’onglet “JS” d’un composant personnalisé, qui contient déjà le boilerplate :

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
   // votre code ici
});

Ou est-il nécessaire de créer une balise personnalisée <script type=”discourse/plugin”> et de la placer dans l’onglet <head> à la place ?


Désolé pour ma confusion ici.

J’ai essayé plusieurs combinaisons des éléments ci-dessus et je n’ai pas réussi à faire apparaître mon sprite, quoi que j’aie fait…

Mon XML de sprite ressemble à ceci :

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">


<symbol id="my-logo" viewBox="0 0 94.652 95.261"><defs><linearGradient id="a" y1="47.631" x2="94.652" y2="47.631" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ff593d"/><stop offset="1" stop-color="#ff7751"/></linearGradient></defs><title>d_only</title><path d="M47.326,0H0V95.261H47.326c23.67,0,47.326-21.326,47.326-47.624S71,0,47.326,0Zm0,69.274a21.644,21.644,0,1,1,21.65-21.637A21.635,21.635,0,0,1,47.326,69.274Z" fill="url(#a)"/></symbol>

</svg>

Le nom du fichier est my-logo.svg et le nom de la variable SCSS est également my-logo.

Et dans l’onglet JS du composant personnalisé, j’ai :

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
    api.replaceIcon("shield-halved", "my-logo")
});

Mais rien ne semble apparaître. Y a-t-il une étape que j’ai manquée, ou une sorte d’interpolation magique de chaîne que je ne comprends pas… ?

1 « J'aime »

Quelqu’un a-t-il réussi à comprendre cela ? Toujours en difficulté avec ceci…

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
    api.replaceIcon("shield-halved", "my-logo")
});

Je ne suis pas sûr d’où vient le deuxième identifiant (« my-logo ») si vous téléchargez le fichier via l’interface utilisateur :

Ni $my-logo, $test, my-logo.svg, l’URL absolue du SVG sur le disque, etc. ne fonctionnent. Le bouclier est bien remplacé, mais par rien. Le SVG devient simplement un \u003cuse href=”#my-logo”\u003e vide sans contenu.

1 « J'aime »

J’ai finalement trouvé la solution (merci, Claude) !

Donc :

  1. Le nom du fichier SVG n’a pas d’importance.

  2. À l’intérieur de la feuille de sprites SVG, c’est l’ID du symbole (id) qui détermine le nom final de l’icône, comme <symbol id=”my-logo” …>

  3. Mais le nom de la variable SCSS DOIT être exactement icons-sprite, PAS quelque chose en rapport avec les ID de la feuille de sprites finale :

  4. Une fois téléchargé, cela ressemblera à ceci :


    (Notez que le nom de la feuille de sprites / variable n’apparaît nulle part. Il doit être exactement $icons-sprite, le $ étant automatiquement ajouté et ne faisant pas partie de ce que vous avez saisi à l’étape précédente)

  5. Ensuite, enfin, dans l’onglet « JS » du thème (pas <head>), c’est là que vous utilisez l’ID de la feuille de sprites de l’étape 1 :

    import { apiInitializer } from “discourse/lib/api”;
    
    export default apiInitializer((api) => {
    api.replaceIcon(“shield-halved”, “my-logo”)
    });
    

Donc, le nom de la variable SCSS doit être exactement icons-sprite, le nom du fichier n’a pas d’importance, et le nom de l’icône de l’API est déterminé par l’ID du symbole à l’intérieur de la feuille de sprites.

3 « J'aime »