Modal zur Themenübersicht

Diese Theme-Komponente installieren

Topic Preview Modal – Öffnen und Interagieren mit Themen, ohne die Themenliste zu verlassen

Ich habe eine neue Discourse-Theme-Komponente namens Topic Preview Modal erstellt.

Die Idee ist recht einfach:

Ein Thema direkt aus der Themenliste in einem nativen Discourse-Modal öffnen, lesen und damit interagieren, und dann weiter in der Liste browsen, ohne diese zu verlassen.

Es begann mit Facebook-style Topic Modal - Is it better? , entwickelte sich aber zu einer ziemlich umfangreichen Integration mit Discourses Systemen für Themen, Post-Streams, Composer, Modals, Lesezeichen, Routing, Präsenz, Leseverfolgung und Prefetching.


Warum?

Der normale Discourse-Workflow ist:

  1. Du durchsuchst eine Themenliste.
  2. Du klickst auf ein Thema.
  3. Discourse navigiert zu /t/....
  4. Du liest/antwortest/interagierst mit dem Thema.
  5. Du gehst zurück zur Themenliste.

Für viele Workflows ist das völlig in Ordnung.

Wenn man jedoch durch eine belebte Themenliste browsed, möchte man manchmal nur schnell ein Thema inspizieren, ein paar Beiträge lesen, die neuesten Antworten prüfen, auf etwas reagieren oder eine kurze Frage beantworten.

Für diesen Anwendungsfall fühlt sich das Verlassen der Themenliste unnötig aufwendig an.

Das Ziel dieser Komponente war es daher, die Themenliste mehr wie einen Posteingang zu gestalten:

Themenliste → Vorschau → Interaktion → Schließen → genau dort weitermachen, wo man war.


Was es macht

Die Vorschau ist nicht nur ein statischer Auszug.

Sie rendert die tatsächlichen Discourse-Beitragskomponenten innerhalb eines nativen DModal.

Das bedeutet, dass Nutzer können:

  • Beiträge lesen
  • durch das Thema scrollen
  • frühere Beiträge laden
  • weitere Beiträge darunter laden
  • auf Beiträge reagieren
  • Beiträge als Lesezeichen markieren
  • Text zitieren
  • auf das Thema antworten
  • auf einzelne Beiträge antworten
  • Beiträge bearbeiten, wenn erlaubt
  • Beiträge löschen/wiederherstellen, wenn erlaubt
  • Beiträge melden
  • Beitragsverlauf anzeigen
  • verschiedene normale Beitragsaktionen ausführen
  • Themenpräsenz sehen
  • Links zu anderen Beiträgen innerhalb desselben Themas folgen
  • direkt zum relevanten Beitrag springen
  • das volle Thema öffnen, wenn nötig

Die Absicht ist, dass sich die Vorschau so nah wie möglich anfühlt, als würde man das Thema tatsächlich öffnen.


Zwei Auslöser-Modi

Es gibt zwei Möglichkeiten, die Vorschau zu öffnen.

1. Ganze Themenlistenzeile

Dies ist die Standardeinstellung.

Die gesamte Themenlistenzeile wird klickbar, während gängige interaktive Elemente wie:

  • Benutzerkarten
  • Teilnehmer
  • Kategorie-Links
  • Tags
  • Themenstatus-Links
  • Mehrfachauswahl

vom Modal-Auslöser ausgeschlossen sind.

Dies macht das Erlebnis beim Browsen einer Themenliste sehr schnell.

2. Expliziter Erweitern-Button

Alternativ kann die Komponente ein kleines Erweitern-Symbol über einen Discourse-Plugin-Ausgang rendern. Custom Themes können einfach einen neuen <PluginOutlet /> erstellen, um den Auslöser anzuzeigen.

In diesem Modus bleibt das normale Verhalten der Themenliste vollständig unberührt.

Der Benutzer klickt auf das Erweitern-Symbol, um die Vorschau zu öffnen, während ein Klick auf den Themennamen die normale Discourse-Navigation ausführt.

Dies ist nützlich, wenn eine Site das Standardinteraktionsmodell der Themenliste beibehalten möchte.

Die Einstellung ist:

trigger_style:
  row

oder:

trigger_style:
  button

Wenn der Button-Modus verwendet wird, ist der Ausgang ebenfalls konfigurierbar.


Die Vorschau startet an der ungelesenen Position des Benutzers

Ein wichtiges Detail ist, dass das Modal nicht einfach den ersten Beitrag lädt.

Wenn ein Thema bereits teilweise gelesen wurde, berechnet die Vorschau:

last_read_post_number + 1

und öffnet sich um diesen Beitrag herum.

Wenn ein Thema also 200 Beiträge hat und der Benutzer bis Beitrag #165 gelesen hat, startet das Öffnen der Vorschau bei #166.

Dies macht die Vorschau für das reale Browsen viel nützlicher.

Es bedeutet auch, dass die Komponente mit beiden Seiten des Beitragsstroms umgehen muss:

  • Laden früherer Beiträge, wenn nötig
  • Laden neuerer Beiträge darunter

Der Button Frühere Beiträge wird angezeigt, wenn es Beiträge oberhalb des aktuell geladenen Bereichs gibt, während ein IntersectionObserver-Sentinel automatisch weitere Beiträge lädt, wenn der Benutzer das Ende erreicht.


Prefetching

Einer der größten Teile der Komponente ist ihr Prefetch-System.

Das Problem mit einem solchen Modal ist, dass der Benutzer erwartet, dass es sich augenblicklich anfühlt.

Wenn wir erst nach dem Klick des Benutzers mit dem Laden des Themas beginnen, kann das Modal spürbare Zeit mit dem Warten auf das Netzwerk verbringen.

Stattdessen kann die Komponente Themen proaktiv prefetchen, während der Benutzer in der Liste browsed.

Wenn eine Themenzeile den Viewport erreicht, kann ein IntersectionObserver einen Prefetch planen.

Es gibt mehrere Schutzmaßnahmen, um zu verhindern, dass dies zu unkontrolliertem Hintergrundverkehr wird.

Debouncing

Ein Thema löst nicht sofort eine Anfrage aus, nur weil es kurz im Viewport erschienen ist.

Die Komponente wartet die konfigurierte Debounce-Periode ab.

Standard:

400 ms

Dies ist besonders nützlich, wenn man schnell durch eine lange Themenliste scrollt.

Root margin

Das Prefetching kann etwas früher beginnen, bevor das Thema tatsächlich den Viewport betritt.

Standard:

50 px

Dies gibt der Anfrage einen kleinen Vorsprung.

Begrenzung gleichzeitiger Anfragen

Die Anzahl der gleichzeitigen Prefetches ist begrenzt.

Standard:

2

Die Einstellung erlaubt zwischen 1 und 6 gleichzeitigen Prefetches.

Budget pro Minute

Es gibt auch einen zweiten Schutzmechanismus:

max_prefetches_per_minute

Der Standard ist:

15

Selbst wenn der Benutzer weiterhin durch Hunderte von Themen scrollt, generiert die Komponente nicht kontinuierlich spekulatives Anfragen.

0 deaktiviert das Limit.

Prefetch kann vollständig deaktiviert werden

Wenn eine Site keinen spekulativen Netzwerkverkehr möchte:

enable_prefetch = false

Die Komponente funktioniert weiterhin normal. Themen laden einfach, wenn die Vorschau geöffnet wird.


Prefetch-Daten werden separat von der normalen Themen-Navigation gespeichert

Hier gibt es ein wichtiges Implementierungsdetail.

Die geprefetchte Antwort wird nicht sofort in Discourses normale topic_<id> Preload-Schlüssel geschrieben.

Stattdessen verwendet die Komponente ihren eigenen Namespace:

topic-preview-modal:prefetch:<topicId>

Nur wenn der Benutzer tatsächlich die Vorschau öffnet, wird das geprefetchte Versprechen zum Kern-Themen-Preload-Schlüssel befördert.

Dies ist beabsichtigt.

Die Vorschau lädt möglicherweise ein Thema beginnend bei last_read_post_number + 1, und ich möchte nicht, dass diese vorschau-spezifische Antwort in eine normale Themen-Route-Navigation überläuft.

Der Lebenszyklus ist also im Wesentlichen:

Thema betritt Viewport
        ↓
prefetch
        ↓
privater Preload-Speicher
        ↓
Benutzer öffnet Vorschau
        ↓
Preload befördern
        ↓
Topic.find()/PostStream verwendet dasselbe Versprechen

Das bedeutet auch, dass das Modal nicht warten muss, bis die Prefetch-Anfrage abgeschlossen ist, bevor es sich öffnet.

Das Modal kann sich sofort mit seinem Skeleton öffnen, während dasselbe Versprechen weiterhin aufgelöst wird.


Mobile-Unterstützung

Dies war tatsächlich einer der Gründe, warum ich erheblich mehr Zeit in die Implementierung investiert habe.

Die ursprüngliche Idee funktionierte auf dem Desktop recht gut, aber Mobile offenbarte mehrere Probleme bezüglich:

  • Touch-Interaktion
  • Modal-Scrollen
  • Fokus
  • verschachtelten Menüs
  • dem Composer
  • Beitrags-Sichtbarkeit
  • Bildladen
  • Leistung

Die finale Implementierung behandelt das Modal daher nicht als völlig separates Miniatur-Forum.

Stattdessen wiederverwendet es so viel von Discourses bestehender Infrastruktur wie möglich.


Echte Discourse-Beitragskomponenten

Das Modal erstellt Beiträge nicht neu mit einer vereinfachten benutzerdefinierten Vorlage.

Es rendert Discourses tatsächliche:

Post
PostSmallAction

Komponenten.

Dies ist wichtig, da sonst die Vorschau schnell zu einer zweiten Implementierung der Beitrags-UI werden würde.

Die Komponente übergibt die relevanten Aktionen an die normalen Beitragskomponenten, einschließlich Dinge wie:

  • antworten
  • bearbeiten
  • löschen
  • wiederherstellen
  • melden
  • Verlauf
  • Lesezeichen
  • Wiki
  • sperren/entsperren
  • Beitragstyp
  • Eigentumsänderungen
  • Abzeichen
  • versteckte Beiträge
  • Zitieren
  • usw.

Das Ergebnis ist, dass sich die Vorschau viel mehr wie ein normales Thema verhalten kann als eine traditionelle „Vorschau“-Komponente.


Antworten und der Composer

Der Composer ist einer der komplizierteren Teile.

Die Vorschau kann den normalen Discourse-Composer öffnen für:

Antworten auf das Thema

Der Themen-Composer wird mit dem Themenmodell und den richtigen Entwurfsinformationen geöffnet.

Antworten auf einen bestimmten Beitrag

Der Beitrag wird an den Composer übergeben, sodass die Antwort wie eine normale Beitragsantwort funktioniert.

Zitieren ausgewählten Textes

Die Komponente integriert sich auch mit PostTextSelection.

Das bedeutet, dass Nutzer Text innerhalb der Vorschau auswählen und Discourses normalen Zitat-/Antwort-Workflow verwenden können.


Verschachtelte Modals

Ein weiterer kniffliger Teil war Discourses Modal-System.

Beiträge können andere Modals und Dialoge öffnen:

  • Melden
  • Verlauf
  • Abzeichen-bezogene Dialoge
  • Eigentumsänderungen
  • Löschbestätigungen
  • usw.

Wenn diese normalerweise mit dem globalen Modal-Service interagieren dürften, könnte das Öffnen eines davon das gesamte Themen-Vorschau-Modal schließen.

Um das zu vermeiden, erstellt die Komponente einen lokalen Sub-Modal-Mechanismus.

Konzeptionell:

Topic Preview Modal
        │
        ├── Melden-Modal
        ├── Verlauf-Modal
        ├── Löschbestätigung
        ├── Abzeichen-Modal
        └── andere beitragbezogene Modals

Die Vorschau bleibt darunter montiert.

Die Komponente patcht vorübergehend die relevanten Modal-Service-Methoden, während sie aktiv ist, und stellt sie wieder her, wenn sie zerstört wird.


Routing innerhalb des Modals

Ein weiteres wichtiges Detail sind Links zu Beiträgen innerhalb desselben Themas.

Wenn ein Beitrag beispielsweise einen Link zu:

/t/my-topic/123

enthält, muss die Vorschau nicht geschlossen und abgelenkt werden.

Stattdessen fängt die Komponente die Navigation innerhalb desselben Themas ab und springt zum angeforderten Beitrag innerhalb des Modals.

Das Gleiche gilt für Links, die das Thema ohne eine bestimmte Beitragsnummer ansprechen.

Dies hält den Benutzer innerhalb der Vorschau.

Wenn der Link zu einem wirklich anderen Thema führt, stellt die Komponente zuerst ihre temporären Service-Patches wieder her und schließt sich, bevor sie den normalen Discourse-Route-Übergang zulässt.

Diese Bereinigung ist wichtig, da sonst die Abonnements und der Timing-Tracker der Vorschau am Leben bleiben könnten, während die echte Themen-Route initialisiert wird.


Leseverfolgung und Zeitverfolgung

Ich wollte auch, dass sich die Vorschau aus Discourses Sicht korrekt verhält.

Das Öffnen einer Vorschau sollte nicht bedeuten, dass die Leseverfolgung vollständig umgangen wird.

Die Komponente verarbeitet daher:

  • Themenbesuchs-Verfolgung
  • Sichtbare Beitrags-Verfolgung
  • Themen-Timing
  • Updates des zuletzt gelesenen Beitrags

Der Timing-Tracker verwendet einen IntersectionObserver, um zu bestimmen, welche Beiträge tatsächlich sichtbar sind.

Alle 5 Sekunden wird das Timing sichtbarer Beiträge an:

/topics/timings

gesendet.

Wenn das Modal geschlossen wird, wird ein letztes Mal gesendet, damit die letzten Sekunden nicht verloren gehen.

Die Implementierung begrenzt auch ein einzelnes Timing-Intervall auf 60 Sekunden.


Synchronisierung des ungelesenen Status der Themenliste

Hier gab es ein weiteres subtiles Problem.

Das Aktualisieren von Discourses Themen-Tracking-Status allein reicht nicht aus, um das ungelesene Abzeichen direkt in einer Themenlistenzeile zu aktualisieren.

Die Komponente aktualisiert daher das tatsächliche Themenobjekt, das mit der Zeile verbunden ist, nachdem Timing-Informationen gesendet wurden.

Es aktualisiert Werte wie:

last_read_post_number
unread_posts
unread
new_posts

wenn appropriate.

Das bedeutet, dass die Themenliste nach dem Lesen eines Themas im Modal den neuen Lesestatus sofort widerspiegeln kann, anstatt einen vollständigen Seiten-Refresh zu erfordern.


Beitrags-Sichtbarkeit

Die Vorschau verwendet einen gemeinsamen IntersectionObserver, um zu bestimmen, wann einzelne Beiträge sichtbar werden.

Es gibt auch eine synchrone Sichtbarkeitsprüfung, wenn der Observer angehängt wird.

Dies behandelt einen Randfall, in dem ein Beitrag bereits sichtbar ist, wenn er montiert wird, aber der asynchrone erste IntersectionObserver-Callback noch nicht ausgelöst wurde.

Dies ist besonders relevant für sehr kurze Themen, bei denen das gesamte Thema bereits sichtbar sein kann, wenn das Modal geöffnet wird.


Leistungsaspekte

Ein Hauptziel war es, zu verhindern, dass das Modal zu einer leistungsaufwendigen Miniatur-Themen-Seite wird.

Einige Dinge werden speziell dafür getan.

Progressives Rendering

Der initiale Ladevorgang rendert nicht sofort jeden Beitrag.

Die Komponente rendert zuerst genug Beiträge, um die Zielposition zu erreichen.

Die verbleibenden Beiträge werden dann progressiv gerendert unter Verwendung von:

requestIdleCallback

wenn verfügbar, mit einem Fallback zu setTimeout.

Dies ist besonders nützlich, wenn man ein langes Thema um einen Beitrag weit unten im Stream herum öffnet.

CSS-Containment

Beiträge verwenden:

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

