Standard-SVG-Icons von Discourse in einem Theme durch benutzerdefinierte Icons ersetzen

Sie können die Standard-SVG-Symbole von Discourse einzeln oder als Ganzes durch Ihre eigenen benutzerdefinierten SVGs ersetzen und sie innerhalb eines Themes oder Theme-Komponenten überschreiben.

Schritt 1 – Erstellen eines SVG-Spritesheets

Um zu beginnen, müssen Sie ein SVG-Spritesheet erstellen. Dieses kann alles enthalten, von einem einzelnen zusätzlichen benutzerdefinierten SVG-Symbol bis hin zu einem vollständigen Ersatzsatz von Hunderten.

Das Spritesheet sollte als SVG-Datei gespeichert werden. Im Prinzip verschachteln Sie den Inhalt des \u003csvg\u003e-Tags aus der ursprünglichen SVG-Icon-Datei in \u003csymbol\u003e-Tags und geben ihnen eine schöne Kennung.

<?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 innerhalb des \u003csvg\u003e-Tags aus der Quell-SVG-Icon-Datei
      dies ist typischerweise alles zwischen den \u003csvg\u003e-Tags
      (aber nicht das SVG-Tag selbst, das wird oben durch \u003csymbol\u003e ersetzt)
      Sie können alle Attribute (d.h. ViewBox="0 0 0 0") auf das \u003csymbol\u003e-Tag übertragen
      -->
  </symbol>

  <symbol id="my-theme-icon-2">
    <!-- SVG-Code hier. Fügen Sie bei Bedarf weitere \u003csymbol\u003e-Blöcke hinzu.
      -->
  </symbol>
</svg>
  • Stellen Sie sicher, dass Sie jedem Symbol im Spritesheet eine benutzerdefinierte ID hinzufügen. Es ist wahrscheinlich hilfreich für Ihre Übersichtlichkeit, Ihre IDs mit Ihrem Themanamen zu präfixen, z. B. my-theme-icon.

  • Damit die Icon-Farbe dynamisch ist wie bei den vorhandenen Icons, setzen Sie fill auf currentColor anstatt auf eine fest codierte Farbe (wie #333).

  • Um Ihr Icon zu skalieren oder korrekt zu zentrieren, verwenden Sie ein viewBox-Attribut für das \u003csymbol\u003e-Tag. Weitere Informationen finden Sie unter How to Scale SVG | CSS-Tricks.

  • Achten Sie auf Stilkonflikte innerhalb Ihrer SVGs. SVGs haben beispielsweise oft einen Inline-Stil wie .st0{fill:#FF0000;} definiert. Wenn Sie mehrere SVGs verwenden, die dieselben Klassen verwenden, kann dies zu Problemen führen (um diese Probleme zu beheben, bearbeiten Sie die Klassen so, dass sie für jedes Icon eindeutig sind).

  • Wenn Sie viele Icons haben, gibt es Möglichkeiten, dies zu automatisieren. https://www.npmjs.com/package/svg-sprite-generator ist ein einfaches Befehlszeilenwerkzeug zum Kombinieren von SVGs in ein Spritesheet.

Beispiel – Spritesheet mit einem einzelnen benutzerdefinierten Icon

<?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>

Schritt 2 – Hinzufügen des Spritesheets zu Ihrem Theme

Sobald Ihr Spritesheet erstellt ist, müssen Sie die SVG-Datei zu Ihrer Komponente/Ihrem Theme hinzufügen. Dies ist einfach über die Benutzeroberfläche möglich, oder Sie können es fest in eine Komponente/ein Theme codieren.

:information_source: Sobald es zu einer installierten Komponente/einem Theme hochgeladen wurde, ist es in Ihrer gesamten Instanz über die ID im \u003csymbol\u003e-Tag verfügbar.

Über die Benutzeroberfläche

Gehen Sie zum Abschnitt „Uploads“ der Theme-/Komponenten-Einstellungen und fügen Sie Ihre Sprite-Datei mit dem SCSS-Variablennamen icons-sprite hinzu:

Festcodiert in ein Theme / eine Komponente

Fügen Sie die Spritesheet-Datei in den /assets-Ordner des Themes ein. Aktualisieren Sie dann Ihre assets.json-Datei im Stammordner.
Für ein SVG-Sprite namens my-icons.svg sollte Ihre about.json Folgendes enthalten:

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

Schritt 3 (Optional) – Überschreiben von Standard-Icons

Nachdem Ihr Spritesheet festgelegt ist, können Sie Discourse anweisen, Icons zu ersetzen. So geht das über einen 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");
  // usw.
});

Die erste ID, bars, ist die Standard-Icon-ID in Discourse, und die zweite ist die ID Ihres Ersatz-Icons. Der einfachste Weg, eine ID eines unserer Icons zu finden, besteht darin, das Icon in Ihrem Browser zu inspizieren.

Hier folgt der Icon-Name dem Präfix d-icon-. In diesem Beispiel ist es also d-unliked

Die meisten unserer Icons folgen den Icon-Namen von https://fontawesome.com/, aber es gibt Ausnahmen (weshalb die Überprüfung der ID in Ihrem Inspektor die zuverlässigste Methode ist). Alle Ausnahmen finden Sie im Block const REPLACEMENTS hier auf github.

