今後のヘッダー変更 - テーマとプラグインの準備

Discourse のヘッダーを従来の「ウィジェット」レンダリングシステムから現代的な Glimmer コンポーネントへ更新する作業を最近 行ってきました。この変更は、Discourse コアにおいて glimmer header mode サイト設定の背後で利用可能になりました。

:timer_clock: 概算タイムライン

(非常に大まかな見積もりです。前後する可能性があります)

2024 年第 1 四半期:

  • :white_check_mark: コア実装完了、Meta で有効化

  • :white_check_mark: アップグレードに関するアドバイス公開、コンソール上の非推奨メッセージ有効化

  • :white_check_mark: 公式およびサードパーティ製プラグイン/テーマの更新作業開始

2024 年第 2 四半期:

  • :white_check_mark: 新しいヘッダー実装のデフォルト有効化開始

  • :white_check_mark: 公式およびサードパーティ製テーマ/プラグインがアップグレードに対応

  • :white_check_mark: 非推奨メッセージにより、残存する問題に対して管理者警告バナーが表示され始める

2024 年第 3 四半期:

  • :white_check_mark: 広範な周知のためのアナウンストピック投稿:Preparing your community for behind-the-scenes header changes

  • :white_check_mark: 2024 年 8 月 5 日週(v3.4.0.beta1):新しいヘッダーがすべてのサイトでデフォルトで有効化されます。管理者は glimmer header mode サイト設定を切り替えることで、引き続き旧ヘッダーに戻すことが可能です。

  • :white_check_mark: 2024 年 9 月 2 日週:機能フラグとレガシーコードの最終削除

:eyes: これは私にとって何を意味しますか?

プラグインやテーマがヘッダーのカスタマイズに「ウィジェット」API を使用している場合、新しいヘッダーとの互換性のために更新が必要です。

:person_tipping_hand: 新しいヘッダーを試すには?

Discourse の最新バージョンでは、すべてのテーマ/プラグインが互換性がある場合、新しいヘッダーが自動的に有効になります。

テーマ/プラグインが互換性がない場合、レガシーヘッダーが引き続き使用され、既存の非推奨メッセージ alongside コンソールに警告が出力されます。また、UI 上でも管理者に警告バナーが表示されます。

まれに、この自動システムが期待通りに動作しない場合、glimmer header mode サイト設定を介してこの「自動機能フラグ」を一時的に上書きできます。その場合は、このトピックでその理由をお知らせください。

:technologist: プラグイン/テーマを更新する必要がありますか?

カスタマイズを更新する必要があるかどうかを判断するには、以下のウィジェットに対して decorateWidgetchangeWidgetSettingreopenWidgetattachWidgetAction を使用しているか確認してください。

  • header
  • site-header
  • header-contents
  • header-buttons
  • user-status-bubble
  • sidebar-toggle
  • header-icons
  • header-topic-info
  • header-notifications
  • home-logo
  • user-dropdown

または、以下のプラグイン API メソッドを使用しているか確認してください。

  • addToHeaderIcons
  • addHeaderPanel

これらすべてが、コンソールに非推奨メッセージを出力する原因となります。非推奨 ID は以下の通りです。

  • discourse.add-header-panel
  • discourse.header-widget-overrides

:warning: インスタンスで複数のテーマを使用している場合は、すべてを確認してください。

管理者通知

2024 年 6 月 20 日より、上記の非推奨に関する管理者通知を有効にしました。

この日以降にデプロイされたインスタンスで、現在のプラグイン、テーマ、またはテーマコンポーネントが非推奨警告のいずれかをトリガーする場合、以下のメッセージが管理者*のみに表示されます。

このメッセージは、影響を受けるカスタマイズを近代化するために早急に対応する必要があることを管理者に警告するものです。レガシーコードベースが削除されるまで、古いカスタマイズは引き続き機能します。

:twisted_rightwards_arrows: 代替手段は何ですか?

テーマやプラグインはそれぞれ異なりますが、最も一般的なユースケースに対するガイダンスを以下に示します。

addToHeaderIcons

:information_source: カスタムヘッダーアイコンについては、コードを削除し、公式の Custom Header Links (Icons) Theme Component をインストールすることを推奨します。要件を満たさない場合は、必要なコード変更の詳細については以下をご覧ください。

addToHeaderIcons プラグイン API は、新しい headerIcons API の採用により非推奨となりました。ヘッダー内のアイコンの追加、削除、または並べ替えを可能にするために存在します。コンポーネントの渡しが必須です。

