utterances
utterances copied to clipboard
Dynamic theme changing
Hey, is dynamic theme changing available? Because, I want this to change the theme automatically, according to the website. Is it available?
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.
How can this be totally possble? I got an idea. By using JSX(combination of JS and HTML), it might be possible(idk).
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
Quick question: Can you use this for Jekyll themes?
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 />
@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>
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 }}
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.
@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>