アイコンの単一インスタンスを変更

この古い投稿を再度表示してください: Changing a single instance of an icon

サイト全体でアイコンの単一のインスタンスを変更する必要があります。replaceIcon() を使用して、そのアイコンのすべてのインスタンスをオーバーライドしたくありません。過去には、サイトの特定の部分でこれが可能であったと見られますが、サイト全体ではありません。

たとえば、ユーザーがクリックしたときに何が起こるかをよりよく反映するために、検索内の歯車アイコンの1つを変更したいと思います。すべての歯車アイコンを変更したくありません。

よろしくお願いします!

「いいね!」 1

CSSだけで同様のことを行えるかもしれないので、このPRを見てみてください。

「いいね!」 3

これはハッキーに思えますが、タブで移動したりキーボードのみを使用したりするとどうなりますか?

「いいね!」 2

砂漠にいて、明らかに水がない場合、ハックは非常に役立ちます!

「いいね!」 2

残念ながら、私たちは砂漠にいるわけではありません…公開サイトをホストするためのプラットフォームを使用するためにお金を払っています。

「いいね!」 2

これは具体的にどのアイコンですか(どこに表示されますか)? 他の人が役立つと思われる合理的なケースがある場合は、個別に置き換えることができるようにエイリアスを作成できます。

「いいね!」 2

展開された検索ページを開くボタンのアクションをコグが反映していない例を次に示します。

「いいね!」 1

デフォルトでは「sliders」アイコンを使用しています(そして、これはデフォルトでDiscourseにおけるこのアイコンの唯一の出現箇所です) — そのため、この場合はreplaceIcon()を使用しても安全です。

image

個々のアイコンを置き換えるAPIがないため、現在これをサポートする最善の方法は、類似のユースケースをグループ化する新しいエイリアスを追加するリクエストを評価することです。

たとえば、heartのエイリアスとしてd-likedを使用しているため、アプリ全体でheartアイコンのすべての出現箇所を置き換えるのではなく、d-likedに対してreplaceIcon()を使用してlikeコンテキストで変更できます。

ただし、テーマでは珍しくない単一の出現箇所を置き換えることができれば良いのですが、いつかそれに対応するAPIができることを願っています。

素晴らしい、Discourseチームが設定の歯車に変更したようですので、修正しました!ありがとうございます :pray:

「いいね!」 2

これで理解できたと思いますが、結論はどうなりますか。APIのアップデートまで利用できないと知って残念ですが、当面はこれまで行ってきた方法を使用します。

@awesomerobot + をグローバルに変更せずに作成トピックアイコンを変更するために行ったことの更新されたコードを次に示します。

<script type="text/discourse-plugin" version="0.8">
    api.onPageChange(() => {
        const button = document.querySelector("#create-topic");

        if (button) {
            // アイコンを置き換えている間、一時的にボタンを非表示にします
            button.style.display = "none";

            // ボタン内のSVGを探します
            const oldIcon = button.querySelector("svg");
            if (oldIcon) {
                // 既存のアイコン(SVG)を削除します
                oldIcon.remove();
            }

            // Font Awesomeアイコン(fa-feather-pointed)用の新しいSVGを作成します
            const newIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            newIcon.setAttribute("class", "fa d-icon d-icon-feather-pointed svg-icon svg-string");
            newIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
            newIcon.innerHTML = '<use href="#feather-pointed"></use>';

            // 新しいアイコンをボタン内に挿入します
            button.insertBefore(newIcon, button.firstChild);

            // アイコンの置き換え後にボタンを再度表示します
            button.style.display = "block";
        }
    });
</script>

複数のアイコン変更のために、もう少し調整する必要があります。

