Emoji nella sezione personalizzata

Sto usando le emoji nella sezione Categorie nella barra laterale, ma ho anche una sezione personalizzata che è pubblica. Volevo avere le stesse icone colorate anche in quella sezione, in modo che non sembrasse così “insipida” rispetto alla sezione Categorie.

È possibile?

2 Mi Piace

Con l’aiuto di ChatGPT e Claude, sono riuscito a farlo funzionare e a renderlo molto personalizzabile:

Se vuoi farlo, crea un nuovo componente e aggiungi questo alla scheda CSS:

.sidebar-section-link-prefix .emoji.prefix-emoji {
  width: 1rem !important;
  height: 1rem !important;
}

Nel mio caso particolare 1rem funziona benissimo. Adatta al tuo forum/community

Poi nella scheda JS:

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

export default apiInitializer("0.11.1", (api) => {
  // Mappa i nomi delle sezioni agli ID
  const sectionIds = {
    "community": 1,
    "tiago": 2,
    "personal-section": 3,
    // Aggiungi altre sezioni qui
  };
  
  // Mappa di [sectionId, itemName] ai nomi delle emoji
  const iconReplacements = {
    // Sezione Community (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",
    
    // Sezione Tiago (ID: 2)
    "2,Journal": "notebook_with_decorative_cover",
    "2,Music": "musical_note",
    "2,About": "bust_in_silhouette",
    
    // Sezione Personale (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(',');
        
        // Elabora solo se questa sostituzione è per la sezione corrente
        if (parseInt(keyId) === sectionId) {
          const url = emojiUrlFor(emojiName);
          
          // Prova più selettori per catturare sia il menu hamburger che la barra laterale fissa
          const selectors = [
            // Selettore barra laterale fissa
            `div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
            // Selettore menu hamburger (più specifico)
            `.menu-panel div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
            // Fallback generico
            `[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) {
              // Controlla se è già stato sostituito per evitare manipolazioni non necessarie del DOM
              if (!prefix.querySelector('.prefix-emoji')) {
                prefix.innerHTML = `
                  <img src="${url}"
                       title="${emojiName}"
                       alt="${emojiName}"
                       class="emoji prefix-emoji">
                `;
              }
              break; // Esci dal ciclo una volta trovata e sostituita l'icona
            }
          }
        }
      });
    });
  }

  // Esegui al cambio pagina
  api.onPageChange(replaceIcons);
  
  // Esegui anche con un ritardo per catturare contenuti caricati dinamicamente
  api.onPageChange(() => {
    setTimeout(replaceIcons, 100);
    setTimeout(replaceIcons, 500);
  });

  // MutationObserver potenziato per catturare le modifiche alla barra laterale
  const observer = new MutationObserver((mutations) => {
    let shouldReplace = false;
    
    mutations.forEach((mutation) => {
      // Osserva i nodi aggiunti (funzionalità originale)
      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;
          }
        }
      });
      
      // Osserva le modifiche agli attributi nelle sezioni della barra laterale (espandi/comprimi)
      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;
        }
      }
      
      // Osserva le modifiche a childList nelle sezioni della barra laterale
      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);
    }
  });

  // Avvia l'osservazione con opzioni potenziate
  observer.observe(document.body, {
    childList: true,
    subtree: true,
    attributes: true, // Osserva le modifiche agli attributi
    attributeFilter: ['class', 'style', 'aria-expanded'], // Attributi comuni che cambiano con espandi/comprimi
  });

  // Listener di eventi aggiuntivi per interazioni comuni della barra laterale
  document.addEventListener('click', (event) => {
    // Controlla se il clic è avvenuto sull'intestazione di una sezione della barra laterale o su un pulsante di attivazione
    if (event.target.closest('.sidebar-section-header') ||
        event.target.closest('[data-section-name]') ||
        event.target.matches('.sidebar-section-toggle')) {
      setTimeout(replaceIcons, 100);
    }
  });
});

Ho fatto in modo di poter aggiungere facilmente nuove sezioni personalizzate per nome, attribuendogli un id e creando poi la mappatura di ciascuna sezione.
Il motivo è che potrei avere 2 sezioni con il titolo Journal, ad esempio, ma magari voglio 2 emoji diverse per ciascuna.

Sono abbastanza sicuro che qualcuno dirà che esiste un componente o un plugin per questo :wink: ma è stato comunque divertente andare avanti e indietro con ChatGPT e Claude finché tutto non ha funzionato come volevo.

Spero che questo aiuti altri utenti.

Se vedi qualcosa che può essere modificato/migliorato, per favore condividilo :raising_hands:

3 Mi Piace

Ho appena aggiornato il codice JS, perché ho notato che su mobile venivano ancora mostrate le icone predefinite. Tutto funziona come previsto sia su mobile che su desktop.

Un’altra modifica: quando collassavo ed espandevo la sezione, le emoji scomparivano e venivano sostituite con le icone originali. Ora funziona e ho aggiornato di nuovo il codice JS.

Sono contento che tu abbia trovato un modo per farlo: penso che si adatterebbe abbastanza naturalmente a una funzionalità principale, ora che supportiamo le emoji per le categorie.

3 Mi Piace

Sono d’accordo. Spero che diventi una funzionalità nativa prima o poi. Fino ad allora, questo componente personalizzato sta facendo il suo dovere :slight_smile:

2 Mi Piace

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.