Vorschau-Dialogfeld für Themen

Dieses Theme-Component installieren

Topic Preview Modal – Themen öffnen und damit interagieren, ohne die Themenliste zu verlassen

Ich habe ein neues Discourse-Theme-Component namens Topic Preview Modal erstellt.

Die Idee ist ziemlich einfach:

Ein Thema direkt aus der Themenliste in einem nativen Discourse-Modal öffnen, das Thema lesen und damit interagieren und anschließend mit dem Durchblättern der Liste genau dort weitermachen, wo man aufgehört hat, ohne die Seite zu wechseln.

Es begann mit Facebook-style Topic Modal - Is it better? , endete aber damit, dass eine recht umfangreiche Integration mit den Systemen für Themen, Beitragsströme, Composer, Modals, Lesezeichen, Routing, Präsenz, Lese-Tracking und Prefetching in Discourse erforderlich war.


Warum?

Der normale Discourse-Workflow ist:

  1. Du durchblätterst 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 Themenliste zurück.

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

Wenn man jedoch eine geschäftige Themenliste durchblättert, möchte man manchmal nur schnell ein Thema inspizieren, ein paar Beiträge lesen, die neuesten Antworten prüfen, auf etwas reagieren oder eine schnelle Frage beantworten.

Für diesen Anwendungsfall fühlt es sich unnötig aufwendig an, die Themenliste zu verlassen.

Das Ziel dieses Components war daher, die Themenliste so zu verhalten, wie ein Posteingang:

Themenliste → Vorschau → Interagieren → Schließen → Genau dort weitermachen, wo man war.


Was es tut

Die Vorschau ist kein statischer Auszug.

Sie rendert die tatsächlichen Discourse-Beitragskomponenten in einem nativen DModal.

Das bedeutet, dass Benutzer:

  • Beiträge lesen
  • durch das Thema scrollen
  • frühere Beiträge laden
  • weitere Beiträge unten laden
  • auf Beiträge reagieren
  • Beiträge als Lesezeichen speichern
  • 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
  • die Präsenz im Thema sehen
  • Links zu anderen Beiträgen innerhalb desselben Themas folgen
  • direkt zum relevanten Beitrag springen
  • das vollständige Thema öffnen, wenn nötig

Die Absicht ist, dass sich die Vorschau so nah wie möglich an das eigentliche Öffnen des Themas anfühlt.


Zwei Auslösermodi

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 ausgenommen sind.

Dies macht die Erfahrung beim Durchblättern einer Themenliste sehr schnell.

2. Expliziter Aufklapp-Button

Alternativ kann das Component ein kleines Aufklapp-Icon über einen Discourse-Plugin-Outlet rendern. Custom-Themes können einfach einen neuen <PluginOutlet /> erstellen, um den Auslöser anzuzeigen.

In diesem Modus bleibt das normale Verhalten der Themenliste völlig unberührt.

Der Benutzer klickt auf das Aufklapp-Icon, um die Vorschau zu öffnen, während das Klicken auf den Themennamen die normale Discourse-Navigation ausführt.

Dies ist nützlich, wenn eine Website das Standard-Interaktionsmodell der Themenliste beibehalten möchte.

Die Einstellung lautet:

trigger_style:
  row

oder:

trigger_style:
  button

Wenn der Button-Modus verwendet wird, ist auch der Outlet 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 also ein Thema 200 Beiträge hat und der Benutzer bis Beitrag #165 gelesen hat, startet das Öffnen der Vorschau bei ca. #166.

Dies macht die Vorschau für das reale Durchblättern viel nützlicher.

Es bedeutet auch, dass das Component mit beiden Seiten des Beitragsstroms umgehen muss:

  • Laden früherer Beiträge bei Bedarf
  • Laden neuerer Beiträge unten

Der Frühere Beiträge-Button 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 des Components ist sein Prefetch-System.

Das Problem mit einem Modal wie diesem ist, dass der Benutzer erwartet, es fühlt sich augenblicklich an.

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

Stattdessen kann das Component Themen proaktiv prefetchen, während der Benutzer die Liste durchblättert.

Wenn eine Themenzeile sich dem Viewport nähert, kann ein IntersectionObserver einen Prefetch planen.

Es gibt mehrere Schutzmechanismen, um zu verhindern, dass dies zu unkontrolliertem Hintergrundverkehr führt.

Debouncing

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

Das Component wartet auf den konfigurierten Debounce-Zeitraum.

Standard:

400 ms

Dies ist besonders nützlich, wenn schnell durch eine lange Themenliste gescrollt wird.

Root Margin

Das Prefetching kann etwas 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 Standardwert ist:

15

Selbst wenn der Benutzer weiter durch Hunderte von Themen scrollt, erzeugt das Component nicht kontinuierlich spekulative Anfragen.

0 deaktiviert die Begrenzung.

Prefetching kann vollständig deaktiviert werden

Wenn eine Website keinen spekulativen Netzwerkverkehr möchte:

enable_prefetch = false

Das Component funktioniert weiterhin normal. Themen werden einfach geladen, wenn die Vorschau geöffnet wird.


Prefetch-Daten werden getrennt von der normalen Themenavigation gespeichert

Hier gibt es ein wichtiges Implementierungsdetail.

Die prefetchte Antwort wird nicht sofort in den normalen topic_<id>-Preload-Schlüssel von Discourse geschrieben.

Stattdessen verwendet das Component seinen eigenen Namespace:

topic-preview-modal:prefetch:<topicId>

Erst wenn der Benutzer die Vorschau tatsächlich öffnet, wird der prefetchte Promise auf den Kern-Themen-Preload-Schlüssel hochgestuft.

Dies ist absichtlich so.

Die Vorschau kann ein Thema ab last_read_post_number + 1 laden, und ich möchte nicht, dass diese vorschau-spezifische Antwort in eine normale Themen-Route-Navigation einfließt.

Der Lebenszyklus ist also im Wesentlichen:

Thema betritt Viewport
        ↓
Prefetch
        ↓
Privater Preload-Speicher
        ↓
Benutzer öffnet Vorschau
        ↓
Preload hochstufen
        ↓
Topic.find()/PostStream verwendet denselben Promise

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

Das Modal kann sofort mit seinem Skeleton-UI geöffnet werden, während derselbe Promise weiterhin aufgelöst wird.


Mobile Unterstützung

Das war tatsächlich einer der Gründe, warum ich deutlich mehr Zeit für die Implementierung aufgewendet habe.

Die ursprüngliche Idee funktionierte auf dem Desktop relativ gut, aber Mobile offenbarte mehrere Probleme im Zusammenhang mit:

  • Touch-Interaktion
  • Modal-Scrolling
  • Fokus
  • verschachtelten Menüs
  • dem Composer
  • Beitragsvisibility
  • Bildladen
  • Leistung

Die finale Implementierung behandelt das Modal daher nicht als vollständig separate Miniatur-Foren-Instanz.

Stattdessen wird so viel wie möglich der vorhandenen Infrastruktur von Discourse wiederverwendet.


Echte Discourse-Beitragskomponenten

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

Es rendert die tatsächlichen:

Post
PostSmallAction

Komponenten von Discourse.

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

Das Component übergibt die relevanten Aktionen an die normalen Beitragskomponenten, einschließlich Dinge wie:

  • Antwort
  • Bearbeiten
  • Löschen
  • Wiederherstellen
  • Melden
  • Verlauf
  • Lesezeichen
  • Wiki
  • Sperren/Entsperren
  • Beitragstyp
  • Eigentumsänderungen
  • Abzeichen
  • verborgene Beiträge
  • Zitieren
  • usw.

Das Ergebnis ist, dass sich die Vorschau viel mehr wie ein normales Thema verhält als wie ein traditionelles „Vorschau“-Component.


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, damit die Antwort wie eine normale Beitragsantwort funktioniert.

Zitieren von ausgewähltem Text

Das Component integriert sich auch mit PostTextSelection.

Das bedeutet, Benutzer können Text in der Vorschau auswählen und den normalen Zitat/Antwort-Workflow von Discourse verwenden.


Verschachtelte Modals

Ein weiterer schwieriger Teil war das Modal-System von Discourse.

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

  • Melden
  • Verlauf
  • abzeichenbezogene Dialoge
  • Eigentumsänderungen
  • Löschbestätigungen
  • usw.

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

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

Konzeptionell:

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

Die Vorschau bleibt darunter gemountet.

