トピックプレビューモーダル

このテーマコンポーネントをインストール

Topic Preview Modal – トピックリストを離れずにトピックを開いて操作する

新しいDiscourseテーマコンポーネント Topic Preview Modal を作成しました。

アイデアは比較的シンプルです。

トピックリストからトピックをネイティブなDiscourseモーダル内で直接開き、トピックを読み、操作し、その後リストから離れずに閲覧を続行します。

この機能は Facebook-style Topic Modal - Is it better? から始まりましたが、最終的にはDiscourseのトピック、投稿ストリーム、コンポーザー、モーダル、ブックマーク、ルーティング、プレゼンス、読み取り追跡、プリフェッチシステムとのかなりの統合が必要になりました。


なぜ必要なのか?

通常のDiscourseの流れは以下の通りです。

  1. トピックリストを閲覧しています。
  2. トピックをクリックします。
  3. Discourseが /t/... に遷移します。
  4. トピックを読み、返信し、操作します。
  5. トピックリストに戻ります。

多くのワークフローでは、これで問題ありません。

しかし、忙しいトピックリストを閲覧している際、トピックを簡単に確認し、いくつかの投稿を読み、最新の返信をチェックし、何かに対してリアクションしたり、簡単な質問に答えたりしたいだけの場合があります。

そのようなユースケースでは、トピックリストを離れるのは不必要にコストが高いと感じます。

したがって、このコンポーネントの目標は、トピックリストをより 受信トレイ のように動作させることでした。

トピックリスト → プレビュー → 操作 → クローズ → ちょうど同じ場所から続行。


機能

プレビューは単なる静的な抜粋ではありません。

ネイティブな DModal 内で実際のDiscourse投稿コンポーネントをレンダリングします。

つまり、ユーザーは以下を行うことができます。

  • 投稿を読む
  • トピックをスクロールする
  • 以前の投稿を読み込む
  • 下の追加投稿を読み込む
  • 投稿にリアクションする
  • 投稿をブックマークする
  • テキストを引用する
  • トピックに返信する
  • 個別の投稿に返信する
  • 許可されている場合、投稿を編集する
  • 許可されている場合、投稿を削除/復元する
  • 投稿をフラグする
  • 投稿履歴を表示する
  • 通常の投稿アクションを実行する
  • トピックのプレゼンスを確認する
  • 同じトピック内の他の投稿へのリンクを開く
  • 該当する投稿に直接ジャンプする
  • 必要に応じて完全なトピックを開く

プレビューは、実際にトピックを開いたものにできるだけ近い感覚になることが意図されています。


2つのトリガーモード

プレビューを開く方法は2つあります。

1. トピックリストの行全体

これがデフォルトです。

トピックリストの行全体がクリック可能になりますが、以下の一般的なインタラクティブ要素はモーダルのトリガーから除外されます。

  • ユーザーカード
  • 参加者
  • カテゴリリンク
  • タグ
  • トピックステータスリンク
  • 一括選択

これにより、トピックリストを閲覧する際の体験が非常に高速になります。

2. 明示的な展開ボタン

代替として、コンポーネントはDiscourseプラグインアウトレットを通じて小さな展開アイコンをレンダリングできます。カスタムテーマは、トリガーを表示するために新しい <PluginOutlet /> を簡単に作成できます。

このモードでは、通常のトピックリストの動作は完全に維持されます。

ユーザーは展開アイコンをクリックしてプレビューを開き、トピックタイトルをクリックすると通常のDiscourse遷移が行われます。

これは、サイトが標準のトピックリストインタラクションモデルを保持したい場合に有用です。

設定は以下の通りです。

trigger_style:
  row

または:

trigger_style:
  button

ボタンモードを使用する場合、アウトレットも設定可能です。


プレビューはユーザーの未読位置から始まります

重要な詳細の一つは、モーダルが 単に最初の投稿を読み込むわけではない ことです。

トピックが部分的に読み取られている場合、プレビューは以下を計算します。

last_read_post_number + 1

そして、その投稿の周りで開きます。

つまり、トピックに200件の投稿があり、ユーザーが165番目の投稿まで読んでいる場合、プレビューを開くと166番目付近から始まります。

これにより、プレビューは実際の閲覧においてはるかに有用になります。

また、コンポーネントは投稿ストリームの両側を処理する必要があります。

  • 必要に応じて以前の投稿を読み込む
  • 下の新しい投稿を読み込む

以前の投稿 ボタンは、現在読み込まれている範囲の上に投稿がある場合に表示され、IntersectionObserver センチネルがユーザーが下部に到達したときに自動的に追加の投稿を読み込みます。


プリフェッチ

コンポーネントの最大の一つの部分は、そのプリフェッチシステムです。

このようなモーダルの問題は、ユーザーが即座に感じることを期待していることです。

ユーザーがクリックした後にのみトピックの読み込みを開始すると、モーダルはネットワークを待っている間に目立つ時間を費やす可能性があります。

代わりに、コンポーネントはユーザーがリストを閲覧している間に能動的にトピックをプリフェッチできます。

トピックの行がビューポートに近づくと、IntersectionObserver がプリフェッチをスケジュールできます。

これが制御不能なバックグラウンドトラフィックに変わらないように、いくつかのセーフガードがあります。

デバウンス

トピックがビューポートに一瞬表示されただけで、すぐにリクエストをトリガーするわけではありません。

コンポーネントは設定されたデバウンス期間を待機します。

デフォルト:

400 ms

これは、長いトピックリストを素早くスクロールする場合に特に有用です。

ルートマージン

プリフェッチは、トピックが実際にビューポートに入る少し前に開始できます。

デフォルト:

50 px

これにより、リクエストに小さな先行時間を与えます。

同時リクエスト数の制限

同時実行されるプリフェッチの数は制限されています。

デフォルト:

2

設定では、1から6までの同時プリフェッチを許可します。

毎分の予算

また、2つ目の保護メカニズムがあります。

max_prefetches_per_minute

デフォルトは:

15

つまり、ユーザーが何百ものトピックをスクロールし続けたとしても、コンポーネントは投機的なリクエストを継続的に生成しません。

0 で制限を無効にします。

プリフェッチを完全に無効にできる

サイトが投機的なネットワークトラフィックを一切望まない場合:

enable_prefetch = false

コンポーネントは通常通り動作します。単にトピックがプレビューを開いたときに読み込まれるだけです。


プリフェッチデータは通常のトピックナビゲーションから分離されます

ここには重要な実装詳細があります。

プリフェッチされたレスポンスは Discourseの通常の topic_<id> プリロードキーに即座に書き込まれません

代わりに、コンポーネントは独自の名前空間を使用します。

topic-preview-modal:prefetch:<topicId>

ユーザーが実際にプレビューを開いたときのみ、プリフェッチされたプロミスがコアトピックプリロードキーに昇格されます。

これは意図的なものです。

プレビューは last_read_post_number + 1 からトピックの読み込みを開始する可能性があり、そのプレビュー固有のレスポンスが通常のトピックルート遷移に漏れ出すことを望んでいません。

したがって、ライフサイクルは基本的に以下の通りです。

topic enters viewport
        ↓
prefetch
        ↓
private preload storage
        ↓
user opens preview
        ↓
promote preload
        ↓
Topic.find()/PostStream uses the same promise

これにより、モーダルはプリフェッチリクエストが完了するのを待たずに開くことができます。

モーダルはスケルトンと共に即座に開き、同じプロミスが解決し続けることができます。


モバイルサポート

実は、これが実装にかなりの時間を費やした理由の一つでした。

初期のアイデアはデスクトップでそこそこうまく機能していましたが、モバイルでは以下の問題がいくつか露呈しました。

  • タッチ操作
  • モーダルのスクロール
  • フォーカス
  • ネストされたメニュー
  • コンポーザー
  • 投稿の可視性
  • 画像の読み込み
  • パフォーマンス

したがって、最終的な実装では、モーダルを完全に独立したミニチュアフォーラムとして扱うことを避けています。

代わりに、Discourseの既存のインフラストラクチャを可能な限り再利用しています。


実際のDiscourse投稿コンポーネント

モーダルは、簡素化されたカスタムテンプレートを使用して投稿を再作成しません。

Discourseの実際の:

Post
PostSmallAction

コンポーネントをレンダリングします。

これは重要です。そうでなければ、プレビューはすぐに投稿UIの第2の実装になってしまうからです。

コンポーネントは、通常の投稿コンポーネントに関連するアクションを渡します。例えば:

  • 返信
  • 編集
  • 削除
  • 復元
  • フラグ
  • 履歴
  • ブックマーク
  • ウィキ
  • ロック/アンロック
  • 投稿タイプ
  • 所有権の変更
  • バッジ
  • 非表示投稿
  • 引用
  • など

その結果、プレビューは従来の「プレビュー」コンポーネントよりも、通常のトピックに гораздо より近い動作をすることができます。


返信とコンポーザー

コンポーザーはより複雑な部分の一つです。

プレビューは、通常のDiscourseコンポーザーを開くことができます。

トピックへの返信

トピックコンポーザーは、トピックモデルと正しい下書き情報と共に開かれます。

特定の投稿への返信

投稿がコンポーザーに渡され、返信が通常の投稿返信のように動作します。

選択されたテキストの引用

コンポーネントは PostTextSelection とも統合されています。

つまり、ユーザーはプレビュー内でテキストを選択し、Discourseの通常の引用/返信フローを使用できます。


ネストされたモーダル

もう一つの厄介な部分は、Discourseのモーダルシステムでした。

投稿は他のモーダルやダイアログを開くことができます。

  • フラグ
  • 履歴
  • バッジ関連のダイアログ
  • 所有権の変更
  • 削除の確認
  • など

それらがグローバルモーダルサービスと通常通りにインタラクトすることを許可すると、それらを開くことでトピックプレビュー全体が閉じてしまう可能性があります。

それを避けるために、コンポーネントはローカルなサブモーダルメカニズムを作成します。

概念的には:

Topic Preview Modal
        │
        ├── Flag modal
        ├── History modal
        ├── Delete confirmation
        ├── Badge modal
        └── other post-related modal

プレビューは下層にマウントされたままです。

コンポーネントはアクティブな間に関連するモーダルサービスメソッドを一時的にパッチし、破棄されたときにそれらを復元します。


モーダル内のルーティング

もう一つの重要な詳細は、同じトピック内の投稿へのリンクです。

例えば、投稿に以下へのリンクが含まれている場合:

/t/my-topic/123

プレビューは閉じて離れる必要はありません。

代わりに、コンポーネントは同じトピック内のナビゲーションをインターセプトし、モーダル内の要求された投稿にジャンプします。

特定の投稿番号なしにトピックをターゲットとするリンクにも同じことが適用されます。

これにより、ユーザーはプレビュー内に留まることができます。

リンクが本当に別のトピックを指している場合、コンポーネントはまず一時的なサービスパッチを復元し、通常のDiscourseルート遷移を許可する前に自身を閉じます。

そのクリーンアップは重要です。そうでなければ、実際のトピックルートが初期化されている間に、プレビューのサブスクリプションとタイミングトラッカーが生きてしまう可能性があるためです。


読み取り追跡と時間追跡

また、プレビューがDiscourseの観点から正しく動作することを望みました。

プレビューを開くことは、読み取り追跡が完全にバイパスされることを意味するべきではありません。

したがって、コンポーネントは以下を処理します。

  • トピック訪問の追跡
  • 可視投稿の追跡
  • トピックのタイミング
  • 最終読取投稿の更新

タイミングトラッカーは、実際にどの投稿が可視かを決定するために IntersectionObserver を使用します。

5秒ごとに、可視投稿のタイミングが以下にフラッシュされます。

/topics/timings

モーダルが閉じられると、最後の数秒が失われないように、最終的なフラッシュが実行されます。

実装はまた、単一のタイミング区間を60秒に制限しています。


トピックリストの未読状態の同期

ここにも微妙な問題がありました。

Discourseのトピック追跡状態を更新するだけでは、トピックリストの行に直接表示される未読バッジを更新するには十分ではありません。

したがって、コンポーネントはタイミング情報がフラッシュされた後、行に関連付けられた実際のトピックオブジェクトを更新します。

適切であれば、以下のような値を更新します。

last_read_post_number
unread_posts
unread
new_posts

これにより、モーダル内でトピックを読んだ後、トピックリストはフルページリフレッシュを必要とせずに、新しい読み取り状態を即座に反映できます。


投稿の可視性

プレビューは、個別の投稿が可視になるタイミングを決定するために共有された IntersectionObserver を使用します。

また、オブザーバーがアタッチされたときにも同期可視性チェックがあります。

これにより、投稿がマウントされた時点ですでに可視だが、非同期の最初の IntersectionObserver コールバックがまだ発火していないというエッジケースを処理します。

これは、モーダルが開いた時点でトピック全体がすでに可視になりうる非常に短いトピックに対して特に関連があります。


パフォーマンスに関する考慮事項

主要な目標の一つは、モーダルをパフォーマンスに重いミニチュアトピックページにすることでした。

それのために、いくつかのことが特に行われています。

段階的レンダリング

初期ロードでは、すべての投稿が即座にレンダリングされるわけではありません。

コンポーネントはまず、ターゲット位置に到達するのに十分な数の投稿をレンダリングします。

残りの投稿は、利用可能な場合 requestIdleCallback を使用し、そうでない場合は setTimeout にフォールバックして、段階的にレンダリングされます。

これは、ストリームのかなり下にある投稿の周りで長いトピックを開く場合に特に有用です。

CSS包含

投稿は以下を使用します。

contain: layout;
content-visibility: auto;
contain-intrinsic-size: 1px 180px;

これにより、ブラウザは現在可視でない投稿に対して不要なレンダリング作業を行うのを避けることができます。

遅延画像

まだ読み込みモードが指定されていない画像には、自動的に以下が与えられます。

loading="lazy"
decoding="async"

これにより、多くの画像を含む長いトピックがすべてを即座に読み込むのを防ぎます。


ローディング状態

リクエストが行われている間、モーダルは単に空白の白い/空の領域を表示するわけではありません。

以下を持つスケルトンUIがあります。

  • アバタープレースホルダー
  • ユーザー名/名前プレースホルダー
  • 投稿本文プレースホルダー
  • シマーアニメーション

シマーは以下を尊重します。

prefers-reduced-motion

したがって、モーションの削減を要求したユーザーにはアニメーションが無効になります。


スクロール位置の安定維持

コンポーネントがスクロール位置を手動で操作する必要がある場所がいくつかあります。

例えば、以前の投稿を読み込む場合、新しく挿入されたコンテンツによりスクロール高さが増加します。

単に投稿を先頭に追加すると、ユーザーの現在の位置がジャンプしてしまいます。

したがって、コンポーネントは以前のスクロール高さを記録し、投稿が挿入された後に差分を補償します。

これにより、現在可視のコンテンツがほぼ同じ場所に保たれます。

特定の投稿にジャンプする場合にも同じことが適用されます。

コンポーネントはレンダリング後の位置決めステップを実行し、まだ安定していない可能性があるコンテンツに対応するために、後続のフレームで位置を再確認します。


トピックプレゼンス

関連するトピックデータが利用可能な場合、プレビューはモーダルの下部にDiscourseのトピックプレゼンス情報を表示することもできます。

これにより、ユーザーはプレビューを離れることなく、現在誰がトピックを表示しているかを確認できます。


モバイルメニューとフォーカスとのインタラクション

モバイルはもう一つの問題のカテゴリを導入しました。

一部のDiscourse UI要素は共有されたモーダル/メニューサービスを使用し、それらのサービスはトピックプレビューが現在ネストされたブラウジングコンテキストとして動作していることを必ずしも認識していません。

したがって、コンポーネントには以下の周囲の追加処理があります。

  • modal.close()
  • Float Kitメニュー
  • フォーカス復元
  • コンポーザー
  • ライトボックスのキーボード制御
  • ボディスクロールロック

例えば、メニューが内部でグローバルモーダルのクローズメソッドを呼び出そうとしても、それは誤ってトピックプレビュー全体を閉じてはなりません。

同様に、コンポーザーが開いている場合、フォーカスはプレビューのフォーカスコンテキストに引き戻されるのではなく、コンポーザー内に留まる必要があります。


設定

コンポーネントは現在、以下の設定を公開しています。

設定 デフォルト 説明
trigger_style row 行全体をクリック可能にするか、明示的なボタンを使用するか
plugin_outlet topic-list-after-title ボタントリガーによって使用されるアウトレット
enable_prefetch true バックグラウンドトピックプリフェッチの有効/無効
max_concurrent_prefetches 2 最大同時プリフェッチリクエスト数
prefetch_debounce_ms 400 プリフェッチ開始前の遅延
prefetch_root_margin_px 50 行がビューポートに入るこのピクセル数前にプリフェッチを開始
max_prefetches_per_minute 15 1分あたりの最大投機的リクエスト数

プリフェッチ制御は意図的に設定可能にされています。コミュニティによってトラフィックパターンやホスティング/ネットワーク特性が非常に異なる可能性があるためです。


主要な設計目標の一つ: 通常のDiscourseを壊さない

コンポーネントをDiscourseの既存アーキテクチャにできるだけ近づけるよう試みました。

独自の投稿レンダラー、独自のコンポーザー、独自のトピックモデル、または完全に独立した投稿ストリームを実装していません。

代わりに、Discourseの既存のコンポーネントとサービスの周りに一時的なブラウジングコンテキストを構築しています。

そのため、実装の一部は、最初に思われるよりも複雑です。

より興味深い課題は以下でした。

トピックが別のUIコンテキスト内で表示されている間、ほぼ通常のDiscourseトピックのように動作することは可能か?

それには、Discourseのグローバルサービスとローカルプレビューの境界を処理する必要がありました。

「いいね!」 18

参考までに:

数学処理に問題があります。ただし、これは別の境界ケースかもしれません。

「いいね!」 1

本当に素晴らしい :slight_smile: さて、これを自分の環境で動作させる方法を探りましょう :slight_smile: @awesomerobot 行全体をクリックできるようにするために、あなたのテーマは何に依存していますか?

api.renderInOutlet("topic-list-before-link", TopicListItemClick);
「いいね!」 2

Reddit-ish テーマを使用している方のために、動作確認が取れた修正方法を共有します。

Reddit-ish テーマとの互換性

Reddit-ish テーマを使用している方への注意点です:モーダルのボタン自体は正常に動作しますが、デフォルトの行トリガーは機能しません。

問題の原因は、Reddit-ish が標準のトピック一覧の行の動作を置き換え、トピックカード全体でのクリックを処理している点にあります。そのため、モーダルの通常の行クリック処理が意図した通りに動作しません。

Topic Preview Modal の設定を以下に変更すると、

Trigger style: button
Plugin outlet: topic-list-after-title

正しく動作します。これは、Reddit-ish が既に topic-list-after-title アウトレットを含んでいるためです。

カード全体のクリック動作を維持するために、Topic Preview Modal をボタンモードのままにし、Reddit-ish の既存の openTopic() アクションを変更して、動作するモーダルボタンをトリガーするようにしました。

元の Reddit-ish のアクションは以下の通りです:

@action
openTopic(event) {
  if (
    (event.target.nodeName === "A" && !event.target.closest(".raw-link")) ||
    event.target.closest(".badge-wrapper")
  ) {
    return;
  }

  const { navigateToTopic, topic } = this.args.outletArgs;

  if (wantsNewWindow(event)) {
    window.open(topic.lastUnreadUrl, "_blank");
  } else {
    navigateToTopic(topic, topic.lastUnreadUrl);
  }
}

これを以下のように変更しました:

@action
openTopic(event) {
  if (
    (event.target.nodeName === "A" && !event.target.closest(".raw-link")) ||
    event.target.closest(".badge-wrapper") ||
    event.target.closest(".topic-preview-modal__trigger-wrapper")
  ) {
    return;
  }

  const { navigateToTopic, topic } = this.args.outletArgs;

  if (wantsNewWindow(event)) {
    window.open(topic.lastUnreadUrl, "_blank");
    return;
  }

  const previewButton = event.currentTarget.querySelector(
    ".topic-preview-modal__trigger-wrapper--button"
  );

  if (previewButton) {
    event.preventDefault();
    event.stopPropagation();
    previewButton.click();
    return;
  }

  navigateToTopic(topic, topic.lastUnreadUrl);
}

モーダルのボタントリガーは以下のようにレンダリングされます:

<div class="topic-preview-modal__trigger-wrapper">
  <span
    role="button"
    class="topic-preview-modal__trigger-wrapper--button"
  >

したがって、これはモーダルのロジックを再作成するものではなく、単に Reddit-ish のカードクリックが既存の動作するプレビューボタンをトリガーするようになります。

その結果、以下のような動作になります:

  • トピックカードのクリックでプレビューモーダルが開きます。
  • トピックタイトルのクリックでプレビューモーダルが開きます。
  • プレビューボタンも引き続き動作します。
  • Cmd/Ctrl+クリックで、通常通り新しいタブでトピックが開きます。
  • カテゴリーやその他の通常のリンクは通常通り動作します。
  • プレビューボタンが存在しない場合、Reddit-ish は通常のトピックナビゲーションにフォールバックします。

つまり、基盤となるモーダルは Reddit-ish と正常に動作しますが、互換性の問題はデフォルトの行トリガーに特化しています。

また、以下の CSS を使用してボタンを非表示にしました:

.topic-preview-modal__trigger-wrapper {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}
「いいね!」 3

次は、モーダルでネストされた返信を動作させることを試してみます :slight_smile:

「いいね!」 1

お前、すごいね。これは久しぶりに見つけた最高に素晴らしいテーマコンポーネントだ。

唯一物足りなかったのは、横幅を大きくしたり設定できたりすること。トピックビューでの投稿と同じ幅にできたら最高なのに。

「いいね!」 2

最大幅を800pxに調整しました

    .d-modal {
        --modal-max-width: 600px;
        --modal-width: 30em;
        --modal-min-width: 400px;
    }
「いいね!」 1

これはすべてのモーダルに適用されます…
アイコンが目立たないようにするために、これも行いました

.topic-preview-modal__trigger-wrapper--button .d-icon {
    fill: #888;
}

@media (width >= 40rem) {
  .d-modal.topic-preview-modal {
      --modal-max-width: 800px;
  }
}
「いいね!」 2

@Don 気になりますが、なぜコアの <PostList> コンポーネントを再利用しなかったのですか?

「いいね!」 1

@Jagster さん、報告ありがとうございます!修正はこちらです:FIX: Replace visibility:hidden to allow MathJax rendering · VaperinaDEV/discourse-topic-preview-modal@f9eb70f · GitHub


@RGJ さん、対応しました。設定項目を追加しました。


良い質問ですね。

PostList/PostListItem は、抜粋ベースのサマリーリスト(下書き、ブックマーク、アクティビティフィードなど)のために構築されており、トピックの実際のインタラクティブな投稿ストリームを表示するためのものではありません。

DDecoratedHtml を通じて @post.excerpt/expandedExcerpt をレンダリングし、アバターやタイトルヘッダー、および抜粋を展開するボタンを表示します。いいね、引用、返信、編集、またはフラグなどのアクションは含まれておらず、モーダルに必要なインタラクティブな投稿機能は一切ありません。

また、PostList のページネーションは単方向(fetchMorePosts は下方への追加のみ)ですが、モーダルは最後に読んだ投稿から開き、その前後の投稿を両方ロードする必要があります。これには、単純な fetch-more コールバックではなく、本物の postStream サービスのギャップローディングが必要です。

したがって、PostList を再利用した場合、異なる用途のために構築されたコンポーネントの上に、Post のインタラクティブな動作の大部分と postStream の双方向ローディングを再実装することになります。代わりに、実際のコア Post コンポーネントと postStream を直接使用することで、モーダルが本物のトピックページと同じように動作することが保証されます。

「いいね!」 3

ネストされたビューでも動作するようになりました。もう少しテストが必要で、おそらく管理画面にオプションを追加する必要があります。ドンがこれをいくつかの人に使ってもらいましたが、非常にスムーズでスクロールも簡単なので、ユーザーがより多くのリクエストを行い、サイトにとどまる時間が長くなっています。この件で素晴らしい仕事をしてくださいました。

「いいね!」 4

今テスト中です!UIの改善が非常に素晴らしいです

「いいね!」 2

ここで急いでブーストが必要なんですが、そのレスポンスタイムを見てちょっと心配になってきました——生きてますか? :laughing:

ありがとう :sign_of_the_horns:

「いいね!」 3

質問:なぜ .topic-avatarborder-top は、スクロール中に前の投稿の可視部分と現在の投稿の開始部分の間に区切り線として表示されるようになるのでしょうか?この border-top の意図は本当にそれなのですか、それとも配置やオーバーフローに関する何らかのルールによってそのような動作をしているのでしょうか?

@media (width >= 40rem) {
    .topic-avatar {
        border-top: 1px solid var(--content-border-color);
        padding-top: var(--space-4);
        width: var(--topic-avatar-width);
        float: left;
        z-index: 2;
        height: 100%;
        overflow-anchor: none;
    }
}
「いいね!」 1

ページ全体の読み込みを待たずに投稿をすばやく確認したい場合に、非常に役立つのではないかと思います。通知をクリックしたときにトピック一覧ではなくモーダルを開くように切り替えられると嬉しいですね。

「いいね!」 1

こんにちは @Don。この素晴らしいコンポーネントを24時間触ってみた結果、一番気に入ったのは「下へスワイプして閉じる」機能でした。親指や手を動かす必要がなく、サイトが非常に使いやすく感じられたからです。ただし、長いトピックの場合、上にスクロールし直すのは少し不便でした。

この問題に対処するため、モバイルデバイスで「右へスワイプして閉じる」機能を追加しました。これは理にかなっており、IMO(個人的な意見)では、素早いスクロールなどを望むユーザーにも非常に効果的です。どう思いますか?

テスト用リンクは https://www.carptalk-online.co.uk/ です。もちろん、モバイルデバイスでのみ動作します。

「いいね!」 3

Damianさん、フォーラムを試してみましたが、このスワイプ操作は本当に完璧ですね。いつも通り素晴らしいです!

このテーマコンポーネントはHorizonでも動作するのでしょうか?2つのリリースで試してみましたが、管理画面の上部にエラーが表示されました。互換性がないようです。

動作してほしいですね。この新しいアプローチで遊べるのは本当に楽しみです。

「いいね!」 2

どんなエラーが発生していますか?

「いいね!」 2

こんにちは :waving_hand:

新しい設定 open_all_topic_links を追加しました。

これを有効にすると、ページ内のどこにいてもトピックを指すリンク(投稿内容、通知、ユーザーカード、検索結果、おすすめ/関連トピック、サイドバーなど)は、トピック一覧の行だけでなく、ページから離れる代わりにプレビューモーダルを開くようになります。特定の投稿へのリンクは、その投稿にスクロールした状態でモーダルを開きます。トピック一覧内や、すでに開いているプレビューモーダル内のリンクは、従来どおりの動作を維持します。

「いいね!」 5

モーダルはGOATですね :slight_smile: モバイルで右にスワイプして閉じる機能をコアに追加し、ネストビューのサポートも追加できる可能性はありますか? :eyes:

「いいね!」 2