Создание баннера на главной странице «Избранные категории»

Я хочу создать секцию баннера, которая будет располагаться под шапкой на главной странице и содержать несколько стилизованных блоков категорий. Например:

Я понимаю, что могу использовать точку вставки “below-site-header” и инструкции из Как добавить пользовательский контент, который отображается только на вашей главной странице, чтобы вывести свой HTML-код.

В идеале я хотел бы иметь пользовательское поле типа enum в настройках для выбора категорий, которые будут отображаться здесь. Возможно ли создать пользовательское поле настроек, которое позволяет искать категории?

Также я хотел бы иметь возможность добавлять пользовательское фоновое изображение для этих карточек, в дополнение к фоновому изображению категории. Возможно ли добавить ещё один элемент ввода файла во вкладку “Изображения” модального окна настроек категории? Например:

В целом, кажется ли это осуществимым, и есть ли какие-либо потенциальные подводные камни или хитрости, о которых мне следует знать?

Начните с использования плагина TLP. Уже существует функция «Избранные изображения», которая привязана к темам. Возможно, вы сможете переиспользовать часть кода.

Может ли он использовать это?

Учитывая, что категории менее динамичны, возможно, имеет смысл более статичный подход :+1:

Полагаю, вам нужно решить, хотите ли вы, чтобы это было основано на данных или нет.

В идеале я хотел бы получить что-то вроде более продвинутой версии блока «Категория с темами», который также подтягивает логотип категории и фоновое изображение вместе с последними темами в этой категории.

Однако, если это не реализуется straightforwardly с помощью стандартных механизмов расширения темы или плагина, усилия могут не окупиться. В таком случае я либо сделаю это статически, либо использую макет главной страницы с блоками категорий и стилизую их по необходимости.

Я считаю, что есть два ключевых вопроса:

  1. Существует ли стандартный способ отображения элемента конфигурации «Выбрать категорию»?
  2. Существует ли стандартный способ добавления полей метаданных в модальное окно настроек категории?

В качестве альтернативы, если я смогу просто использовать идентификаторы категорий в конфигурации, но при этом иметь возможность программно получать данные, это тоже будет приемлемо.

Однако, если получить данные о категориях таким образом действительно невозможно, я воспользуюсь одним из других подходов.

В плагине вы можете делать что угодно (хотя, очевидно, лучше использовать стратегии, которые минимизируют риск поломки вашего плагина после обновления ядра). Обрисуйте свои идеи, возьмите примеры из существующих плагинов и ядра Discourse, а затем начните с простой версии и постепенно развивайте её.

Я изучил предыдущий пост Криса и адаптировал его под задачу, которую вы можете использовать как основу. Большая часть того, что здесь описано, уже была изложена им в его оригинальной теме.
https://meta.discourse.org/t/how-to-add-a-featured-topic-list-to-your-discourse-homepage/132949

Весь код будет добавлен в секцию </head> (head_tag.html) вашей темы.

Этот первый блок проверяет, находитесь ли вы на «главной странице».

Затем мы получим категории сайта, используя метод Category.list() из класса Category.

Далее мы сравним их с категориями, которые вы хотите выделить. Они будут находиться в массиве definedFeaturedCategories, определенном в коде ниже. Те, которые вы разрешите, будут переданы компоненту для рендеринга в шаблоне.

<script type="text/discourse-plugin" version="0.8">
  const Category = require("discourse/models/category").default;
  // мы будем использовать модель Category для получения категорий сайта

  api.registerConnectorClass('above-main-container', 'featured-categories', {
    // above-main-container — это выходной порт плагина,
    // featured-topics — имя вашего пользовательского компонента

    setupComponent(args, component) {

      api.onPageChange((url, title) => {
        console.log(url,title)
        if ((url === "/") || (url === "/latest") ) {
        // при изменении страницы проверяем, совпадает ли URL
        // если ваша главная страница не /latest, измените это на /categories
        
          $('html').addClass('custom-featured-categories');
          // добавляем класс к тегу HTML для удобного выбора в CSS

          let definedFeaturedCategories = ["uncategorized","blog","two"]
          // массив категорий, которые вы хотите выделить
          // убедитесь, что названия категорий указаны в нижнем регистре

          let featuredCategories = [];

          categories = Category.list();

          for (let cat of categories) {
            if (definedFeaturedCategories.includes(cat.name.toLowerCase())) {
              // в массив для рендеринга добавляются только те категории, которые вы хотите выделить
              featuredCategories.push(cat)
            }
          }

          component.set('featuredCategories', featuredCategories)

        } else {

        // Если страница не соответствует указанным выше URL, сделайте следующее:
          $('html').removeClass('custom-featured-categories');
          // удаляем наш пользовательский класс
          component.set('categories',[])
          // устанавливаем категории в пустой массив, чтобы отключить рендеринг
        }
      });
    }
  });
