أنا أستخدم الرموز التعبيرية في قسم الفئات في الشريط الجانبي، ولكن لدي أيضًا قسم مخصص عام. أردت أن أحصل على نفس الأيقونات الملونة في هذا القسم حتى لا يبدو “باهتًا” مقارنة بقسم الفئات.
هل هذا ممكن؟
أنا أستخدم الرموز التعبيرية في قسم الفئات في الشريط الجانبي، ولكن لدي أيضًا قسم مخصص عام. أردت أن أحصل على نفس الأيقونات الملونة في هذا القسم حتى لا يبدو “باهتًا” مقارنة بقسم الفئات.
هل هذا ممكن؟
بمساعدة كل من ChatGPT و Claude، تمكنت من جعله يعمل وقابل للتخصيص للغاية:
إذا كنت ترغب في القيام بذلك، قم بإنشاء مكون جديد وأضف هذا إلى علامة التبويب CSS:
.sidebar-section-link-prefix .emoji.prefix-emoji {
width: 1rem !important;
height: 1rem !important;
}
في حالتي الخاصة، يعمل
1remبشكل رائع. اضبطه ليناسب منتدى/مجتمعك
ثم في علامة التبويب JS:
import { apiInitializer } from "discourse/lib/api";
import { emojiUrlFor } from "discourse/lib/text";
export default apiInitializer("0.11.1", (api) => {
// Map section names to IDs
const sectionIds = {
"community": 1,
"tiago": 2,
"personal-section": 3,
// Add more sections here
};
// Map of [sectionId, itemName] to emoji names
const iconReplacements = {
// Community section (ID: 1)
"1,admin": "wrench",
"1,review": "triangular_flag_on_post",
"1,everything": "books",
"1,my-posts": "writing_hand",
"1,my-messages": "envelope_with_arrow",
// Tiago section (ID: 2)
"2,Journal": "notebook_with_decorative_cover",
"2,Music": "musical_note",
"2,About": "bust_in_silhouette",
// Personal section (ID: 3)
"3,Backups": "floppy_disk",
"3,Scheduled": "clock3",
"3,Staff": "lock",
"3,Components": "electric_plug",
};
function replaceIcons() {
Object.entries(sectionIds).forEach(([sectionName, sectionId]) => {
Object.entries(iconReplacements).forEach(([key, emojiName]) => {
const [keyId, itemName] = key.split(',');
// Only process if this replacement is for the current section
if (parseInt(keyId) === sectionId) {
const url = emojiUrlFor(emojiName);
// Try multiple selectors to catch both hamburger menu and fixed sidebar
const selectors = [
// Fixed sidebar selector
`div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
// Hamburger menu selector (more specific)
`.menu-panel div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
// Generic fallback
`[data-section-name="${sectionName}"] [data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`
];
for (const selector of selectors) {
const prefix = document.querySelector(selector);
if (prefix && url) {
// Check if it's already replaced to avoid unnecessary DOM manipulation
if (!prefix.querySelector('.prefix-emoji')) {
prefix.innerHTML = `
<img src="${url}"
title="${emojiName}"
alt="${emojiName}"
class="emoji prefix-emoji">
`;
}
break; // Exit loop once we find and replace the icon
}
}
}
});
});
}
// Run on page change
api.onPageChange(replaceIcons);
// Also run with delay to catch dynamically loaded content
api.onPageChange(() => {
setTimeout(replaceIcons, 100);
setTimeout(replaceIcons, 500);
});
// Enhanced MutationObserver to catch sidebar changes
const observer = new MutationObserver((mutations) => {
let shouldReplace = false;
mutations.forEach((mutation) => {
// Watch for added nodes (original functionality)
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.classList?.contains('menu-panel') ||
node.querySelector?.('.sidebar-sections') ||
node.classList?.contains('sidebar-sections') ||
node.querySelector?.('[data-section-name]')) {
shouldReplace = true;
}
}
});
// Watch for attribute changes on sidebar sections (collapse/expand)
if (mutation.type === 'attributes' && mutation.target.nodeType === Node.ELEMENT_NODE) {
const target = mutation.target;
if (target.matches('[data-section-name]') ||
target.closest('[data-section-name]') ||
target.matches('.sidebar-section') ||
target.closest('.sidebar-section')) {
shouldReplace = true;
}
}
// Watch for childList changes in sidebar sections
if (mutation.type === 'childList' && mutation.target.nodeType === Node.ELEMENT_NODE) {
const target = mutation.target;
if (target.matches('[data-section-name]') ||
target.closest('[data-section-name]') ||
target.querySelector('[data-section-name]')) {
shouldReplace = true;
}
}
});
if (shouldReplace) {
setTimeout(replaceIcons, 50);
}
});
// Start observing with enhanced options
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true, // Watch for attribute changes
attributeFilter: ['class', 'style', 'aria-expanded'], // Common attributes that change on collapse/expand
});
// Additional event listeners for common sidebar interactions
document.addEventListener('click', (event) => {
// Check if click was on a sidebar section header or toggle button
if (event.target.closest('.sidebar-section-header') ||
event.target.closest('[data-section-name]') ||
event.target.matches('.sidebar-section-toggle')) {
setTimeout(replaceIcons, 100);
}
});
});
لقد جعلتها بحيث يمكنني بسهولة إضافة أقسام مخصصة جديدة بالاسم، وتعيين id لها ثم إنشاء تعيين لكل قسم.
السبب في ذلك هو أنه قد يكون لدي قسمان بعنوان “Journal”، على سبيل المثال، ولكن ربما أريد رمزين تعبيريين مختلفين لكل منهما.
أنا متأكد من أن هناك من سيقول أن هناك مكونًا أو إضافة لهذا الغرض ؛) ولكن لا يزال من الممتع العودة إلى الوراء مع ChatGPT و Claude حتى يعمل كل شيء بالطريقة التي أردتها.
آمل أن يساعد هذا المستخدمين الآخرين.
إذا رأيت أي شيء يمكن تعديله/تحسينه، فيرجى مشاركته
لقد قمت للتو بتحديث كود JavaScript، لأنني لاحظت أنه لا يزال يعرض الأيقونات الافتراضية على الهاتف المحمول. كل شيء يعمل كما هو متوقع على كل من الهاتف المحمول وسطح المكتب.
تعديل آخر: عندما كنت أقوم بطي وتوسيع القسم، كانت الرموز التعبيرية تختفي وتستبدل بالأيقونات الأصلية. إنها تعمل الآن وقمت بتحديث كود جافاسكريبت مرة أخرى.
يسرني أنك وجدت طريقة للقيام بذلك - أعتقد أن هذا سيكون مناسبًا جدًا كميزة أساسية، الآن بعد أن أصبحنا ندعم الرموز التعبيرية للفئات.
أتفق. آمل أن تصبح هذه ميزة أصلية في النهاية. حتى يحدث ذلك، فإن هذه المكونات المخصصة تؤدي الغرض منها ![]()
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.