Das Component patcht die relevanten Modal-Service-Methoden temporär, während es aktiv ist, und stellt sie wieder her, wenn es zerstört wird.


Routing innerhalb des Modals

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

Wenn beispielsweise ein Beitrag einen Link zu:

/t/my-topic/123

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

Stattdessen fängt das Component Navigationen innerhalb desselben Themas ab und springt zum angeforderten Beitrag innerhalb des Modals.

Gleiches gilt für Links, die auf das Thema ohne eine bestimmte Beitragsnummer abzielen.

Dies hält den Benutzer innerhalb der Vorschau.

Wenn der Link auf ein wirklich anderes Thema zeigt, stellt das Component seine temporären Service-Patches zuerst wieder her und schließt sich selbst, bevor es die normale Discourse-Route-Übergabe erlaubt.

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


Lese-Tracking und Zeit-Tracking

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

Das Öffnen einer Vorschau sollte nicht bedeuten, dass das Lese-Tracking vollständig umgangen wird.

Das Component behandelt daher:

  • Themenbesuchs-Tracking
  • sichtbare Beitrags-Tracking
  • Themen-Timing
  • Aktualisierung des letzten 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 Intervall auf 60 Sekunden.


Den ungelesenen Status der Themenliste synchron halten

Hier gab es ein weiteres subtiles Problem.

Nur den Themen-Tracking-Status von Discourse zu aktualisieren, reicht nicht aus, um das Ungelesen-Badge anzuzeigen, das direkt auf einer Themenlistenzeile angezeigt wird.

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

Es aktualisiert Werte wie:

last_read_post_number
unread_posts
unread
new_posts

wenn angemessen.

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


Beitragsvisibility

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

Es gibt auch einen synchronen Visibility-Check, wenn der Observer angehängt wird.

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

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


Leistungsüberlegungen

Ein Hauptziel war es, zu vermeiden, das Modal in eine leistungstechnisch schwere Miniatur-Themenseite zu verwandeln.

Dafür werden einige Dinge speziell unternommen.

Progressives Rendering

Das anfängliche Laden rendert nicht sofort jeden Beitrag.

Das Component rendert zunächst genügend Beiträge, um die Zielposition zu erreichen.

Die verbleibenden Beiträge werden dann progressiv gerendert, wobei verwendet wird:

requestIdleCallback

wenn verfügbar, mit einem Fallback auf setTimeout.

Das ist besonders nützlich, wenn ein langes Thema um einen weit unten im Strom liegenden Beitrag herum geöffnet wird.

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 Lade-Modus angegeben haben, erhalten automatisch:

loading="lazy"
decoding="async"

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


Ladezustand

Das Modal zeigt nicht nur eine leere weiße/leere Fläche an, während die Anfrage gestellt wird.

Es hat ein Skeleton-UI mit:

  • Avatar-Platzhaltern
  • Benutzername/Name-Platzhaltern
  • Beitragskörper-Platzhaltern
  • Schimmer-Animation

Der Schimmer respektiert:

prefers-reduced-motion

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


Scrollposition stabil halten

Es gibt einige Stellen, an denen das Component die Scrollposition manuell manipulieren muss.

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

Einfaches Voranfügen der Beiträge würde dazu führen, dass sich die aktuelle Position des Benutzers verschiebt.

Das Component zeichnet daher die vorherige Scrollhöhe auf und kompensiert die Differenz, nachdem die Beiträge eingefügt wurden.

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

Gleiches gilt, wenn zu einem bestimmten Beitrag gesprungen wird.

Das Component führt einen Positionsbestimmungsschritt nach dem Rendering durch und überprüft die Position erneut in nachfolgenden Frames, um Inhalte zu berücksichtigen, die sich möglicherweise noch einrichten.


Themenpräsenz

Wenn die relevanten Themedaten verfügbar sind, kann die Vorschau auch die Themenpräsenz-Informationen von Discourse unten im Modal anzeigen.

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


Interaktion mit mobilen Menüs und Fokus

Mobile brachte eine weitere Kategorie von Problemen mit sich.

Einige Discourse-UI-Elemente verwenden gemeinsame Modal/Menu-Services, und diese Services wissen nicht unbedingt, dass die Themen-Vorschau derzeit als verschachtelter Kontext für das Durchblättern dient.

