Avec l’aide de ChatGPT et de Claude, j’ai réussi à le faire fonctionner et à le rendre très personnalisable :
Si vous souhaitez le faire, créez un nouveau composant et ajoutez ceci à l’onglet CSS :
.sidebar-section-link-prefix .emoji.prefix-emoji {
width: 1rem !important;
height: 1rem !important;
}
Dans mon cas particulier, 1rem fonctionne très bien. Adaptez-le à votre forum/communauté.
Ensuite, dans l’onglet JS :
import { apiInitializer } from "discourse/lib/api";
import { emojiUrlFor } from "discourse/lib/text";
export default apiInitializer("0.11.1", (api) => {
// Mappe les noms de sections aux IDs
const sectionIds = {
"community": 1,
"tiago": 2,
"personal-section": 3,
// Ajoutez d'autres sections ici
};
// Mappe [sectionId, itemName] aux noms d'emojis
const iconReplacements = {
// Section Communauté (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",
// Section Tiago (ID: 2)
"2,Journal": "notebook_with_decorative_cover",
"2,Music": "musical_note",
"2,About": "bust_in_silhouette",
// Section Personnelle (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(',');
// Traite uniquement si ce remplacement concerne la section actuelle
if (parseInt(keyId) === sectionId) {
const url = emojiUrlFor(emojiName);
// Essaye plusieurs sélecteurs pour attraper le menu hamburger et la barre latérale fixe
const selectors = [
// Sélecteur de barre latérale fixe
`div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
// Sélecteur de menu hamburger (plus spécifique)
`.menu-panel div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
// Solution de repli générique
`[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) {
// Vérifie s'il a déjà été remplacé pour éviter des manipulations DOM inutiles
if (!prefix.querySelector('.prefix-emoji')) {
prefix.innerHTML = `
<img src="${url}"
title="${emojiName}"
alt="${emojiName}"
class="emoji prefix-emoji">
`;
}
break; // Sort de la boucle une fois l'icône trouvée et remplacée
}
}
}
});
});
}
// Exécute lors du changement de page
api.onPageChange(replaceIcons);
// Exécute également avec un délai pour attraper le contenu chargé dynamiquement
api.onPageChange(() => {
setTimeout(replaceIcons, 100);
setTimeout(replaceIcons, 500);
});
// MutationObserver amélioré pour attraper les changements de la barre latérale
const observer = new MutationObserver((mutations) => {
let shouldReplace = false;
mutations.forEach((mutation) => {
// Surveille les nœuds ajoutés (fonctionnalité d'origine)
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;
}
}
});
// Surveille les changements d'attributs sur les sections de la barre latérale (réduction/expansion)
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;
}
}
// Surveille les changements de childList dans les sections de la barre latérale
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);
}
});
// Commence l'observation avec des options améliorées
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true, // Surveille les changements d'attributs
attributeFilter: ['class', 'style', 'aria-expanded'], // Attributs courants qui changent lors de la réduction/expansion
});
// Écouteurs d'événements supplémentaires pour les interactions courantes de la barre latérale
document.addEventListener('click', (event) => {
// Vérifie si le clic a eu lieu sur un en-tête de section de la barre latérale ou un bouton de bascule
if (event.target.closest('.sidebar-section-header') ||
event.target.closest('[data-section-name]') ||
event.target.matches('.sidebar-section-toggle')) {
setTimeout(replaceIcons, 100);
}
});
});
J’ai fait en sorte de pouvoir facilement ajouter de nouvelles sections personnalisées par nom, en leur attribuant un id puis en créant la correspondance de chaque section.
La raison est que je peux avoir 2 sections avec le titre Journal, par exemple, mais je veux peut-être 2 emojis différents pour chacune.
Je suis à peu près sûr que quelqu’un dira qu’il existe un composant ou un plugin pour cela
mais c’était quand même amusant d’échanger avec ChatGPT et Claude jusqu’à ce que tout fonctionne comme je le voulais.
J’espère que cela aidera d’autres utilisateurs.
Si vous voyez quelque chose qui peut être ajusté/amélioré, n’hésitez pas à partager 