Discourse 3.1.0.beta6 wird mit einer brandneuen, komponentenbasierten <DModal>-API ausgeliefert. DModal ist Teil des UI-Kits und wird aus discourse/ui-kit/d-modal importiert.
Dies ersetzt die alte, kontrollerbasierte API, die nun veraltet ist. Wenn du bestehende Modals mit den alten APIs verwendest, findest du den Migrationsleitfaden hier.
Ein Modal rendern
Modals werden gerendert, indem die <DModal>-Komponente in einer Handlebars-Vorlage eingebunden wird. Falls du noch keine geeignete Vorlage hast, schau dir Using Plugin Outlet Connectors from a Theme or Plugin an.
Ein einfaches Modal könnte so aussehen:
<DButton
@translatedLabel="Show Modal"
@action={{fn (mut this.modalIsVisible) true}}
/>
{{#if this.modalIsVisible}}
<DModal @title="My Modal" @closeModal={{fn (mut this.modalIsVisible) false}}>
Hello world, this is some content in a modal
</DModal>
{{/if}}
Der
mut-Helper wird hier als hbs-spezifische Methode verwendet, um einen Wert zu setzen. Du könntestmodalIsVisibleauch mit jeder anderen Standard-Ember-Methode setzen.
Dieses Beispiel erstellt ein einfaches Modal wie dieses:
In einer Komponente kapseln
Bevor weitere Komplexität eingeführt wird, ist es in der Regel am besten, das neue Modal in seiner eigenen Komponenten-Definition zu kapseln. Verschieben wir den <DModal>-Teil in eine neue <MyModal />-Komponente:
// components/my-modal.gjs
<template>
<DModal @title="My Modal" @closeModal={{@closeModal}}>
Hello world, this is some content in a modal
</DModal>
</template>
Das Upgrade dieser .gjs-Datei zu einer klassenbasierten Komponente ermöglicht es dir, komplexere Logik und Zustände einzuführen.
Um die neue Komponente zu nutzen, aktualisiere die Aufrufstelle, um sie zu referenzieren, und achte darauf, ein @closeModal-Argument zu übergeben.
<DButton
@translatedLabel="Show Modal"
@action={{fn (mut this.modalIsVisible) true}}
/>
{{#if this.modalIsVisible}}
<MyModal @closeModal={{fn (mut this.modalIsVisible) false}} />
{{/if}}
Eine Fußzeile hinzufügen
Viele Modals haben eine Art Call-to-Action. In Discourse befinden sich diese tendenziell am unteren Rand des Modals. Um dies zu ermöglichen, verfügt DModal über eine Reihe von „named blocks“ (benannten Blöcken), in die Inhalte gerendert werden können. Hier ist das Beispiel aktualisiert, um zwei Buttons in der Fußzeile zu enthalten, wobei einer unser Standard-DModalCancel-Button ist:
<DModal @title="My Modal" @closeModal={{@closeModal}}>
<:body>
Hello world, this is some content in a modal
</:body>
<:footer>
<DButton class="btn-primary" @translatedLabel="Submit" />
<DModalCancel @close={{@closeModal}} />
</:footer>
</DModal>
Ein Modal aus einem nicht-hbs-Kontext rendern
Idealerweise sollten <DModal>-Instanzen innerhalb einer Ember-Vorlage mit der oben demonstrierten deklarativen Technik gerendert werden. Falls dies für deinen Anwendungsfall nicht machbar ist, kann dies durch das Injizieren des modal-Services und den Aufruf von modal.show() erledigt werden.
Stelle sicher, dass du dein Modal wie oben beschrieben in seiner eigenen Komponente gekapselt hast. Dann löst du das Modal aus, indem du eine Referenz deiner Komponentenklasse an showModal übergibst:
import MyModal from "discourse/components/my-modal";
// (injiziere den modal-Service an der relevanten Stelle)
// Füge diesen Aufruf hinzu, wann immer du das Modal öffnen möchtest.
// Ein `@closeModal`-Argument wird deiner Komponente automatisch übergeben.
this.modal.show(MyModal);
// Optional: Übergib einen '`model`'-Parameter. Wird als `@model` an deine Komponente übergeben.
// Dies kann Daten sowie Aktionen/Callbacks für dein Modal enthalten.
this.modal.show(MyModal, {
model: { topic: this.topic, someAction: this.someAction },
});
// `modal.show()` gibt ein Promise zurück, sodass du darauf warten kannst, dass es geschlossen wird.
// Es wird mit den Daten aufgelöst, die an die `@closeModal`-Aktion übergeben wurden.
const result = await this.modal.show(MyModal);
Mehr Anpassungsfähigkeit!
<DModal> verfügt über eine Reihe von benannten Blöcken und Argumenten.
Argumente
| Arg | Zweck |
|---|---|
@closeModal |
Erforderlich, damit die UI zum Schließen überhaupt angezeigt wird. |
@title |
Rendert <h1 id="discourse-modal-title">; verdrahtet aria-labelledby. |
@subtitle |
Kleiner Text unter dem Titel. |
@flash / @flashType |
Inline-Warnung oben im Modal (DFlashMessage). |
@hideHeader, @hideFooter |
Versteckt ganze Bereiche. |
@headerClass, @bodyClass |
Zusätzliche Klasse für Header-/Body-Wrapper. |
@dismissable |
Standardmäßig true, wenn @closeModal gesetzt ist. Deaktiviert Esc / Klick auf den Hintergrund / X. |
@autofocus |
Standardmäßig true. Fokussiert automatisch das erste fokussierbare Element via dTrapTab. |
@submitOnEnter |
Standardmäßig true. Enter klickt .d-modal__footer .btn-primary, außer der Fokus ist in einem Formular / Textbereich / Select-Kit. |
@beforeClose |
async ({ initiatedBy }) => boolean. Gib false zurück, um das Schließen abzubrechen (z. B. Bestätigung bei ungespeicherten Änderungen). |
@hidden |
Pausiert die Tastaturverarbeitung; wird verwendet, wenn ein verschachteltes Modal darüber liegt. |
@tagName |
"div" (Standard) oder "form". Verwende "form" für Formulare, damit das native Absenden funktioniert. |
Blöcke
| Block | Position | Wann verwenden |
|---|---|---|
default / :body |
Hauptinhaltsbereich | Standardbereich |
:aboveHeader |
Ganz oben, vor dem Header | Selten benötigt; für Inhalte, die über der Titelleiste sitzen müssen (z. B. ein Banner). |
:headerAboveTitle |
Im Header, vor dem Titel | Vorhanden, aber ungenutzt. Selten benötigt. |
:belowModalTitle |
Innerhalb von .d-modal__title, nach dem <h1> |
Hervorragende Position für ergänzende Metainformationen. |
:headerBelowTitle |
Im Header, nach dem Titelblock | Tabs, Sub-Navigation oder Suchfeld, das Teil des Headers ist. |
:headerPrimaryAction |
Rechte Seite des Headers nur auf Mobilgeräten | Ersetzt den X-Schließen-Button durch eine Hauptaktion (z. B. „Speichern“). Rendert auch automatisch einen „Abbrechen“-Button links und fügt .--has-primary-action zum Header hinzu. |
:belowHeader |
Zwischen Header und Body | Persistenter Sub-Header-Inhalt (z. B. Suche), der außerhalb des scrollbaren Body liegt, für eine Sticky-Anzeige. |
:aboveFooter |
Zwischen Body und Footer | Wird unterdrückt, wenn @hideFooter gesetzt ist. Verwende für Inhalte, die mit dem Footer verbunden sind, aber außerhalb liegen. 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 benötigt; ignoriert @hideFooter. Nützlich für Status-Text außerhalb des gerahmten Footer-Bereichs. |
Quellen: der interaktive Styleguide für Argumente und die d-modal-Vorlagenimplementierung für benannte Blöcke.
CSS
Verwende die .d-modal-Klassen als Anker, um Core-Styles zu überschreiben, und vermeide den Legacy-.modal-Selektor.
4 Modifikatoren verfügbar:
- .
--largesetzt die maximale Breite auf 800px (nur Desktop) - .
--maxsetzt die maximale Breite auf 90vw (nur Desktop) - .
has-searchsetzt die feste Höhe (80vh): für Modals mit Such-/Filtersystem gedacht, um Höhenänderungen basierend auf der Ergebnislänge zu vermeiden (nur Desktop) .--stackedsetzt die Footer-Buttons auf Stapelung (nur Mobilgeräte)
Dieses Dokument wird versioniert verwaltet – schlage Änderungen auf GitHub vor.

