تصنيفات فرعية قابلة للطي في الشريط الجانبي

لقد رأيت بعض المنشورات حول هذا الأمر ولكن لم يقدم أي منها إجابات نهائية.

هل لدى Unreal Engine Discourse (المميز في صفحة “Discover” الخاصة بـ Discourse) سمة مخصصة بالكامل، أم أن هناك مكونات يمكنها تحقيق ذلك؟

ألاحظ أيضًا أنهم يعرضون الفئات الفرعية كروابط على المستوى الأعلى عند النقر فوق إحداها، ثم يسردون جميع المواضيع أسفلها. يبدو أن ما يحدث هنا هو تعيين “نمط قائمة الفئات الفرعية” إلى “صفوف” في الفئة الأم لتحقيق ذلك؟

إعجاب واحد (1)

يبدو أن هذا قد لا يكون قابلاً للحل باستخدام مكون. ومع ذلك، تمكنت من إنشاء شفرتي JS و CSS يحققان ذلك بمساعدة بسيطة من الذكاء الاصطناعي، وإذا كان أي شخص مهتمًا، أنا سعيد بمشاركتها.

3 إعجابات

لقد رأيت هذا، أليس كذلك؟

وهذا:

بكل سرور، شارك الكود الخاص بك. بالطبع، التحدي مع أشياء كهذه هو الصيانة المستمرة.

إعجابَين (2)

نعم، يبدو أن الكثير مما يقومون به هو أشياء مخصصة.

سكريبت الخاص بي يبدو هكذا:

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;

    // بناء خريطة من parent_id => [معرفات الفئات الفرعية]
    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 = {}; // يتابع حالة الانهيار لكل أب

    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]) => {
        // تعيين الحالة الافتراضية للانهيار
        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); // <-- استعادة الأزرار
        });
      });

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

لقد وضعته للتو في لوحة كود الثيم الخاص بي. والكود CSS ذي الصلة:

.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;
}

هو يعمل بشكل جيد بما يكفي لأغراضي ولكن لا أوصي به إذا كان لديك الكثير من الفئات الفرعية.