Sostituire le icone SVG predefinite di Discourse con icone personalizzate in un tema

È possibile sostituire singolarmente o in blocco le icone SVG predefinite di Discourse con icone SVG personalizzate, sovrascrivendole all’interno di un tema o di un componente di tema.

Passo 1 - Creare un foglio sprite SVG

Per iniziare, è necessario creare un foglio sprite SVG (SVG Spritesheet). Questo può contenere qualsiasi cosa, da una singola icona SVG personalizzata aggiuntiva a un intero set sostitutivo composto da centinaia di icone.

Il foglio sprite deve essere salvato come file SVG. In linea di principio, si annidano i contenuti del tag <svg> del file di icona SVG originale all’interno di tag <symbol> assegnando loro un identificativo descrittivo.

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="my-theme-icon-1">
    <!--
      Il codice all'interno del tag <svg> del file di icona SVG sorgente
      di solito si tratta di tutto ciò che si trova tra i tag <svg>
      (ma non il tag SVG stesso, che viene sostituito dal <symbol> sopra)
      È possibile trasferire qualsiasi attributo (ad esempio ViewBox="0 0 0 0") al tag <symbol>
      -->
  </symbol>

  <symbol id="my-theme-icon-2">
    <!-- Codice SVG qui. Aggiungi più blocchi <symbol> se necessario.
      -->
  </symbol>
</svg>
  • Assicurati di aggiungere un ID personalizzato a ciascun simbolo nel foglio sprite. Probabilmente ti sarà utile per la sanità mentale prefissare i tuoi ID con il nome del tuo tema my-theme-icon.

  • Per rendere il colore dell’icona dinamico come le icone esistenti, imposta il riempimento su currentColor anziché su un colore fisso (come #333)

  • Per ridimensionare o centrare correttamente la tua icona, utilizza l’attributo viewBox sul tag <symbol>. Consulta How to Scale SVG | CSS-Tricks per ulteriori informazioni.

  • Fai attenzione a possibili collisioni di stili all’interno dei tuoi SVG. Ad esempio, gli SVG spesso hanno uno stile inline definito come .st0{fill:#FF0000;}. Se hai più SVG che utilizzano le stesse classi, questo può causare problemi (per risolvere questi problemi, modifica le classi per renderle uniche per ciascuna icona).

  • Se hai molte icone, esistono modi per automatizzare questo processo. https://www.npmjs.com/package/svg-sprite-generator è un semplice strumento da riga di comando per combinare SVG in un foglio sprite.

Esempio - foglio sprite con una singola icona personalizzata

<?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>

Passo 2 - Aggiungere il foglio sprite al tuo tema

Una volta creato il foglio sprite, è necessario aggiungere il file SVG al tuo componente/tema. Questo è facile da fare tramite l’interfaccia utente, oppure puoi codificarlo direttamente in un componente/tema.

:information_source: Una volta caricato in qualsiasi componente/tema installato, sarà disponibile in tutta la tua istanza utilizzando l’ID nel tag <symbol>.

Tramite l’interfaccia utente

Vai alla sezione Caricamenti delle impostazioni del tema/componente e aggiungi il tuo file sprite con un nome di variabile SCSS icons-sprite:

Codifica diretta in un Tema / Componente

Aggiungi il file del foglio sprite alla cartella /assets del Tema. Quindi aggiorna il file assets.json nella cartella principale.
Per uno sprite SVG chiamato my-icons.svg, il tuo about.json dovrebbe includere questo:

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

Passo 3 (facoltativo) - Sovrascrittura delle icone predefinite

Ora che il tuo foglio sprite è impostato, puoi dire a Discourse di sostituire le icone. Ecco come farlo da un api-initializer:

// {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");
  // ecc.
});

Il primo ID, bars, è l’ID dell’icona predefinita in Discourse e il secondo è l’ID della tua icona sostitutiva. Il modo più semplice per trovare l’ID di una delle nostre icone è ispezionare l’icona nel browser.

Qui il nome dell’icona segue il prefisso d-icon-. Quindi in questo esempio è d-unliked

La maggior parte delle nostre icone segue i nomi delle icone da https://fontawesome.com/, ma ci sono eccezioni (ecco perché controllare l’ID nel tuo ispettore è il metodo più affidabile). Puoi vedere tutte le eccezioni nel blocco const REPLACEMENTS qui su github.

Ecco fatto. Ora puoi personalizzare lo stile di Discourse con le tue icone personalizzate!


Questo documento è sottoposto a controllo di versione - suggerisci modifiche su github.

58 Mi Piace

Come si potrebbe selezionare un’icona specifica in un elemento specifico? Nel mio caso, vorrei sostituire l’icona Docs nel menu della barra laterale con un’altra icona FA.

1 Mi Piace

Lo nasconderei con CSS e aggiungerei un nuovo pulsante per esso.

Common / CSS

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

Aggiungi un nuovo pulsante in Altro > Personalizza questa sezione

4 Mi Piace

Questo non funziona. Ho provato a fare un:

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

da qui, ma non sembra funzionare. Penso che il metodo del tag script sia rotto, dato che questo non funziona con il link di anteprima. Onestamente non sono sicuro.

1 Mi Piace

funziona per me :woman_shrugging:t2:

lo stai inserendo nella scheda head? ho anche sostituito il robot nel mio header:

potrebbe essere necessario aggiungere l’icona all’impostazione SVG icon subset dell’admin.

2 Mi Piace

[citazione=“Lilly, post:40, topic:115736”]
lo stai mettendo nella scheda head?
[/citazione]

Sì, nella scheda head. E nella scheda header, dato che lo dice la guida.

[citazione=“Lilly, post:40, topic:115736”]
SVG icon subset
[/citazione]
Fatto. Ora funziona. Grazie!

1 Mi Piace

@NateDhaliwal Potresti mandarmi un messaggio privato per favore? Ho bisogno di aiuto con qualcosa e non vedo l’opzione chat nel tuo profilo. Grazie!

1 Mi Piace
Per il menu di sinistra, ridefiniamo lo sfondo dell'elemento con la classe prefix-span all'interno della categoria 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;

quando clicco sulla pagina principale l’icona quadrata appare di nuovo! puoi dirmi cosa sto sbagliando? e sulla pagina della categoria stessa funziona

Ciao, qualcuno potrebbe per favore chiarire la relazione tra un nome di tema/componente, nome del file, nome della variabile SCSS e l’ID del simbolo…?

Sto cercando di sostituire l’icona del moderatore shield-halved con una nostra, ma le istruzioni sono un po’ poco chiare.

Nel passaggio 2:

  • Lo screenshot “Tramite l’interfaccia utente” mostra un nome di file baticonsprite.svg con un nome di variabile SCSS icons-sprite
  • Ma poi in “Codifica manuale in un tema”, ti dice di codificarlo manualmente in un tema/componente
  • Ma come? Non vedo un file assets.json nell’editor. Se esporto il componente, vedo un about.json, che mostra lo sprite che ho caricato tramite l’interfaccia utente
  • Ma questo esempio mostra anche un nome di file diverso /assets/my-icons.svg — è inteso come lo stesso file di baticonsprite.svg?
  • Questi sono due modi alternativi per fare la stessa cosa, e devi farne solo uno OPPURE l’altro, non entrambi…?

Nel passaggio 3:

  • Ma poi ora, in api.replaceIcon(), il secondo parametro non utilizza nessuno degli ID precedenti, né icons-sprite né bat-icon né baticonsprite.svg né my-icons.svg. Invece, otteniamo un my-theme-icon-bars completamente nuovo… confuso.
  • È richiesto il prefisso my-theme, e se sì, da dove proviene questa stringa “nome del tema”? Come se dovesse essere my-theme-bat-icon? E se è un componente, non un tema?
  • E per la parte icon-bars, dovrebbe essere:
  • L’ID del simbolo dal file XML dello sprite SVG
  • Il nome del file SVG
  • Il nome della variabile SCSS che gli dai
  • Una combinazione di quanto sopra (come icons-sprite-bat-icon?)

E dove metti effettivamente la chiamata api.replaceIcon()? Va bene metterla nella scheda “JS” di un componente personalizzato, che ha già il boilerplate:

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

export default apiInitializer((api) => {
  // il tuo codice qui
});

O è necessario creare un tag personalizzato <script type=”discourse/plugin”> e metterlo invece nella scheda <head>?


Scusa per la mia confusione qui.

Ho provato diverse combinazioni di quanto sopra e non sono riuscito a far apparire il mio sprite in nessun modo…

Il mio sprite XML assomiglia a:

<?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>

Il nome del file è my-logo.svg e anche il nome della variabile SCSS è my-logo

E nella scheda JS del componente personalizzato, ho:

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

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

Ma non sembra apparire nulla. Manca un passaggio, o c’è un qualche tipo di interpolazione di stringa magica che non sto capendo…?

1 Mi Piace

Qualcuno è riuscito a risolvere questo problema? Sto ancora avendo difficoltà…

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

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

Non sono sicuro da dove provenga il secondo ID (“my-logo”) se si carica il file tramite l’interfaccia utente:

Né $my-logo, $test, my-logo.svg, l’URL assoluto dell’SVG su disco, ecc. funzionano. Lo scudo viene sostituito, ma con nulla. L’SVG diventa semplicemente un vuoto <use href=”#my-logo”> senza contenuto.

1 Mi Piace

Finalmente ho capito (grazie, Claude)!

Quindi:

  1. Il nome del file SVG non ha importanza.

  2. All’interno del foglio di sprite SVG, è l’id del simbolo che determina il nome finale dell’icona, come in <symbol id=”my-logo” …>

  3. Ma il nome della variabile SCSS DEVE essere esattamente icons-sprite, NON qualcosa che abbia a che fare con gli ID del foglio di sprite finale:

  4. Una volta caricato, apparirà così:


    (Nota che il nome del foglio di sprite / variabile non si trova da nessuna parte. Deve essere esattamente $icons-sprite, con il $ anteposto automaticamente e non parte di ciò che hai inserito nel passaggio precedente)

  5. Quindi, infine, nella scheda “JS” del tema (non in <head>), è lì che usi l’ID del foglio di sprite dal passaggio 1:

    import { apiInitializer } from “discourse/lib/api”;
    
    export default apiInitializer((api) => {
    api.replaceIcon(“shield-halved”, “my-logo”)
    });
    

Quindi il nome della variabile SCSS deve essere esattamente icons-sprite, il nome del file non ha importanza e il nome dell’icona API è determinato dall’ID del simbolo all’interno del foglio di sprite.

3 Mi Piace