nnbb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +1 -0
- package/.env.local +2 -0
- package/.eslintrc.json +15 -0
- package/.github/stale.yml +16 -0
- package/.github/workflows/codeql-analysis.yml +73 -0
- package/.github/workflows/docker-ghcr.yaml +59 -0
- package/.prettierrc +9 -0
- package/.vscode/launch.json +28 -0
- package/.vscode/settings.json +6 -0
- package/Dockerfile +38 -0
- package/LICENSE +21 -0
- package/README.md +16 -0
- package/blog.config.js +454 -0
- package/components/Ackee.js +83 -0
- package/components/AdBlockDetect.js +40 -0
- package/components/AlgoliaSearchModal.js +250 -0
- package/components/Artalk.js +30 -0
- package/components/Busuanzi.js +26 -0
- package/components/ChatBase.js +19 -0
- package/components/Collapse.tsx +134 -0
- package/components/Comment.js +161 -0
- package/components/CommonHead.tsx +101 -0
- package/components/CommonScript.js +125 -0
- package/components/CusdisComponent.js +35 -0
- package/components/CustomContextMenu.js +221 -0
- package/components/DebugPanel.js +134 -0
- package/components/DisableCopy.js +21 -0
- package/components/Draggable.js +167 -0
- package/components/Equation.js +31 -0
- package/components/ExternalPlugins.js +75 -0
- package/components/ExternalScript.js +29 -0
- package/components/FacebookMessenger.js +255 -0
- package/components/FacebookPage.js +34 -0
- package/components/Fireworks.js +210 -0
- package/components/FlipCard.js +56 -0
- package/components/FlutteringRibbon.js +322 -0
- package/components/FullScreenButton.js +48 -0
- package/components/Giscus.js +33 -0
- package/components/Gitalk.js +42 -0
- package/components/GoogleAdsense.js +111 -0
- package/components/Gtag.js +18 -0
- package/components/HeroIcons.tsx +321 -0
- package/components/KatexReact.js +53 -0
- package/components/LazyImage.js +95 -0
- package/components/Live2D.js +52 -0
- package/components/Loading.js +20 -0
- package/components/Mark.js +28 -0
- package/components/NProgress.ts +8 -0
- package/components/Nest.js +124 -0
- package/components/NotionIcon.js +20 -0
- package/components/NotionPage.tsx +206 -0
- package/components/Player.js +54 -0
- package/components/PrismMac.js +236 -0
- package/components/QrCode.js +34 -0
- package/components/Ribbon.js +98 -0
- package/components/Sakura.js +192 -0
- package/components/Select.js +40 -0
- package/components/ShareBar.js +29 -0
- package/components/ShareButtons.js +403 -0
- package/components/SideBarDrawer.js +50 -0
- package/components/StarrySky.js +130 -0
- package/components/Tabs.js +64 -0
- package/components/ThemeSwitch.js +67 -0
- package/components/Twikoo.js +27 -0
- package/components/TwikooCommentCount.js +22 -0
- package/components/TwikooCommentCounter.js +78 -0
- package/components/TwikooRecentComments.js +11 -0
- package/components/Utterances.js +35 -0
- package/components/VConsole.js +76 -0
- package/components/ValineComponent.js +59 -0
- package/components/ValineCount.js +6 -0
- package/components/ValinePanel.js +3 -0
- package/components/Vercel.tsx +54 -0
- package/components/WWAds.js +18 -0
- package/components/WalineComponent.js +83 -0
- package/components/WebMention.js +173 -0
- package/components/Webwhiz.js +17 -0
- package/components/WordCount.js +73 -0
- package/hooks/useToggleClickOutSide.ts +32 -0
- package/hooks/useWindowSize.ts +30 -0
- package/lib/algolia.js +108 -0
- package/lib/busuanzi.js +99 -0
- package/lib/cache/cacheManager.ts +49 -0
- package/lib/cache/localFileCache.ts +56 -0
- package/lib/cache/memoryMache.ts +20 -0
- package/lib/cache/mongoDbCache.ts +70 -0
- package/lib/cache/types.ts +5 -0
- package/lib/font.js +46 -0
- package/lib/global.tsx +129 -0
- package/lib/gtag.js +17 -0
- package/lib/mailchimp.js +49 -0
- package/lib/memorize.js +0 -0
- package/lib/mhchem.js +1696 -0
- package/lib/notion/getAllCategories.ts +51 -0
- package/lib/notion/getAllPageIds.ts +51 -0
- package/lib/notion/getAllPosts.js +68 -0
- package/lib/notion/getAllTags.ts +43 -0
- package/lib/notion/getNotionData.ts +340 -0
- package/lib/notion/getPageInfoOfPostPage.ts +58 -0
- package/lib/notion/getPageProperties.ts +203 -0
- package/lib/notion/getPageTableOfContents.ts +107 -0
- package/lib/notion/getPostBlocks.ts +147 -0
- package/lib/notion/mapImage.ts +130 -0
- package/lib/notion/types.ts +125 -0
- package/lib/notion.js +2 -0
- package/lib/robots.txt.js +25 -0
- package/lib/rss.js +63 -0
- package/lib/sitemap.xml.js +67 -0
- package/lib/utils.js +212 -0
- package/next-env.d.ts +5 -0
- package/next-i18next.config.js +7 -0
- package/next-sitemap.config.js +11 -0
- package/next.config.js +124 -0
- package/package.json +92 -0
- package/pages/404.tsx +40 -0
- package/pages/[prefix]/[slug].tsx +123 -0
- package/pages/[prefix]/index.tsx +223 -0
- package/pages/_app.js +59 -0
- package/pages/_document.js +42 -0
- package/pages/api/subscribe.js +22 -0
- package/pages/archive/index.tsx +79 -0
- package/pages/category/[category]/index.tsx +87 -0
- package/pages/category/[category]/page/[page].tsx +103 -0
- package/pages/category/index.tsx +43 -0
- package/pages/index.tsx +88 -0
- package/pages/page/[page].tsx +93 -0
- package/pages/search/[keyword]/index.tsx +162 -0
- package/pages/search/[keyword]/page/[page].tsx +166 -0
- package/pages/search/index.tsx +69 -0
- package/pages/sitemap.xml.js +70 -0
- package/pages/tag/[tag]/index.tsx +73 -0
- package/pages/tag/[tag]/page/[page].tsx +87 -0
- package/pages/tag/index.tsx +42 -0
- package/postcss.config.js +6 -0
- package/public/ads.txt +1 -0
- package/public/avatar.png +0 -0
- package/public/avatar.svg +11 -0
- package/public/bg_image.jpg +0 -0
- package/public/css/all.min.css +9 -0
- package/public/css/custom.css +8 -0
- package/public/css/img-shadow.css +5 -0
- package/public/css/prism-mac-style.css +58 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +9 -0
- package/public/js/cusdis.es.js +107 -0
- package/public/js/custom.js +1 -0
- package/public/locales/en/common.json +44 -0
- package/public/locales/en/menu.json +9 -0
- package/public/locales/en/nav.json +11 -0
- package/public/locales/zh-CN/common.json +44 -0
- package/public/locales/zh-CN/menu.json +9 -0
- package/public/locales/zh-CN/nav.json +9 -0
- package/public/webfonts/fa-brands-400.ttf +0 -0
- package/public/webfonts/fa-brands-400.woff2 +0 -0
- package/public/webfonts/fa-regular-400.ttf +0 -0
- package/public/webfonts/fa-regular-400.woff2 +0 -0
- package/public/webfonts/fa-solid-900.ttf +0 -0
- package/public/webfonts/fa-solid-900.woff2 +0 -0
- package/public/webfonts/fa-v4compatibility.ttf +0 -0
- package/public/webfonts/fa-v4compatibility.woff2 +0 -0
- package/styles/animate.css +503 -0
- package/styles/globals.css +183 -0
- package/styles/notion.css +2064 -0
- package/styles/nprogress.css +84 -0
- package/styles/prism-theme.css +119 -0
- package/styles/utility-patterns.css +79 -0
- package/tailwind.config.js +37 -0
- package/theme/index.ts +6 -0
- package/theme/types/@theme-components.d.ts +29 -0
- package/theme/useLayout.ts +41 -0
- package/theme/utils.ts +108 -0
- package/themes/innocent/package.json +7 -0
- package/themes/innocent/theme.config.js +1 -0
- package/themes/nobelium/components/Announcement.tsx +27 -0
- package/themes/nobelium/components/ArticleFooter.tsx +39 -0
- package/themes/nobelium/components/ArticleInfo.tsx +58 -0
- package/themes/nobelium/components/ArticleLock.tsx +86 -0
- package/themes/nobelium/components/BlogArchiveItem.js +41 -0
- package/themes/nobelium/components/BlogListBar.js +39 -0
- package/themes/nobelium/components/BlogListPage.tsx +67 -0
- package/themes/nobelium/components/BlogListScroll.tsx +96 -0
- package/themes/nobelium/components/BlogPost.tsx +33 -0
- package/themes/nobelium/components/DarkModeButton.tsx +50 -0
- package/themes/nobelium/components/ExampleRecentComments.js +35 -0
- package/themes/nobelium/components/Footer.tsx +35 -0
- package/themes/nobelium/components/JumpToTopButton.tsx +39 -0
- package/themes/nobelium/components/LanguageSwitchButton.tsx +58 -0
- package/themes/nobelium/components/MenuItemCollapse.tsx +92 -0
- package/themes/nobelium/components/MenuItemDrop.tsx +83 -0
- package/themes/nobelium/components/Nav/Nav.module.css +50 -0
- package/themes/nobelium/components/Nav/Nav.tsx +187 -0
- package/themes/nobelium/components/RandomPostButton.tsx +31 -0
- package/themes/nobelium/components/SearchButton.tsx +31 -0
- package/themes/nobelium/components/SearchInput.tsx +94 -0
- package/themes/nobelium/components/SearchNavBar.js +19 -0
- package/themes/nobelium/components/SideBar.js +83 -0
- package/themes/nobelium/components/SvgIcon.js +29 -0
- package/themes/nobelium/components/TagItem.js +13 -0
- package/themes/nobelium/components/Tags.tsx +44 -0
- package/themes/nobelium/components/Title.js +19 -0
- package/themes/nobelium/index.tsx +28 -0
- package/themes/nobelium/layout/LayoutBase.tsx +79 -0
- package/themes/nobelium/pages/Archive.tsx +30 -0
- package/themes/nobelium/pages/Category.tsx +43 -0
- package/themes/nobelium/pages/Home.tsx +22 -0
- package/themes/nobelium/pages/PageNotFound.tsx +15 -0
- package/themes/nobelium/pages/Post.tsx +34 -0
- package/themes/nobelium/pages/PostList.tsx +74 -0
- package/themes/nobelium/pages/Search.tsx +65 -0
- package/themes/nobelium/pages/Tag.tsx +42 -0
- package/themes/nobelium/providers/index.tsx +60 -0
- package/themes/nobelium/stores/index.tsx +42 -0
- package/themes/nobelium/theme.config.ts +17 -0
- package/themes/nobelium/types/index.ts +10 -0
- package/tsconfig.json +29 -0
- package/types/index.ts +1 -0
- package/types/page.ts +102 -0
- package/vercel.json +5 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
import { useGlobal } from '@/lib/global';
|
2
|
+
import React, { useState } from 'react';
|
3
|
+
import { Draggable } from './Draggable';
|
4
|
+
import { THEMES } from '@/theme';
|
5
|
+
import { useRouter } from 'next/router';
|
6
|
+
/**
|
7
|
+
*
|
8
|
+
* @returns 主题切换
|
9
|
+
*/
|
10
|
+
const ThemeSwitch = () => {
|
11
|
+
const { theme } = useGlobal();
|
12
|
+
const router = useRouter();
|
13
|
+
const [isLoading, setIsLoading] = useState(false);
|
14
|
+
|
15
|
+
// 修改当前路径url中的 theme 参数
|
16
|
+
// 例如 http://localhost?theme=hexo 跳转到 http://localhost?theme=newTheme
|
17
|
+
const onSelectChange = (e) => {
|
18
|
+
setIsLoading(true);
|
19
|
+
const newTheme = e.target.value;
|
20
|
+
const query = router.query;
|
21
|
+
query.theme = newTheme;
|
22
|
+
router.push({ pathname: router.pathname, query }).then(() => {
|
23
|
+
setIsLoading(false);
|
24
|
+
});
|
25
|
+
};
|
26
|
+
|
27
|
+
return (
|
28
|
+
<>
|
29
|
+
<Draggable>
|
30
|
+
<div
|
31
|
+
id="draggableBox"
|
32
|
+
style={{ left: '10px', top: '80vh' }}
|
33
|
+
className="fixed z-50 rounded-2xl bg-gray-50 drop-shadow-lg dark:bg-black dark:text-white"
|
34
|
+
>
|
35
|
+
<div className="group flex w-full items-center p-3 text-sm transition-all duration-200">
|
36
|
+
<div className="w-0 overflow-hidden transition-all duration-200 group-hover:w-20">
|
37
|
+
<select
|
38
|
+
value={theme}
|
39
|
+
onChange={onSelectChange}
|
40
|
+
name="themes"
|
41
|
+
className="cursor-pointer appearance-none bg-gray-50 uppercase outline-none dark:bg-black dark:text-white"
|
42
|
+
>
|
43
|
+
{THEMES?.map((t) => {
|
44
|
+
return (
|
45
|
+
<option key={t} value={t}>
|
46
|
+
{t}
|
47
|
+
</option>
|
48
|
+
);
|
49
|
+
})}
|
50
|
+
</select>
|
51
|
+
</div>
|
52
|
+
<i className="fa-solid fa-palette pl-2"></i>
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
{/* 切换主题加载时的全屏遮罩 */}
|
56
|
+
<div
|
57
|
+
className={`${isLoading ? 'opacity-50 ' : 'opacity-0'} shadow-text pointer-events-none fixed left-0 top-0 z-50 flex h-screen
|
58
|
+
w-screen items-center justify-center bg-black text-white shadow-inner transition-all duration-1000`}
|
59
|
+
>
|
60
|
+
<i className="fas fa-spinner mr-5 animate-spin text-3xl" />
|
61
|
+
</div>
|
62
|
+
</Draggable>
|
63
|
+
</>
|
64
|
+
);
|
65
|
+
};
|
66
|
+
|
67
|
+
export default ThemeSwitch;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import BLOG from '@/blog.config'
|
2
|
+
// import { loadExternalResource } from '@/lib/utils'
|
3
|
+
import { useEffect } from 'react'
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Giscus评论 @see https://giscus.app/zh-CN
|
7
|
+
* Contribute by @txs https://github.com/txs/NotionNext/commit/1bf7179d0af21fb433e4c7773504f244998678cb
|
8
|
+
* @returns {JSX.Element}
|
9
|
+
* @constructor
|
10
|
+
*/
|
11
|
+
|
12
|
+
const Twikoo = ({ isDarkMode }) => {
|
13
|
+
useEffect(() => {
|
14
|
+
window?.twikoo?.init({
|
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
|
+
}, [isDarkMode])
|
22
|
+
return (
|
23
|
+
<div id="twikoo"></div>
|
24
|
+
)
|
25
|
+
}
|
26
|
+
|
27
|
+
export default Twikoo
|
@@ -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
|
@@ -0,0 +1,78 @@
|
|
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
|
+
commentsData = res
|
31
|
+
updateCommentCount()
|
32
|
+
}).catch(function (err) {
|
33
|
+
// 发生错误
|
34
|
+
console.error(err)
|
35
|
+
})
|
36
|
+
} catch (error) {
|
37
|
+
console.error('twikoo 加载失败', error)
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
const updateCommentCount = () => {
|
42
|
+
if (commentsData.length === 0) {
|
43
|
+
return
|
44
|
+
}
|
45
|
+
props.posts.forEach(post => {
|
46
|
+
const matchingRes = commentsData.find(r => r.url === post.slug)
|
47
|
+
if (matchingRes) {
|
48
|
+
// 修改评论数量div
|
49
|
+
const textElements = document.querySelectorAll(`.comment-count-text-${post.id}`)
|
50
|
+
textElements.forEach(element => {
|
51
|
+
element.innerHTML = matchingRes.count
|
52
|
+
})
|
53
|
+
// 取消隐藏
|
54
|
+
const wrapperElements = document.querySelectorAll(`.comment-count-wrapper-${post.id}`)
|
55
|
+
wrapperElements.forEach(element => {
|
56
|
+
element.classList.remove('hidden')
|
57
|
+
})
|
58
|
+
}
|
59
|
+
})
|
60
|
+
}
|
61
|
+
const router = useRouter()
|
62
|
+
|
63
|
+
useEffect(() => {
|
64
|
+
// console.log('路由触发评论计数')
|
65
|
+
if (props?.posts && props?.posts?.length > 0) {
|
66
|
+
fetchTwikooData(props.posts)
|
67
|
+
}
|
68
|
+
}, [router.events])
|
69
|
+
|
70
|
+
// 监控主题变化时的的评论数
|
71
|
+
useEffect(() => {
|
72
|
+
// console.log('主题触发评论计数', commentsData)
|
73
|
+
updateCommentCount()
|
74
|
+
}, [theme])
|
75
|
+
return null
|
76
|
+
}
|
77
|
+
|
78
|
+
export default TwikooCommentCounter
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import BLOG from '@/blog.config';
|
2
|
+
import { useEffect } from 'react';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* 评论插件
|
6
|
+
* @param issueTerm
|
7
|
+
* @param layout
|
8
|
+
* @returns {JSX.Element}
|
9
|
+
* @constructor
|
10
|
+
*/
|
11
|
+
const Utterances = () => {
|
12
|
+
useEffect(() => {
|
13
|
+
const theme =
|
14
|
+
BLOG.APPEARANCE === 'auto'
|
15
|
+
? 'preferred-color-scheme'
|
16
|
+
: BLOG.APPEARANCE === 'light'
|
17
|
+
? 'github-light'
|
18
|
+
: 'github-dark';
|
19
|
+
const script = document.createElement('script');
|
20
|
+
const anchor = document.getElementById('comments');
|
21
|
+
script.setAttribute('src', 'https://utteranc.es/client.js');
|
22
|
+
script.setAttribute('crossorigin', 'anonymous');
|
23
|
+
script.setAttribute('async', true);
|
24
|
+
script.setAttribute('repo', BLOG.COMMENT_UTTERRANCES_REPO);
|
25
|
+
script.setAttribute('issue-term', 'title');
|
26
|
+
script.setAttribute('theme', theme);
|
27
|
+
anchor.appendChild(script);
|
28
|
+
return () => {
|
29
|
+
anchor.innerHTML = '';
|
30
|
+
};
|
31
|
+
});
|
32
|
+
return <div id="comments" className="utterances"></div>;
|
33
|
+
};
|
34
|
+
|
35
|
+
export default Utterances;
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { loadExternalResource } from '@/lib/utils';
|
2
|
+
import { useEffect, useRef } from 'react';
|
3
|
+
|
4
|
+
const VConsole = () => {
|
5
|
+
const clickCountRef = useRef(0); // 点击次数
|
6
|
+
const lastClickTimeRef = useRef(); // 最近一次点击时间戳
|
7
|
+
const timerRef = useRef(); // 定时器引用
|
8
|
+
|
9
|
+
const loadVConsole = async () => {
|
10
|
+
try {
|
11
|
+
const url = await loadExternalResource(
|
12
|
+
'https://cdn.bootcss.com/vConsole/3.3.4/vconsole.min.js',
|
13
|
+
'js',
|
14
|
+
);
|
15
|
+
if (!url) {
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
const VConsole = window.VConsole;
|
19
|
+
const vConsole = new VConsole();
|
20
|
+
return vConsole;
|
21
|
+
} catch (error) {
|
22
|
+
console.log(error);
|
23
|
+
}
|
24
|
+
};
|
25
|
+
|
26
|
+
useEffect(() => {
|
27
|
+
const clickListener = () => {
|
28
|
+
const now = Date.now();
|
29
|
+
// 只监听窗口中心的100x100像素范围内的单击事件
|
30
|
+
const centerX = window.innerWidth / 2;
|
31
|
+
const centerY = window.innerHeight / 2;
|
32
|
+
const range = 50;
|
33
|
+
const inRange =
|
34
|
+
event.clientX >= centerX - range &&
|
35
|
+
event.clientX <= centerX + range &&
|
36
|
+
event.clientY >= centerY - range &&
|
37
|
+
event.clientY <= centerY + range;
|
38
|
+
|
39
|
+
if (!inRange) {
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
|
43
|
+
// 如果在1秒内连续点击了8次
|
44
|
+
if (
|
45
|
+
now - lastClickTimeRef.current < 1000 &&
|
46
|
+
clickCountRef.current + 1 === 8
|
47
|
+
) {
|
48
|
+
loadVConsole();
|
49
|
+
clickCountRef.current = 0; // 重置计数器
|
50
|
+
clearTimeout(timerRef.current); // 清除定时器
|
51
|
+
window.removeEventListener('click', clickListener);
|
52
|
+
} else {
|
53
|
+
// 如果不满足条件,则重新设置时间戳和计数器
|
54
|
+
lastClickTimeRef.current = now;
|
55
|
+
clickCountRef.current += 1;
|
56
|
+
// 如果计数器不为0,则设置定时器
|
57
|
+
if (clickCountRef.current > 0) {
|
58
|
+
clearTimeout(timerRef.current);
|
59
|
+
timerRef.current = setTimeout(() => {
|
60
|
+
clickCountRef.current = 0;
|
61
|
+
}, 1000);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
};
|
65
|
+
// 监听窗口点击事件
|
66
|
+
window.addEventListener('click', clickListener);
|
67
|
+
return () => {
|
68
|
+
window.removeEventListener('click', clickListener);
|
69
|
+
clearTimeout(timerRef.current);
|
70
|
+
};
|
71
|
+
}, []);
|
72
|
+
|
73
|
+
return null;
|
74
|
+
};
|
75
|
+
|
76
|
+
export default VConsole;
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import BLOG from '@/blog.config';
|
2
|
+
import { loadExternalResource } from '@/lib/utils';
|
3
|
+
import { useEffect } from 'react';
|
4
|
+
|
5
|
+
const ValineComponent = ({ path }) => {
|
6
|
+
const loadValine = async () => {
|
7
|
+
try {
|
8
|
+
await loadExternalResource(BLOG.COMMENT_VALINE_CDN, 'js');
|
9
|
+
const Valine = window.Valine;
|
10
|
+
// eslint-disable-next-line no-unused-vars
|
11
|
+
new Valine({
|
12
|
+
el: '#valine', // 容器元素
|
13
|
+
lang: BLOG.LANG, // 用于手动设定评论区语言,支持的语言列表 https://github.com/imaegoo/twikoo/blob/main/src/client/utils/i18n/index.js
|
14
|
+
appId: BLOG.COMMENT_VALINE_APP_ID,
|
15
|
+
appKey: BLOG.COMMENT_VALINE_APP_KEY,
|
16
|
+
avatar: '',
|
17
|
+
path,
|
18
|
+
recordIP: true,
|
19
|
+
placeholder: BLOG.COMMENT_VALINE_PLACEHOLDER,
|
20
|
+
serverURLs: BLOG.COMMENT_VALINE_SERVER_URLS,
|
21
|
+
visitor: true,
|
22
|
+
});
|
23
|
+
} catch (error) {
|
24
|
+
console.error('twikoo 加载失败', error);
|
25
|
+
}
|
26
|
+
};
|
27
|
+
|
28
|
+
useEffect(() => {
|
29
|
+
loadValine();
|
30
|
+
}, []);
|
31
|
+
|
32
|
+
return <div id="valine"></div>;
|
33
|
+
|
34
|
+
// const updateValine = url => {
|
35
|
+
// // 移除旧的评论区,否则会重复渲染。
|
36
|
+
// const wrapper = document.getElementById('v-wrapper')
|
37
|
+
// const comments = document.getElementById('v-comments')
|
38
|
+
// wrapper.removeChild(comments)
|
39
|
+
// const newComments = document.createElement('div')
|
40
|
+
// newComments.id = 'v-comments'
|
41
|
+
// newComments.name = new Date()
|
42
|
+
// wrapper.appendChild(newComments)
|
43
|
+
// initValine(url)
|
44
|
+
// }
|
45
|
+
|
46
|
+
// useEffect(() => {
|
47
|
+
// initValine()
|
48
|
+
// router.events.on('routeChangeComplete', updateValine)
|
49
|
+
// return () => {
|
50
|
+
// router.events.off('routeChangeComplete', updateValine)
|
51
|
+
// }
|
52
|
+
// }, [])
|
53
|
+
|
54
|
+
// return <div id='v-wrapper'>
|
55
|
+
// <div id='v-comments'></div>
|
56
|
+
// </div>
|
57
|
+
};
|
58
|
+
|
59
|
+
export default ValineComponent;
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import { useGlobal } from '@/lib/global';
|
2
|
+
|
3
|
+
const Vercel = () => {
|
4
|
+
const { isDarkMode } = useGlobal();
|
5
|
+
|
6
|
+
const fontColor = isDarkMode ? 'black' : 'white';
|
7
|
+
const bgColor = isDarkMode ? 'white' : 'black';
|
8
|
+
const dividerColor = isDarkMode ? '#050505' : '#e5e5e5';
|
9
|
+
|
10
|
+
return (
|
11
|
+
<a
|
12
|
+
href="https://vercel.com?utm_source=Craigary&utm_campaign=oss"
|
13
|
+
target="_blank"
|
14
|
+
rel="noreferrer"
|
15
|
+
aria-label="Vercel"
|
16
|
+
>
|
17
|
+
<svg
|
18
|
+
width="135"
|
19
|
+
height="28"
|
20
|
+
viewBox="0 0 135 28"
|
21
|
+
fill="none"
|
22
|
+
xmlns="http://www.w3.org/2000/svg"
|
23
|
+
className="inline-block"
|
24
|
+
>
|
25
|
+
<g clipPath="url(#clip0)">
|
26
|
+
<path
|
27
|
+
d="M129.818 0H5.09091C2.27928 0 0 2.27928 0 5.09091V22.9091C0 25.7207 2.27928 28 5.09091 28H129.818C132.63 28 134.909 25.7207 134.909 22.9091V5.09091C134.909 2.27928 132.63 0 129.818 0Z"
|
28
|
+
fill={bgColor}
|
29
|
+
/>
|
30
|
+
<path
|
31
|
+
d="M38.4601 9.68997V16.8639H39.355V14.3036H41.1597C42.507 14.3036 43.4665 13.354 43.4665 12.0117C43.4665 10.6445 42.5268 9.68997 41.1696 9.68997H38.4601ZM39.355 10.4854H40.9359C41.975 10.4854 42.5467 11.0273 42.5467 12.0117C42.5467 12.9613 41.9551 13.5081 40.9359 13.5081H39.355V10.4854ZM46.6734 16.9584C48.1996 16.9584 49.1442 15.9044 49.1442 14.1843C49.1442 12.4591 48.1996 11.4101 46.6734 11.4101C45.1471 11.4101 44.2025 12.4591 44.2025 14.1843C44.2025 15.9044 45.1471 16.9584 46.6734 16.9584ZM46.6734 16.1878C45.6591 16.1878 45.0874 15.452 45.0874 14.1843C45.0874 12.9116 45.6591 12.1807 46.6734 12.1807C47.6875 12.1807 48.2593 12.9116 48.2593 14.1843C48.2593 15.452 47.6875 16.1878 46.6734 16.1878ZM56.8255 11.5046H55.9654L54.9115 15.7901H54.8319L53.6338 11.5046H52.8135L51.6153 15.7901H51.5358L50.4818 11.5046H49.6167L51.1182 16.8639H51.9832L53.1764 12.7177H53.2559L54.4541 16.8639H55.3241L56.8255 11.5046ZM59.7043 12.1658C60.5544 12.1658 61.1212 12.7922 61.1411 13.7418H58.1879C58.2526 12.7922 58.8492 12.1658 59.7043 12.1658ZM61.1162 15.4769C60.8925 15.9492 60.4252 16.2027 59.7341 16.2027C58.8243 16.2027 58.2327 15.5315 58.1879 14.4726V14.4328H62.0409V14.1047C62.0409 12.4392 61.161 11.4101 59.7142 11.4101C58.2427 11.4101 57.298 12.5038 57.298 14.1892C57.298 15.8845 58.2277 16.9584 59.7142 16.9584C60.8875 16.9584 61.7227 16.3916 61.9714 15.4769H61.1162ZM63.1796 16.8639H64.0346V13.5429C64.0346 12.7873 64.6264 12.2404 65.4416 12.2404C65.6109 12.2404 65.9189 12.2702 65.9889 12.2901V11.435C65.8794 11.42 65.6999 11.4101 65.5612 11.4101C64.8504 11.4101 64.2338 11.778 64.0747 12.3H63.9951V11.5046H63.1796V16.8639ZM68.8423 12.1658C69.6925 12.1658 70.2595 12.7922 70.2792 13.7418H67.3259C67.3908 12.7922 67.9877 12.1658 68.8423 12.1658ZM70.2544 15.4769C70.0304 15.9492 69.5633 16.2027 68.8722 16.2027C67.9622 16.2027 67.371 15.5315 67.3259 14.4726V14.4328H71.179V14.1047C71.179 12.4392 70.2989 11.4101 68.8525 11.4101C67.3806 11.4101 66.4362 12.5038 66.4362 14.1892C66.4362 15.8845 67.3659 16.9584 68.8525 16.9584C70.0259 16.9584 70.8609 16.3916 71.1097 15.4769H70.2544ZM74.3017 16.9584C75.0424 16.9584 75.6788 16.6055 76.0167 16.0088H76.0962V16.8639H76.9114V9.37675H76.0568V12.3497H75.9817C75.6788 11.7631 75.0475 11.4101 74.3017 11.4101C72.9392 11.4101 72.0496 12.5038 72.0496 14.1843C72.0496 15.8696 72.929 16.9584 74.3017 16.9584ZM74.5002 12.1807C75.47 12.1807 76.0765 12.9563 76.0765 14.1843C76.0765 15.4222 75.4745 16.1878 74.5002 16.1878C73.5209 16.1878 72.9341 15.4371 72.9341 14.1843C72.9341 12.9364 73.5259 12.1807 74.5002 12.1807ZM83.7033 16.9584C85.0607 16.9584 85.9503 15.8597 85.9503 14.1843C85.9503 12.4989 85.0651 11.4101 83.7033 11.4101C82.9677 11.4101 82.316 11.773 82.0227 12.3497H81.9431V9.37675H81.0879V16.8639H81.9037V16.0088H81.9832C82.3211 16.6055 82.9575 16.9584 83.7033 16.9584ZM83.5041 12.1807C84.4835 12.1807 85.0651 12.9314 85.0651 14.1843C85.0651 15.4371 84.4835 16.1878 83.5041 16.1878C82.5299 16.1878 81.9234 15.4222 81.9234 14.1843C81.9234 12.9464 82.5299 12.1807 83.5041 12.1807ZM87.3478 18.8029C88.2972 18.8029 88.7249 18.435 89.1818 17.1921L91.2754 11.5046H90.3654L88.8986 15.9144H88.819L87.3478 11.5046H86.4231L88.4067 16.8689L88.3068 17.1871C88.0834 17.8334 87.8149 18.0671 87.3229 18.0671C87.2033 18.0671 87.069 18.0621 86.9647 18.0422V18.773C87.0843 18.7929 87.2332 18.8029 87.3478 18.8029ZM98.4148 16.8639L100.895 9.68997H99.5284L97.7383 15.3675H97.6543L95.8496 9.68997H94.4324L96.9384 16.8639H98.4148ZM103.516 12.295C104.257 12.295 104.744 12.8121 104.769 13.6175H102.208C102.263 12.822 102.78 12.295 103.516 12.295ZM104.778 15.3675C104.6 15.7702 104.177 15.9939 103.565 15.9939C102.755 15.9939 102.233 15.4272 102.203 14.5223V14.4577H106.001V14.06C106.001 12.3447 105.072 11.3156 103.521 11.3156C101.945 11.3156 100.965 12.4144 100.965 14.1644C100.965 15.9144 101.93 16.9733 103.53 16.9733C104.813 16.9733 105.723 16.3568 105.947 15.3675H104.778ZM107.036 16.8639H108.269V13.7219C108.269 12.9613 108.826 12.4641 109.626 12.4641C109.835 12.4641 110.163 12.4989 110.257 12.5337V11.3902C110.143 11.3555 109.924 11.3355 109.745 11.3355C109.045 11.3355 108.458 11.7333 108.308 12.2702H108.224V11.425H107.036V16.8639ZM115.627 13.2546C115.498 12.1111 114.652 11.3156 113.255 11.3156C111.62 11.3156 110.66 12.3647 110.66 14.1296C110.66 15.9193 111.625 16.9733 113.26 16.9733C114.638 16.9733 115.493 16.2077 115.627 15.0692H114.454C114.324 15.636 113.897 15.9392 113.255 15.9392C112.415 15.9392 111.908 15.273 111.908 14.1296C111.908 13.001 112.41 12.3497 113.255 12.3497C113.932 12.3497 114.339 12.7276 114.454 13.2546H115.627ZM118.883 12.295C119.624 12.295 120.112 12.8121 120.136 13.6175H117.576C117.63 12.822 118.148 12.295 118.883 12.295ZM120.147 15.3675C119.967 15.7702 119.545 15.9939 118.933 15.9939C118.123 15.9939 117.601 15.4272 117.571 14.5223V14.4577H121.369V14.06C121.369 12.3447 120.439 11.3156 118.888 11.3156C117.312 11.3156 116.333 12.4144 116.333 14.1644C116.333 15.9144 117.298 16.9733 118.899 16.9733C120.181 16.9733 121.091 16.3568 121.314 15.3675H120.147ZM122.453 16.8639H123.686V9.32202H122.453V16.8639Z"
|
32
|
+
fill={fontColor}
|
33
|
+
/>
|
34
|
+
<path
|
35
|
+
d="M14.8431 8.27271L20.7772 18.4545H8.90918L14.8431 8.27271Z"
|
36
|
+
fill={fontColor}
|
37
|
+
/>
|
38
|
+
<path
|
39
|
+
d="M27.6819 0V28"
|
40
|
+
stroke={dividerColor}
|
41
|
+
strokeWidth="0.636364"
|
42
|
+
/>
|
43
|
+
</g>
|
44
|
+
<defs>
|
45
|
+
<clipPath id="clip0">
|
46
|
+
<rect width="134.909" height="28" fill="white" />
|
47
|
+
</clipPath>
|
48
|
+
</defs>
|
49
|
+
</svg>
|
50
|
+
</a>
|
51
|
+
);
|
52
|
+
};
|
53
|
+
|
54
|
+
export default Vercel;
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import BLOG from '@/blog.config'
|
3
|
+
|
4
|
+
/**
|
5
|
+
* 万维广告插件
|
6
|
+
* @param {string} orientation - 广告方向,可以是 'vertical' 或 'horizontal'
|
7
|
+
* @param {boolean} sticky - 是否粘性定位
|
8
|
+
* @returns {JSX.Element | null} - 返回渲染的 JSX 元素或 null
|
9
|
+
*/
|
10
|
+
export default function WWAds({ orientation = 'vertical', sticky = false, className }) {
|
11
|
+
if (!JSON.parse(BLOG.AD_WWADS_ID)) {
|
12
|
+
return null
|
13
|
+
}
|
14
|
+
|
15
|
+
return (
|
16
|
+
<div className={`wwads-cn ${orientation === 'vertical' ? 'wwads-vertical' : 'wwads-horizontal'} ${sticky ? 'wwads-sticky' : ''} z-30 ${className || ''}`} data-id={BLOG.AD_WWADS_ID}></div>
|
17
|
+
)
|
18
|
+
}
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { init } from '@waline/client'
|
3
|
+
import BLOG from '@/blog.config'
|
4
|
+
import { useRouter } from 'next/router'
|
5
|
+
import '@waline/client/dist/waline.css'
|
6
|
+
|
7
|
+
const path = ''
|
8
|
+
let waline = null
|
9
|
+
/**
|
10
|
+
* @see https://waline.js.org/guide/get-started.html
|
11
|
+
* @param {*} props
|
12
|
+
* @returns
|
13
|
+
*/
|
14
|
+
const WalineComponent = (props) => {
|
15
|
+
const containerRef = React.createRef()
|
16
|
+
const router = useRouter()
|
17
|
+
|
18
|
+
const updateWaline = url => {
|
19
|
+
if (url !== path && waline) {
|
20
|
+
waline.update(props)
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
React.useEffect(() => {
|
25
|
+
if (!waline) {
|
26
|
+
waline = init({
|
27
|
+
...props,
|
28
|
+
el: containerRef.current,
|
29
|
+
serverURL: BLOG.COMMENT_WALINE_SERVER_URL,
|
30
|
+
lang: BLOG.lang,
|
31
|
+
reaction: true,
|
32
|
+
dark: 'html.dark',
|
33
|
+
emoji: [
|
34
|
+
'//npm.elemecdn.com/@waline/emojis@1.1.0/tieba',
|
35
|
+
'//npm.elemecdn.com/@waline/emojis@1.1.0/weibo',
|
36
|
+
'//npm.elemecdn.com/@waline/emojis@1.1.0/bilibili'
|
37
|
+
]
|
38
|
+
})
|
39
|
+
}
|
40
|
+
|
41
|
+
// 跳转评论
|
42
|
+
router.events.on('routeChangeComplete', updateWaline)
|
43
|
+
const anchor = window.location.hash
|
44
|
+
if (anchor) {
|
45
|
+
// 选择需要观察变动的节点
|
46
|
+
const targetNode = document.getElementsByClassName('wl-cards')[0]
|
47
|
+
|
48
|
+
// 当观察到变动时执行的回调函数
|
49
|
+
const mutationCallback = (mutations) => {
|
50
|
+
for (const mutation of mutations) {
|
51
|
+
const type = mutation.type
|
52
|
+
if (type === 'childList') {
|
53
|
+
const anchorElement = document.getElementById(anchor.substring(1))
|
54
|
+
if (anchorElement && anchorElement.className === 'wl-item') {
|
55
|
+
anchorElement.scrollIntoView({ block: 'end', behavior: 'smooth' })
|
56
|
+
setTimeout(() => {
|
57
|
+
anchorElement.classList.add('animate__animated')
|
58
|
+
anchorElement.classList.add('animate__bounceInRight')
|
59
|
+
observer.disconnect()
|
60
|
+
}, 300)
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
// 观察子节点 变化
|
67
|
+
const observer = new MutationObserver(mutationCallback)
|
68
|
+
observer.observe(targetNode, { childList: true })
|
69
|
+
}
|
70
|
+
|
71
|
+
return () => {
|
72
|
+
if (waline) {
|
73
|
+
waline.destroy()
|
74
|
+
waline = null
|
75
|
+
}
|
76
|
+
router.events.off('routeChangeComplete', updateWaline)
|
77
|
+
}
|
78
|
+
}, [])
|
79
|
+
|
80
|
+
return <div ref={containerRef} />
|
81
|
+
}
|
82
|
+
|
83
|
+
export default WalineComponent
|