Skip to content

Commit 6357aa8

Browse files
authoredMay 7, 2023
Merge pull request tangly1024#1038 from tangly1024/feat/twikoo-comment-count
Feat/twikoo comment count
2 parents 03b138c + 2ac31cc commit 6357aa8

20 files changed

+366
-228
lines changed
 

‎.env.local

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
2-
NEXT_PUBLIC_VERSION=3.13.5
2+
NEXT_PUBLIC_VERSION=3.13.6

‎blog.config.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ const BLOG = {
185185
// ----> 评论互动 可同时开启多个支持 WALINE VALINE GISCUS CUSDIS UTTERRANCES GITALK
186186

187187
// twikoo
188-
COMMENT_TWIKOO_ENV_ID: process.env.NEXT_PUBLIC_COMMENT_ENV_ID || '', // TWIKOO地址 腾讯云环境填 envId;Vercel 环境域名地址(https://xxx.vercel.app)
188+
COMMENT_TWIKOO_ENV_ID: process.env.NEXT_PUBLIC_COMMENT_ENV_ID || '', // TWIKOO后端地址 腾讯云环境填envId;Vercel环境填域名,教程:https://tangly1024.com/article/notionnext-twikoo
189+
COMMENT_TWIKOO_COUNT_ENABLE: process.env.NEXT_PUBLIC_COMMENT_TWIKOO_COUNT_ENABLE || false, // 博客列表是否显示评论数
190+
COMMENT_TWIKOO_CDN_URL: process.env.NEXT_PUBLIC_COMMENT_TWIKOO_CDN_URL || 'https://cdn.staticfile.org/twikoo/1.6.16/twikoo.all.min.js', // twikoo客户端cdn
189191

190192
// utterance
191193
COMMENT_UTTERRANCES_REPO:

‎components/PrismMac.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ const PrismMac = () => {
2323
loadExternalResource('/css/prism-mac-style.css', 'css')
2424
}
2525
loadExternalResource(BLOG.PRISM_THEME_PATH, 'css')
26-
loadExternalResource(BLOG.PRISM_JS_AUTO_LOADER, 'js').then((e) => {
27-
Prism.plugins.autoloader.languages_path = BLOG.PRISM_JS_PATH
26+
loadExternalResource(BLOG.PRISM_JS_AUTO_LOADER, 'js').then((url) => {
27+
if (window?.Prism?.plugins?.autoloader) {
28+
window.Prism.plugins.autoloader.languages_path = BLOG.PRISM_JS_PATH
29+
}
2830
renderPrismMac()
2931
})
3032
}

‎components/Twikoo.js

+44-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import BLOG from '@/blog.config'
2-
import React from 'react'
3-
import twikoo from 'twikoo'
2+
import { loadExternalResource } from '@/lib/utils'
3+
import { useEffect } from 'react'
4+
// import twikoo from 'twikoo'
45

56
/**
67
* Giscus评论 @see https://giscus.app/zh-CN
@@ -10,17 +11,48 @@ import twikoo from 'twikoo'
1011
*/
1112

1213
const Twikoo = ({ isDarkMode }) => {
13-
React.useEffect(() => {
14-
twikoo({
15-
envId: BLOG.COMMENT_TWIKOO_ENV_ID, // 腾讯云环境填 envId;Vercel 环境填地址(https://xxx.vercel.app)
16-
el: '#twikoo', // 容器元素
17-
lang: BLOG.LANG // 用于手动设定评论区语言,支持的语言列表 https://github.com/imaegoo/twikoo/blob/main/src/client/utils/i18n/index.js
18-
// region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,腾讯云环境填 ap-shanghai 或 ap-guangzhou;Vercel 环境不填
19-
// path: location.pathname, // 用于区分不同文章的自定义 js 路径,如果您的文章路径不是 location.pathname,需传此参数
20-
})
21-
})
14+
const loadTwikoo = async () => {
15+
try {
16+
const url = await loadExternalResource(BLOG.COMMENT_TWIKOO_CDN_URL, 'js')
17+
console.log('twikoo 加载成功', url)
18+
const twikoo = window.twikoo
19+
twikoo.init({
20+
envId: BLOG.COMMENT_TWIKOO_ENV_ID, // 腾讯云环境填 envId;Vercel 环境填地址(https://xxx.vercel.app)
21+
el: '#twikoo', // 容器元素
22+
lang: BLOG.LANG // 用于手动设定评论区语言,支持的语言列表 https://github.com/imaegoo/twikoo/blob/main/src/client/utils/i18n/index.js
23+
// region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,腾讯云环境填 ap-shanghai 或 ap-guangzhou;Vercel 环境不填
24+
// path: location.pathname, // 用于区分不同文章的自定义 js 路径,如果您的文章路径不是 location.pathname,需传此参数
25+
})
26+
27+
twikoo.getCommentsCount({
28+
envId: BLOG.COMMENT_TWIKOO_ENV_ID, // 环境 ID
29+
// region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,如果您的环境地域不是上海,需传此参数
30+
urls: [ // 不包含协议、域名、参数的文章路径列表,必传参数
31+
'/article/notion-next',
32+
'/article/notion-next-guide'
33+
],
34+
includeReply: false // 评论数是否包括回复,默认:false
35+
}).then(function (res) {
36+
console.log(res)
37+
// 返回示例: [
38+
// { url: '/2020/10/post-1.html', count: 10 },
39+
// { url: '/2020/11/post-2.html', count: 0 },
40+
// { url: '/2020/12/post-3.html', count: 20 }
41+
// ]
42+
}).catch(function (err) {
43+
// 发生错误
44+
console.error(err)
45+
})
46+
} catch (error) {
47+
console.error('twikoo 加载失败', error)
48+
}
49+
}
50+
51+
useEffect(() => {
52+
loadTwikoo()
53+
}, [])
2254
return (
23-
<div id="twikoo"></div>
55+
<div id="twikoo"></div>
2456
)
2557
}
2658

‎components/TwikooCommentCount.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import BLOG from '@/blog.config'
2+
// import twikoo from 'twikoo'
3+
4+
/**
5+
* 获取博客的评论数,用与在列表中展示
6+
* @returns {JSX.Element}
7+
* @constructor
8+
*/
9+
10+
const TwikooCommentCount = ({ post, className }) => {
11+
if (!JSON.parse(BLOG.COMMENT_TWIKOO_COUNT_ENABLE)) {
12+
return null
13+
}
14+
return <a href={`${post.slug}?target=comment`} className={`mx-1 hidden comment-count-wrapper-${post.id} ${className || ''}`}>
15+
<i className="far fa-comment mr-1"></i>
16+
<span className={`comment-count-text-${post.id}`}>
17+
{/* <i className='fa-solid fa-spinner animate-spin' /> */}
18+
</span>
19+
</a>
20+
}
21+
22+
export default TwikooCommentCount

‎components/TwikooCommentCounter.js

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import BLOG from '@/blog.config'
2+
import { useGlobal } from '@/lib/global'
3+
import { loadExternalResource } from '@/lib/utils'
4+
import { useRouter } from 'next/router'
5+
import { useEffect } from 'react'
6+
7+
/**
8+
* 获取博客的评论数,用与在列表中展示
9+
* @returns {JSX.Element}
10+
* @constructor
11+
*/
12+
13+
const TwikooCommentCounter = (props) => {
14+
let commentsData = []
15+
const { theme } = useGlobal()
16+
17+
const fetchTwikooData = async (posts) => {
18+
posts.forEach(post => {
19+
post.slug = post.slug.startsWith('/') ? post.slug : `/${post.slug}`
20+
})
21+
try {
22+
await loadExternalResource(BLOG.COMMENT_TWIKOO_CDN_URL, 'js')
23+
const twikoo = window.twikoo
24+
twikoo.getCommentsCount({
25+
envId: BLOG.COMMENT_TWIKOO_ENV_ID, // 环境 ID
26+
// region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,如果您的环境地域不是上海,需传此参数
27+
urls: posts.map(post => post.slug), // 不包含协议、域名、参数的文章路径列表,必传参数
28+
includeReply: true // 评论数是否包括回复,默认:false
29+
}).then(function (res) {
30+
console.log('查询', res)
31+
commentsData = res
32+
updateCommentCount()
33+
}).catch(function (err) {
34+
// 发生错误
35+
console.error(err)
36+
})
37+
} catch (error) {
38+
console.error('twikoo 加载失败', error)
39+
}
40+
}
41+
42+
const updateCommentCount = () => {
43+
if (commentsData.length === 0) {
44+
return
45+
}
46+
props.posts.forEach(post => {
47+
const matchingRes = commentsData.find(r => r.url === post.slug)
48+
if (matchingRes) {
49+
// 修改评论数量div
50+
const textElements = document.querySelectorAll(`.comment-count-text-${post.id}`)
51+
textElements.forEach(element => {
52+
element.innerHTML = matchingRes.count
53+
})
54+
// 取消隐藏
55+
const wrapperElements = document.querySelectorAll(`.comment-count-wrapper-${post.id}`)
56+
wrapperElements.forEach(element => {
57+
element.classList.remove('hidden')
58+
})
59+
}
60+
})
61+
}
62+
const router = useRouter()
63+
64+
useEffect(() => {
65+
console.log('路由触发评论计数')
66+
if (props?.posts && props?.posts?.length > 0) {
67+
fetchTwikooData(props.posts)
68+
}
69+
}, [router.events])
70+
71+
// 监控主题变化时的的评论数
72+
useEffect(() => {
73+
console.log('主题触发评论计数', commentsData)
74+
updateCommentCount()
75+
}, [theme])
76+
return null
77+
}
78+
79+
export default TwikooCommentCounter

‎components/TwikooRecentComments.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
/**
3+
* 显示最近评论 TODO
4+
* @returns {JSX.Element}
5+
* @constructor
6+
*/
7+
8+
const TwikooRecentComments = (props) => {
9+
return null
10+
}
11+
12+
export default TwikooRecentComments

‎package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "notion-next",
3-
"version": "3.13.5",
3+
"version": "3.13.6",
44
"homepage": "https://github.com/tangly1024/NotionNext.git",
55
"license": "MIT",
66
"repository": {
@@ -55,7 +55,6 @@
5555
"react-share": "^4.4.1",
5656
"react-tweet-embed": "~2.0.0",
5757
"smoothscroll-polyfill": "^0.4.4",
58-
"twikoo": "^1.6.16",
5958
"typed.js": "^2.0.12",
6059
"use-ackee": "^3.0.0",
6160
"valine": "^1.4.18"

‎pages/_app.js

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import smoothscroll from 'smoothscroll-polyfill'
2626
import AOS from 'aos'
2727
import 'aos/dist/aos.css' // You can also use <link> for styles
2828
import { isMobile } from '@/lib/utils'
29+
import TwikooCommentCounter from '@/components/TwikooCommentCounter'
2930

3031
const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false })
3132
const Gtag = dynamic(() => import('@/components/Gtag'), { ssr: false })
@@ -53,6 +54,7 @@ const MyApp = ({ Component, pageProps }) => {
5354
{JSON.parse(BLOG.MUSIC_PLAYER) && <MusicPlayer />}
5455
{JSON.parse(BLOG.NEST) && <Nest />}
5556
{JSON.parse(BLOG.FLUTTERINGRIBBON) && <FlutteringRibbon />}
57+
{JSON.parse(BLOG.COMMENT_TWIKOO_COUNT_ENABLE) && <TwikooCommentCounter {...pageProps}/>}
5658
{JSON.parse(BLOG.RIBBON) && <Ribbon />}
5759
<ExternalScript/>
5860
</>

‎pages/index.js

+10
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,22 @@ import * as ThemeMap from '@/themes'
55
import { useGlobal } from '@/lib/global'
66
import { generateRss } from '@/lib/rss'
77
import { generateRobotsTxt } from '@/lib/robots.txt'
8+
9+
/**
10+
* 首页布局
11+
* @param {*} props
12+
* @returns
13+
*/
814
const Index = props => {
915
const { theme } = useGlobal()
1016
const ThemeComponents = ThemeMap[theme]
1117
return <ThemeComponents.LayoutIndex {...props} />
1218
}
1319

20+
/**
21+
* SSG 获取数据
22+
* @returns
23+
*/
1424
export async function getStaticProps() {
1525
const from = 'index'
1626
const props = await getGlobalNotionData({ from })

‎themes/example/components/BlogListPage.js

+3-40
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useGlobal } from '@/lib/global'
44
import { useRouter } from 'next/router'
55
import Link from 'next/link'
66
import CONFIG_EXAMPLE from '../config_example'
7+
import BlogPostCard from './BlogPostCard'
78

89
export const BlogListPage = props => {
910
const { page = 1, posts, postCount } = props
@@ -22,46 +23,8 @@ export const BlogListPage = props => {
2223
<div className={`w-full ${showPageCover ? 'md:pr-2' : 'md:pr-12'}} mb-12`}>
2324

2425
<div id="container">
25-
{posts?.map(p => (
26-
<article key={p.id} className={`mb-12 ${showPageCover ? 'flex md:flex-row flex-col-reverse' : ''}`}>
27-
<div className={`${showPageCover ? 'md:w-7/12' : ''}`}>
28-
<h2 className="mb-4">
29-
<Link
30-
href={`/${p.slug}`}
31-
className="text-black dark:text-gray-100 text-xl md:text-2xl no-underline hover:underline">
32-
{p.title}
33-
</Link>
34-
</h2>
35-
36-
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
37-
by <a href="#" className="text-gray-700 dark:text-gray-300">{BLOG.AUTHOR}</a> on {p.date?.start_date || p.createdTime}
38-
<span className="font-bold mx-1"> | </span>
39-
<a href={`/category${p.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{p.category}</a>
40-
{/* <span className="font-bold mx-1"> | </span> */}
41-
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
42-
</div>
43-
44-
<p className="text-gray-700 dark:text-gray-400 leading-normal p-3-lines">
45-
{p.summary}
46-
</p>
47-
{/* 搜索结果 */}
48-
{p.results && (
49-
<p className="p-4-lines mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
50-
{p.results.map(r => (
51-
<span key={r}>{r}</span>
52-
))}
53-
</p>
54-
)}
55-
</div>
56-
{/* 图片封面 */}
57-
{showPageCover && (
58-
<div className="md:w-5/12 w-full overflow-hidden p-1">
59-
<Link href={`${BLOG.SUB_PATH}/${p.slug}`} passHref legacyBehavior>
60-
<div className='h-44 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${p?.page_cover}')` }} />
61-
</Link>
62-
</div>
63-
)}
64-
</article>
26+
{posts?.map(post => (
27+
<BlogPostCard key={post.id} post = {post}/>
6528
))}
6629
</div>
6730

+16-53
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import BLOG from '@/blog.config'
22
import { useGlobal } from '@/lib/global'
3-
import Link from 'next/link'
4-
import React from 'react'
3+
import React, { useEffect } from 'react'
54
import throttle from 'lodash.throttle'
5+
import BlogPostCard from './BlogPostCard'
66
import CONFIG_EXAMPLE from '../config_example'
77

88
export const BlogListScroll = props => {
@@ -35,69 +35,32 @@ export const BlogListScroll = props => {
3535
handleGetMore()
3636
}
3737
}, 500))
38+
const showPageCover = CONFIG_EXAMPLE.POST_LIST_COVER
3839

39-
React.useEffect(() => {
40+
useEffect(() => {
4041
window.addEventListener('scroll', scrollTrigger)
4142

4243
return () => {
4344
window.removeEventListener('scroll', scrollTrigger)
4445
}
4546
})
4647

47-
const showPageCover = CONFIG_EXAMPLE.POST_LIST_COVER
48-
4948
return (
50-
<div id="container" className="w-full md:pr-12 mb-12" ref={targetRef}>
51-
{postsToShow.map(p => (
52-
<article key={p.id} className={`mb-12 ${showPageCover ? 'flex md:flex-row flex-col-reverse' : ''}`}>
53-
<div className={`${showPageCover ? 'md:w-7/12' : ''}`}>
54-
<h2 className="mb-4">
55-
<Link
56-
href={`/${p.slug}`}
57-
className="text-black dark:text-gray-100 text-xl md:text-2xl no-underline hover:underline">
58-
{p.title}
59-
</Link>
60-
</h2>
6149

62-
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
63-
by <a href="#" className="text-gray-700 dark:text-gray-300">{BLOG.AUTHOR}</a> on {p.date?.start_date || p.createdTime}
64-
<span className="font-bold mx-1"> | </span>
65-
<a href={`/category${p.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{p.category}</a>
66-
{/* <span className="font-bold mx-1"> | </span> */}
67-
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
68-
</div>
50+
<div className={`w-full ${showPageCover ? 'md:pr-2' : 'md:pr-12'}} mb-12`} ref={targetRef}>
6951

70-
<p className="text-gray-700 dark:text-gray-400 leading-normal p-3-lines">
71-
{p.summary}
72-
</p>
73-
{/* 搜索结果 */}
74-
{p.results && (
75-
<p className="p-4-lines mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
76-
{p.results.map(r => (
77-
<span key={r}>{r}</span>
78-
))}
79-
</p>
80-
)}
81-
</div>
82-
{/* 图片封面 */}
83-
{showPageCover && (
84-
<div className="md:w-5/12 w-full overflow-hidden p-1">
85-
<Link href={`${BLOG.SUB_PATH}/${p.slug}`} passHref legacyBehavior>
86-
<div className='h-44 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${p?.page_cover}')` }} />
87-
</Link>
88-
</div>
89-
)}
90-
</article>
91-
))}
52+
{postsToShow?.map(post => (
53+
<BlogPostCard key={post.id} post={post} />
54+
))}
9255

93-
<div
94-
onClick={handleGetMore}
95-
className="w-full my-4 py-4 text-center cursor-pointer "
96-
>
97-
{' '}
98-
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
99-
</div>
56+
<div
57+
onClick={handleGetMore}
58+
className="w-full my-4 py-4 text-center cursor-pointer "
59+
>
60+
{' '}
61+
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
62+
</div>
10063

101-
</div>
64+
</div>
10265
)
10366
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import BLOG from '@/blog.config'
2+
import CONFIG_EXAMPLE from '../config_example'
3+
import Link from 'next/link'
4+
import TwikooCommentCount from '@/components/TwikooCommentCount'
5+
6+
const BlogPostCard = ({ post }) => {
7+
const showPageCover = CONFIG_EXAMPLE.POST_LIST_COVER
8+
9+
return <article className={`mb-12 ${showPageCover ? 'flex md:flex-row flex-col-reverse' : ''}`}>
10+
<div className={`${showPageCover ? 'md:w-7/12' : ''}`}>
11+
<h2 className="mb-4">
12+
<Link
13+
href={`/${post.slug}`}
14+
className="text-black dark:text-gray-100 text-xl md:text-2xl no-underline hover:underline">
15+
{post.title}
16+
</Link>
17+
</h2>
18+
19+
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
20+
by <a href="#" className="text-gray-700 dark:text-gray-300">{BLOG.AUTHOR}</a> on {post.date?.start_date || post.createdTime}
21+
<TwikooCommentCount post={post} className='pl-1'/>
22+
<span className="font-bold mx-1"> | </span>
23+
<a href={`/category${post.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{post.category}</a>
24+
{/* <span className="font-bold mx-1"> | </span> */}
25+
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
26+
</div>
27+
28+
<p className="text-gray-700 dark:text-gray-400 leading-normal p-3-lines">
29+
{post.summary}
30+
</p>
31+
{/* 搜索结果 */}
32+
{post.results && (
33+
<p className="p-4-lines mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
34+
{post.results.map(r => (
35+
<span key={r}>{r}</span>
36+
))}
37+
</p>
38+
)}
39+
</div>
40+
{/* 图片封面 */}
41+
{showPageCover && (
42+
<div className="md:w-5/12 w-full overflow-hidden p-1">
43+
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
44+
<div className='h-44 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${post?.page_cover}')` }} />
45+
</Link>
46+
</div>
47+
)}
48+
</article>
49+
}
50+
51+
export default BlogPostCard