Dies ermöglicht es dem Browser, unnötige Rendering-Arbeit für Beiträge zu vermeiden, die derzeit nicht sichtbar sind.

Lazy Images

Bilder, die noch keinen Lademodus angegeben haben, erhalten automatisch:

loading="lazy"
decoding="async"

Dies verhindert, dass ein langes Thema mit vielen Bildern sofort alles lädt.


Ladezustand

Das Modal zeigt nicht nur einen leeren weißen Bereich an, während die Anfrage gestellt wird.

Es hat eine Skeleton-UI mit:

  • Avatar-Platzhaltern
  • Benutzername/Namen-Platzhaltern
  • Beitragskörper-Platzhaltern
  • Shimmer-Animation

Der Shimmer beachtet:

prefers-reduced-motion

so dass die Animation für Benutzer deaktiviert ist, die reduzierte Bewegung angefordert haben.


Stabilisierung der Scroll-Position

Es gibt einige Stellen, an denen die Komponente die Scroll-Position manuell manipulieren muss.

Wenn beispielsweise frühere Beiträge geladen werden, erhöht der neu eingefügte Inhalt die Scroll-Höhe.

Das einfache Voranstellen der Beiträge würde dazu führen, dass die aktuelle Position des Benutzers springt.

Die Komponente zeichnet daher die vorherige Scroll-Höhe auf und kompensiert den Unterschied, nachdem die Beiträge eingefügt wurden.

Dies hält den aktuell sichtbaren Inhalt ungefähr an derselben Stelle.

Das Gleiche gilt beim Springen zu einem bestimmten Beitrag.

Die Komponente führt einen Post-Rendering-Positionierungsschritt durch und überprüft die Position in nachfolgenden Frames erneut, um Inhalte zu berücksichtigen, die sich möglicherweise noch einpendeln.


Themen-Präsenz

Wenn die relevanten Thementdaten verfügbar sind, kann die Vorschau auch Discourses Themen-Präsenzinformationen am unteren Rand des Modals anzeigen.

So können Benutzer sehen, wer else sich das Thema gerade ansieht, ohne die Vorschau verlassen zu müssen.


Interaktion mit mobilen Menüs und Fokus

Mobile führte eine weitere Kategorie von Problemen ein.

Einige Discourse-UI-Elemente verwenden gemeinsame Modal-/Menü-Services, und diese Services wissen nicht unbedingt, dass die Themen-Vorschau derzeit als verschachtelter Browser-Kontext fungiert.

Die Komponente hat daher zusätzliche Handhabung für:

  • modal.close()
  • Float Kit-Menüs
  • Fokus-Wiederherstellung
  • den Composer
  • Lightbox-Tastatursteuerungen
  • Body-Scroll-Locks

Wenn ein Menü intern versucht, die globale Modal-Schließmethode aufzurufen, sollte das nicht versehentlich das gesamte Themen-Vorschau-Modal schließen.

Wenn der Composer geöffnet ist, muss der Fokus innerhalb des Composers bleiben, anstatt in den Fokus-Kontext der Vorschau gezogen zu werden.


Konfiguration

Die Komponente stellt derzeit die folgenden Einstellungen zur Verfügung:

Einstellung Standard Beschreibung
trigger_style row Ganze Zeile klickbar machen oder expliziten Button verwenden
plugin_outlet topic-list-after-title Ausgang, der vom Button-Auslöser verwendet wird
enable_prefetch true Hintergrund-Themen-Prefetching aktivieren/deaktivieren
max_concurrent_prefetches 2 Maximale gleichzeitige Prefetch-Anfragen
prefetch_debounce_ms 400 Verzögerung vor dem Start eines Prefetch
prefetch_root_margin_px 50 Prefetching in dieser vielen Pixeln vor dem Betreten des Viewports starten
max_prefetches_per_minute 15 Maximale spekulative Anfragen pro Minute

Die Prefetch-Steuerungen sind absichtlich konfigurierbar, da verschiedene Communities sehr unterschiedliche Verkehrsmuster und Hosting-/Netzwerkmerkmale haben können.


Eines der Hauptdesignziele: Normales Discourse nicht kaputt machen

