diff --git a/.env.local b/.env.local
index 5c68a5c9..5eb0e3a1 100644
--- a/.env.local
+++ b/.env.local
@@ -1,2 +1,6 @@
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
NEXT_PUBLIC_VERSION=3.12.4
+NEXT_PUBLIC_THEME=nobelium
+NEXT_PUBLIC_WEBMENTION_ENABLE=yes
+NEXT_PUBLIC_WEBMENTION_AUTH=https://github.com/siygle
+NEXT_PUBLIC_WEBMENTION_HOSTNAME=chat.sylee.dev
\ No newline at end of file
diff --git a/blog.config.js b/blog.config.js
index 7befd15f..16b043b2 100644
--- a/blog.config.js
+++ b/blog.config.js
@@ -178,9 +178,9 @@ const BLOG = {
COMMENT_WALINE_RECENT: process.env.NEXT_PUBLIC_WALINE_RECENT || false, // 最新评论
COMMENT_WEBMENTION: {
- ENABLE: (process.env.WEBMENTION_ENABLE === 'yes'),
- AUTH: process.env.WEBMENTION_AUTH || '',
- HOSTNAME: process.env.WEBMENTION_HOSTNAME || ''
+ ENABLE: process.env.NEXT_PUBLIC_WEBMENTION_ENABLE || false,
+ AUTH: process.env.NEXT_PUBLIC_WEBMENTION_AUTH || '',
+ HOSTNAME: process.env.NEXT_PUBLIC_WEBMENTION_HOSTNAME || ''
},
// <---- 评论插件
diff --git a/components/Comment.js b/components/Comment.js
index 570d122d..d624e468 100644
--- a/components/Comment.js
+++ b/components/Comment.js
@@ -43,6 +43,12 @@ const GiscusComponent = dynamic(
},
{ ssr: false }
)
+const WebMentionComponent = dynamic(
+ () => {
+ return import('@/components/WebMention')
+ },
+ { ssr: false }
+)
const ValineComponent = dynamic(() => import('@/components/ValineComponent'), {
ssr: false
@@ -100,6 +106,10 @@ const Comment = ({ frontMatter }) => {
{BLOG.COMMENT_GITALK_CLIENT_ID && (
)}
+
+ {BLOG.COMMENT_WEBMENTION.ENABLE === 'yes' && (
+
+
)}
)
diff --git a/components/CommonHead.js b/components/CommonHead.js
index 8104ea80..e4ed9a50 100644
--- a/components/CommonHead.js
+++ b/components/CommonHead.js
@@ -44,6 +44,7 @@ const CommonHead = ({ meta, children }) => {
+ {console.log(BLOG)}
{BLOG.COMMENT_WEBMENTION.ENABLE && (
<>
diff --git a/components/WebMention.js b/components/WebMention.js
new file mode 100644
index 00000000..a22a6e60
--- /dev/null
+++ b/components/WebMention.js
@@ -0,0 +1,168 @@
+import BLOG from '@/blog.config'
+import { useEffect, useState } from 'react'
+import { useRouter } from 'next/router'
+
+/**
+ * 评论插件
+ * @param issueTerm
+ * @param layout
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const WebmentionCount = ({ target }) => {
+ const initialCounts = {
+ count: 0,
+ type: {
+ like: 0,
+ mention: 0,
+ reply: 0,
+ repost: 0
+ }
+ }
+ const [counts, setCounts] = useState(initialCounts)
+ const fetchCounts = async (target) => {
+ const responseData = await fetch(`https://webmention.io/api/count.json?target=${target}`)
+ console.log('!!!', responseData)
+ return (responseData.json) ? await responseData.json() : responseData
+ }
+ useEffect(() => {
+ async function getCounts() {
+ const responseCounts = await fetchCounts(target)
+ console.log('rere', responseCounts)
+ setCounts(responseCounts)
+ }
+ getCounts()
+ }, [target])
+
+ return (
+
+ {counts
+ ? (
+
+
+ {counts.type.like || 0} Likes
+
+
+ {counts.type.reply || 0} Replies
+
+
+
+ {(counts.type.repost || 0) + (counts.type.mention || 0)}
+
+ Mentions
+
+
+ )
+ : (
+
Failed to fetch Webmention counts
+ )
+ }
+
+ )
+}
+
+const Avatar = ({ author }) => (
+
+
+
+)
+
+const WebmentionReplies = ({ target }) => {
+ const [mentions, setMentions] = useState([])
+ const fetchMentions = async (target) =>
+ fetch(
+ `https://webmention.io/api/mentions.jf2?per-page=500&target=${target}`
+ ).then((response) => (response.json ? response.json() : response))
+ useEffect(() => {
+ async function getMentions() {
+ const responseMentions = await fetchMentions(target)
+ if (responseMentions.children) {
+ setMentions(responseMentions.children)
+ }
+ }
+
+ getMentions()
+ }, [target])
+
+ const distinctMentions = [
+ ...new Map(mentions.map((item) => [item.author.url, item])).values()
+ ].sort((a, b) => new Date(a['wm-received']) - new Date(b['wm-received']))
+
+ const replies = distinctMentions.filter(
+ (mention) => 'in-reply-to' in mention && 'content' in mention
+ )
+
+ return (
+
+
+ {distinctMentions.length > 0
+ ? `Already ${distinctMentions.length} people liked, shared or talked about this article:`
+ : 'Be the first one to share this article!'}
+
+
+ {distinctMentions.map((reply) => (
+
+ ))}
+
+ {replies && replies.length
+ ? (
+
+
Replies
+
+ {replies.map((reply) => (
+
+
+
+
{reply.author.name}
+
{reply.content.text}
+
+
+ ))}
+
+
+ )
+ : null}
+
+ )
+}
+
+const WebMentionBlock = ({ frontMatter }) => {
+ const router = useRouter()
+ const url = `https://${BLOG.COMMENT_WEBMENTION.HOSTNAME}/${router.asPath}`
+ const tweet = `${frontMatter.title} by @siygle ${url}`
+
+ return (
+
+
+ This post is using{' '}
+
+ WebMention.io
+ {' '}
+ as the comment system.{' '}
+
+ , the comments will show up here.
+
+
+
+
+
+
+ )
+}
+
+export default WebMentionBlock
diff --git a/styles/globals.css b/styles/globals.css
index 569fbfc6..73e733f6 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -222,4 +222,73 @@ nav {
/* twikoo 评论区超链接样式 */
.tk-main a {
@apply text-blue-700
+}
+
+/* Webmention style */
+.post-footer {
+ background: rgba(0, 116, 222, .2);
+ padding: 1rem 2rem;
+ border-radius: 5px;
+}
+
+.webmention {
+ margin-top: 1rem;
+ padding-top: 1rem;
+ border-top: 1px solid rgba(0, 0, 0, 0.2);
+}
+
+.webmention-counts .count {
+ font-weight: bold;
+ margin-right: .2rem;
+}
+
+/* .webmention-counts .counts > span {
+ margin-right: .8rem;
+} */
+.webmention-counts .counts>span:not(:last-child):after {
+ content: " • ";
+}
+
+a.avatar-wrapper {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ position: relative;
+}
+
+.webmention-avatars .avatar-wrapper {
+ margin-right: -8px;
+}
+
+.avatar {
+ border-radius: 50%;
+ margin: 0;
+ border: 3px solid rgba(0, 116, 222, .5);
+}
+
+.replies {
+ margin: 0;
+ padding: 0;
+}
+
+.reply {
+ list-style: none;
+ display: flex;
+ position: relative;
+ padding: 0;
+ align-items: flex-start;
+ margin-top: .6rem;
+}
+
+.reply p {
+ margin: 0;
+}
+
+.reply .text {
+ margin-left: 1rem;
+ font-size: 14px;
+}
+
+.reply-author-name {
+ font-weight: 500;
}
\ No newline at end of file