コンポーネントは以下のように渡します。

以前 以後
api.addToHeaderIcons(“widget-foo”) api.headerIcons.add(“foo”, FooIcon)
api.decorateWidget(“header-icons:before”, () => return helper.h(“div”, “widget-foo”)) api.headerIcons.add(“foo”, FooIcon, { before: “search” })
api.decorateWidget(“header-icons:after”, () => return helper.h(“div”, “widget-foo”)) api.headerIcons.add(“foo”, FooComponent, { after: “search” })

この例では、Ember の Template Tag Format (gjs) を使用して、コンポーネントをインラインで定義し、headerButtons.add API に渡しています。

// .../discourse/api-initializers/add-my-button.gjs

import DButton from "discourse/components/d-button";
import { apiInitializer } from "discourse/lib/api";

export default apiInitializer("1.0", (api) => {
  api.headerIcons.add("some-unique-name", <template>
    <li><DButton class="icon btn-flat" @href="/u" @icon="address-book" /></li>
  </template>);
});

または、ドロップダウンの場合は、<DButton の代わりに <DMenu を使用できます。

import DButton from "discourse/components/d-button";
import { apiInitializer } from "discourse/lib/api";
import DMenu from "float-kit/components/d-menu";

export default apiInitializer("1.0", (api) => {
  api.headerIcons.add("some-unique-name", <template>
    <li>
      <DMenu class="icon btn-flat" @icon="address-book">
        <DButton @translatedLabel="User 1" @href="/u/user1" />
        <DButton @translatedLabel="User 2" @href="/u/user2" />
        <DButton @translatedLabel="User 3" @href="/u/user3" />
      </DMenu>
    </li>
  </template>);
});

アップグレードのコミット例:

decorateWidget("header-buttons:*")

:information_source: カスタムヘッダーリンクについては、コードを削除し、公式の Custom Header Links Theme Component をインストールすることを推奨します。要件を満たさない場合は、必要なコード変更の詳細については以下をご覧ください。

header-buttons ウィジェットは非推奨となり、新しい headerButtons プラグイン API が導入されました。ヘッダー内のボタンの追加、削除、または並べ替えを可能にするために存在します。コンポーネントの渡しが必須です。

以前 以後
api.decorateWidget(“header-buttons:before”) api.headerButtons(“button-name”, ButtonComponent, { before: “auth” })
api.decorateWidget(“header-buttons:after”) api.headerButtons(“button-name”, ButtonComponent, { after: “auth” })

ヘッダーウィジェットに対する changeWidgetSetting(...)

:information_source: changeWidgetSetting の最も一般的な使用例は、以下のテーマコンポーネントで達成できます。

これらがユースケースに合わない場合は、以下をお読みください…

ヘッダーウィジェットのカスタマイズの一部は、changeWidgetSetting API を使用していました。

上記のようなカスタマイズに対する直接的な代替手段はありませんが、Glimmer コンポーネントのフィールドの動作方法により、Discourse 3.3.0.beta3 でこれらのケースの一部を処理するための新しいプラグイン API が導入されました。

registerValueTransformer は、ソースコード内で上書き可能としてタグ付けされた値を上書きするために使用できます。これは、プラグイン outlets が機能する方法と類似したアプローチです。

ソースコードベースで一般的に見つかったユースケースに対して、すでに 2 つのトランスフォーマーを追加しました。

  • home-logo-href: ホームロゴのアンカー内の URL を上書きするために使用できます。詳細については、以下の home-logo セクションをご覧ください。

  • header-notifications-avatar-size: ヘッダー内のユーザーアバターに取得される画像のサイズを変更するために使用できます。例:

以下のコード:

api.changeWidgetSetting(
  "header-notifications",
  "avatarSize",
  settings.header_avatars_size
);

は以下に変換されます。

api.registerValueTransformer(
  "header-notifications-avatar-size",
  () => settings.header_avatars_size
);

これらのトランスフォーマーは Discourse ソースコードに追加する必要があります。別のものが必要な場合は、以下のユースケースを投稿してお知らせください。

新しい値トランスフォーマー API に関する詳細は こちら で確認できます。

home-logo

home-logo:before または home-logo:after のウィジェット装飾に代わるものとして、home-logo プラグイン outlet を導入しました。コネクタファイルで自動的な __before および __after 命名規則を使用して、カスタムコンテンツを配置する場所を指定できます。

