DiscourseのデフォルトのSVGアイコンをテーマ内のカスタムアイコンに置き換える

You can replace a Discourse’s default SVG icons individually or as a whole with your own custom SVG and override them within a theme or theme component.

Step 1 - Create an SVG Spritesheet

To get started, you must create an SVG Spritesheet. This can contain anything from a single additional custom SVG icon up to an entire replacement set of hundreds.

The spritesheet should be saved as an SVG file. In principle, you are nesting the <svg> tag contents from the original SVG icon file into <symbol> tags and giving them a nice identifier.

<?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 inside the <svg> tag from the source SVG icon file
      this is typically everything between the <svg> tags
      (but not the SVG tag itself, that's replaced by <symbol> above)
      You can transfer any attributes (i.e. ViewBox="0 0 0 0") to the <symbol> tag
      -->
  </symbol>

  <symbol id="my-theme-icon-2">
    <!-- SVG code here. Add more <symbol> blocks as needed.
      -->
  </symbol>
</svg>
  • Be sure to add a custom ID to each symbol in the spritesheet. It’s probably helpful for your sanity to prefix your IDs with your theme name my-theme-icon.

  • To have the icon color to be dynamic like the existing icons, set the fill to currentColor rather than a hardcoded color (like #333)

  • To scale or correctly centre your icon, utilise a viewBox attribute on the <symbol> tag. See How to Scale SVG | CSS-Tricks for more information.

  • Be on the lookout for style collisions within your SVGs. For example, SVGs will often have an inline style like .st0{fill:#FF0000;} defined. If you have multiple SVGs using the same classes this can cause issues (to fix these issues, edit the classes to be unique to each icon).

  • If you have many icons, there are ways to automate this. svg-sprite-generator - npm is a simple command line tool for combining SVGs into a spritesheet.

Example - single custom icon spritesheet

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

Step 2 - Add the spritesheet to your theme

Once your spritesheet is built, you need to add the SVG file to your component/theme. This is easy via the UI, or you can hard code it into a component/theme.

:information_source: Once it is uploaded to any installed component/theme, it is available throughout your instance using the ID in the <symbol> tag.

Via the UI

Go to the Uploads section of the theme/component settings and add your sprite file with a SCSS var name of icons-sprite:

Hardcode into a Theme / Component

Add the spritesheet file to the Theme’s /assets folder. Then update your assets.json file in the root folder.
For an SVG sprite called my-icons.svg, your about.json should include this:

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

Step 3 (optional) - Overriding default icons

Now that your spritesheet is set, you can tell Discourse to replace icons. This is how you do it from an 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.
});

The first ID, bars, is the default icon ID in Discourse and the second is the ID of your replacement icon. The easiest way to find an ID of one of our icons is to inspect the icon in your browser.

Here the icon name follows the d-icon- prefix. So in this example it’s d-unliked

Most of our icons follow the icon names from https://fontawesome.com/, but there are exceptions (which is why checking the ID in your inspector is the most reliable method). You can see all the exceptions in the const REPLACEMENTS block here on github.

That’s it. You can now style Discourse with your own custom icons!


This document is version controlled - suggest changes on github.

「いいね!」 57

特定の要素内の特定のアイコンをどのようにターゲットにできますか?私の場合は、サイドバーメニューのドキュメントアイコンを別のFAアイコンに置き換えたいです。

CSSで非表示にして、新しいボタンを追加します。

Common / CSS

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

More > Customize this section で新しいボタンを追加します。

「いいね!」 3

これは機能しません。試してみたのは次のとおりです。

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

ここからですが、機能していないようです。プレビューリンクでこれが機能しないため、スクリプトタグの方法は壊れていると思います。正直よくわかりません。

私には機能します :woman_shrugging:t2:

ヘッドタブに入れていますか?ヘッダーのロボットも置き換えました。

管理者の SVG アイコンサブセット 設定にアイコンを追加する必要があるかもしれません。

「いいね!」 1

はい、ヘッドタブです。ガイドにそう書いてあるので、ヘッダータブでもあります。

完了しました。これで動作します。ありがとうございます!

「いいね!」 1

@NateDhaliwalさん、プライベートメッセージをいただけますか?何かお手伝いが必要なのですが、プロフィールにチャットオプションが見当たりません。ありがとうございます!

「いいね!」 1

左側のメニューでは、カテゴリ「Audi」内のプレフィックス-spanクラスを持つ要素の背景を再定義します */

.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;


メインページをクリックすると、正方形のアイコンが再び表示されます!何が間違っているのか教えていただけますか?カテゴリページ自体では機能します。

テーマ/コンポーネント名、ファイル名、SCSS変数名、シンボルIDの関係について、どなたか明確にしていただけますでしょうか?

モデレーターの shield-halved アイコンを自社のものに置き換えようとしていますが、手順が少し不明瞭です。

ステップ2では:

  • 「UI経由」(Replace Discourse's default SVG icons with custom icons in a theme icons-sprite のファイル名 baticonsprite.svg が表示されています。
  • しかし、「テーマにハードコードする」(Replace Discourse's default SVG icons with custom icons in a theme
    • しかし、どうすればよいのでしょうか?エディタに assets.json ファイルが見当たりません。コンポーネントをエクスポートすると、about.json が表示され、UI経由でアップロードしたスプライトが表示されます。
    • しかし、この例ではファイル名が /assets/my-icons.svg と異なっています。これは baticonsprite.svg と同じファイルのことでしょうか?
    • これら2つは同じことを行うための代替方法であり、両方ではなく、どちらか一方を行うだけでよいのでしょうか…?

ステップ3では:

  • しかし、api.replaceIcon() では、2番目のパラメータは、以前のID(icons-spritebat-iconbaticonsprite.svgmy-icons.svg のいずれでもありません)を使用していません。代わりに、まったく新しい my-theme-icon-bars が表示されます…混乱しています。
    • my-theme という接頭辞は必要ですか?もしそうなら、その「テーマ名」文字列はどこから来るのですか?例えば、my-theme-bat-icon となるべきでしょうか?テーマではなくコンポーネントの場合はどうなりますか?
    • そして、icon-bars の部分については、次のいずれかであるべきでしょうか?
      • SVGスプライトシートXMLのシンボルID
      • SVGファイルのファイル名
      • 指定したSCSS変数名
      • 上記のいずれかの組み合わせ(例:icons-sprite-bat-icon?)

そして、api.replaceIcon() の呼び出しはどこに配置すべきですか?カスタムコンポーネントの「JS」タブに配置しても問題ありませんか?そこにはすでに以下の定型文があります。

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

export default apiInitializer((api) => {
  // your code here
});

それとも、カスタム <script type=”discourse/plugin”> タグを作成し、それを <head> タブに配置する必要がありますか?


この件で混乱させてしまい申し訳ありません。

上記のいくつかの組み合わせを試しましたが、どんなに試してもスプライトが表示されませんでした…

私のスプライトXMLは次のようになっています。

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

ファイル名は my-logo.svg で、SCSS変数名も my-logo です。

そして、カスタムコンポーネントの「JS」タブには次のコードがあります。

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

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

しかし、何も表示されません。何か手順が抜けているのでしょうか、それとも理解できていない魔法の文字列補間があるのでしょうか…?