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:
Actualmente no tenemos planes de añadir esta función. Los sitios pueden añadir estilos de modo oscuro a su hoja de estilos incrustada como solución alternativa (o utilizar la técnica postMessage comentada anteriormente).
El bloque de código ① agrega un detector de eventos en el iframe de Discourse incrustado que enviará un mensaje a mi sitio web que contiene el iframe de Discourse incrustado una vez que Discourse incrustado se cargue.
Cuando mi sitio web reciba el mensaje de Discourse incrustado, realizará una validación, como se muestra en el bloque de código ②, y si pasa, llamará a la función setIframeStyle para configurar Discourse incrustado.
La función setIframeStyle, que se muestra en el bloque de código ③, pasa el modo de color, “oscuro” o “claro”, al iframe llamando a postMessage. Además, una vez que se cambie el modo oscuro, la función se puede llamar para mantener Discourse incrustado con el mismo modo de color que mi sitio web.
El bloque de código ④ permite que Discourse incrustado pueda procesar el mensaje del modo de color enviado desde mi sitio web. Aquí cambio el modo de color cambiando el nombre de la clase a la etiqueta del cuerpo.
Además, los bloques de código ① y ④ se agregan a través de la página de administración de Discourse, como se muestra a continuación:
¡Gracias por el esquema anterior @mikeguo, está maravillosamente explicado!
Además, ten en cuenta que necesitas tener la última versión de Discourse para lograr esto, la capacidad de Encabezado Embebido se agregó hace solo unos días.
Confirmo que el método anterior todavía funciona, pero habría sido bueno no tener que escribir código de una captura de pantalla Así que, aquí está, ligeramente actualizado:
Pasos
El iframe de comentarios termina de renderizarse y envía un mensaje a la ventana principal del navegador, informándole.
El navegador consulta su configuración de modo oscuro/claro y envía el valor de vuelta al iframe.
El iframe recibe el mensaje y establece un atributo de datos, una clase o similar, basándose en la configuración de modo oscuro/claro.
Código
Una vez que el iframe se carga, envía una notificación a la ventana principal. Esto debe introducirse en Discourse, en Admin -> Personalizar -> (seleccionar tema) -> Editar CSS/HTML -> Encabezado incrustado.
Maneja este disparador entrante en la ventana principal. Este código vive en tu sitio de blog:
const discourse_url = "https://your.discourse-instance.org";
// Aquí, determinamos el tema y enviamos un mensaje al iframe para que sepa cuál es el tema
// Ver más abajo cómo conectamos notifyFrameStyle
const notifyIFrameOfTheme = () => {
const iframe = document.getElementById("discourse-embed-frame");
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage(
{
// Modifica la línea de abajo para obtener la configuración del modo oscuro, dependiendo de cómo la almacenes
theme: document.documentElement.getAttribute("data-theme")
},
discourse_url
);
}
};
// Llama a setFrameStyle cuando recibimos el mensaje "iframe loaded"
const handleMessageListener = (event) => {
var origin = event.origin;
if ((origin === discourse_url) && (event.data == "iframe loaded")) {
notifyIFrameOfTheme();
}
};
En el bloque <script> de (1), añade un listener para el mensaje del tema enviado por notifyFrameStyle:
window.addEventListener("message", (event) => {
const payload = event.data;
if (payload.theme) {
// Haz algo con la configuración del tema; establecí el atributo `data-theme` en el `<html>` del iframe,
// pero es posible que desees establecer un atributo de clase o similar
document.documentElement.setAttribute("data-theme", payload.theme);
}
}, false);
Estilo
En Admin -> Personalizar -> (seleccionar tema) -> Editar CSS/HTML -> CSS incrustado, ahora puedes proporcionar CSS para cada modo. Por ejemplo, puedes anular las variables de estilo de Discourse:
¡Gracias por darte cuenta! Ya no puedo editar la publicación anterior, pero window.addEventListener va al final del fragmento de código debajo del (2).