Notifica di nuovi argomenti o argomenti aggiornati in evidenza

Ciao,

Questo potrebbe essere utile se la sezione Vedi x nuovi o aggiornati argomenti fosse fissata in alto sotto l’intestazione, così da essere visibile immediatamente mentre scorri l’elenco degli argomenti. Quando fai clic sulla barra, la pagina scorrerà verso l’alto per caricare gli argomenti nuovi o aggiornati.

La parte fissa funziona benissimo con questo :arrow_down:

#list-area .show-more.has-topics {
  position: sticky;
  top: var(--header-offset);
}

L’altra parte (JavaScript) dovrebbe essere una funzione di clic per saltare in cima o scorrere fino all’inizio, ma non so come farlo o qual è il modo migliore per farlo.

Ho trovato questa sezione nel template discovery/topics.hbs e discovery/categories.hbs. Se modificassi l’<a href in <a href="/"> potrebbe funzionare (non sono sicuro, non l’ho provato), ma in questo modo ogni volta si ricaricherebbe come se avessi cliccato sul logo.

Grazie per l’aiuto :slightly_smiling_face:

Sì, aggiungere un URL causerà la navigazione, dato che non esiste una logica per intercettare l’evento.

Il link sta chiamando un’azione di Ember. Tutte le azioni in Discourse sono estendibili. Quindi, agiscono in un certo senso come hook di personalizzazione. Allora, come si modifica un’azione? Bene, controlliamo prima cosa fa.

Cerca su GitHub o localmente il nome dell’azione. Le azioni sono sempre definite nei file JS e richiamate in Handlebars. Vogliamo vedere la definizione, quindi restringiamo la ricerca ai file JS.

Repository search results · GitHub

Otterrai quattro file. Quale dovresti esaminare? Vuoi personalizzare il

discovery/topics.hbs

template. Quindi

discovery/topics.js

è quello che ti serve.

C’è qualche parte di questo codice che può esserti utile? No, ma ora sappiamo dove è definita l’azione. Quindi, modifichiamola.

discovery/topics.js è una classe Ember. Puoi modificare le classi Ember con un metodo nell’API dei plugin chiamato… modifyClass :stuck_out_tongue:

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L166-L195

Sappiamo già la Classe che vogliamo modificare. È discovery/topics. Dobbiamo sapere che tipo di Classe sia. Quindi, controlliamo la directory dei file.

discourse/app/controllers/discovery/topics.js

È un controller.

Sappiamo anche che vogliamo modificare l’azione showInserted in quella Classe. Quindi, iniziamo così.

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
      // facciamo un po' di lavoro
    }
  }
});

Puoi quindi aggiungere tutto il codice che desideri per scorrere la finestra quando l’utente clicca sul banner “nuovi argomenti”. Io ho optato per qualcosa di simile.

const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();

Puoi leggere di più su scrollIntoView() qui.

Poi aggiungi questo al metodo plugin-api in questo modo.

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
+     const listControls = document.querySelector(".list-controls");
+     listControls.scrollIntoView();
    }
  }
});

Allora, abbiamo finito? No. Questo rompe Discourse perché stai sovrascrivendo completamente l’azione. Cliccando il link ora si scorrerà fino all’elemento list-controls, ma non caricherà i nuovi argomenti. Perché? Perché il codice nel core non viene più applicato. Intendo, questa roba qui

Allora, come si risolve? Con questa semplice riga

this._super(...arguments);

Non devi copiare alcun codice dal core se vuoi solo aggiungerci qualcosa. Fai il tuo lavoro, poi aggiungi quella riga. Tutto quello che fa è assicurarsi che il codice del core venga applicato.

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
     const listControls = document.querySelector(".list-controls");
     listControls.scrollIntoView();
+
+    this._super(...arguments);
    }
  }
});

Se provi questo, vedrai che quasi tutto funziona benissimo, tranne… l’intestazione si sovrappone a list-controls. Perché? Perché l’intestazione è impostata come sticky.

Puoi risolvere in diversi modi in JS: calcolare l’altezza, ottenere l’offset, importare un helper da Discourse… ecc. Non entrerò in questi dettagli.

Il modo più semplice è con CSS usando scroll-margin-top, di cui puoi leggere qui.

Quindi, aggiungiamo questo

.list-controls {
  scroll-margin-top: calc(var(--header-offset) * 2);
}

In inglese: Quando il link viene cliccato, scorri fino alla parte superiore di list-controls - 2 * l’altezza dell’intestazione, così non si sovrappone e ha un po’ di spazio sotto di essa.

Quindi, mettiamo tutto insieme.

scheda header comune

<script type="text/discourse-plugin" version="0.8">
api.modifyClass("controller:discovery/topics", {
  pluginId: "sticky-new-topics-banner",
  actions: {
    showInserted() {
      const listControls = document.querySelector(".list-controls");
      listControls.scrollIntoView();
      this._super(...arguments);
    }
  }
});
</script>

CSS comune

#list-area {
  // mobile ha un layout diverso
  .alert-info,
  .show-more.has-topics {
    position: sticky;
    // safari a volte è capriccioso senza il prefisso
    position: -webkit-sticky;
    top: var(--header-offset);
    // il banner deve essere sopra il contenuto
    z-index: z("header");
  }
}

.list-controls {
  scroll-margin-top: calc(var(--header-offset) * 2);
}

Grazie @Johani! È stato molto utile per me e credo di aver finalmente capito molte cose. Mi piacciono molto le tue risposte dettagliate perché possiamo imparare molto da esse, come funzionano le cose e, naturalmente, funzionano perfettamente. Grazie ancora! :slightly_smiling_face: