66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import type { WalineInstance, WalineInitOptions } from '@waline/client';
|
|
import { init } from '@waline/client';
|
|
import '@waline/client/style';
|
|
import '@/styles/waline-custom.css';
|
|
|
|
import type { Lang } from '@/types/i18n';
|
|
|
|
export type CommentsProps = Partial<Omit<WalineInitOptions, 'el' | 'serverURL'>> & { lang?: Lang };
|
|
|
|
export default function Comments({ lang = 'en', ...props }: CommentsProps) {
|
|
const walineInstanceRef = useRef<WalineInstance | null>(null);
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
|
|
const walineLang = lang === 'zh' ? 'zh-CN' : 'en';
|
|
const getTheme = () => (document.documentElement.classList.contains('dark') ? 'html.dark' : false);
|
|
|
|
useEffect(() => {
|
|
if (!containerRef.current) return;
|
|
|
|
const pathname = window.location.pathname;
|
|
const postsMatch = pathname.match(/\/posts\/([^/]+)/);
|
|
const path = postsMatch ? postsMatch[1] : pathname;
|
|
|
|
walineInstanceRef.current = init({
|
|
...props,
|
|
el: containerRef.current,
|
|
serverURL: import.meta.env.PUBLIC_WALINE_SERVER_URL,
|
|
lang: walineLang,
|
|
dark: getTheme(),
|
|
pageview: true,
|
|
comment: true,
|
|
path,
|
|
});
|
|
|
|
const handleThemeChange = () => {
|
|
walineInstanceRef.current?.update({
|
|
...props,
|
|
lang: walineLang,
|
|
dark: getTheme(),
|
|
});
|
|
};
|
|
|
|
const observer = new MutationObserver(handleThemeChange);
|
|
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
|
|
|
|
return () => {
|
|
observer.disconnect();
|
|
const instance = walineInstanceRef.current;
|
|
walineInstanceRef.current = null;
|
|
|
|
if (instance) {
|
|
try {
|
|
instance.destroy();
|
|
} catch {
|
|
if (containerRef.current) {
|
|
containerRef.current.innerHTML = '';
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}, [props, walineLang]);
|
|
|
|
return <div ref={containerRef} className="waline-container" />;
|
|
}
|