‎themes/hexo/components/BlogPostCardInfo.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import BLOG from '@/blog.config'
22
import NotionPage from '@/components/NotionPage'
33
import Link from 'next/link'
44
import TagItemMini from './TagItemMini'
5+
import TwikooCommentCount from '@/components/TwikooCommentCount'
56

67
/**
78
* 博客列表的文字内容
@@ -26,17 +27,19 @@ export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary
2627
{/* 日期 */}
2728
<div
2829
className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'
29-
} flex-wrap dark:text-gray-500 text-gray-400 hover:text-indigo-700 dark:hover:text-indigo-400`}
30+
} flex-wrap dark:text-gray-500 text-gray-400 `}
3031
>
3132
<Link
3233
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
3334
passHref
34-
className="font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
35+
className="font-light cursor-pointer text-sm leading-4 mr-3 hover:text-indigo-700 dark:hover:text-indigo-400">
3536

3637
<i className="far fa-calendar-alt mr-1" />
3738
{post.date?.start_date || post.lastEditedTime}
3839

3940
</Link>
41+
42+
<TwikooCommentCount className='text-sm hover:text-indigo-700 dark:hover:text-indigo-400' post={post}/>
4043
</div>
4144

4245
{/* 摘要 */}

‎themes/hexo/components/HexoRecentComments.js

