تغيير حالة واحدة من الأيقونة

أعد نشر هذا المنشور القديم: Changing a single instance of an icon

أحتاج إلى تغيير حالات فردية للأيقونات في جميع أنحاء الموقع. لا أريد استخدام replaceIcon() وتجاوز جميع حالات تلك الأيقونة. أرى أنه في الماضي تم جعل هذا ممكنًا لمناطق معينة من الموقع، أو هكذا يبدو، ولكن ليس في جميع أنحاء الموقع.

على سبيل المثال، أريد تغيير إحدى أيقونات التروس في البحث لتعكس بشكل أفضل ما يحدث عندما ينقر عليها المستخدم. لا أريد تغيير جميع أيقونات التروس.

شكرا!

إعجاب واحد (1)

ألقِ نظرة على طلب السحب هذا، قد تتمكن من فعل شيء مشابه باستخدام CSS فقط:

3 إعجابات

يبدو هذا غير احترافي، كيف يعمل عند التنقل باستخدام لوحة المفاتيح فقط؟

إعجابَين (2)

عندما يكون المرء في الصحراء ولا يوجد ماء على ما يبدو، يمكن أن تكون الحيل مفيدة جدًا!

إعجابَين (2)

للأسف، نحن لسنا في الصحراء… نحن ندفع لاستخدام منصة لاستضافة موقع عام.

إعجابَين (2)

أيقونة، ما هي هذه الأيقونة تحديدًا (أين تظهر)؟ إذا بدا أن هناك حالة معقولة يمكن للآخرين الاستفادة منها، فيمكننا إنشاء اسم مستعار لها للسماح باستبدالها بشكل منفصل.

إعجابَين (2)

إليك مثال حيث لا يعكس الترس إجراء الزر لفتح صفحة البحث الموسعة:

إعجاب واحد (1)

نحن نستخدم أيقونة “sliders” هنا افتراضيًا (وهي الحالة الوحيدة لهذه الأيقونة في Discourse افتراضيًا) - لذا سيكون من الآمن استخدام replaceIcon() في هذه الحالة

image

نظرًا لعدم وجود واجهة برمجة تطبيقات لاستبدال الأيقونات الفردية، فإن أفضل طريقة لدعم ذلك اليوم هي تقييم الطلبات لإضافة أسماء مستعارة جديدة تجمع حالات الاستخدام المتشابهة.

على سبيل المثال، نستخدم d-liked كاسم مستعار لـ heart حتى يمكن استخدام replaceIcon() ضد d-liked لتغييرها في سياق الإعجاب، بدلاً من استبدال كل ظهور لأيقونة القلب في التطبيق.

سيكون من الجيد استبدال أي ظهور فردي، وهذا ليس موقفًا غير عادي في السمات - نأمل أن يكون لدينا واجهة برمجة تطبيقات لذلك يومًا ما.

رائع، يبدو أن فريق discourse قد غيّر إعداداتنا إلى ترس الإعدادات، لذا فقد قمت بإصلاحها! شكراً لك :pray:

إعجابَين (2)

حسنًا، يبدو أنني أفهم الآن ما هو الحكم في هذا الأمر. يؤسفني أن أعرف أنه غير متاح حتى يتم تحديث واجهة برمجة التطبيقات، لذا سأضطر إلى استخدام الطريقة التي اتبعتها في الوقت الحالي.

