Reemplazar los iconos SVG predeterminados de Discourse con iconos personalizados en un tema

Puede reemplazar los iconos SVG predeterminados de Discourse individualmente o en su totalidad con su propio SVG personalizado y anularlos dentro de un tema o componente de tema.

Paso 1 - Crear una Hoja de Sprites SVG

Para empezar, debe crear una Hoja de Sprites SVG. Esta puede contener cualquier cosa, desde un único icono SVG personalizado adicional hasta un conjunto de reemplazo completo de cientos.

La hoja de sprites debe guardarse como un archivo SVG. En principio, está anidando el contenido de la etiqueta <svg> del archivo de icono SVG original dentro de etiquetas <symbol> y dándoles un identificador agradable.

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="my-theme-icon-1">
    <!--
      Código dentro de la etiqueta <svg> del archivo SVG de origen
      esto es típicamente todo lo que está entre las etiquetas <svg>
      (pero no la etiqueta SVG en sí, esa es reemplazada por <symbol> arriba)
      Puede transferir cualquier atributo (es decir, ViewBox="0 0 0 0") a la etiqueta <symbol>
      -->
  </symbol>

  <symbol id="my-theme-icon-2">
    <!-- Código SVG aquí. Agregue más bloques <symbol> según sea necesario.
      -->
  </symbol>