+15-13
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,23 @@ const HexoRecentComments = (props) => {
2525
}, [])
2626

2727
return (
28-
<Card >
29-
<div className=" mb-2 px-1 justify-between">
30-
<i className="mr-2 fas fas fa-comment" />
31-
{locale.COMMON.RECENT_COMMENTS}
32-
</div>
28+
<Card >
29+
<div className=" mb-2 px-1 justify-between">
30+
<i className="mr-2 fas fas fa-comment" />
31+
{locale.COMMON.RECENT_COMMENTS}
32+
</div>
3333

34-
{onLoading && <div>Loading...<i className='ml-2 fas fa-spinner animate-spin' /></div>}
35-
{!onLoading && comments && comments.length === 0 && <div>No Comments</div>}
36-
{!onLoading && comments && comments.length > 0 && comments.map((comment) => <div key={comment.objectId} className='pb-2 pl-1'>
37-
<div className='dark:text-gray-200 text-sm waline-recent-content wl-content' dangerouslySetInnerHTML={{ __html: comment.comment }} />
38-
<div className='dark:text-gray-400 text-gray-400 text-sm text-right cursor-pointer hover:text-red-500 hover:underline pt-1 pr-2'><Link href={{ pathname: comment.url, hash: comment.objectId, query: { target: 'comment' } }}>--{comment.nick}</Link></div>
39-
</div>)}
34+
{onLoading && <div>Loading...<i className='ml-2 fas fa-spinner animate-spin' /></div>}
35+
{!onLoading && comments && comments.length === 0 && <div>No Comments</div>}
36+
{!onLoading && comments && comments.length > 0 && comments.map((comment) => <div key={comment.objectId} className='pb-2 pl-1'>
37+
<div className='dark:text-gray-200 text-sm waline-recent-content wl-content' dangerouslySetInnerHTML={{ __html: comment.comment }} />
38+
<div className='dark:text-gray-400 text-gray-400 text-sm text-right cursor-pointer hover:text-red-500 hover:underline pt-1 pr-2'>
39+
<Link href={{ pathname: comment.url, hash: comment.objectId, query: { target: 'comment' } }}>--{comment.nick}</Link>
40+
</div>
41+
</div>)}
4042

41-
</Card>
42-
);
43+
</Card>
44+
)
4345
}
4446

4547
export default HexoRecentComments

‎themes/matery/components/BlogPostCard.js

+71-67
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Link from 'next/link'
33
import React from 'react'
44
import TagItemMini from './TagItemMini'
55
import CONFIG_MATERY from '../config_matery'
6+
import TwikooCommentCount from '@/components/TwikooCommentCount'
67
// import Image from 'next/image'
78

89
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
@@ -14,84 +15,87 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
1415
const showPageCover = CONFIG_MATERY.POST_LIST_COVER && post?.page_cover
1516
const delay = (index % 3) * 300
1617
return (
17-
<div
18-
data-aos="zoom-in"
19-
data-aos-duration="500"
20-
data-aos-delay={delay}
21-
data-aos-once="true"
22-
data-aos-anchor-placement="top-bottom"
23-
className="w-full mb-4 overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
18+
<div
19+
data-aos="zoom-in"
20+
data-aos-duration="500"
21+
data-aos-delay={delay}
22+
data-aos-once="true"
23+
data-aos-anchor-placement="top-bottom"
24+
className="w-full mb-4 overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
2425

25-
{/* 固定高度 ,空白用图片拉升填充 */}
26-
<div className="flex flex-col h-80 justify-between">
26+
{/* 固定高度 ,空白用图片拉升填充 */}
27+
<div className="flex flex-col h-80 justify-between">
2728

28-
{/* 头部图片 填充卡片 */}
29-
{showPageCover && (
30-
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
31-
<div
32-
className="flex flex-grow w-full relative duration-200 bg-black rounded-t-md cursor-pointer transform overflow-hidden">
33-
{/* eslint-disable-next-line @next/next/no-img-element */}
34-
<img
35-
src={post?.page_cover}
36-
alt={post.title}
37-
className="opacity-50 h-full w-full hover:scale-125 rounded-t-md transform object-cover duration-500"
38-
/>
39-
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace break-words w-full' > {post.title}</span>
40-
</div>
41-
</Link>
42-
)}
29+
{/* 头部图片 填充卡片 */}
30+
{showPageCover && (
31+
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
32+
<div
33+
className="flex flex-grow w-full relative duration-200 bg-black rounded-t-md cursor-pointer transform overflow-hidden">
34+
{/* eslint-disable-next-line @next/next/no-img-element */}
35+
<img
36+
src={post?.page_cover}
37+
alt={post.title}
38+
className="opacity-50 h-full w-full hover:scale-125 rounded-t-md transform object-cover duration-500"
39+
/>
40+
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace break-words w-full' > {post.title}</span>
41+
</div>
42+
</Link>
43+
)}
4344

44-
{/* 文字描述 */}
45-
<div >
46-
{/* 描述 */}
47-
<div className="px-4 flex flex-col w-full text-gray-700 dark:text-gray-300">
45+
{/* 文字描述 */}
46+
<div >
47+
{/* 描述 */}
48+
<div className="px-4 flex flex-col w-full text-gray-700 dark:text-gray-300">
4849

49-
{(!showPreview || showSummary) && post.summary && (
50-
<p style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '4', WebkitBoxOrient: 'vertical' }}
51-
className="replace my-2 text-sm font-light leading-7">
52-
{post.summary}
53-
</p>
54-
)}
50+
{(!showPreview || showSummary) && post.summary && (
51+
<p style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '4', WebkitBoxOrient: 'vertical' }}
52+
className="replace my-2 text-sm font-light leading-7">
53+
{post.summary}
54+
</p>
55+
)}
5556