</script>

Этот следующий блок внедряет шаблон для созданного выше компонента в выходной порт плагина above-main-container. Он вызовет пользовательский categories-wrapper, созданный на третьем шаге, и определит categories как featuredCategories, созданный выше.

<script type="text/x-handlebars" data-template-name="/connectors/above-main-container/featured-categories">
      <div class="custom-featured-categories-wrapper">
        {{categories-wrapper categories=featuredCategories}}
          <!-- используйте шаблон categories-wrapper, созданный ниже -->
          <!-- определите категории как featuredCategories, созданный в скрипте выше -->
      </div>
</script>

Третий раздел создает пользовательский шаблон Handlebars categories-wrapper для отображения выделенных категорий. Он напрямую адаптирован из categories-only.hbs Discourse, используемого на странице категорий Discourse.

<script type="text/x-handlebars" data-template-name="components/categories-wrapper">
  <!-- Это создает шаблон компонента с названием 'categories wrapper' -->
  <!-- Весь этот код шаблона был адаптирован из собственного шаблона страницы категорий Discourse
   https://github.com/discourse/discourse/blob/acd1693dac1bff6ff50250d942134bc48a27ff14/app/assets/javascripts/discourse/templates/components/categories-only.hbs -->

  <div class="top-categories-wrapper">
    {{#each categories as |c|}}
        <div class="top-category-column-one">
          {{category-title-link category=c}}
          {{#if c.description}}
            <div class="category-description">
              {{dir-span c.description}}
            </div>
          {{/if}}
          {{#if c.isGrandParent}}
            <table class="category-list subcategories-with-subcategories">
              <tbody>
                {{#each c.subcategories as |subcategory|}}
                  <tr
                    data-category-id={{subcategory.id}}
                    data-notification-level={{subcategory.notificationLevelString
                    }}
                    class="{{if
                        subcategory.description_excerpt
                        "has-description"
                        "no-description"
                      }}
  
                      {{if subcategory.uploaded_logo.url "has-logo" "no-logo"}}"
                  >
                    <td
                      class="category"
                      style={{border-color subcategory.color}}
                    >
                      {{category-title-link tagName="h4" category=subcategory}}
                      {{#if subcategory.description_excerpt}}
                        <div
                          class="category-description subcategory-description"
                        >
                          {{{dir-span subcategory.description_excerpt}}}
                        </div>
                      {{/if}}
                      {{#if subcategory.subcategories}}
                        <div class="subcategories">
                          {{#each subcategory.subcategories as |subsubcategory|
                          }}
                            {{#unless subsubcategory.isMuted}}
                              <span class="subcategory">
                                {{category-title-before category=subsubcategory
                                }}
                                {{category-link subsubcategory hideParent="true"
                                }}
                              </span>
                            {{/unless}}
                          {{/each}}
                        </div>
                      {{else if subcategory.description_excerpt}}
                        <div
                          class="category-description subcategory-description"
                        >
                          {{{dir-span subcategory.description_excerpt}}}
                        </div>
                      {{/if}}
                    </td>
                  </tr>
                {{/each}}
              </tbody>
            </table>
          {{else if c.subcategories}}
            <div class="subcategories">
              {{#each c.subcategories as |subcategory|}}
                {{#unless subcategory.isMuted}}
                  <span class="subcategory">
                    {{category-title-before category=subcategory}}
                    {{category-link subcategory hideParent="true"}}
                    {{category-unread category=subcategory}}
                  </span>
                {{/unless}}
              {{/each}}
            </div>
          {{/if}}
        </div>
        <div class="top-category-column-two">
          <span class="topics-header">
            Темы
          </span>
          <span class="topics-count">
            {{c.topic_count}}
          </span>
          {{category-unread category=c tagName="div" class="unread-new"}}
        </div>
    {{/each}}
  </div>
</script>

Это должно помочь вам начать делать то, что вы просили в своем первом посте.

Для стилизации цвета каждого блока категории в соответствии с его пользовательскими цветами, в третьем разделе вы можете жестко задать стили, используя # + c.color, чтобы получить код цвета категории.

Помимо этого, стилизацию можно выполнить в файле common.scss.

Вау! Спасибо за такой подробный и очень полезный ответ, @jordan.vidrine! Я попробую и расскажу, как у меня получится :slight_smile:

Это сработало отлично, @jordan.vidrine:

Единственная странность в том, что темы загружаются только после посещения /categories; в противном случае кажется, что тем вообще нет:

Есть какие-то идеи, что там происходит?

Хм. Извините, я не уверен. Мне не удалось воспроизвести эту проблему.