Ich habe versucht, die Komponente so nah wie möglich an Discourses bestehende Architektur zu halten.

Es implementiert keinen eigenen Beitrags-Renderer, keinen eigenen Composer, kein eigenes Themenmodell oder keinen eigenen völlig separaten Beitragsstrom.

Stattdessen baut es einen temporären Browser-Kontext um Discourses bestehende Komponenten und Services herum.

Das ist auch der Grund, warum einige Teile der Implementierung komplizierter sind, als sie auf den ersten Blick erscheinen mögen.

Die interessantere Herausforderung war:

Kann sich ein Thema fast wie ein normales Discourse-Thema verhalten, während es tatsächlich innerhalb eines anderen UI-Kontexts angezeigt wird?

Das erforderte den Umgang mit den Grenzen zwischen Discourses globalen Services und der lokalen Vorschau.

5 „Gefällt mir“

Zur Information:

Es gibt Probleme mit der Mathematik. Das könnte jedoch ein weiterer Sonderfall sein.

1 „Gefällt mir“

Ein absoluter Legende :slight_smile: jetzt muss ich nur noch herausfinden, wie ich das mit meinem Setup zum Laufen bringe :slight_smile: @awesomerobot wovon hängt dein Theme für den Klick auf die gesamte Zeile ab?

api.renderInOutlet("topic-list-before-link", TopicListItemClick);
2 „Gefällt mir“

Für alle, die das Reddit-ähnliche Theme verwenden, hier eine Lösung, die bei mir funktioniert hat.

Kompatibilität mit dem Reddit-ähnlichen Theme

Nur eine kurze Anmerkung für alle, die das Reddit-ähnliche Theme verwenden: Der Modal-Button selbst funktioniert, aber der Standard-Zeilen-Trigger nicht.

Das Problem ist, dass das Reddit-ähnliche Theme das Standardverhalten der Themenlistenzeile ersetzt und Klicks auf die gesamte Themenkarte selbst verarbeitet. Deshalb funktioniert die normale Klickverarbeitung der Zeile für den Modal nicht wie beabsichtigt.

Wenn man die Einstellung für den Themen-Vorschau-Modal auf ändert:

Trigger-Stil: button
Plugin-Ausgang: topic-list-after-title

funktioniert es korrekt, da das Reddit-ähnliche Theme den Ausgang topic-list-after-title bereits enthält.

Um das Klickverhalten der gesamten Karte beizubehalten, habe ich den Themen-Vorschau-Modal im Button-Modus belassen und die bestehende openTopic()-Aktion des Reddit-ähnlichen Themas so geändert, dass sie den funktionierenden Button des Modals auslöst.

Die ursprüngliche Aktion des Reddit-ähnlichen Themas ist:

@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);
  }
}

Ich habe sie geändert zu:

@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);
}

Der Trigger-Button des Modals wird gerendert als:

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

Somit wird keine der Modal-Logik neu erstellt. Es lässt einfach den Klick auf die Karte des Reddit-ähnlichen Themas den bestehenden funktionierenden Vorschau-Button auslösen.

Das Ergebnis ist:

  • Ein Klick auf die Themenkarte öffnet den Vorschau-Modal.

  • Ein Klick auf den Thementitel öffnet den Vorschau-Modal.

  • Der Vorschau-Button funktioniert weiterhin.

  • Cmd/Ctrl-Klick öffnet weiterhin das normale Thema in einem neuen Tab.

  • Kategorie- und andere normale Links verhalten sich weiterhin normal.

  • Wenn der Vorschau-Button nicht vorhanden ist, fällt das Reddit-ähnliche Theme auf seine normale Themen-Navigation zurück.

Der zugrunde liegende Modal funktioniert also einwandfrei mit dem Reddit-ähnlichen Theme; die Inkompatibilität betrifft spezifisch den Standard-Zeilen-Trigger.

Ich habe den Button außerdem versteckt, indem ich verwendet habe:

.topic-preview-modal__trigger-wrapper {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}
2 „Gefällt mir“

Nun versuche ich, verschachtelte Antworten im Modal-Dialog zum Laufen zu bringen :slight_smile:

1 „Gefällt mir“