56-
<div className='text-gray-800 justify-between flex my-2 dark:text-gray-300'>
57-
<Link
58-
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
59-
passHref
60-
className="font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
57+
<div className='text-gray-800 justify-between flex my-2 dark:text-gray-300'>
58+
<div>
59+
<Link
60+
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
61+
passHref
62+
className="font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
6163

62-
<i className="far fa-clock mr-1" />
63-
{post.date?.start_date || post.lastEditedTime}
64+
<i className="far fa-clock mr-1" />
65+
{post.date?.start_date || post.lastEditedTime}
6466

65-
</Link>
66-
<Link
67-
href={`/category/${post.category}`}
68-
passHref
69-
className="cursor-pointer font-light text-sm hover:underline hover:text-indigo-700 dark:hover:text-indigo-400 transform">
67+
</Link>
68+
<TwikooCommentCount post={post} className='hover:underline cursor-pointer text-sm'/>
69+
</div>
70+
<Link
71+
href={`/category/${post.category}`}
72+
passHref
73+
className="cursor-pointer font-light text-sm hover:underline hover:text-indigo-700 dark:hover:text-indigo-400 transform">
7074

71-
<i className="mr-1 far fa-folder" />
72-
{post.category}
75+
<i className="mr-1 far fa-folder" />
76+
{post.category}
7377

74-
</Link>
75-
</div>
76-
</div>
78+
</Link>
79+
</div>
80+
</div>
7781

78-
{post?.tagItems && post?.tagItems.length > 0 && (<>
79-
<hr />
80-
<div className="text-gray-400 justify-between flex px-5 py-3">
81-
<div className="md:flex-nowrap flex-wrap md:justify-start inline-block">
82-
<div>
83-
{' '}
84-
{post.tagItems.map(tag => (
85-
<TagItemMini key={tag.name} tag={tag} />
86-
))}
87-
</div>
88-
</div>
89-
</div>
90-
</>)}
91-
</div>
92-
</div>
82+
{post?.tagItems && post?.tagItems.length > 0 && (<>
83+
<hr />
84+
<div className="text-gray-400 justify-between flex px-5 py-3">
85+
<div className="md:flex-nowrap flex-wrap md:justify-start inline-block">
86+
<div>
87+
{' '}
88+
{post.tagItems.map(tag => (
89+
<TagItemMini key={tag.name} tag={tag} />
90+
))}
91+
</div>
92+
</div>
93+
</div>
94+
</>)}
95+
</div>
96+
</div>
9397

94-
</div>
98+
</div>
9599
)
96100
}
97101

‎themes/medium/components/BlogPostCard.js

+4-7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import React from 'react'
66
import CONFIG_MEDIUM from '../config_medium'
77
import CategoryItem from './CategoryItem'
88
import TagItemMini from './TagItemMini'
9+
import TwikooCommentCount from '@/components/TwikooCommentCount'
910

1011
const BlogPostCard = ({ post, showSummary }) => {
1112
const showPreview = CONFIG_MEDIUM.POST_LIST_PREVIEW && post.blockMap
@@ -43,13 +44,9 @@ const BlogPostCard = ({ post, showSummary }) => {
4344
}
4445
>
4546
<div className="text-sm py-1">{post.date?.start_date}</div>
46-
{CONFIG_MEDIUM.POST_LIST_CATEGORY && (
47-
<CategoryItem category={post.category} />
48-
)}
49-
{CONFIG_MEDIUM.POST_LIST_TAG &&
50-
post?.tagItems?.map(tag => (
51-
<TagItemMini key={tag.name} tag={tag} />
52-
))}
47+
{CONFIG_MEDIUM.POST_LIST_CATEGORY && <CategoryItem category={post.category} />}
48+
{CONFIG_MEDIUM.POST_LIST_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
49+
<TwikooCommentCount post={post} className='hover:underline'/>
5350
</div>
5451

5552
<div className="flex"></div>

‎themes/next/LayoutBase.js

+10-14
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import SideAreaLeft from './components/SideAreaLeft'
88
import SideAreaRight from './components/SideAreaRight'
99
import TopNav from './components/TopNav'
1010
import { useGlobal } from '@/lib/global'
11-
import PropTypes from 'prop-types'
12-
import React from 'react'
11+
import { useEffect, useRef, useState } from 'react'
1312
import CONFIG_NEXT from './config_next'
1413
import Live2D from '@/components/Live2D'
1514
import BLOG from '@/blog.config'
@@ -22,12 +21,13 @@ import BLOG from '@/blog.config'
2221
const LayoutBase = (props) => {
2322
const { children, headerSlot, meta, sideBarSlot, floatSlot, rightAreaSlot, siteInfo } = props
2423
const { onLoading } = useGlobal()
25-
const targetRef = React.useRef(null)
26-
const floatButtonGroup = React.useRef(null)
24+
const targetRef = useRef(null)
25+
const floatButtonGroup = useRef(null)
2726
const leftAreaSlot = <Live2D/>
2827

29-
const [show, switchShow] = React.useState(false)
30-
const [percent, changePercent] = React.useState(0) // 页面阅读百分比
28+
const [showRightFloat, switchShow] = useState(false)
29+
const [percent, changePercent] = useState(0) // 页面阅读百分比
30+
3131
const scrollListener = () => {
3232
const targetRef = document.getElementById('wrapper')
3333
const clientHeight = targetRef?.clientHeight
@@ -37,13 +37,13 @@ const LayoutBase = (props) => {
3737
if (per > 100) per = 100
3838
const shouldShow = scrollY > 100 && per > 0
3939

40-
if (shouldShow !== show) {
40+
if (shouldShow !== showRightFloat) {
4141
switchShow(shouldShow)
4242
}
4343
changePercent(per)
4444
}
4545

46-
React.useEffect(() => {
46+
useEffect(() => {
4747
// facebook messenger 插件需要调整右下角悬浮按钮的高度
4848
const fb = document.getElementsByClassName('fb-customerchat')
4949
if (fb.length === 0) {
@@ -54,7 +54,7 @@ const LayoutBase = (props) => {
5454

5555
document.addEventListener('scroll', scrollListener)
5656
return () => document.removeEventListener('scroll', scrollListener)
57-
}, [show])
57+
}, [showRightFloat])
5858

5959
return (<div id='theme-next'>
6060

@@ -78,7 +78,7 @@ const LayoutBase = (props) => {
7878

7979
{/* 右下角悬浮 */}
8080
<div ref={floatButtonGroup} className='right-8 bottom-12 lg:right-2 fixed justify-end z-20 font-sans'>
81-
<div className={(show ? 'animate__animated ' : 'hidden') + ' animate__fadeInUp rounded-md glassmorphism justify-center duration-500 animate__faster flex space-x-2 items-center cursor-pointer '}>
81+
<div className={(showRightFloat ? 'animate__animated ' : 'hidden') + ' animate__fadeInUp rounded-md glassmorphism justify-center duration-500 animate__faster flex space-x-2 items-center cursor-pointer '}>
8282
<JumpToTopButton percent={percent}/>
8383
<JumpToBottomButton />
8484
<FloatDarkModeButton/>
@@ -91,8 +91,4 @@ const LayoutBase = (props) => {
9191
)
9292
}
9393

94-
LayoutBase.propTypes = {
95-
children: PropTypes.node
96-
}
97-
9894
export default LayoutBase

‎themes/next/components/BlogPostCard.js

+11-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import TagItemMini from './TagItemMini'
88
import CONFIG_NEXT from '../config_next'
99
import NotionPage from '@/components/NotionPage'
1010
import NotionIcon from '@/components/NotionIcon'
11+
import TwikooCommentCount from '@/components/TwikooCommentCount'
1112

1213
const BlogPostCard = ({ post, showSummary }) => {
1314
const { locale } = useGlobal()
@@ -31,15 +32,15 @@ const BlogPostCard = ({ post, showSummary }) => {
3132

3233
<div
3334
className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'
34-
} flex-wrap dark:text-gray-500 text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 `}
35+
} flex-wrap dark:text-gray-500 text-gray-400 `}
3536
>
3637
<div>
3738
{post.category && (
3839
<>
3940
<Link
4041
href={`/category/${post.category}`}
4142
passHref
42-
className="cursor-pointer font-light text-sm hover:underline transform">
43+
className="hover:text-blue-500 dark:hover:text-blue-400 cursor-pointer font-light text-sm hover:underline transform">
4344

4445
<i className="mr-1 fas fa-folder" />
4546
{post.category}
@@ -48,22 +49,18 @@ const BlogPostCard = ({ post, showSummary }) => {
4849
<span className="mx-2">|</span>
4950
</>
5051
)}
51-
<Link
52-
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
53-
passHref
54-
className="font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
55-
56-
{post.date?.start_date}
57-
58-
</Link>
52+
<Link
53+
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
54+
passHref
55+
className="hover:text-blue-500 dark:hover:text-blue-400 font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
56+
{post.date?.start_date}
57+
</Link>
5958
</div>
60-
<div className="md:flex-nowrap flex-wrap md:justify-start inline-block">
61-
<div>
62-
{' '}
59+
<TwikooCommentCount post={post} className='hover:text-blue-500 dark:hover:text-blue-400 hover:underline text-sm'/>
60+
<div className="hover:text-blue-500 dark:hover:text-blue-400 md:flex-nowrap flex-wrap md:justify-start inline-block">
6361
{post.tagItems?.map(tag => (
6462
<TagItemMini key={tag.name} tag={tag} />
6563
))}
66-
</div>
6764
</div>
6865
</div>
6966

‎themes/simple/components/BlogItem.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import BLOG from '@/blog.config'
22
import Link from 'next/link'
33
import CONFIG_SIMPLE from '../config_simple'
4+
import TwikooCommentCount from '@/components/TwikooCommentCount'
45

56
export const BlogItem = props => {
67
const { post } = props
@@ -18,6 +19,7 @@ export const BlogItem = props => {
1819
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
1920
<span> <i className="fa-regular fa-user"></i> <a href={CONFIG_SIMPLE.AUTHOR_LINK}>{BLOG.AUTHOR}</a></span>
2021
<span> - <i className="fa-regular fa-clock"></i> {post.date?.start_date || post.createdTime}</span>
22+
<span> - <TwikooCommentCount post={post}/></span>
2123
{post.category && <span> - <i className="fa-regular fa-folder"></i> <a href={`/category/${post.category}`} className="hover:text-red-400 transition-all duration-200">{post.category}</a></span>}
2224
{post.tags && post.tags?.length > 0 && post.tags.map(t => <span key={t}> / <Link href={`/tag/${t}`}><span className=' hover:text-red-400 transition-all duration-200'>{t}</span></Link></span>)}
2325
</div>

0 commit comments

Comments
 (0)
Please sign in to comment.