Das Component hat daher zusätzliche Handhabung für:

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

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

Ähnlich muss, wenn der Composer geöffnet ist, der Fokus innerhalb des Composers bleiben und nicht in den Fokus-Kontext der Vorschau zurückgezogen werden.


Konfiguration

Das Component bietet derzeit die folgenden Einstellungen an:

Einstellung Standard Beschreibung
trigger_style row Ganze Zeile klickbar machen oder expliziten Button verwenden
plugin_outlet topic-list-after-title Outlet, das 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 Prefetches
prefetch_root_margin_px 50 Prefetching diese Anzahl an Pixeln vor dem Betreten des Viewports durch die Zeile starten
max_prefetches_per_minute 15 Maximale spekulative Anfragen pro Minute

Die Prefetch-Steuerungen sind absichtlich konfigurierbar, da verschiedene Gemeinschaften sehr unterschiedliche Verkehrs- und Netzwerkmerkmale haben können.


Eines der Hauptdesignziele: Normales Discourse nicht kaputt machen

Ich habe versucht, das Component so nah wie möglich an die vorhandene Architektur von Discourse zu halten.

Es implementiert keinen eigenen Beitrags-Renderer, keinen eigenen Composer, kein eigenes Themenmodell oder keinen eigenen, vollständig getrennten Beitragsstrom.

Stattdessen baut es einen temporären Durchblättern-Kontext um die vorhandenen Komponenten und Services von Discourse 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 in einem anderen UI-Kontext angezeigt wird?

Das erforderte es, die Grenzen zwischen den globalen Services von Discourse und der lokalen Vorschau zu behandeln.

18 „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;
}
3 „Gefällt mir“

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

1 „Gefällt mir“

Du, mein Freund, bist großartig. Das muss das fantastischste Theme-Element sein, das ich seit langer Zeit gesehen habe.

Das einzige, was mir fehlt, ist eine größere / konfigurierbare Breite. Es wäre schön, wenn wir sie auf die gleiche Breite wie die Beiträge in der Themenansicht einstellen könnten.

2 „Gefällt mir“

Ich habe die maximale Breite auf 800 px angepasst

    .d-modal {
        --modal-max-width: 600px;
        --modal-width: 30em;
        --modal-min-width: 400px;
    }
1 „Gefällt mir“

Das würde für alle Modals gelten…
Ich habe das auch gemacht, damit das Icon weniger hervorsticht

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

@media (width >= 40rem) {
  .d-modal.topic-preview-modal {
      --modal-max-width: 800px;
  }
}
2 „Gefällt mir“

@Don Ich bin neugierig: Warum hast du das <PostList>-Komponente von core nicht wiederverwendet <PostList>?

1 „Gefällt mir“

Hey @Jagster, danke für den Bericht! Hier ist die Korrektur: FIX: Replace visibility:hidden to allow MathJax rendering · VaperinaDEV/discourse-topic-preview-modal@f9eb70f · GitHub


Danke @RGJ, ich habe eine Einstellung dafür hinzugefügt.


Das ist eine gute Frage.

PostList/PostListItem ist für zusammenfassende Listen auf Basis von Auszügen (Entwürfe, Lesezeichen, Aktivitätsfeeds) konzipiert, nicht für die Darstellung des tatsächlichen interaktiven Beitragsstroms eines Themas.

Es rendert @post.excerpt/expandedExcerpt über DDecoratedHtml, sowie einen Avatar-/Titel-Header und eine Schaltfläche zum Erweitern des Auszugs. Es gibt keine Aktionen zum Liken, Zitieren, Antworten, Bearbeiten oder Melden – also keine der interaktiven Beitragselemente, die das Modal benötigt.

Die Paginierung von PostList ist zudem einseitig (fetchMorePosts hängt nur nach unten an), während das Modal beim zuletzt gelesenen Beitrag öffnen und sowohl frühere als auch spätere Beiträge darum herum laden muss – dafür wird das Lückenladen des echten postStream-Services benötigt, nicht ein einfacher „mehr laden“-Callback.

Die Wiederverwendung von PostList hätte also bedeutet, den Großteil des interaktiven Verhaltens von Post und das bidirektionale Laden von postStream auf Basis einer Komponente nachzubauen, die für einen anderen Zweck gedacht ist. Die direkte Verwendung der echten Kern-Post-Komponente und von postStream stellt stattdessen sicher, dass sich das Modal identisch zur echten Themenseite verhält.

