Sous-catégories repliables dans la barre latérale

J’ai vu quelques publications à ce sujet mais aucune n’a de réponses définitives.

Est-ce que le Discourse d’Unreal Engine (présent sur la page « Découvrir » de Discourse) a un thème entièrement personnalisé, ou existe-t-il des composants qui peuvent y parvenir ?

Je remarque également qu’ils affichent les sous-catégories sous forme de liens de premier niveau lorsque vous cliquez sur l’une d’elles, puis que vous listez tous les sujets en dessous. Il semble que ce qui se passe ici est de définir le « Style de liste des sous-catégories » sur « Lignes » dans la catégorie parente pour y parvenir ?

1 « J'aime »

Il semble que cela ne soit peut-être pas résolvable avec un composant.

Cependant, j’ai réussi à générer du JavaScript et du CSS qui permettent d’y parvenir avec un peu d’aide de l’IA. Si quelqu’un est intéressé, je suis heureux de partager.

3 « J'aime »

Vous avez vu ceci, j’imagine :

Et ceci :

Partagez votre code, bien sûr. Bien sûr, le défi avec ce genre de choses est la maintenance continue.

2 « J'aime »

Oui, il semble que beaucoup de ce qu’ils font soit personnalisé.

Mon script ressemble à ceci :

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

export default apiInitializer("0.11.1", (api) => {
  ajax("/site.json").then((data) => {
    const categories = data.categories;

    // Construire une carte de parent_id => [id des sous-catégories]
    const childMap = {};
    categories.forEach((cat) => {
      if (cat.parent_category_id) {
        if (!childMap[cat.parent_category_id]) {
          childMap[cat.parent_category_id] = [];
        }
        childMap[cat.parent_category_id].push(cat.id);
      }
    });

    const collapseState = {}; // Suit l'état de la collapse pour chaque parent

    function applyCollapseState(parentId, childIds, collapsed) {
      childIds.forEach((childId) => {
        const childEl = document.querySelector(
          `.sidebar-section-link-wrapper[data-category-id="${childId}"]`
        );
        if (childEl) {
          childEl.classList.toggle("is-collapsed", collapsed);
          childEl.classList.add("is-subcategory");
        }
      });
    }

    function ensureToggleExists(parentId, childIds) {
      const parentEl = document.querySelector(
        `.sidebar-section-link-wrapper[data-category-id="${parentId}"]`
      );
      if (!parentEl || parentEl.classList.contains("has-toggle")) return;

      const toggle = document.createElement("span");
      toggle.innerText = collapseState[parentId] ? "▸" : "▾";
      toggle.className = "toggle-subcategories";
      toggle.style.cursor = "pointer";
      toggle.style.marginLeft = "0.5em";

      toggle.onclick = () => {
        const isNowCollapsed = !collapseState[parentId];
        applyCollapseState(parentId, childIds, isNowCollapsed);
        toggle.innerText = isNowCollapsed ? "▸" : "▾";
        collapseState[parentId] = isNowCollapsed;
      };

      parentEl.classList.add("has-toggle");
      const link = parentEl.querySelector(".sidebar-section-link");
      if (link) link.appendChild(toggle);
    }

    api.onPageChange(() => {
      Object.entries(childMap).forEach(([parentId, childIds]) => {
        // Définir l'état de collapse par défaut
        if (collapseState[parentId] === undefined) {
          collapseState[parentId] = true;
        }

        applyCollapseState(parentId, childIds, collapseState[parentId]);
        ensureToggleExists(parentId, childIds);
      });

      const container = document.querySelector('[data-section-name="categories"]');
      if (!container) return;

      const observer = new MutationObserver(() => {
        Object.entries(childMap).forEach(([parentId, childIds]) => {
          applyCollapseState(parentId, childIds, collapseState[parentId]);
          ensureToggleExists(parentId, childIds); // -- Restaure les toggles
        });
      });

      observer.observe(container, {
        childList: true,
        subtree: true,
      });
    });
  });
});

Je l’ai simplement ajouté dans le panneau JS du thème. Le CSS pertinent :

.sidebar-section-link-wrapper.is-collapsed {
  display: none !important;
}

.sidebar-section-link-wrapper.is-subcategory {
  padding-left: 1.5em;
}

.toggle-subcategories {
  float: right;
  display: flex;
  width: 30px;
  align-items: center;
  font-size: 0.9em;
  line-height: 1;
  height: 30px;
}

Il fonctionne assez bien pour mes besoins mais je ne le recommandera pas si vous avez beaucoup de sous-catégories.