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 }) => ( + + {author.name} + +) + +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

+ +
+ ) + : 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.{' '} + Tweet this post + , 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