블로그에 댓글기능을 추가하고 싶어서 알아보던 중, 깃헙의 utterances를 사용했다.
이유는 깃헙에 로그인을 해야 댓글을 달 수 있고, 마크다운을 사용할 수 있고, 직접 구현하지 않고 삽입해서 바로 사용가능하기 때문이다.
Create Repository & Install Utterances
- 우선 댓글용 레포지터리를 새로 생성한 뒤,
- Install Utterances에서 앱을 설치하고 새로 생성한 레포지터리를 연결한다.
- 그럼 아래 스크립트가 생성된다.
<script
src="https://utteranc.es/client.js"
repo="레포지트리명"
issue-term="pathname"
theme="github-light"
crossorigin="anonymous"
async
></script>
Comment 컴포넌트 생성
- 리액트는 xss보안 이슈 때문에 위 스크립트가 적용된 컴포넌트를 생성해줘야한다.
import React, { useEffect } from "react"
const COMMENTS_ID = 'comments-container';
export default function Comment() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://utteranc.es/client.js';
script.setAttribute('repo', "레포지트리명");
script.setAttribute('issue-term', 'pathname');
script.setAttribute('theme', 'github-light');
script.setAttribute('crossorigin', 'anonymous');
script.async = true;
const comments = document.getElementById(COMMENTS_ID);
if (comments) comments.appendChild(script);
return () => {
const comments = document.getElementById(COMMENTS_ID);
if (comments) comments.innerHTML = '';
};
}, []);
return (
<div id={COMMENTS_ID} />
);
};
Comment 컴포넌트 삽입
- 원하는 위치에 Comment 컴포넌트를 삽입한다.
- 보통 블로그에서 사용하려면, 상세페이지에서 블로그 글 하단에 삽입할 것이다.
다크모드 구현하기
본 블로그는 next-themes(next-themes)라이브러리 + tailwindCSS를 사용하여 다크모드가 구현되어 있고, Utterances 댓글의 다크모드 구현도 마찬가지로 해당 라이브러리를 통해 아주 아주 간편하게 구현되어 있어서 Utterances의 다크모드 역시 손쉽게 구현할 수 있었다.
utterances에서 제공하는 테마
👉🏽 🔮utterances 에서 확인할 수 있다.
Comment 초기 Theme 설정
- 만들어둔 Comment컴포넌트에서 useTheme Hook을 사용하여 분기처리만 해주면 된다.
- theme이 아닌, resolvedTheme을 통해 분기처리를 한 이유는 enableSystem을 true로 설정했기 때문에, theme값(현재 적용된 theme)을 사용할 경우 그 값은 'light'나 'dark'가 아닌 'system'으로 반환될 수 있고, 이럴 경우 원하는 결과가 나오지 않을 수 있기 때문이다. (상기 기재한 바와 같이, 수동으로 토글로 다크모드 전환을 하지 않을 경우 기본값은 'system'이 됨).
- resolvedTheme을 사용하면 활성 테마가 "system"인 경우 시스템 기본 설정이 "dark"인지 "light"인지를 반환하기에, 실제 적용된 테마에 따라 분기처리가 가능하다.
- 참고로 theme값은 로컬스토리지에 저장되기 때문에, 사용자가 재방문 시 마지막 설정된 값으로 적용된다.
'use client';
import { useTheme } from "next-themes";
import React, { useEffect } from "react"
const COMMENTS_ID = 'comments-container';
export default function Comment() {
const { resolvedTheme } = useTheme();
const utterancesTheme = resolvedTheme === 'light' ? "github-light" : "photon-dark" ;
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://utteranc.es/client.js';
script.setAttribute('repo', "carrotpieOwO/ha0peno-comment");
script.setAttribute('issue-term', 'pathname');
script.setAttribute('theme', utterancesTheme);
script.setAttribute('crossorigin', 'anonymous');
script.async = true;
const comments = document.getElementById(COMMENTS_ID);
if (comments) comments.appendChild(script);
return () => {
const comments = document.getElementById(COMMENTS_ID);
if (comments) comments.innerHTML = '';
};
}, []);
return (
<div id={COMMENTS_ID} />
);
};
동적으로 theme 변경하기
- 다크모드 버튼 컴포넌트에서 수동으로 theme이 변경될 시, utterances theme을 바꿔준다.
- utterances는 iframe으로 생성되기 때문에 window.postMessage()메서드를 사용해서 iframe에 메세지 이벤트를 전달해야 한다.
- 이를 활용하여 HTMLIframeElement.contentWindow속성을 통해 iframe에 접근하여 테마가 변경될 때 set-theme이벤트를 전달하도록 하였다.
"use client"
import { useTheme } from "next-themes"
export default function DarkModeBtn() {
const { systemTheme, theme, setTheme } = useTheme()
const currentTheme = theme === "system" ? systemTheme : theme
useEffect(() => {
const isComment = document.querySelector('iframe.utterances-frame');
if (isComment) {
const utterancesTheme = theme === 'light' ? "github-light" : "photon-dark" ;
const utterancesEl = document.querySelector('iframe.utterances-frame') as HTMLIFrameElement;
(
utterancesEl?.contentWindow?.postMessage(
{ type: "set-theme", theme: utterancesTheme },
"https://utteranc.es/"
)
)
}
}, [systemTheme, theme])
return (
<div>
<button
className="bg-pink-100 dark:bg-white flex items-center transition duration-300 focus:outline-none shadow"
onClick={() => {
setTheme( currentTheme === 'dark' ? 'light' : 'dark')
}}
>
{
currentTheme === 'dark' ?
<div>
...다크모드 버튼
</div>
:
<div
...라이트모드 버튼
</div>
}
</button>
</div>
)
}