Emojis na Seção Personalizada

Estou usando emojis na seção Categorias na barra lateral, mas também tenho uma seção personalizada que é pública. Eu queria ter os mesmos ícones coloridos nessa seção para que ela não fique tão “sem graça” em comparação com a seção Categorias.

Isso é possível?

2 curtidas

Com a ajuda do ChatGPT e do Claude, consegui fazer funcionar e ser muito personalizável:

Se você quiser fazer isso, crie um novo componente e adicione isto à aba CSS:

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

No meu caso particular, 1rem funciona muito bem. Ajuste para o seu fórum/comunidade

Em seguida, na aba JS:

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

export default apiInitializer("0.11.1", (api) => {
  // Mapeia nomes de seções para IDs
  const sectionIds = {
    "community": 1,
    "tiago": 2,
    "personal-section": 3,
    // Adicione mais seções aqui
  };
  
  // Mapeamento de [sectionId, itemName] para nomes de emoji
  const iconReplacements = {
    // Seção da comunidade (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",
    
    // Seção Tiago (ID: 2)
    "2,Journal": "notebook_with_decorative_cover",
    "2,Music": "musical_note",
    "2,About": "bust_in_silhouette",
    
    // Seção Pessoal (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(',');
        
        // Processa apenas se esta substituição for para a seção atual
        if (parseInt(keyId) === sectionId) {
          const url = emojiUrlFor(emojiName);
          
          // Tenta vários seletores para capturar o menu hambúrguer e a barra lateral fixa
          const selectors = [
            // Seletor da barra lateral fixa
            `div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
            // Seletor do menu hambúrguer (mais específico)
            `.menu-panel div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
            // Fallback genérico
            `[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) {
              // Verifica se já foi substituído para evitar manipulação desnecessária do DOM
              if (!prefix.querySelector('.prefix-emoji')) {
                prefix.innerHTML = `
                  <img src="${url}"
                       title="${emojiName}"
                       alt="${emojiName}"
                       class="emoji prefix-emoji">
                `;
              }
              break; // Sai do loop assim que encontrarmos e substituirmos o ícone
            }
          }
        }
      });
    });
  }

  // Executa na mudança de página
  api.onPageChange(replaceIcons);
  
  // Também executa com atraso para capturar conteúdo carregado dinamicamente
  api.onPageChange(() => {
    setTimeout(replaceIcons, 100);
    setTimeout(replaceIcons, 500);
  });

  // MutationObserver aprimorado para capturar alterações na barra lateral
  const observer = new MutationObserver((mutations) => {
    let shouldReplace = false;
    
    mutations.forEach((mutation) => {
      // Observa nós adicionados (funcionalidade original)
      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;
          }
        }
      });
      
      // Observa alterações de atributos nas seções da barra lateral (fechar/abrir)
      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;
        }
      }
      
      // Observa alterações de childList em seções da barra lateral
      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);
    }
  });

  // Inicia a observação com opções aprimoradas
  observer.observe(document.body, {
    childList: true,
    subtree: true,
    attributes: true, // Observa alterações de atributos
    attributeFilter: ['class', 'style', 'aria-expanded'], // Atributos comuns que mudam ao fechar/abrir
  });

  // Ouvintes de eventos adicionais para interações comuns da barra lateral
  document.addEventListener('click', (event) => {
    // Verifica se o clique foi em um cabeçalho de seção da barra lateral ou botão de alternância
    if (event.target.closest('.sidebar-section-header') ||
        event.target.closest('[data-section-name]') ||
        event.target.matches('.sidebar-section-toggle')) {
      setTimeout(replaceIcons, 100);
    }
  });
});

Eu fiz de forma que eu possa adicionar facilmente novas seções personalizadas por nome, atribuindo um id e, em seguida, criando o mapeamento de cada seção.
O motivo para isso é que eu posso ter 2 seções com o título Journal, por exemplo, mas talvez eu queira 2 emojis diferentes para cada uma.

Tenho certeza de que haverá alguém dizendo que existe um componente ou plugin para isso :wink: mas ainda assim foi divertido ir e voltar com o ChatGPT e o Claude até que tudo funcionasse como eu queria.

Espero que isso ajude outros usuários.

Se você vir algo que possa ser ajustado/melhorado, por favor, compartilhe :raising_hands:

3 curtidas

Acabei de atualizar o código JS, pois notei que no celular ainda estavam sendo exibidos os ícones padrão. Tudo está funcionando como esperado tanto no celular quanto no desktop.

Outra edição: quando eu colapsava e expandia a seção, os emojis sumiam e eram substituídos pelos ícones originais. Agora está funcionando e atualizei o código JS novamente.

Fico feliz que você tenha encontrado uma maneira de fazer isso – acho que seria uma adaptação bastante natural para um recurso principal, agora que oferecemos suporte a emojis para categorias.

3 curtidas

Concordo. Espero que isso se torne um recurso nativo eventualmente. Até que isso aconteça, este componente personalizado está fazendo seu trabalho :slight_smile:

2 curtidas

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