3 „Gefällt mir“

Ich habe dies mit verschachtelten Ansichten zum Laufen gebracht, es braucht noch mehr Tests und wahrscheinlich eine Option im Admin-Bereich. Einige Leute haben dies bereits ausprobiert, Don, und es führt dazu, dass die Nutzer mehr Anfragen stellen und länger auf der Seite bleiben, da es einfach so flüssig und leicht zu scrollen ist. Du hast hier eine fantastische Arbeit geleistet.

4 „Gefällt mir“

Wird jetzt getestet! Sehr beeindruckende UI-Verbesserung

2 „Gefällt mir“

Wir brauchen hier dringend Boosts, aber wegen dieser Antwortzeit bin ich jetzt etwas besorgt — habt ihr noch ein Leben? :laughing:

Danke :sign_of_the_horns:

3 „Gefällt mir“

Frage: Warum erscheint die border-top-Eigenschaft von .topic-avatar als Trennlinie zwischen dem noch sichtbaren Teil des vorherigen Beitrags beim Scrollen und dem Beginn des aktuellen Beitrags? Ist dies die eigentliche Absicht dieser border-top-Eigenschaft, oder gibt es eine Positionierungs-/Overflow-Regel, die dieses Verhalten verursacht?

@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 „Gefällt mir“

Ich denke, das könnte sehr nützlich sein, um Beiträge schnell zu überprüfen, wenn man nicht auf das vollständige Laden der Seite warten möchte. Es wäre toll, wenn es einen Schalter gäbe, damit Benachrichtigungsklicks das Modal-Dialogfenster statt der Themenliste auslösen.

1 „Gefällt mir“

Hi @Don, nachdem ich mich 24 Stunden lang mit dieser fantastischen Komponente gespielt habe, hat mir eine Sache besonders gut gefallen: das Wischen nach unten zum Schließen. Ich musste meinen Daumen und meine Hand nicht bewegen, und es fühlte sich so einfach an, die Seite zu nutzen. Allerdings war das Zurückscrollen bei längeren Themen nicht optimal.

Um das zu beheben, habe ich auf Mobilgeräten ein Wischen nach rechts zum Schließen hinzugefügt. Das ergibt so viel Sinn, und für alle, die schnell scrollen möchten, funktioniert es meiner Meinung nach hervorragend. Was denkst du darüber?

Der Link zum Testen ist https://www.carptalk-online.co.uk/ und funktioniert natürlich nur auf Mobilgeräten.

3 „Gefällt mir“

Ich habe dein Forum ausprobiert, Damian, und diese Wischgeste ist wirklich perfekt. Gute Arbeit, wie immer!

Ich frage mich, ob dieses Theme-Component in Horizon funktionieren sollte. Ich habe es bei zwei Releases ausprobiert, und es wird Admins oben ein Fehler angezeigt. Scheint nicht kompatibel zu sein?

Ich hoffe, es geht; ich mag diese neue Perspektive zum Ausprobieren wirklich.

2 „Gefällt mir“

Welchen Fehler bekommst du?

2 „Gefällt mir“

Hallo :waving_hand:

Ich habe eine neue Einstellung hinzugefügt: open_all_topic_links.

Wenn diese aktiviert ist, öffnet jeder Link, der irgendwo auf der Seite (Beitragsinhalt, Benachrichtigungen, Benutzerkarte, Suchergebnisse, vorgeschlagene/verwandte Themen, Seitenleiste usw.) auf ein Thema verweist, das Vorschau-Modal anstelle einer Navigation – nicht nur Zeilen in der Themenliste. Ein Link zu einem bestimmten Beitrag öffnet das Modal, das zu diesem Beitrag gescrollt ist. Links innerhalb der Themenliste und innerhalb eines bereits geöffneten Vorschau-Modals behalten ihr bestehendes Verhalten bei.

5 „Gefällt mir“

Ihr seid die Modal-Größen :slight_smile: Gibt es eine Chance, dass ihr das Schließen durch Wischen nach rechts auf dem Mobilgerät in den Core aufnehmt und Unterstützung für verschachtelte Ansichten hinzufügt? :eyes:

2 „Gefällt mir“