DModal-API verwenden, um Modal-Fenster (aka Popups/Dialoge) in Discourse darzustellen

Discourse 3.1.0.beta6 bringt eine brandneue, komponentenbasierte API für <DModal> mit.

:information_source: Diese ersetzt die alte controller-basierte API, die nun als veraltet gilt. Falls Sie bestehende Modals mit den alten APIs verwenden, werfen Sie einen Blick auf den Migrationsleitfaden hier.

Ein Modal rendern

Modals werden gerendert, indem die <DModal>-Komponente in einer Handlebars-Vorlage eingebunden wird. Falls Sie noch keine geeignete Vorlage haben, schauen Sie sich Using Plugin Outlet Connectors from a Theme or Plugin an.

Ein einfaches Modal sieht ungefähr so aus:

<DButton
  @translatedLabel="Modal anzeigen"
  @action={{fn (mut this.modalIsVisible) true}}
/>

{{#if this.modalIsVisible}}
  <DModal @title="Mein Modal" @closeModal={{fn (mut this.modalIsVisible) false}}>
    Hallo Welt, dies ist etwas Inhalt in einem Modal
  </DModal>
{{/if}}

:information_source: Der mut-Helper wird hier als hbs-spezifische Möglichkeit verwendet, einen Wert zu setzen. Sie könnten modalIsVisible auch mit jeder anderen Standard-Ember-Methode setzen.

Dieses Beispiel erstellt ein einfaches Modal wie dieses:

In eine Komponente einpacken

Bevor Sie weitere Komplexität einführen, ist es meist am besten, Ihr neues Modal in eine eigene Komponentendefinition zu verpacken. Verschieben wir den <DModal>-Teil in eine neue <MyModal />-Komponente.

// components/my-modal.gjs
<template>
  <DModal @title="Mein Modal" @closeModal={{@closeModal}}>
    Hallo Welt, dies ist etwas Inhalt in einem Modal
  </DModal>
</template>

Das Aktualisieren dieser .gjs-Datei zu einer klassenbasierten Komponente ermöglicht es Ihnen, komplexere Logik und Zustände einzuführen.

Um die neue Komponente zu nutzen, aktualisieren Sie die Aufrufstelle, um darauf zu verweisen, und stellen Sie sicher, dass Sie ein @closeModal-Argument übergeben.

<DButton
  @translatedLabel="Modal anzeigen"
  @action={{fn (mut this.modalIsVisible) true}}
/>

{{#if this.modalIsVisible}}
  <MyModal @closeModal={{fn (mut this.modalIsVisible) false}} />
{{/if}}

Einen Footer hinzufügen

Viele Modals haben eine Art Handlungsaufforderung. In Discourse befinden sich diese tendenziell am unteren Rand des Modals. Um dies zu ermöglichen, verfügt DModal über mehrere „benannte Blöcke“, in die Inhalte gerendert werden können. Hier ist das aktualisierte Beispiel mit zwei Buttons im Footer, wobei einer davon unser Standard-DModalCancel-Button ist:

<DModal @title="Mein Modal" @closeModal={{@closeModal}}>
  <:body>
    Hallo Welt, dies ist etwas Inhalt in einem Modal
  </:body>
  <:footer>
    <DButton class="btn-primary" @translatedLabel="Absenden" />
    <DModalCancel @close={{@closeModal}} />
  </:footer>
</DModal>

Ein Modal aus einem Nicht-HBS-Kontext rendern

Idealerweise sollten <DModal>-Instanzen innerhalb einer Ember-Vorlage mit der oben gezeigten deklarativen Technik gerendert werden. Falls dies für Ihren Anwendungsfall nicht machbar ist, kann dies durch Einbinden des modal-Services und Aufrufen von modal.show() erfolgen.

Stellen Sie sicher, dass Sie Ihr Modal wie oben beschrieben in eine eigene Komponente verpackt haben. Lösen Sie das Modal dann aus, indem Sie einen Verweis auf Ihre Komponentenklasse an showModal übergeben:

import MyModal from "discourse/components/my-modal";

// (den modal-Service an der relevanten Stelle einbinden)

// Rufen Sie dies immer auf, wenn Sie das Modal öffnen möchten.
// Ein `@closeModal`-Argument wird automatisch an Ihre Komponente übergeben.
this.modal.show(MyModal);

// Optional: Übergeben Sie einen `model`-Parameter. Wird als `@model` an Ihre Komponente übergeben.
// Dies kann Daten sowie Aktionen/Rückrufe enthalten, die Ihr Modal verwenden kann.
this.modal.show(MyModal, {
  model: { topic: this.topic, someAction: this.someAction },
});

// `modal.show()` gibt ein Promise zurück, sodass Sie auf das Schließen warten können.
// Es wird mit den Daten aufgelöst, die an die `@closeModal`-Aktion übergeben wurden.
const result = await this.modal.show(MyModal);

Noch mehr Anpassungsmöglichkeiten!

<DModal> verfügt über mehrere benannte Blöcke und Argumente.

Argumente

Arg Zweck
@closeModal Erforderlich, damit die Schließen-UI überhaupt angezeigt wird.
@title Rendert <h1 id="discourse-modal-title">; verknüpft aria-labelledby.
@subtitle Kleiner Text unter der Überschrift.
@flash / @flashType Inline-Warnung am oberen Rand des Modals (DFlashMessage).
@hideHeader, @hideFooter Ganze Bereiche ausblenden.
@headerClass, @bodyClass Zusätzliche Klasse für Header-/Body-Umhüllungen.
@dismissable Standardmäßig true, wenn @closeModal gesetzt. Deaktiviert Esc / Klick auf Hintergrund / X.
@autofocus Standardmäßig true. Fokussiert automatisch das erste fokussierbare Element über dTrapTab.
@submitOnEnter Standardmäßig true. Enter klickt auf .d-modal__footer .btn-primary, es sei denn, der Fokus liegt in einem Formular / Textfeld / Select-Kit.
@beforeClose async ({ initiatedBy }) => boolean. Geben Sie false zurück, um das Schließen abzubrechen (z. B. bei Dirty-Form-Bestätigung).
@hidden Pausiert die Tastaturbehandlung; wird verwendet, wenn sich ein verschachteltes Modal darüber befindet.
@tagName "div" (Standard) oder "form". Verwenden Sie "form" für Formulare, damit die native Einreichung funktioniert.

Blöcke

Block Position Wann zu verwenden
default / :body Hauptinhaltsbereich Standardbereich
:aboveHeader Ganz oben, vor dem Header Selten erforderlich; für Inhalte, die über der Titelleiste sitzen müssen (z. B. ein Banner).
:headerAboveTitle Im Header, vor der Überschrift Vorhanden, aber ungenutzt. Selten erforderlich.
:belowModalTitle In .d-modal__title, nach dem <h1> Ausgezeichnete Position für zusätzliche Metainformationen.
:headerBelowTitle Im Header, nach dem Titelblock Tabs, Unter-Navigation oder Suchfeld, die Teil des Headers sind.
:headerPrimaryAction Rechte Seite des Headers nur auf Mobilgeräten Ersetzt den X-Schließen-Button durch eine Hauptaktion (z. B. „Speichern“). Rendert automatisch einen „Abbrechen“-Button links und fügt .--has-primary-action zum Header hinzu.
:belowHeader Zwischen Header und Body Persistenter Subheader-Inhalt (z. B. Suche), der außerhalb des scrollbaren Bodies liegt, also für eine feste Anzeige.
:aboveFooter Zwischen Body und Footer Unterdrückt, wenn @hideFooter gesetzt ist. Verwenden Sie dies für Inhalte, die mit dem Footer verbunden, aber außerhalb davon sind. Auch selten.
:footer Untere Aktionsleiste Primäre + sekundäre Buttons. Der erste .btn-primary hier ist das, was Enter auslöst.
:belowFooter Nach dem Footer Selten erforderlich; ignoriert @hideFooter. Nützlich für Status-Text außerhalb des umrandeten Footer-Bereichs.

Quellen: der interaktive Styleguide für Argumente und die d-modal-Vorlagenimplementierung für benannte Blöcke.

CSS

Verwenden Sie die .d-modal-Klassen als Anker, um das Core-Design zu überschreiben, und vermeiden Sie den veralteten .modal-Selektor.

4 Modifikatoren verfügbar:

  • .--large setzt die maximale Breite auf 800px (nur Desktop)
  • .--max setzt die maximale Breite auf 90vw (nur Desktop)
  • .has-search setzt eine feste Höhe (80vh): gedacht für Modals mit Such-/Filtersystem, um eine Höhenänderung basierend auf der Ergebnislänge zu vermeiden (nur Desktop)
  • .--stacked setzt Footer-Buttons auf Stapelung (nur Mobilgeräte)

Dieses Dokument ist versionskontrolliert – schlagen Sie Änderungen auf GitHub vor.

17 „Gefällt mir“

Ein Beitrag wurde in ein neues Thema aufgeteilt: Kann ich ein Modal aus head_tag anzeigen