前後のコネクタファイル命名に関する詳細は こちら で確認できます。

以前 以後
api.decorateWidget(“home-logo:before”) コンテンツを /connectors/home-logo__before に移動
api.decorateWidget(“header-buttons:after”) コンテンツを /connectors/home-logo__after に移動

ホームロゴアンカー URL の変更:

非常に一般的な要件として、home-logo がリンクする URL を変更する場合があります。これに対処するために home-logo-href 値トランスフォーマーを導入しました。例:

  • リンクを静的な URL に変更する場合

    api.registerValueTransformer("home-logo-href", () => "https://example.com");
    
  • 現在のユーザーに基づいて動的な URL を返す場合

    api.registerValueTransformer("home-logo-href", () => {
      const currentUser = api.getCurrentUser();
      return `https://example.com/${currentUser.username}`;
    });
    
  • テーマコンポーネントの設定に基づいて URL を返す場合

    api.registerValueTransformer("home-logo-href", () => {
      return settings.example_logo_url_setting;
    });
    

:sos: その他のカスタマイズはどうなりますか?

CSS、PluginOutlets、または導入した新しい API を使用してカスタマイズを実現できない場合は、新しい Development トピックを作成して議論してください。

:sparkles: 新旧両方のヘッダーをサポートするようにテーマ/プラグインを更新するには?

このドキュメントに記載されているすべての新しい API とプラグイン outlets は、新しいヘッダーと古いヘッダーの両方でサポートされています。したがって、テーマ/プラグインの更新は現在 1 回だけで済み、ユーザーは切り替えの準備が整います。

しかし、FooIcon をどのように定義すればよいのでしょうか?

プラグインで /assets/javascripts/discourse/components/server-link.js を作成しようとしました(他のコンポーネントを hbs ファイルで使用しているように)。

import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";

export default Component.extend({
// 何かを入れる必要がありますか?
});

そして、assets/javascripts/discourse/templates/components/server-link.hbs
this is a link
(この「Hello, world」が機能すれば、リンクにできると思います)

上記の例には const IconWithDropdown = ... がありますが、それはどこに配置すればよいのでしょうか? 初期化子(api.decorateWidget があった場所)に入れようとしましたが、私や Ember にとっては有効な JavaScript ではなさそうです。

以前は headerlinks 配列があり、次のようにしていました。

        headerLinks.push(
          h(
            `li.headerLink.no-servers`,
            h("a", anchorAttributes, I18n.t("pfaffmanager.no_servers_title"))
          )
        );

リンクを追加するために。もし

      api.headerIcons.add("foo", ServerLink, { before: "search" });

が機能すれば、その配列を構築したループにそれを配置できると思います。

OMG。Glimmerコンポーネントはassets/javascripts/discourse/componentに、Embrerコンポーネントはassets/javascripts/discourse/componentsに入るということですか?!?!

これでserver-link.gjsができました。

import Component from "@ember/component";
export default class ServerLink extends Component {
  // URLに必要な引数
  url = null;
  // リンクテキストのオプション引数
  text = 'asdf';
  click() {
    console.log('ServerLink clicked!',this);

  }
  // コンポーネントのテンプレート
  <template>
    {{log "my template" this}}
    LINK!
    <a href={{this.url}}>{{this.text}}</a>
  </template>
}

そして、イニシャライザーにこれがあります。

      api.headerIcons.add("foo", ServerLink, { param: "url, yo", before: "search" });

これでヘッダーに何か表示されました。

しかし、ServerLinkにどうやって値を渡せばいいのでしょうか?異なるURLと異なるクリック用テキストで数回呼び出す必要があります。コンポーネント内の{}にあるものが表示されません。

また、<template>の前にJavaScriptを入れたくないですよね。私のconsole.log("")は解析されません!

以下も試しました。

      const x = new ServerLink({
        url: "mylink",
        text: "my-text",
        name: 'Bob',
        message: 'Generated from JavaScript',
      });

そして、ServerLinkの代わりにxを渡しましたが、うまくいきませんでした。

ヘッダーに異なるアイコン/テキスト/URLを持つ複数のボタンが必要ですか、それとも同じボタンですが、コンテキストに応じてテキスト/URLを変更したいということですか?

はい、クラス内です。そこで変数、関数、またはテンプレートを宣言します!

はい。リンクはユーザーごとに異なります。古いコードは servers の配列を通じてリンクし、それらをこの配列に追加していました。

            headerLinks.push(
              h(
                `li.headerLink${deviceClass}${newClass}`,
                h("a", anchorAttributes, linkText)
              )
            );

