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

DiscourseのデフォルトのSVGアイコンは、1つずつ、または全体として、独自のカスタムSVGに置き換えることができます。これらはテーマまたはテーマコンポーネント内でオーバーライドできます。

ステップ 1 - SVGスプライトシートの作成

始めるにあたり、まずSVGスプライトシートを作成する必要があります。これには、1つの追加カスタムSVGアイコンから、数百個に及ぶ完全な置き換えセットまで、何でも含めることができます。

スプライトシートはSVGファイルとして保存してください。基本的には、元のSVGアイコンファイルの<svg>タグの内容を<symbol>タグにネストし、適切な識別子(ID)を付与します。

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="my-theme-icon-1">
    <!--
      ソースSVGアイコンファイルの<svg>タグ内のコード
      通常、これは<svg>タグの間にあるすべての要素です
      (ただし、<svg>タグ自体は除外し、上記の<symbol>に置き換えられます)
      属性(例: ViewBox="0 0 0 0")を<symbol>タグに移すことができます
      -->
  </symbol>

  <symbol id="my-theme-icon-2">
    <!-- ここにSVGコードを記述します。必要に応じて<symbol>ブロックを追加してください。
      -->
  </symbol>
</svg>
  • スプライトシート内の各シンボルにカスタムIDを追加してください。精神衛生のため、IDにテーマ名(例: my-theme-icon)をプレフィックスとして付けるのがおすすめです。

  • 既存のアイコンと同様に、アイコンの色を動的に変更できるようにするには、ハードコードされた色(例: #333)ではなく、fillをcurrentColorに設定してください。

  • アイコンをスケーリングしたり、正しく中央揃えにしたりするには、<symbol>タグにviewBox属性を使用してください。詳細は How to Scale SVG | CSS-Tricks を参照してください。

  • SVG内のスタイルの競合に注意してください。例えば、SVGには.st0{fill:#FF0000;}のようなインラインスタイルが定義されていることがよくあります。複数のSVGが同じクラスを使用している場合、問題が発生する可能性があります(これらの問題を修正するには、各アイコン固有のユニークなクラス名に変更してください)。

  • アイコンが多い場合、これを自動化する方法があります。 https://www.npmjs.com/package/svg-sprite-generator は、SVGをスプライトシートに結合するためのシンプルなコマンドラインツールです。

例 - 単一のカスタムアイコンのスプライトシート

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

ステップ 2 - スプライトシートをテーマに追加

スプライトシートが作成できたら、SVGファイルをコンポーネント/テーマに追加する必要があります。UI経由で行うことも、コンポーネント/テーマにハードコードすることも可能です。

:information_source: インストールされているコンポーネント/テーマにアップロードすると、<symbol>タグのIDを使用してインスタンス全体で使用できるようになります。

UI経由

テーマ/コンポーネント設定の「アップロード」セクションに移動し、SCSS変数名をicons-spriteとしてスプライトファイルを追加してください:

テーマ/コンポーネントにハードコード

スプライトシートファイルをテーマの/assetsフォルダに追加します。次に、ルートフォルダのassets.jsonファイルを更新してください。
my-icons.svgというSVGスプライトの場合、about.jsonには以下を含める必要があります:

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

ステップ 3(任意) - デフォルトアイコンのオーバーライド

スプライトシートが設定されたら、Discourseにアイコンの置き換えを指示できます。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");
  // 以下同様に
});

最初のID(bars)はDiscourseのデフォルトアイコンIDであり、2番目は置き換えアイコンのIDです。アイコンのIDを見つける最も簡単な方法は、ブラウザでアイコンを検査することです。

ここでは、アイコン名がd-icon-プレフィックスに従っています。したがって、この例ではd-unlikedになります。

私たちのアイコンの多くは https://fontawesome.com/ のアイコン名に従っていますが、例外もあります(そのため、インスペクタでIDを確認するのが最も信頼できる方法です)。すべての例外は、GitHub上の const REPLACEMENTS ブロックで確認できます。

以上です。これで、Discourseを独自のカスタムアイコンでスタイル化できます!


このドキュメントはバージョン管理されています - 変更提案は GitHub でお願いします。

「いいね!」 58

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

「いいね!」 1

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

Common / CSS

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

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

「いいね!」 4

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

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

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

「いいね!」 1

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

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

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

「いいね!」 2

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

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

「いいね!」 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-sprite、bat-icon、baticonsprite.svg、my-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")
});

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

「いいね!」 1

これを解決できた方はいらっしゃいますか?まだこれで苦戦しています…

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

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

UIからファイルをアップロードした場合、2番目のID(「my-logo」)がどこから来るのかわかりません。

$my-logo、$test、my-logo.svg、ディスク上のSVGへの絶対URLなどはどれも機能しません。shieldは置き換えられますが、何も表示されません。SVGはコンテンツのない空の<use href=”#my-logo”>になります。

「いいね!」 1

ついに解決しました(Claude、ありがとう)!

つまり:

  1. SVGのファイル名は関係ありません。

  2. SVGスプライトシート内では、最終的なアイコン名を決定するのはシンボル id です。例:\u003csymbol id=”my-logo” …\u003e

  3. ただし、SCSSの変数名は、最終的なスプライトシートIDとは一切関係なく、正確に icons-sprite である必要があります。

  4. アップロード後、次のようになります。


    (スプライトシート/変数名がどこにも見当たらないことに注意してください。前のステップで入力したものの一部ではなく、正確に $icons-sprite である必要があります)

  5. そして最後に、テーマの「JS」タブ(\u003chead\u003e ではない)で、ステップ1のspritesheet IDを使用します。

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

したがって、SCSSの変数名は正確に icons-sprite である必要があり、ファイル名は関係なく、APIのアイコン名はスプライトシート内のシンボルIDによって決定されます。

「いいね!」 3