「注目のカテゴリ」ホームページバナーの作成

ホームページのヘッダーの下に配置され、少し装飾を施したカテゴリボックスを特徴とするバナーセクションを作成したいと考えています。例:

「below-site-header」アウトレットを使用し、ホームページにのみ表示されるカスタムコンテンツの追加方法の手順に従ってマークアップを出力できることは理解しています。

理想的には、ここで紹介するカテゴリを選択するためのカスタム設定の列挙型フィールド(enum field)を持てるとよいのですが、カテゴリを検索できるカスタム設定フィールドは可能でしょうか?

また、カテゴリの背景画像に加えて、これらのカード用のカスタム背景画像も持てるとよいのですが、カテゴリ設定モーダルの「画像」タブに別のファイル入力フィールドを追加することは可能でしょうか。例:

全体として、これは実現可能でしょうか?また、注意すべき潜在的な落とし穴やコツはありますか?

まずは、TLP プラグインの使用を検討してください。トピックを指す「特集画像」機能は既に存在します。そのコードの一部を再利用できるかもしれません。

これを使えるでしょうか?

カテゴリがあまり動的でない場合、より静的なアプローチが適しているかもしれません :+1:

データ駆動型にするかどうかも、判断が必要です。

理想的には、カテゴリロゴと背景画像、そしてそのカテゴリの最新トピックも取得できる「トピック付きカテゴリボックス」の高級版のようなものが欲しいです。

ただし、標準的なテーマやプラグイン拡張メカニズムを使ってこれが容易に実現できない場合、手間に見合わないかもしれません。その場合は、静的に実装するか、カテゴリボックスのホームページレイアウトを使用して必要に応じてスタイルを適用します。

重要なテストポイントは以下の2つだと思います:

  1. 「カテゴリ選択」設定項目を表示する標準的な方法はありますか?
  2. カテゴリ設定モーダルにメタデータフィールドを追加する標準的な方法はありますか?

あるいは、設定でカテゴリIDを使用しつつ、プログラム的にデータを取得できるのであれば、それで問題ないでしょう。

しかし、そのようにしてカテゴリデータにアクセスすることが現実的でない場合は、他のアプローチのいずれかを使用します。

プラグインでは、やりたいことは何でも可能です(ただし、コアのアップデート後にプラグインが破損するリスクを最小限に抑える戦略を採用するのが当然ベストです)。アイデアをスケッチし、既存のプラグインや Discourse コアからコピーして、シンプルなバージョンから始めて反復的に改良していきましょう。

Kris による過去の投稿を参照し、それをベースとして使える形に直接 Adapt しました。ここで扱われている多くの内容は、元のトピックで彼が既に説明しています。
https://meta.discourse.org/t/how-to-add-a-featured-topic-list-to-your-discourse-homepage/132949

すべてのコードは、テーマの <head> (head_tag.html) セクションに追加されます。

最初のセクションでは、現在表示されているページが「ホームページ」かどうかを確認します。

次に、Category.list() メソッドを使用して、サイトのカテゴリを取得します。

その後、それらをfeatured として表示したいカテゴリと比較します。これらは以下のコードで定義されている 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');
          // CSS ターゲットリングを容易にするために HTML タグにクラスを追加

          let definedFeaturedCategories = ["uncategorized","blog","two"]
          // featured として表示したいカテゴリの配列
          // カテゴリ名はすべて小文字で入力してください

          let featuredCategories = [];

          categories = Category.list();

          for (let cat of categories) {
            if (definedFeaturedCategories.includes(cat.name.toLowerCase())) {
              // featured として表示したいカテゴリのみを配列に追加してレンダリングします
              featuredCategories.push(cat)
            }
          }

          component.set('featuredCategories', featuredCategories)

        } else {

        // 上記の URL と一致しないページの場合は、以下を実行します
          $('html').removeClass('custom-featured-categories');
          // カスタムクラスを削除
          component.set('categories',[])
          // カテゴリを空配列に設定してレンダリングを無効化
        }
      });
    }
  });
</script>

次のセクションでは、上記で作成したコンポーネントのテンプレートをプラグインの出口 above-main-container に注入します。これは、3 番目のステップで作成されたカスタム 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>

3 番目のセクションでは、featured カテゴリをレンダリングするためのカスタム categories-wrapper Handlebars テンプレートを作成します。これは、Discourse の categories-only.hbs から直接 Adapt されたもので、Discourse のカテゴリページで使用されています

<script type="text/x-handlebars" data-template-name="components/categories-wrapper">
  <!-- 'categories wrapper' というコンポーネントテンプレートを作成 -->
  <!-- このテンプレートコードのすべては、Discourse 自身のカテゴリページテンプレートから Adapt されました
   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>

これで、OP でリクエストされたことを始める手助けになるはずです。

各カテゴリボックスの色を、カスタム定義された色に応じてスタイリングするには、3 番目のセクションで # + c.color を使用してハードコードされたスタイルを設定し、カテゴリの色コードにアクセスできます。

それ以外の場合は、common.scss ファイルでスタイリングを行うことができます。

わあ!@jordan.vidrine さん、こんなに詳しくてとても役立つ返信をありがとうございます!試してみますね。結果をお知らせしますね :slight_smile:

素晴らしい結果ですね、@jordan.vidrine さん:

唯一の不思議な点は、/categories にアクセスしないとトピックが読み込まれないことです。アクセスしないと、トピックが一切存在しないかのようです:

何か原因がわかりますか?

うーん、申し訳ありませんが、わかりません。その問題は再現できませんでした。