@awesomerobot إليك رمز محدث لما فعلته لتغيير أيقونة إنشاء الموضوع وهي علامة + بدون تغيير عام لجميع علامات +\n\n\n<script type=\"text/discourse-plugin\" version=\"0.8\">\n api.onPageChange(() => {\n const button = document.querySelector(\"#create-topic\");\n\n if (button) {\n // إخفاء الزر مؤقتًا أثناء استبدال الأيقونة\n button.style.display = \"none\";\n\n // البحث عن SVG داخل الزر\n const oldIcon = button.querySelector(\"svg\");\n if (oldIcon) {\n // إزالة الأيقونة الحالية (SVG)\n oldIcon.remove();\n }\n\n // إنشاء SVG جديد لأيقونة Font Awesome (fa-feather-pointed)\n const newIcon = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n newIcon.setAttribute(\"class\", \"fa d-icon d-icon-feather-pointed svg-icon svg-string\");\n newIcon.setAttribute(\"xmlns\", \"http://www.w3.org/2000/svg\");\n newIcon.innerHTML = '<use href=\"#feather-pointed\"></use>';\n\n // إدراج الأيقونة الجديدة داخل الزر\n button.insertBefore(newIcon, button.firstChild);\n\n // إظهار الزر مرة أخرى بعد استبدال الأيقونة\n button.style.display = \"block\";\n }\n });\n</script>\n\n\nيجب تحسينه قليلاً لتغيير أيقونات متعددة\n\n\n<script type=\"text/discourse-plugin\" version=\"0.8\">\n api.onPageChange(() => {\n // قائمة محددات الأزرار ومحتوى SVG المخصص المقابل\n const iconsToReplace = [\n { selector: \"#create-topic\", newSVG: `\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\">\n <path d=\"M12 2L15 5H13V9H11V5H9L12 2ZM3 12L5 10V13H9V15H5V18L3 16V12ZM21 12L19 10V13H15V15H19V18L21 16V12Z\"/>\n </svg>\n ` },\n { selector: \"#some-other-button\", newSVG: `\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\">\n <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\"/>\n </svg>\n ` },\n { selector: \"#another-button\", newSVG: `\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\">\n <path d=\"M12 2L8 6H10V10H14V6H16L12 2ZM12 12L8 16H10V20H14V16H16L12 12Z\"/>\n </svg>\n ` }\n ];\n\n iconsToReplace.forEach(icon => {\n const button = document.querySelector(icon.selector);\n\n if (button) {\n // إخفاء الزر مؤقتًا أثناء استبدال الأيقونة\n button.style.display = \"none\";\n\n // البحث عن SVG الحالي داخل الزر\n const oldIcon = button.querySelector(\"svg\");\n if (oldIcon) {\n // إزالة الأيقونة الحالية (SVG)\n oldIcon.remove();\n }\n\n // إنشاء عنصر SVG جديد وتعيين محتواه\n const newIcon = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n newIcon.innerHTML = icon.newSVG; // تعيين محتوى SVG المخصص\n\n // إدراج أيقونة SVG الجديدة داخل الزر\n button.insertBefore(newIcon, button.firstChild);\n\n // إظهار الزر مرة أخرى بعد استبدال الأيقونة\n button.style.display = \"block\";\n }\n });\n });\n</script>\n\n

يمكنك أيضًا استخدام 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 يطلق عند تغيير المسار.

وهذا قبل عملية العرض بشكل جيد.

لذلك هناك خطر من أن العناصر لن تكون معروضة قبل أن تحاول العثور عليها وتجاوزها.

قد تكون محظوظًا ولكن لا يضمن ذلك. ومن ثم يثير awesomerobot أنه سيكون من الجميل لو كانت هناك واجهة برمجة تطبيقات مخصصة …

(@Don أعتقد أن حلك لديه مشكلة مماثلة)

إعجابَين (2)

نعم، أنت على حق! هذا ليس مستقرًا جدًا. ربما يمكن أن يكون أكثر استقرارًا مع requestAnimationFrame أو MutationObserver؟ :thinking: ولكن نعم، الأفضل سيكون واجهة برمجة تطبيقات مخصصة كما ذكرت.

إعجابَين (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();

                // إنشاء وإدراج أيقونة SVG جديدة من Font Awesome
                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 للتأكد من أن البرنامج النصي يعمل فقط بمجرد وجود العنصر المستهدف فعليًا، ويقوم بقطع نفسه بعد القيام بعمله لتجنب الحمل الزائد غير الضروري. لا يزال يحاول إجراء فحص فوري في حال كان العنصر موجودًا بالفعل.

أنا غير قادر على جلب أيقونة SVG التي أريدها من نظام أيقونات Discourse، على الرغم من أنني سجلت مجموعة أيقونات SVG إدارية حيث يبدو أنها موجودة في Font Awesome ولكن ليس في Discourse.

إعجاب واحد (1)