そして、これを実行しました。

      // api.decorateWidget("header-buttons:before", (helper) => {
      //   return helper.h("ul.pfaffmanager-header-links", headerLinks);
      // });

これにより、ヘッダーに最大3つのリンクが追加され、それぞれが個別のサーバーURLにリンクされていました。

なるほど。そういうことだったんですね。

いいえ、心配しないでください。規約はまだ/components/です :sweat_smile:

(技術的には、GJSコンポーネントはどのようにでも定義して渡すことができるため、好きなディレクトリ名を選ぶことができます。しかし、私たちは/components/にこだわっています。)

はい、それはもっともな質問です。ヘッダーにアイコンを追加する方法について、ゼロからドキュメントを作成します。そうすれば、より良い参照点が得られます。

それまでの間、discourse-icon-header-linksの更新を参考にするとよいでしょう。GJSを使用するクールな点は、コンポーネントをどこにでも定義でき、ローカルスコープの変数にアクセスできることです。

したがって、イニシャライザーを.gjsにリネームすると、次のようなことができます。

servers.forEach((server) => {
  api.headerIcons.add(`server-${server.id}`, <li><DButton @translatedLabel={{server.name}} @icon="server" /></li>);
});

または、同じファイル内のより早い段階でコンポーネントを定義し、次のように使用することもできます。

class ServerButton extends Component {
  get icon(){
    // アイコンを決定するロジック
  }
  <li><DButton @translatedLabel={{@server.name}} @icon={{this.icon}} /></li>
}

...

servers.forEach((server) => {
  api.headerIcons.add(`server-${server.id}`, <ServerButton @server={{server}} />);
});

または、サーバーのリストが実行時に変更される可能性のあるTrackedArrayである場合に便利な、テンプレート内にイテレーションを移動することもできます。

api.headerIcons.add("server-buttons", {{#each servers as |server|}}
  <ServerButton @server={{server}} />
{{/each}});

ああ。やったー。components で試したのですが、うまくいかなかったと思ったのです。

ありがとうございます!これらのうちの1つを機能させることができると思います。ヘッダーリンクへのリンクは大きな助けになります。私がコードを書いたとき、それを理解するためにそのコンポーネント自体を見たのに十分な判断力があったと確信しています。

希望の兆しが見えてきた!

@david@Arkshine さん、やりました!

ななな、なんだって?ただ名前を変えるだけ?それはクレイジーだ。でも、確かに。やってみたら、今では

          servers.filter(Boolean).map((server) => {
            const linkHref = `/pfaffmanager/servers/${server.id}`;
            const linkTitle = `click to configure server ${server.id}`;
            let host = String(server.hostname);
            const linkText = host.replace(
              /www.|community.|forums?.|talk.|discourse./,
              ""
            );
            const serverLink = <template>
              <li class="headerLink">
                <a class="btn-flat" href={{linkHref}} title={{linkTitle}}>
                  {{host}}
                </a>
              </li>
            </template>;
            const beforeIcon = ["chat", "search", "hamburger", "user-menu"];
            api.headerIcons.add(host, serverLink, { before: beforeIcon });
          });

そして、以前と同じように動作しました。それが私が望んでいたことです!

ええ、それはとてもクールで、私が望むものにさらに近いですが、それらのことはあまり頻繁には変更されないので、今日はこれで終わりにします。ホスト名を変更した場合は、リンクを変更するためにページをリロードする必要があります。

上記を更新する際に、私の余分なゴミは削除されると思いますが(そうでなければ、ドキュメントトピックであまりおしゃべりしなかったかもしれません…)。

OP を完全に機能する gjs の例で更新し、Ember のアップストリーム ドキュメントへのリンクを含めました。 @pfaffman さん、どのように見えますか? 追加する価値があると思われるものは他にありますか?

動作する例があるので、以前より良くなりました。しかし、EmberコンポーネントとGlimmerコンポーネントがあるという理解で合っていますか?もしそうなら、Glimmerコンポーネントが必要であると述べるべきだと思います。

また、それらがどのように機能するかについてのGlimmerのドキュメントへのリンクも追加した方が良いかもしれません。

例のようにインラインコンポーネントを使用することもでき、同じファイル内の変数に割り当てるか、コンポーネントディレクトリに配置してインクルードする別のファイルに配置する別のタイプもあるようです。このトピックには情報が多すぎるかもしれませんが、それに関する専用のトピックがあれば嬉しいです。

これらは完全に相互に交換可能です。クラシックなエンバーコンポーネントまたはグリマーコンポーネントを使用できます。どちらの場合も、古い形式の .js/.hbs または新しい形式の .gjs を使用して作成することを選択できます。

エンバーのドキュメントへのリンクをいくつか含めるようにします :+1:

:mega: 本日、この変更をマージしました。これにより、互換性のあるテーマ/プラグインを使用しているサイトでは、新しいヘッダー実装が自動的に有効になります。

テーマ/プラグインが互換性がない場合、レガシーヘッダーが引き続き使用され、既存の非推奨メッセージと共にコンソールに警告が表示されます。近い将来、このコンソール警告はUIの警告バナーにアップグレードされます。

この自動変更により問題が発生する可能性は低いですが、万が一問題が発生した場合は、glimmer header mode サイト設定を通じて、この「自動フィーチャーフラグ」を一時的に無効にすることができます。その場合は、このトピックで理由をお知らせください。

変更するつもりはありませんでしたが、非推奨の通知がそうではないことを示しています。

したがって、選択肢があり、現状維持を続ける簡単な方法があるのでしょうか?

または

古いヘッダーを維持することを選択した場合、何が欠けていますか?新しいヘッダーの意味がわかりません。グループ設定があり、異なるグループへのカスタムテーラリングは興味深いですが、何がカスタム可能ですか?

今日見つけたのはこれです。

私はこれらの変更に関してグルやウィズではありません。時間がかかり、ユーザーがここで簡単に理解/知っているように見えるテクニックを学ぶことを本当に望むほど頻繁には行いません。

そもそもそれらを行うことをいくらか不本意に思っていますが、プリンがなくなった老人のように叫ぶ前に、何が、なぜ、どこに向かっているのかを知りたいです。

私はこれを生業としていますが、それでもこのJavaScriptは簡単ではないと感じています。

私は老人で、あなたの痛みがわかります。

残念ながら、これは進歩です。このEmberのアップグレードは多くのものを壊しましたが、まだ終わっていません。

そのカスタマイズをしたとき、あなたは「それを求めた」のです。過去5年間で新しい電話やラップトップを手に入れたのではないでしょうか。

もし私があなただったら(そしてあなたが私のような人で、フルタイムのDiscourseの仕事をしていないとしたら)、#marketplaceに投稿するでしょう。もし私が私だったら、300ドル未満では応答しない可能性が高いですが、誰かが100ドルか200ドルで応答する可能性は十分にあります。それが再び壊れるのは、さらに5年以上先のことだと思います。

ハンバーガーテーマセレクターは削除して、サイドバーを使用できると思います。

丁寧で正直な返信、ありがとうございます。しかし、あまり作業するものがありません。おそらく、もっと何か出てくるでしょう(そう願っています)。

そもそも、ここで扱っているのがJavaだとは知りませんでした :man_shrugging:

あなたのプリン(分け前)を誰かに奪われたくないですからね :face_with_hand_over_mouth:

ええ、しかし、目指すべき目標は何なのでしょうか?このソフトウェアはあまりにも多くのことに手を出しているので、誰が何を見ているのか疑問に思います。

これは単にEmberのアップグレードから必要とされたのでしょうか?

Emberがなぜ行われたのかもわかりませんが、もしそれが機能しているのであれば、なぜ修正する必要があるのでしょうか?すべてが将来につながる長い深い説明があるはずですが、共有される真のビジョンはないのでしょうか?

私は非常に古いソフトウェアを使用している他のフォーラムを訪れます。個人的には、Discourseはそれらのどれよりもはるかに優れていると思いますが、彼らは比較において苦しんでいるようには見えません。彼らは同じ成長の問題を抱えています。ほとんどは、私の意見では、個性対ソフトウェアであり、プリンを失った古参が多すぎます。将来、それらのフォーラムを文字通り時代遅れにするIoTはありますか?それらはまったく機能しなくなり、Discourseはそれを認識して準備しているのでしょうか?

あなたが提供する正直さのさらに良い例ですね :grin: その通りです。そして、私はもっと学びたかった、もっと野心的だった、より価値があると感じていました。それ以来、打ちのめされ、轢かれ、死んだように放置されてきました。

よし、その賭けに乗った。あなたはすでに負けたので、これで私を助けてくれるだろう。友達になろう。

そうしたら、おそらくずっと前に辞めていただろう。打ちのめされ、轢かれ、死んだように放置されたというのは、少し婉曲的な表現でした。私だけがハンドルを握っています。他の誰かは、ハイパードライブを修理しようとしているどこかのパネルにいるのでしょう。私は他の人とあまりコミュニケーションをとらないので、わかりません。資金はありません。私たち(FULL30)はソーシャルメディアとDiscourseからもプラットフォームから追放されました。Discourseが自発的にどれだけの有料顧客を切り捨てたのか、またはその信念が攻撃的だと見なされたためにDiscourseが公にお金をかけて反対した顧客がどれだけいたのか疑問に思いますか?

しかし、真実を語る間、私は気分を害しません。生きて、そして生きさせよ。未来が来ることはわかっています。なぜ私がまだここにいて、まだ試みているのかはわかりませんが、試みています。だから、AAのように、今日だけ試み続けます :hugs:

しかし、私がそれを採用したときは、すべてが流行っていました :expressionless:

サイドバー(ここでは)はハンバーガーメニューで閉じることができます。機能に大きな違いはありません。ナビゲーションウィンドウを開閉しますが、私のものは簡単に保存できませんか?

はい、カスタマイズしたコードを整理して、物事をうまく機能させるために誰かに支払いたいと思っています。喜んで支払います。他人を雇用すること、富を分かち合うことを楽しんでいます。成長したら慈善家になりたいですが、今日は慈善家が必要です :innocent: そして、再び、他人が提供できるどんな助けにも感謝します。

もう一つの方法は、コミュニティに助けを求めることです。カスタマイズしていた作業を中止し、コードを共有する新しいトピックを開始して助けを求めてください。最近、そのような件で多くの助けを得ました。

残念ながら、そうではありません。「古いヘッダー」に固執する機能は、移行期間中のあくまで一時的なものです。すぐに、新しいヘッダーのみが唯一の選択肢となります。

はい!Dev での質問にはいつでも喜んでお手伝いします。さらに、コードとソリューションを公開することで、他の人にとって役立つリソースが作成されます。

ふぅ、私のコミュニティは他の問題にもっと精通しています。

確かにここで共有することはできますが、それは逆効果になります。どのようなコーダーが私たちを助けることに興味を持つでしょうか?

皮肉なことに、コーディングは将来の銃器になる可能性があり、さらに多くの死と破壊を引き起こす可能性さえあります。話が逸れました。

なるほど、それは私にとってどういう意味ですか?ユーザーグループを作成し、公開して、ログインしていない状態にするのでしょうか?

これらのグループ設定は、実際の異なるグループ(狩猟グループや釣りグループなど)ではなく、信頼レベルに基づいていると認識していますか?

まず、目標を理解し、私の努力が最も効果を発揮する場所、つまり時間とフォーラムのカスタム感を節約できる場所を理解する必要があります。


誰かのスレッドを脱線させたくありません。これが独自のスレッドと見なされるべきであれば、私はそれで構いません。

しかし、人々が不快に感じるものを削除する必要がある場合、真にまとまりのある関係がどのようにして生まれるのでしょうか?

他者を理解するには忍耐が必要です。削除されたリンクは、投稿中は表示されませんでしたが、ロゴが見つからないことを示していました。これも議論すべきヘッダーの問題ですか?

それは私のフォーラムでの投稿で、80歳を過ぎたと思われる男性によって書かれたものでした。確かに尋ねることはできますが、彼は私と話すことを拒否します。彼を叱責、禁止、または避けるべきですか?

いいえ、なぜなら、より良い方法があるからです。しかし、それは他者とその考えを受け入れることを意味します。私は悪い地域で良い人々を見つけ、悪く見える良い人々、そしてその逆も見つけます。

まさに、エラーを見つけたばかりで、それに対処したいのですが、将来が進んでいるという以外に根本原因を理解していません。新しいヘッダーが必要だ、それはいいとして、どこに焦点を当てるべきか、単純な調整か、全面的なコース修正か?

これらの3つの領域のみを修正する必要がある議論をしていますか?

コンポーネントの使用が混在しています。最初は何も使用していませんでしたが、それらが有益であると学びました。コンポーネントを完全に導入したことはなく、さまざまなものが混在しています。

参考までに、コンポーネントなしの私のテーマは次のとおりです。
discourse-full30-ii.zip (10.1 KB)
それらも投稿できます。モダールの一部は、最近すでに機能していません。