</svg>
  • Asegúrese de agregar un ID personalizado a cada símbolo en la hoja de sprites. Probablemente sea útil para su cordura anteponer a sus ID el nombre de su tema, por ejemplo, my-theme-icon.

  • Para que el color del icono sea dinámico como los iconos existentes, establezca el fill en currentColor en lugar de un color codificado (como #333)

  • Para escalar o centrar correctamente su icono, utilice un atributo viewBox en la etiqueta <symbol>. Consulte How to Scale SVG | CSS-Tricks para obtener más información.

  • Esté atento a las colisiones de estilos dentro de sus SVG. Por ejemplo, los SVG a menudo tendrán un estilo en línea como .st0{fill:#FF0000;} definido. Si tiene varios SVG que utilizan las mismas clases, esto puede causar problemas (para solucionar estos problemas, edite las clases para que sean únicas para cada icono).

  • Si tiene muchos iconos, existen formas de automatizar esto. https://www.npmjs.com/package/svg-sprite-generator es una herramienta simple de línea de comandos para combinar SVG en una hoja de sprites.

Ejemplo - hoja de sprites de un solo icono personalizado

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="bat-icon" viewBox="6 6 36 36">
    <path
      fill="currentColor"
      d="M24,18.2c0.7,0,0.9,0.2,0.9,0.2l0.4-1.7c0,0,0.4,1.5,0.4,2.8c0.2,1.1,2.2,0.4,3.9,0C31.4,19.1,32,16,32,16h16c0,0-9.4,3.5-7,10c0,0-14.8-2-17,7l0,0c-2.2-9-17-7-17-7c2.4-6.5-7-10-7-10h16c0,0,0.6,3.1,2.3,3.5c1.7,0.4,3.9,1.1,3.9,0c0.2-1.1,0.4-2.8,0.4-2.8l0.4,1.7C23.1,18.4,23.4,18.2,24,18.2L24,18.2L24,18.2z"
    />
  </symbol>
</svg>

Paso 2 - Agregar la hoja de sprites a su tema

Una vez que su hoja de sprites esté lista, debe agregar el archivo SVG a su componente/tema. Esto es fácil a través de la interfaz de usuario, o puede codificarlo en un componente/tema.

:information_source: Una vez que se carga en cualquier componente/tema instalado, está disponible en toda su instancia utilizando el ID en la etiqueta <symbol>.

A través de la interfaz de usuario

Vaya a la sección de Cargas (Uploads) de la configuración del tema/componente y agregue su archivo de sprite con un nombre de variable SCSS de icons-sprite:

Codificar en un Tema / Componente

Agregue el archivo de la hoja de sprites a la carpeta /assets del Tema. Luego actualice su archivo assets.json en la carpeta raíz.
Para un sprite SVG llamado my-icons.svg, su about.json debería incluir esto:

"assets": {
  "icons-sprite": "/assets/my-icons.svg"
}

Paso 3 (opcional) - Anular iconos predeterminados

Ahora que su hoja de sprites está configurada, puede indicarle a Discourse que reemplace los iconos. Así es como se hace desde un inicializador de api:

// {theme}/javascripts/discourse/api-initializers/init-theme.gjs

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

export default apiInitializer((api) => {
  api.replaceIcon("bars", "my-theme-icon-bars");
  api.replaceIcon("link", "my-theme-icon-link");
  // etc.
});

El primer ID, bars, es el ID de icono predeterminado en Discourse y el segundo es el ID de su icono de reemplazo. La forma más fácil de encontrar un ID de uno de nuestros iconos es inspeccionar el icono en su navegador.

Aquí, el nombre del icono sigue el prefijo d-icon-. Entonces, en este ejemplo, es d-unliked

La mayoría de nuestros iconos siguen los nombres de iconos de https://fontawesome.com/, pero hay excepciones (por eso verificar el ID en su inspector es el método más confiable). Puede ver todas las excepciones en el bloque const REPLACEMENTS aquí en github.

Eso es todo. ¡Ahora puede dar estilo a Discourse con sus propios iconos personalizados!


Este documento está controlado por versiones: sugiera cambios en github.

57 Me gusta

¿Cómo se puede seleccionar un icono específico dentro de un elemento específico? En mi caso, me gustaría reemplazar el icono de Documentos en el menú lateral con otro icono de FA.

Lo ocultaría con CSS y añadiría un nuevo botón para ello.

Común / CSS

.sidebar-section-wrapper {
  li[data-list-item-name=docs] {
    display: none !important;
  }
}

Añade un nuevo botón en Más > Personalizar esta sección

3 Me gusta

Esto no funciona. Intenté hacer un:

<script type="text/discourse-plugin" version="0.8">
    api.replaceIcon("shield-halved", "hat-wizard");
</script>

desde aquí, pero no parece funcionar. Creo que el método de la etiqueta script está roto, ya que esto no funciona con el enlace de vista previa. Sinceramente, no estoy seguro.

me funciona :woman_shrugging:t2:

¿lo estás poniendo en la pestaña head? también reemplazo el robot en mi encabezado:

puede que tengas que añadir el icono a la configuración SVG icon subset del administrador.

1 me gusta

[cita=“Lilly, post:40, topic:115736”]
¿Lo estás poniendo en la pestaña head?
[/quote]

Sí, en la pestaña head. Y en la pestaña header, ya que la guía dice eso.

[cita=“Lilly, post:40, topic:115736”]
SVG icon subset
[/quote]
Hecho. Ahora funciona. ¡Gracias!

1 me gusta

@NateDhaliwal ¿Podrías enviarme un mensaje privado por favor? Necesito ayuda con algo y no veo una opción de chat en tu perfil. ¡Gracias!

1 me gusta
/* Para el menú de la izquierda, redefinimos el fondo del elemento con la clase prefix-span dentro de la categoría Audi */
.navigation-category [data-category-id="6"] .prefix-span {
  background: url("https://raw.githubusercontent.com/tima4502/car-icons/bb0d0fae3e5b66c512a27a130b219ec0ee342ada/audi.svg") center/contain no-repeat !important;

¡Cuando hago clic en la página principal, el icono cuadrado vuelve a aparecer! ¿Puedes decirme qué estoy haciendo mal? Y en la propia página de categoría funciona.

Hola, ¿alguien podría aclarar la relación entre el nombre de un tema/componente, el nombre del archivo, el nombre de la variable SCSS y el ID del símbolo…?

Estoy intentando reemplazar el icono del moderador shield-halved por uno propio, pero las instrucciones no son muy claras.

En el Paso 2:

  • La captura de pantalla “A través de la UI” muestra un nombre de archivo de baticonsprite.svg con un nombre de variable SCSS de icons-sprite.
  • Pero luego, en “Codificar directamente en un tema”, te indica que lo codifiques directamente en un tema/componente.
  • ¿Pero cómo? No veo ningún archivo assets.json en el editor. Si exporto el componente, veo un about.json, que sí muestra el sprite que subí a través de la UI.
  • Pero este ejemplo también muestra un nombre de archivo diferente de /assets/my-icons.svg, ¿se supone que es el mismo archivo que baticonsprite.svg?
  • ¿Son estas dos formas alternativas de hacer lo mismo, y solo necesitas hacer una U OTRA, no ambas…?

En el Paso 3:

  • Pero entonces, en api.replaceIcon(), el segundo parámetro no utiliza ninguno de los IDs anteriores, ni icons-sprite, ni bat-icon, ni baticonsprite.svg, ni my-icons.svg. En cambio, obtenemos un my-theme-icon-bars completamente nuevo… confundido.
  • ¿Es necesario el prefijo my-theme y, si es así, de dónde proviene esa cadena “nombre del tema”? ¿Como si se supusiera que es my-theme-bat-icon? ¿Y qué pasa si es un componente, no un tema?
  • Y para la parte icon-bars, ¿se supone que es:
    • El ID del símbolo del XML de la hoja de sprites SVG
    • El nombre del archivo del archivo SVG
    • El nombre de la variable SCSS que le das
    • ¿Alguna combinación de lo anterior (como icons-sprite-bat-icon)?

¿Y dónde pones realmente la llamada api.replaceIcon()? ¿Está bien ponerla en la pestaña “JS” de un componente personalizado, que ya tiene el código base:

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

export default apiInitializer((api) => {
   // tu código aquí
});

¿O es necesario crear una etiqueta personalizada <script type=”discourse/plugin”> y ponerla en la pestaña <head> en su lugar?


Disculpen mi confusión.

He intentado varias combinaciones de lo anterior y no he podido hacer que mi sprite aparezca sin importar qué…

Mi XML de sprite se ve así:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">


<symbol id="my-logo" viewBox="0 0 94.652 95.261"><defs><linearGradient id="a" y1="47.631" x2="94.652" y2="47.631" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ff593d"/><stop offset="1" stop-color="#ff7751"/></linearGradient></defs><title>d_only</title><path d="M47.326,0H0V95.261H47.326c23.67,0,47.326-21.326,47.326-47.624S71,0,47.326,0Zm0,69.274a21.644,21.644,0,1,1,21.65-21.637A21.635,21.635,0,0,1,47.326,69.274Z" fill="url(#a)"/></symbol>

</svg>

El nombre del archivo es my-logo.svg y el nombre de la variable SCSS también es my-logo.

Y en la pestaña JS del componente personalizado, tengo:

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

export default apiInitializer((api) => {
    api.replaceIcon("shield-halved", "my-logo")
});

Pero nada parece aparecer. ¿Me falta algún paso, o hay alguna interpolación mágica de cadenas que no estoy entendiendo…?