With (automatic) color scheme switching available, I’m wondering if there might also be some way to switch back and forth between light and dark Discourse modes when embedded as comments in a blog. Specifically, my Ghost blog has a toggle that users can click on to manually switch back and forth between light and dark modes. I know that my blog’s CSS can’t effect the CSS within Discourse’s iframe, but with this new addition might there be another way that the toggle could also switch the Discourse color scheme? You can see an example post with comments at the bottom of this post.
This is potentially doable but a little tricky. At the moment, we haven’t added dark mode auto switching to the embedded comments endpoint. We can add that, and it would work if your Ghost site was auto-switching to dark mode when the browser switches to dark mode. But from what I can tell, your Ghost site uses a dark mode button, which won’t work with the Discourse implementation.
What you can do in your specific case, is toggle a class in the Discourse embedded comments iframe when clicking the button, and then use that class to toggle colors in your embedded stylesheet.
Sounds good. While I am currently putting together several dark mode utilizing (Ghost) themes for colleagues of mine, all of which will share a single Discourse instance, that’s still a bit further down the road.
I unfortunately don’t quite understand what you’re suggesting here. Currently, any elements that I want to utilize dark mode styling within my blog have their CSS doubled up by preceding such items with body.dark. As in
p {
color: #000;
}
body.dark p {
color: #FFF;
}
Might you be suggesting that I use that body.dark code to change things in the Discourse iframe? Because I tried inserting the following into Discourse’s Embedded CSS field, which unfortunately had no effect:
.FF2F-discourse p {
color: #000;
}
body.dark .FF2F-discourse p {
color: #FFF;
}
That being so, are you instead suggesting that I have some separate JS written so that the toggle will affect a separate change via specific targeting of a class in the iframe? Because like I stated in my previous comment, I didn’t think that external coding could affect CSS within an iframe, hence my confusion. But I’m very much solely an HTML/CSS amateur, so there’s no doubt that you know better than me and/or that I’m misunderstanding something else.
Yes, that’s what I am suggesting. Your blog’s stylesheets cannot apply to the iframe, but you can use JS to toggle the dark class in the iframe’s html or body element, and then update your Discourse embedded stylesheet accordingly.
I’ve found two pages explaining how toggling between light and dark modes for Discourse’s embed might be done, but the guy who writes my JS is wondering if the method you’re suggesting entails using postMessage (which the pages I found state) or something else.
Here’s a page explaining how to implement cross-window messaging with postMessage
While this one is actually a tutorial on how to change the CSS within an iframe via postMessage, specifically for switching between light and dark modes:
Entschuldigen Sie, dass ich ein so altes Thema aufgreife, aber gibt es Pläne, den Dark-Mode-Automatikwechsel für eingebettete Kommentar-Endpunkte zu implementieren?
Wir haben derzeit keine Pläne, diese Funktion hinzuzufügen. Websites können Dark-Mode-Stile zu ihrem eingebetteten Stylesheet hinzufügen (als Workaround oder die oben diskutierte postMessage-Technik verwenden).
postMessage benötigt ein eingebettetes iframe, um das message-Ereignis zu verarbeiten.
Wo füge ich Code in ein iframe ein, um das Ereignis zu verarbeiten?
Codeblock ① fügt einen Event-Listener in den eingebetteten Discourse-iframe ein, der eine Nachricht an meine Website sendet, die den eingebetteten Discourse-iframe enthält, sobald Discourse eingebettet ist.
Wenn meine Website eine Nachricht von eingebettetem Discourse empfängt, führt sie eine Validierung durch, wie in Codeblock ② gezeigt, und wenn diese erfolgreich ist, wird die Funktion setIframeStyle aufgerufen, um eingebettetes Discourse einzustellen.
Die Funktion setIframeStyle, die in Codeblock ③ gezeigt wird, übergibt den Farbmodus, „dark“ oder „light“, an den iframe, indem sie postMessage aufruft. Zusätzlich kann die Funktion aufgerufen werden, um den eingebetteten Discourse im gleichen Farbmodus wie meine Website zu halten, sobald der dunkle Modus umgeschaltet wird.
Codeblock ④ ermöglicht es eingebettetem Discourse, die von meiner Website gesendete Farbmodus-Nachricht zu verarbeiten. Hier schalte ich den Farbmodus um, indem ich den Klassennamen des Body-Tags ändere.
Zusätzlich werden Codeblock ① und ④ über die Discourse-Admin-Seite hinzugefügt, wie unten gezeigt:
Vielen Dank für den obigen Überblick, @mikeguo, das ist wunderbar erklärt!
Beachten Sie außerdem, dass Sie die neueste Discourse-Version verwenden müssen, um dies zu erreichen. Die Funktion für eingebettete Header wurde erst vor wenigen Tagen hinzugefügt.
Ich kann bestätigen, dass die obige Methode immer noch funktioniert, aber es wäre schön gewesen, wenn ich den Code nicht von einem Screenshot hätte abtippen müssen Hier ist er also, leicht aktualisiert:
Schritte
Der Kommentare-Iframe ist gerendert und sendet eine Nachricht an das Haupt-Browserfenster, dass er fertig ist.
Der Browser fragt seine Dunkel-/Hellmodus-Einstellung ab und sendet den Wert zurück in den Iframe.
Der Iframe empfängt die Nachricht und setzt ein data-Attribut, eine Klasse oder Ähnliches basierend auf der Dunkel-/Hellmodus-Einstellung.
Code
Sobald der Iframe geladen ist, senden Sie eine Benachrichtigung an das übergeordnete Fenster. Dies muss in Discourse unter Admin -> Anpassen -> (Thema auswählen) -> CSS/HTML bearbeiten -> Eingebetteter Header eingegeben werden.
Behandeln Sie diesen eingehenden Trigger im Hauptfenster. Dieser Code befindet sich auf Ihrer Blog-Website:
<script type="text/javascript">
const discourse_url = "https://your.discourse-instance.org";
// Hier bestimmen wir das Thema und senden eine Nachricht an den Iframe, um ihn darüber zu informieren
// Siehe unten, wie wir notifyFrameStyle einrichten
const notifyIFrameOfTheme = () => {
const iframe = document.getElementById("discourse-embed-frame");
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage(
{
// Ändern Sie die folgende Zeile, um die Dunkelmodus-Einstellung abzurufen, je nachdem, wie Sie sie speichern
theme: document.documentElement.getAttribute("data-theme")
},
discourse_url
);
}
};
// Rufen Sie setFrameStyle auf, wenn wir die Nachricht "iframe loaded" erhalten
const handleMessageListener = (event) => {
var origin = event.origin;
if ((origin === discourse_url) && (event.data == "iframe loaded")) {
notifyIFrameOfTheme();
}
};
</script>
Fügen Sie im script-Block aus (1) einen Listener für die vom notifyFrameStyle gesendete Thema-Nachricht hinzu:
window.addEventListener("message", (event) => {
const payload = event.data;
if (payload.theme) {
// Tun Sie etwas mit der Thema-Einstellung; ich setze das `data-theme`-Attribut auf dem `html`-Element des Iframes,
// aber Sie möchten vielleicht ein class-Attribut oder Ähnliches setzen
document.documentElement.setAttribute("data-theme", payload.theme);
}
}, false);
Styling
Unter Admin -> Anpassen -> (Thema auswählen) -> CSS/HTML bearbeiten -> Eingebettetes CSS können Sie nun CSS für jeden Modus bereitstellen. Sie können z. B. die Discourse-Styling-Variablen überschreiben:
Danke, dass Sie das bemerkt haben! Ich kann den obigen Beitrag nicht mehr bearbeiten, aber window.addEventListener gehört am Ende des Code-Snippets unter (2).