Das war’s. Sie können Discourse jetzt mit Ihren eigenen benutzerdefinierten Icons gestalten!


Dieses Dokument wird versioniert – schlagen Sie Änderungen auf github vor.

57 „Gefällt mir“

Wie kann man ein bestimmtes Symbol in einem bestimmten Element ansprechen? In meinem Fall möchte ich das Docs-Symbol im Sidebar-Menü durch ein anderes FA-Symbol ersetzen.

Ich würde es mit CSS ausblenden und einen neuen Button dafür hinzufügen.

Common / CSS

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

Fügen Sie einen neuen Button in Mehr > Diesen Abschnitt anpassen hinzu

3 „Gefällt mir“

Das funktioniert nicht. Ich habe versucht:

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

von hier, aber es scheint nicht zu funktionieren. Ich glaube, die Skript-Tag-Methode ist kaputt, da dies mit dem Vorschau-Link nicht funktioniert. Ehrlich gesagt, ich bin mir nicht sicher.

works for me :woman_shrugging:t2:

steckst du es in den Kopf-Tab? ich habe auch den Roboter in meinem Header ersetzt:

du musst das Icon möglicherweise zur Admin-Einstellung SVG icon subset hinzufügen.

1 „Gefällt mir“

Ja, im Kopf-Tab. Und im Header-Tab, da die Anleitung das besagt.

Erledigt. Es funktioniert jetzt. Danke!

1 „Gefällt mir“

@NateDhaliwal Könnten Sie mir bitte eine private Nachricht senden? Ich brauche Hilfe bei etwas und sehe keine Chat-Option in Ihrem Profil. Danke!

1 „Gefällt mir“
Für das linke Menü definieren wir den Hintergrund des Elements mit der Klasse prefix-span innerhalb der Kategorie Audi neu */
.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;

Wenn ich auf die Hauptseite klicke, erscheint das quadratische Symbol wieder! Können Sie mir sagen, was ich falsch mache? Und auf der Kategorieseite selbst funktioniert es.

Hallo, könnte mir bitte jemand die Beziehung zwischen einem Theme-/Komponenten-Namen, einem Dateinamen, einem SCSS-Variablennamen und der Symbol-ID erläutern?

Ich versuche, das Moderator-Icon shield-halved durch eines unserer eigenen zu ersetzen, aber die Anweisungen sind etwas unklar.

In Schritt 2:

  • Der Screenshot unter „Über die Benutzeroberfläche“ zeigt einen Dateinamen von baticonsprite.svg mit einem SCSS-Variablennamen von icons-sprite.
  • Aber dann wird unter „Hardcode in ein Theme“ erklärt, wie man es in ein Theme/eine Komponente hartkodiert.
  • Aber wie? Ich sehe keine assets.json-Datei im Editor. Wenn ich die Komponente exportiere, sehe ich eine about.json, die den über die Benutzeroberfläche hochgeladenen Sprite anzeigt.
  • Aber dieses Beispiel zeigt auch einen anderen Dateinamen von /assets/my-icons.svg – soll das dieselbe Datei wie baticonsprite.svg sein?
  • Sind dies zwei alternative Wege, um dasselbe zu tun, und man muss nur das eine ODER das andere tun, nicht beides…?

In Schritt 3:

  • Aber dann verwendet der zweite Parameter in api.replaceIcon() keine der vorherigen IDs, weder icons-sprite noch bat-icon oder baticonsprite.svg oder my-icons.svg. Stattdessen erhalten wir ein völlig neues my-theme-icon-bars… verwirrt.
  • Ist das Präfix my-theme erforderlich, und wenn ja, woher stammt dieser „Theme-Name“-String? Ist er als my-theme-bat-icon gedacht? Und was ist, wenn es sich um eine Komponente und nicht um ein Theme handelt?
  • Und für den Teil icon-bars, soll es sein:
    • Die Symbol-ID aus dem SVG-Spritesheet-XML
    • Der Dateiname der SVG-Datei
    • Der SCSS-Variablenname, den Sie ihm geben
    • Eine Kombination aus den oben genannten (wie icons-sprite-bat-icon?)

Und wo platziert man den Aufruf api.replaceIcon()? Ist es in Ordnung, ihn im „JS“-Tab einer benutzerdefinierten Komponente zu platzieren, die bereits den Boilerplate-Code enthält:

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

export default apiInitializer((api) => {
   // dein Code hier
});

Oder ist es notwendig, ein benutzerdefiniertes <script type=”discourse/plugin”>-Tag zu erstellen und dieses stattdessen im <head>-Tab zu platzieren?


Entschuldigung für meine Verwirrung hier.

Ich habe mehrere Kombinationen der oben genannten versucht und konnte meinen Sprite nicht anzeigen lassen, egal was ich tat…

Mein Sprite-XML sieht so aus:

<?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>

Der Dateiname ist my-logo.svg und der SCSS-Variablenname ist ebenfalls my-logo.

Und im JS-Tab der benutzerdefinierten Komponente habe ich:

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

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

Aber es scheint nichts angezeigt zu werden. Fehlt ein Schritt oder verstehe ich eine Art magische String-Interpolation falsch…?