utterances icon indicating copy to clipboard operation
utterances copied to clipboard

Dynamic theme changing

Open im-coder-lg opened this issue 4 years ago • 9 comments

Hey, is dynamic theme changing available? Because, I want this to change the theme automatically, according to the website. Is it available?

im-coder-lg avatar Jul 15 '21 08:07 im-coder-lg

Related to #367 and #544. Things don't have to overly complicated. If the widget were to add support for it, users could easily and dynamically set theme using CSS variables.

danisztls avatar Jul 15 '21 18:07 danisztls

How can this be totally possble? I got an idea. By using JSX(combination of JS and HTML), it might be possible(idk).

im-coder-lg avatar Aug 19 '21 06:08 im-coder-lg

  function utterancesTheme () {
    if (document.querySelector('.utterances-frame')) {
      const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'github-dark' : 'github-light'
      const message = {
        type: 'set-theme',
        theme: theme
      };
      const iframe = document.querySelector('.utterances-frame');
      iframe.contentWindow.postMessage(message, 'https://utteranc.es');
    }
  }

call it when you need to change the theme it works for me

jerryc127 avatar Aug 28 '21 10:08 jerryc127

Quick question: Can you use this for Jekyll themes?

im-coder-lg avatar Aug 28 '21 10:08 im-coder-lg

this is react jsx. works fine for me

import { useTheme } from 'next-themes'
import React, { useEffect, useRef } from 'react'

export const UtterancesComments: React.FC = () => {
  const { theme } = useTheme()
  const elementRef = useRef<HTMLDivElement>(null)
  const t = theme === 'dark' ? 'github-dark' : 'github-light'

  // first load
  useEffect(() => {
    if (!elementRef.current) {
      return
    }

    const scriptElem = document.createElement('script')
    scriptElem.src = 'https://utteranc.es/client.js'
    scriptElem.async = true
    scriptElem.crossOrigin = 'anonymous'
    scriptElem.setAttribute('repo', 'azrizhaziq/portfolio')
    scriptElem.setAttribute('issue-term', 'url')
    scriptElem.setAttribute('label', 'blog-comment')
    scriptElem.setAttribute('theme', t)
    elementRef.current.appendChild(scriptElem)
  }, [])

  // when theme change
  useEffect(() => {
    if (document.querySelector('.utterances-frame')) {
      const iframe = document.querySelector<HTMLIFrameElement>('.utterances-frame')

      if (!iframe) {
        return
      }

      iframe?.contentWindow?.postMessage({ type: 'set-theme', theme: t }, 'https://utteranc.es')
    }
  }, [t])

  return <section ref={elementRef} />
}

// use it like 
<UtterancesComments />

AzrizHaziq avatar Sep 05 '21 01:09 AzrizHaziq

@im-coder-lg: Quick question: Can you use this for Jekyll themes?

I'm using the chirpy jekyll theme on my GitHub pages-hosted blog. This is what I have at the moment in my post.html, borrowing some ideas from #427 (h/t: @brennerm and @Dialvive)

Seems to work great - if someone is using light mode, the light mode utterances shows, if someone is using dark mode, the dark mode utterances shows. The only thing it doesn't do is update the theme dynamically if someone changes their theme when they already have the post open. But I do not consider that a huge deal breaker because the vast majority of people aren't going to be switching their theme mid-post very often. This was just to cover a gap where the utterances widget would match the system theme but not the blog theme, if for example someone was using dark mode in their OS but liked reading the blog in light mode (or vice-versa).

    <!-- When page loads, determine whether to show light mode or dark mode utterances comments -->
    <section>
      <div id="light-mode">
        <script src="https://utteranc.es/client.js"
          repo="joshjohanning/joshjohanning.github.io"
          issue-term="title"
          theme="github-light"
          crossorigin="anonymous"
          async>
        </script>
      </div>

      <div id="dark-mode">
        <script src="https://utteranc.es/client.js"
          repo="joshjohanning/joshjohanning.github.io"
          issue-term="title"
          theme="github-dark"
          crossorigin="anonymous"
          async>
        </script>
      </div>

      <script>
        var uttLight = document.getElementById("light-mode");
        var uttDark = document.getElementById("dark-mode");

        let initTheme = "light";
        if ($("html[mode=dark]").length > 0
          || ($("html[mode]").length == 0
            && window.matchMedia("(prefers-color-scheme: dark)").matches ) ) {
          initTheme = "dark";
        }

        if(initTheme === "dark"){
          uttLight.parentNode.removeChild(uttLight);
        } else {
          uttDark.parentNode.removeChild(uttDark);
        }
      </script>
    </section>

joshjohanning avatar Sep 10 '21 17:09 joshjohanning

i use hugo, it's my code

{{ if .Site.Params.utteranc.enable }}

<div class="comments">
    <script>
        // load utteranc comment
        var getTheme = window.localStorage && window.localStorage.getItem("theme");
        getTheme = getTheme == null ? '{{$.Site.Params.defaultTheme}}' : getTheme;

        let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
        let s = document.createElement('script');
        s.src = 'https://utteranc.es/client.js';
        s.setAttribute('repo', '{{ .Site.Params.utteranc.repo }}');
        s.setAttribute('issue-term', '{{ .Site.Params.utteranc.issueTerm }}');
        s.setAttribute('theme', theme);
        s.setAttribute('crossorigin', 'anonymous');
        s.setAttribute('async', '');
        document.querySelector('div.comments').innerHTML = '';
        document.querySelector('div.comments').appendChild(s);

        // auto swith utteranc theme by body class change
        const mutationObserver = new MutationObserver((mutationsList, observer) => {
            mutationsList.forEach(mutation => {
                if (mutation.attributeName === "class") {
                    if (document.querySelector('.utterances-frame')) {
                        const theme = mutation.target.classList.contains("dark-theme") ? 'github-dark' : 'github-light'
                        const message = {
                            type: 'set-theme',
                            theme: theme
                        };
                        const iframe = document.querySelector('.utterances-frame');
                        iframe.contentWindow.postMessage(message, 'https://utteranc.es');
                    }
                }
            })
        });
        mutationObserver.observe(document.body, { attributes: true });
    </script>
</div>
{{ end }}

ehlxr avatar Mar 23 '22 02:03 ehlxr

Interesting... I think I will test JS or TS since I seem to have done it on Next.js, except dynamic theming, whic I will do when I get free. Maybe next month, by the end of April.

im-coder-lg avatar Mar 23 '22 10:03 im-coder-lg

@ehlxr I referred to your code, thank you

<div class="comments">
    <script>
        // load utteranc comment
        let html = document.querySelector('html');
        var getTheme = html.dataset['mode'];
        getTheme = getTheme == null ? 'light' : getTheme;

        let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
        let s = document.createElement('script');
        s.src = 'https://utteranc.es/client.js';
        s.setAttribute('repo', 'tlqhrm/tlqhrm.github.io');
        s.setAttribute('issue-term', 'title');
        s.setAttribute('theme', theme);
        s.setAttribute('crossorigin', 'anonymous');
        s.setAttribute('async', '');
        document.querySelector('div.comments').innerHTML = '';
        document.querySelector('div.comments').appendChild(s);
    </script>
</div>

tlqhrm avatar Oct 15 '22 13:10 tlqhrm