Subcategorías colapsables en la barra lateral

He visto algunas publicaciones al respecto, pero ninguna tiene respuestas definitivas.

¿El Discourse de Unreal Engine (presentado en la página “Discover” de Discourse) tiene un tema completamente personalizado o hay componentes que puedan lograr esto?

También noto que muestran las subcategorías como enlaces de nivel superior cuando haces clic en una, y debajo enumeran todos los temas. ¿Parece que lo que está sucediendo aquí es establecer el “Estilo de lista de subcategorías” en “Filas” en la categoría principal para lograr eso?

1 me gusta

Parece que esto puede no ser algo que se pueda resolver con un componente.

Sin embargo, pude generar JS y CSS que logran esto con un poco de ayuda de IA, si alguien está interesado, feliz de compartirlo.

3 Me gusta

Ya has visto esto, ¿verdad?

Y esto:

Por supuesto, comparte tu código. Claro está, el desafío con cosas como esta es el mantenimiento continuo.

2 Me gusta

Sí, parece que muchas de las cosas que están haciendo son funciones personalizadas.

Mi script se ve así:

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;

    // Construir un mapa de parent_id => [ids de categorías hijas]
    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 = {}; // Rastrea el estado de colapso por padre

    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]) => {
        // Establecer estado de colapso predeterminado
        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); // -- Restaurar toggles
        });
      });

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

Solo pegué eso en el panel de JS del tema. La CSS relevante:

.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: .9em;
    line-height: 1;
    height: 30px;
}

Funciona bastante bien para mis propósitos, pero no recomendaría esto si tienes muchas subcategorías.