feat: 添加 GiscusComments 组件,支持文章评论功能
This commit is contained in:
52
src/components/blog/GiscusComments.tsx
Normal file
52
src/components/blog/GiscusComments.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import Giscus from '@giscus/react';
|
||||||
|
import type { Lang } from '@/types/i18n';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export interface GiscusCommentsProps {
|
||||||
|
lang?: Lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function GiscusComments({ lang = 'en' }: GiscusCommentsProps) {
|
||||||
|
const [theme, setTheme] = useState<'light' | 'dark'>('light');
|
||||||
|
const [term, setTerm] = useState<string>('');
|
||||||
|
|
||||||
|
const giscusLang = lang === 'zh' ? 'zh-CN' : lang;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const getTheme = () => document.documentElement.classList.contains('dark') ? 'dark' : 'light';
|
||||||
|
|
||||||
|
const pathname = window.location.pathname;
|
||||||
|
const postsMatch = pathname.match(/\/posts\/([^/]+)/);
|
||||||
|
const discussionTerm = postsMatch ? postsMatch[1] : pathname;
|
||||||
|
|
||||||
|
setTheme(getTheme());
|
||||||
|
setTerm(discussionTerm);
|
||||||
|
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
setTheme(getTheme());
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Giscus
|
||||||
|
repo="zguiyang/blog-giscus"
|
||||||
|
repoId="R_kgDOQ2Wnxw"
|
||||||
|
category="Announcements"
|
||||||
|
categoryId="DIC_kwDOQ2Wnx84C0vSJ"
|
||||||
|
mapping="specific"
|
||||||
|
term={term}
|
||||||
|
strict="0"
|
||||||
|
reactionsEnabled="1"
|
||||||
|
emitMetadata="0"
|
||||||
|
inputPosition="top"
|
||||||
|
theme={theme}
|
||||||
|
lang={giscusLang}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import TableOfContents from '@/components/layout/TableOfContents.astro';
|
|||||||
import BlogNavigation from '@/components/layout/BlogNavigation.astro';
|
import BlogNavigation from '@/components/layout/BlogNavigation.astro';
|
||||||
import PostMeta from '@/components/blog/PostMeta.astro';
|
import PostMeta from '@/components/blog/PostMeta.astro';
|
||||||
import Container from '../components/ui/Container';
|
import Container from '../components/ui/Container';
|
||||||
|
import GiscusComments from '@/components/blog/GiscusComments';
|
||||||
|
|
||||||
// Use Astro's MarkdownLayoutProps for proper type safety
|
// Use Astro's MarkdownLayoutProps for proper type safety
|
||||||
export type Props = MarkdownLayoutProps<FrontmatterProps>;
|
export type Props = MarkdownLayoutProps<FrontmatterProps>;
|
||||||
@@ -82,6 +83,11 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
|
|||||||
<div class="mt-8 sm:mt-12">
|
<div class="mt-8 sm:mt-12">
|
||||||
<BlogNavigation />
|
<BlogNavigation />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Comments Section -->
|
||||||
|
<div class="mt-10 sm:mt-16 border-t border-border pt-10">
|
||||||
|
<GiscusComments client:only="react" lang={lang} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Author Card moved to bottom with enhanced styling -->
|
<!-- Author Card moved to bottom with enhanced styling -->
|
||||||
<div class="mt-10 sm:mt-16 border-t border-border pt-10">
|
<div class="mt-10 sm:mt-16 border-t border-border pt-10">
|
||||||
|
|||||||
Reference in New Issue
Block a user