<script type="text/discourse-plugin" version="0.8">
    api.onPageChange(() => {
        // 置き換えるボタンのセレクターと対応するカスタムSVGコンテンツのリスト
        const iconsToReplace = [
            { selector: "#create-topic", newSVG: `
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
                    <path d="M12 2L15 5H13V9H11V5H9L12 2ZM3 12L5 10V13H9V15H5V18L3 16V12ZM21 12L19 10V13H15V15H19V18L21 16V12Z" />
                </svg>
            ` },
            { selector: "#some-other-button", newSVG: `
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
                    <path d="M21 3H3C2.44772 3 2 3.44772 2 4V20C2 20.5523 2.44772 21 3 21H21C21.5523 21 22 20.5523 22 20V4C22 3.44772 21.5523 3 21 3ZM20 19H4V5H20V19Z" />
                </svg>
            ` },
            { selector: "#another-button", newSVG: `
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
                    <path d="M12 2L8 6H10V10H14V6H16L12 2ZM12 12L8 16H10V20H14V16H16L12 12Z" />
                </svg>
            ` }
        ];

        iconsToReplace.forEach(icon => {
            const button = document.querySelector(icon.selector);

            if (button) {
                // アイコンを置き換えている間、一時的にボタンを非表示にします
                button.style.display = "none";

                // ボタン内の既存のSVGを探します
                const oldIcon = button.querySelector("svg");
                if (oldIcon) {
                    // 既存のアイコン(SVG)を削除します
                    oldIcon.remove();
                }

                // 新しいSVG要素を作成し、その内容を設定します
                const newIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
                newIcon.innerHTML = icon.newSVG; // カスタムSVGコンテンツを設定します

                // 新しいSVGアイコンをボタン内に挿入します
                button.insertBefore(newIcon, button.firstChild);

                // アイコンの置き換え後にボタンを再度表示します
                button.style.display = "block";
            }
        });
    });
</script>

iconHTML を使用して、アイコンを手動で追加する代わりに、次のようにすることもできます。

import { apiInitializer } from "discourse/lib/api";
import { iconHTML } from "discourse/lib/icon-library";

export default apiInitializer((api) => {
  api.onPageChange(() => {
    const btnIcon = document.querySelector("#create-topic .d-icon");
    if (btnIcon) {
      btnIcon.outerHTML = iconHTML("plus");
    }
  });
});
「いいね!」 1

これは少し不安定になる可能性があります。

api.onPageChange がルート変更時に発生していると思います。

これはレンダリングよりもずっと前です。

そのため、要素がレンダリングされる前にそれらを見つけて上書きしようとするリスクがあります。

運が良ければうまくいくかもしれませんが、保証はありません。そのため、専用のAPIがあれば良いということをawesomerobotが指摘しています…

@Don あなたのソリューションにも同様の問題があると思います)

「いいね!」 2

そうですね、おっしゃる通りです!これはあまり安定していませんね。requestAnimationFrameMutationObserver を使えば、もっと安定させられるかもしれませんね?:thinking: でも、おっしゃる通り、専用のAPIが一番良いでしょうね。

「いいね!」 2

指摘してくれてありがとう。あなたは完全に正しいです。api.onPageChange だけを使用するのは信頼性が低い可能性があります。これは DOM レンダリング後ではなく、ルート変更時に発生するためです。これにより、スクリプトが #create-topic ボタンにアクセスしようとしたときに、ボタンがまだ存在しないという競合状態のリスクが生じます。

 api.onPageChange(() => {
        const targetSelector = "#create-topic";

        const tryEnhanceButton = () => {
            const button = document.querySelector(targetSelector);

            if (button) {
                // 要素が見つかったらオブザーバーを切断
                observer.disconnect();

                // アイコンを置き換える間、一時的にボタンを非表示にする
                button.style.display = "none";

                // 古いアイコンがあれば削除
                const oldIcon = button.querySelector("svg");
                if (oldIcon) oldIcon.remove();

                // 新しいFont Awesome SVGアイコンを作成して挿入
                const newIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
                newIcon.setAttribute("class", "fa d-icon d-icon-feather-pointed svg-icon svg-string");
                newIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
                newIcon.innerHTML = '<use href="#feather-pointed"></use>';

                button.insertBefore(newIcon, button.firstChild);

                // ボタンを再度表示
                button.style.display = "block";
            }
        };

        // DOMの変更を監視し、ターゲット要素が追加されたらボタンを強化しようとする
        const observer = new MutationObserver(() => tryEnhanceButton());
        observer.observe(document.body, { childList: true, subtree: true });

        // 要素が既に存在する場合に備えて、すぐに試行する
        tryEnhanceButton();
    });

@Don MutationObserver を含めました。これにより、ターゲット要素が実際に存在するまでスクリプトが実行されないようになり、ジョブが完了したら不要なオーバーヘッドを避けるために自己切断されます。要素が既に存在する場合に備えて、即時チェックも試行されます。

Discourse のアイコンシステムから目的の SVG を取得できません。管理者の SVG アイコンサブセットに登録しましたが、Font Awesome には存在するものの、Discourse には存在しないようです。

「いいね!」 1