Modo escuro automático para comentários incorporados também?

Automatic Dark Mode color scheme switching is a fantastic addition, thanks for integrating it!

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.

11 curtidas

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.

13 curtidas

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.

Thanks again for any hints.

6 curtidas

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.

10 curtidas

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:

https://cobwwweb.com/change-css-iframe

Might I be on the right track with all this?

8 curtidas

My apologies, I forgot to respond here, yes, I think postMessage can work for your use case.

11 curtidas

Olá,

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?

1 curtida

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).

7 curtidas

postMessage precisa de um iframe incorporado para lidar com o evento message.
Onde adiciono código a um iframe para lidar com o evento?

2 curtidas

Eu implementei usando postMessage. Os códigos e sua lógica de execução são os seguintes:

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:

E as classes CSS personalizadas devem ser adicionadas como abaixo:

12 curtidas

Alguém sabe onde editar se não pudermos editar “CSS incorporado” (porque não é um tema oficial)?

2 curtidas

Você acabou de criar um novo componente e usar sua aba Incorporado?

3 curtidas

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.

8 curtidas

EDIT: Era isso que eu precisava fazer Structure of themes and theme components

Isso parece estar errado?

const handleMessageListener = (event:MessageEvent<any>)

2 curtidas

Ainda não consigo ativar este código (!) Alguém poderia, por favor, revisá-lo?

Vejo que ninguém consegue ativar isto e quase todos estão usando o modo claro forçado, o que é muito ruim para os nossos olhos :frowning:

1 curtida

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 :slight_smile: Então, aqui está ele, ligeiramente atualizado:

Passos

  1. O iframe de comentários termina de renderizar e envia uma mensagem para a janela principal do navegador, informando isso.
  2. O navegador consulta sua configuração de modo escuro/claro e envia o valor de volta para o iframe.
  3. 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

  1. 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.
<script type="text/javascript">
    window.addEventListener("load", (event) => {
        window.parent.postMessage("iframe loaded", "*");
    }, false);
</script>
  1. 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>
  1. 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:

html[data-theme="dark"] {
  --primary: #ced6dd;
  --primary-low: #48566b;
  --secondary: #14181e;
  --tertiary: #2b7e8d;
}

Espero que isso ajude!

6 curtidas

O código copiável acima está faltando a adição do ouvinte de eventos na janela de incorporação:

window.addEventListener("message", handleMessageListener);

E uma observação: Nenhuma configuração especial de CORS é necessária para isso.

Obrigado por perceber! Não posso mais editar a postagem acima, mas o window.addEventListener vai no final do trecho de código em (2).

Veja este exemplo real.

5 curtidas