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:
Desculpe desenterrar um tópico tão antigo, mas há planos para implementar a troca automática de modo escuro para o endpoint de comentários incorporados?
No momento, não temos planos de adicionar esse recurso. Os sites podem adicionar estilos de modo escuro à sua folha de estilos incorporada como uma solução alternativa (ou usar a técnica postMessage discutida acima).
O bloco de código ① adiciona um ouvinte de eventos no iframe incorporado do Discourse, que enviará uma mensagem para o meu site que contém o iframe incorporado do Discourse assim que o Discourse incorporado for carregado.
Quando meu site recebe a mensagem do Discourse incorporado, ele fará uma validação, como mostrado no bloco de código ②, e se aprovado, chamará a função setIframeStyle para definir o Discourse incorporado.
A função setIframeStyle, mostrada no bloco de código ③, passa o modo de cor, “dark” ou “light”, para o iframe chamando postMessage. Além disso, uma vez que o modo escuro é alternado, a função pode ser chamada para manter o Discourse incorporado com o mesmo modo de cor do meu site.
O bloco de código ④ permite que o Discourse incorporado possa processar a mensagem do modo de cor enviada do meu site. Aqui eu alterno o modo de cor trocando o nome da classe para a tag body.
Adicionalmente, os blocos de código ① e ④ são adicionados pela página de administração do Discourse, como abaixo:
Obrigado pelo esboço acima @mikeguo, isso foi maravilhosamente explicado!
Observe também que você precisa estar na versão mais recente do Discourse para realizar isso, a capacidade de cabeçalho incorporado foi adicionada apenas há alguns dias.
Posso confirmar que o método acima ainda funciona, mas teria sido bom não ter que digitar o código de uma captura de tela Então, aqui está ele, ligeiramente atualizado:
Passos
O iframe de comentários termina de renderizar e envia uma mensagem para a janela principal do navegador, informando isso.
O navegador consulta sua configuração de modo escuro/claro e envia o valor de volta para o iframe.
O iframe recebe a mensagem e define um atributo de dados, classe ou similar, com base na configuração de modo escuro/claro.
Código
Assim que o iframe for carregado, envie uma notificação para a janela pai. Isso precisa ser inserido no Discourse, em Admin -> Personalizar -> (selecionar tema) -> Editar CSS/HTML -> Cabeçalho Embutido.
Manipule este gatilho de entrada na janela principal. Este código fica no seu site de blog:
<script type="text/javascript">
const discourse_url = "https://your.discourse-instance.org";
// Aqui, determinamos o tema e enviamos uma mensagem para o iframe para informá-lo sobre o tema
// Veja abaixo como configuramos notifyFrameStyle
const notifyIFrameOfTheme = () => {
const iframe = document.getElementById("discourse-embed-frame");
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage(
{
// Modifique a linha abaixo para capturar a configuração do modo escuro, dependendo de como você a armazena
theme: document.documentElement.getAttribute("data-theme")
},
discourse_url
);
}
};
// Chama setFrameStyle quando recebemos a mensagem "iframe loaded"
const handleMessageListener = (event) => {
var origin = event.origin;
if ((origin === discourse_url) && (event.data == "iframe loaded")) {
notifyIFrameOfTheme();
}
};
</script>
No bloco <script> de (1), adicione um listener para a mensagem de tema enviada por notifyFrameStyle:
window.addEventListener("message", (event) => {
const payload = event.data;
if (payload.theme) {
// Faça algo com a configuração do tema; eu defino o atributo `data-theme` no `<html>` do iframe,
// mas você pode querer definir um atributo de classe ou similar
document.documentElement.setAttribute("data-theme", payload.theme);
}
}, false);
Estilização
Em Admin -> Personalizar -> (selecionar tema) -> Editar CSS/HTML -> CSS Embutido, você agora pode fornecer CSS para cada modo. Por exemplo, você pode substituir as variáveis de estilo do Discourse: