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,124 @@
|
|
1
|
+
/* eslint-disable */
|
2
|
+
import { useEffect } from 'react'
|
3
|
+
const id = 'canvasNestCreated'
|
4
|
+
const Nest = () => {
|
5
|
+
const destroyNest = ()=>{
|
6
|
+
const nest = document.getElementById(id)
|
7
|
+
if(nest && nest.parentNode){
|
8
|
+
nest.parentNode.removeChild(nest)
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
useEffect(() => {
|
13
|
+
createNest()
|
14
|
+
return () => destroyNest()
|
15
|
+
}, [])
|
16
|
+
return <></>
|
17
|
+
}
|
18
|
+
|
19
|
+
export default Nest
|
20
|
+
|
21
|
+
/**
|
22
|
+
* 创建连接点
|
23
|
+
* @param config
|
24
|
+
*/
|
25
|
+
function createNest() {
|
26
|
+
const e = document.getElementById('__next')
|
27
|
+
if(!e) return
|
28
|
+
function n(e, n, t) {
|
29
|
+
return e.getAttribute(n) || t
|
30
|
+
}
|
31
|
+
function t() {
|
32
|
+
;(u = i.width =
|
33
|
+
window.innerWidth ||
|
34
|
+
document.documentElement.clientWidth ||
|
35
|
+
document.body.clientWidth),
|
36
|
+
(d = i.height =
|
37
|
+
window.innerHeight ||
|
38
|
+
document.documentElement.clientHeight ||
|
39
|
+
document.body.clientHeight)
|
40
|
+
}
|
41
|
+
function o() {
|
42
|
+
c.clearRect(0, 0, u, d)
|
43
|
+
const e = [s].concat(x)
|
44
|
+
let n, t, i, l, r, w
|
45
|
+
x.forEach(function (o) {
|
46
|
+
for (
|
47
|
+
o.x += o.xa,
|
48
|
+
o.y += o.ya,
|
49
|
+
o.xa *= o.x > u || o.x < 0 ? -1 : 1,
|
50
|
+
o.ya *= o.y > d || o.y < 0 ? -1 : 1,
|
51
|
+
c.fillRect(o.x - 0.5, o.y - 0.5, 1, 1),
|
52
|
+
t = 0;
|
53
|
+
t < e.length;
|
54
|
+
t++
|
55
|
+
)
|
56
|
+
(n = e[t]),
|
57
|
+
o !== n &&
|
58
|
+
null !== n.x &&
|
59
|
+
null !== n.y &&
|
60
|
+
((l = o.x - n.x),
|
61
|
+
(r = o.y - n.y),
|
62
|
+
(w = l * l + r * r),
|
63
|
+
w < n.max &&
|
64
|
+
(n === s &&
|
65
|
+
w >= n.max / 2 &&
|
66
|
+
((o.x -= 0.03 * l), (o.y -= 0.03 * r)),
|
67
|
+
(i = (n.max - w) / n.max),
|
68
|
+
c.beginPath(),
|
69
|
+
(c.lineWidth = i / 2),
|
70
|
+
(c.strokeStyle = 'rgba(' + a.c + ',' + (i + 0.2) + ')'),
|
71
|
+
c.moveTo(o.x, o.y),
|
72
|
+
c.lineTo(n.x, n.y),
|
73
|
+
c.stroke()))
|
74
|
+
e.splice(e.indexOf(o), 1)
|
75
|
+
}),
|
76
|
+
m(o)
|
77
|
+
}
|
78
|
+
var i = document.createElement('canvas')
|
79
|
+
i.id = id
|
80
|
+
var a = (function () {
|
81
|
+
const t = e
|
82
|
+
return {
|
83
|
+
z: n(t, 'zIndex', 0),
|
84
|
+
o: n(t, 'opacity', 0.7),
|
85
|
+
c: n(t, 'color', '0,0,0'),
|
86
|
+
n: n(t, 'count', 99)
|
87
|
+
}
|
88
|
+
})(),
|
89
|
+
c = i.getContext('2d')
|
90
|
+
let u, d
|
91
|
+
var m =
|
92
|
+
window.requestAnimationFrame ||
|
93
|
+
window.webkitRequestAnimationFrame ||
|
94
|
+
window.mozRequestAnimationFrame ||
|
95
|
+
window.oRequestAnimationFrame ||
|
96
|
+
window.msRequestAnimationFrame ||
|
97
|
+
function (e) {
|
98
|
+
window.setTimeout(e, 1e3 / 45)
|
99
|
+
}
|
100
|
+
const l = Math.random
|
101
|
+
var r,
|
102
|
+
s = { x: null, y: null, max: 2e4 }
|
103
|
+
;(i.style.cssText =
|
104
|
+
'position:fixed;top:0;left:0;pointer-events:none;z-index:' + a.z + ';opacity:' + a.o),
|
105
|
+
(r = 'body'), e.appendChild(i),
|
106
|
+
t(),
|
107
|
+
(window.onresize = t),
|
108
|
+
(window.onmousemove = function (e) {
|
109
|
+
;(e = e || window.event), (s.x = e.clientX), (s.y = e.clientY)
|
110
|
+
}),
|
111
|
+
(window.onmouseout = function () {
|
112
|
+
;(s.x = null), (s.y = null)
|
113
|
+
})
|
114
|
+
for (var x = [], w = 0; a.n > w; w++) {
|
115
|
+
const e = l() * u,
|
116
|
+
n = l() * d,
|
117
|
+
t = 2 * l() - 1,
|
118
|
+
o = 2 * l() - 1
|
119
|
+
x.push({ x: e, y: n, xa: t, ya: o, max: 6e3 })
|
120
|
+
}
|
121
|
+
setTimeout(function () {
|
122
|
+
o()
|
123
|
+
}, 100)
|
124
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import LazyImage from './LazyImage'
|
2
|
+
|
3
|
+
/**
|
4
|
+
* notion的图标icon
|
5
|
+
* 可能是emoji 可能是 svg 也可能是 图片
|
6
|
+
* @returns
|
7
|
+
*/
|
8
|
+
const NotionIcon = ({ icon }) => {
|
9
|
+
if (!icon) {
|
10
|
+
return <></>
|
11
|
+
}
|
12
|
+
|
13
|
+
if (icon.startsWith('http') || icon.startsWith('data:')) {
|
14
|
+
return <LazyImage src={icon} className='w-8 h-8 my-auto inline mr-1'/>
|
15
|
+
}
|
16
|
+
|
17
|
+
return <span className='mr-1'>{icon}</span>
|
18
|
+
}
|
19
|
+
|
20
|
+
export default NotionIcon
|
@@ -0,0 +1,206 @@
|
|
1
|
+
import { NotionRenderer } from 'react-notion-x';
|
2
|
+
import dynamic from 'next/dynamic';
|
3
|
+
import mediumZoom from 'medium-zoom';
|
4
|
+
import React, { type FC, useEffect, useRef } from 'react';
|
5
|
+
// import { Code } from 'react-notion-x/build/third-party/code'
|
6
|
+
import TweetEmbed from 'react-tweet-embed';
|
7
|
+
|
8
|
+
import BLOG from '@/blog.config';
|
9
|
+
import 'katex/dist/katex.min.css';
|
10
|
+
import { mapImgUrl } from '@/lib/notion/mapImage';
|
11
|
+
import { isBrowser } from '@/lib/utils';
|
12
|
+
|
13
|
+
import type { PageInfo } from '@/lib/notion/types';
|
14
|
+
|
15
|
+
const Code = dynamic(
|
16
|
+
() =>
|
17
|
+
import('react-notion-x/build/third-party/code').then(async (m) => {
|
18
|
+
return m.Code;
|
19
|
+
}),
|
20
|
+
{ ssr: false },
|
21
|
+
);
|
22
|
+
|
23
|
+
const Equation = dynamic(
|
24
|
+
() =>
|
25
|
+
import('@/components/Equation').then(async (m) => {
|
26
|
+
// 化学方程式
|
27
|
+
await import('@/lib/mhchem');
|
28
|
+
return m.Equation;
|
29
|
+
}),
|
30
|
+
{ ssr: false },
|
31
|
+
);
|
32
|
+
|
33
|
+
const Pdf = dynamic(
|
34
|
+
() => import('react-notion-x/build/third-party/pdf').then((m) => m.Pdf),
|
35
|
+
{
|
36
|
+
ssr: false,
|
37
|
+
},
|
38
|
+
);
|
39
|
+
|
40
|
+
// https://github.com/txs
|
41
|
+
// import PrismMac from '@/components/PrismMac'
|
42
|
+
const PrismMac = dynamic(() => import('@/components/PrismMac'), {
|
43
|
+
ssr: false,
|
44
|
+
});
|
45
|
+
|
46
|
+
const Collection = dynamic(
|
47
|
+
() =>
|
48
|
+
import('react-notion-x/build/third-party/collection').then(
|
49
|
+
(m) => m.Collection,
|
50
|
+
),
|
51
|
+
{ ssr: true },
|
52
|
+
);
|
53
|
+
|
54
|
+
const Modal = dynamic(
|
55
|
+
() => import('react-notion-x/build/third-party/modal').then((m) => m.Modal),
|
56
|
+
{ ssr: false },
|
57
|
+
);
|
58
|
+
|
59
|
+
const Tweet: FC<{
|
60
|
+
id: string;
|
61
|
+
}> = ({ id }) => {
|
62
|
+
return <TweetEmbed tweetId={id} />;
|
63
|
+
};
|
64
|
+
|
65
|
+
const NotionPage: FC<{
|
66
|
+
post: PageInfo;
|
67
|
+
className?: string;
|
68
|
+
}> = ({ post, className = '' }) => {
|
69
|
+
useEffect(() => {
|
70
|
+
autoScrollToTarget();
|
71
|
+
}, []);
|
72
|
+
|
73
|
+
const zoom =
|
74
|
+
typeof window !== 'undefined' &&
|
75
|
+
mediumZoom({
|
76
|
+
container: '.notion-viewport',
|
77
|
+
background: 'rgba(0, 0, 0, 0.2)',
|
78
|
+
margin: getMediumZoomMargin(),
|
79
|
+
});
|
80
|
+
const zoomRef = useRef(zoom ? zoom.clone() : null);
|
81
|
+
|
82
|
+
useEffect(() => {
|
83
|
+
// 将相册gallery下的图片加入放大功能
|
84
|
+
if (BLOG.POST_DISABLE_GALLERY_CLICK) {
|
85
|
+
setTimeout(() => {
|
86
|
+
if (isBrowser) {
|
87
|
+
const imgList = document?.querySelectorAll(
|
88
|
+
'.notion-collection-card-cover img',
|
89
|
+
);
|
90
|
+
if (imgList && zoomRef.current) {
|
91
|
+
for (let i = 0; i < imgList.length; i++) {
|
92
|
+
zoomRef.current.attach(imgList[i] as HTMLElement);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
const cards = document.getElementsByClassName(
|
97
|
+
'notion-collection-card',
|
98
|
+
);
|
99
|
+
for (const e of cards) {
|
100
|
+
e.removeAttribute('href');
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}, 800);
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* 处理页面内连接跳转
|
108
|
+
* 如果链接就是当前网站,则不打开新窗口访问
|
109
|
+
*/
|
110
|
+
if (isBrowser) {
|
111
|
+
const currentURL = window.location.origin + window.location.pathname;
|
112
|
+
const allAnchorTags = document.getElementsByTagName('a'); // 或者使用 document.querySelectorAll('a') 获取 NodeList
|
113
|
+
for (const anchorTag of allAnchorTags) {
|
114
|
+
if (anchorTag?.target === '_blank') {
|
115
|
+
const hrefWithoutQueryHash = anchorTag.href
|
116
|
+
.split('?')[0]
|
117
|
+
.split('#')[0];
|
118
|
+
const hrefWithRelativeHash =
|
119
|
+
currentURL.split('#')[0] + anchorTag.href.split('#')[1];
|
120
|
+
|
121
|
+
if (
|
122
|
+
currentURL === hrefWithoutQueryHash ||
|
123
|
+
currentURL === hrefWithRelativeHash
|
124
|
+
) {
|
125
|
+
anchorTag.target = '_self';
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}, []);
|
131
|
+
|
132
|
+
if (!post || !post.blockMap) {
|
133
|
+
return <>{post?.summary || ''}</>;
|
134
|
+
}
|
135
|
+
|
136
|
+
return (
|
137
|
+
<div id="notion-article" className={`mx-auto overflow-hidden ${className}`}>
|
138
|
+
<NotionRenderer
|
139
|
+
recordMap={post.blockMap}
|
140
|
+
mapPageUrl={mapPageUrl}
|
141
|
+
mapImageUrl={mapImgUrl}
|
142
|
+
components={{
|
143
|
+
Code,
|
144
|
+
Collection,
|
145
|
+
Equation,
|
146
|
+
Modal,
|
147
|
+
Pdf,
|
148
|
+
Tweet,
|
149
|
+
}}
|
150
|
+
/>
|
151
|
+
|
152
|
+
<PrismMac />
|
153
|
+
</div>
|
154
|
+
);
|
155
|
+
};
|
156
|
+
|
157
|
+
/**
|
158
|
+
* 根据url参数自动滚动到指定区域
|
159
|
+
*/
|
160
|
+
const autoScrollToTarget = () => {
|
161
|
+
setTimeout(() => {
|
162
|
+
// 跳转到指定标题
|
163
|
+
const needToJumpToTitle = window.location.hash;
|
164
|
+
if (needToJumpToTitle) {
|
165
|
+
const tocNode = document.getElementById(
|
166
|
+
window.location.hash.substring(1),
|
167
|
+
);
|
168
|
+
if (tocNode && tocNode?.className?.indexOf('notion') > -1) {
|
169
|
+
tocNode.scrollIntoView({ block: 'start', behavior: 'smooth' });
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}, 180);
|
173
|
+
};
|
174
|
+
|
175
|
+
/**
|
176
|
+
* 将id映射成博文内部链接。
|
177
|
+
* @param {*} id
|
178
|
+
* @returns
|
179
|
+
*/
|
180
|
+
const mapPageUrl = (id: string) => {
|
181
|
+
// return 'https://www.notion.so/' + id.replace(/-/g, '')
|
182
|
+
return '/' + id.replace(/-/g, '');
|
183
|
+
};
|
184
|
+
|
185
|
+
/**
|
186
|
+
* 缩放
|
187
|
+
* @returns
|
188
|
+
*/
|
189
|
+
function getMediumZoomMargin() {
|
190
|
+
const width = window.innerWidth;
|
191
|
+
|
192
|
+
if (width < 500) {
|
193
|
+
return 8;
|
194
|
+
} else if (width < 800) {
|
195
|
+
return 20;
|
196
|
+
} else if (width < 1280) {
|
197
|
+
return 30;
|
198
|
+
} else if (width < 1600) {
|
199
|
+
return 40;
|
200
|
+
} else if (width < 1920) {
|
201
|
+
return 48;
|
202
|
+
} else {
|
203
|
+
return 72;
|
204
|
+
}
|
205
|
+
}
|
206
|
+
export default NotionPage;
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import BLOG from '@/blog.config'
|
2
|
+
import { useEffect, useRef, useState } from 'react'
|
3
|
+
|
4
|
+
const Player = () => {
|
5
|
+
const [player, setPlayer] = useState()
|
6
|
+
const ref = useRef(null)
|
7
|
+
|
8
|
+
const lrcType = JSON.parse(BLOG.MUSIC_PLAYER_LRC_TYPE)
|
9
|
+
const playerVisible = JSON.parse(BLOG.MUSIC_PLAYER_VISIBLE)
|
10
|
+
const autoPlay = JSON.parse(BLOG.MUSIC_PLAYER_AUTO_PLAY)
|
11
|
+
|
12
|
+
const meting = JSON.parse(BLOG.MUSIC_PLAYER_METING)
|
13
|
+
|
14
|
+
useEffect(() => {
|
15
|
+
if (!meting && window.APlayer) {
|
16
|
+
setPlayer(new window.APlayer({
|
17
|
+
container: ref.current,
|
18
|
+
fixed: true,
|
19
|
+
lrcType: lrcType,
|
20
|
+
autoplay: autoPlay,
|
21
|
+
order: BLOG.MUSIC_PLAYER_ORDER,
|
22
|
+
audio: BLOG.MUSIC_PLAYER_AUDIO_LIST
|
23
|
+
}))
|
24
|
+
}
|
25
|
+
return () => {
|
26
|
+
setPlayer(undefined)
|
27
|
+
}
|
28
|
+
}, [])
|
29
|
+
|
30
|
+
return (
|
31
|
+
<div className={playerVisible ? 'visible' : 'invisible'}>
|
32
|
+
<link
|
33
|
+
rel="stylesheet"
|
34
|
+
type="text/css"
|
35
|
+
href="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.css"
|
36
|
+
/>
|
37
|
+
{meting
|
38
|
+
? <meting-js
|
39
|
+
fixed="true"
|
40
|
+
type="playlist"
|
41
|
+
preload="auto"
|
42
|
+
lrc-type={BLOG.MUSIC_PLAYER_METING_LRC_TYPE}
|
43
|
+
autoplay={autoPlay}
|
44
|
+
order={BLOG.MUSIC_PLAYER_ORDER}
|
45
|
+
server={BLOG.MUSIC_PLAYER_METING_SERVER}
|
46
|
+
id={BLOG.MUSIC_PLAYER_METING_ID}
|
47
|
+
/>
|
48
|
+
: <div ref={ref} data-player={player} />
|
49
|
+
}
|
50
|
+
</div>
|
51
|
+
)
|
52
|
+
}
|
53
|
+
|
54
|
+
export default Player
|
@@ -0,0 +1,236 @@
|
|
1
|
+
import { useEffect } from 'react';
|
2
|
+
import Prism from 'prismjs';
|
3
|
+
// 所有语言的prismjs 使用autoloader引入
|
4
|
+
// import 'prismjs/plugins/autoloader/prism-autoloader'
|
5
|
+
import 'prismjs/plugins/toolbar/prism-toolbar';
|
6
|
+
import 'prismjs/plugins/toolbar/prism-toolbar.min.css';
|
7
|
+
import 'prismjs/plugins/show-language/prism-show-language';
|
8
|
+
import 'prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard';
|
9
|
+
import 'prismjs/plugins/line-numbers/prism-line-numbers';
|
10
|
+
import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
|
11
|
+
|
12
|
+
// mermaid图
|
13
|
+
import BLOG from '@/blog.config';
|
14
|
+
import { loadExternalResource } from '@/lib/utils';
|
15
|
+
import { useRouter } from 'next/navigation';
|
16
|
+
import { useGlobal } from '@/lib/global';
|
17
|
+
|
18
|
+
/**
|
19
|
+
* 代码美化相关
|
20
|
+
* @author https://github.com/txs/
|
21
|
+
* @returns
|
22
|
+
*/
|
23
|
+
const PrismMac = () => {
|
24
|
+
const router = useRouter();
|
25
|
+
const { isDarkMode } = useGlobal();
|
26
|
+
|
27
|
+
useEffect(() => {
|
28
|
+
if (JSON.parse(BLOG.CODE_MAC_BAR)) {
|
29
|
+
loadExternalResource('/css/prism-mac-style.css', 'css');
|
30
|
+
}
|
31
|
+
// 加载prism样式
|
32
|
+
loadPrismThemeCSS(isDarkMode);
|
33
|
+
// 折叠代码
|
34
|
+
loadExternalResource(BLOG.PRISM_JS_AUTO_LOADER, 'js').then(() => {
|
35
|
+
if (window?.Prism?.plugins?.autoloader) {
|
36
|
+
window.Prism.plugins.autoloader.languages_path = BLOG.PRISM_JS_PATH;
|
37
|
+
}
|
38
|
+
|
39
|
+
renderPrismMac();
|
40
|
+
renderMermaid();
|
41
|
+
renderCollapseCode();
|
42
|
+
});
|
43
|
+
}, [router, isDarkMode]);
|
44
|
+
|
45
|
+
return <></>;
|
46
|
+
};
|
47
|
+
|
48
|
+
/**
|
49
|
+
* 加载样式
|
50
|
+
*/
|
51
|
+
const loadPrismThemeCSS = (isDarkMode) => {
|
52
|
+
let PRISM_THEME;
|
53
|
+
let PRISM_PREVIOUS;
|
54
|
+
if (JSON.parse(BLOG.PRISM_THEME_SWITCH)) {
|
55
|
+
if (isDarkMode) {
|
56
|
+
PRISM_THEME = BLOG.PRISM_THEME_DARK_PATH;
|
57
|
+
PRISM_PREVIOUS = BLOG.PRISM_THEME_LIGHT_PATH;
|
58
|
+
} else {
|
59
|
+
PRISM_THEME = BLOG.PRISM_THEME_LIGHT_PATH;
|
60
|
+
PRISM_PREVIOUS = BLOG.PRISM_THEME_DARK_PATH;
|
61
|
+
}
|
62
|
+
const previousTheme = document.querySelector(
|
63
|
+
`link[href="${PRISM_PREVIOUS}"]`,
|
64
|
+
);
|
65
|
+
if (previousTheme) {
|
66
|
+
previousTheme.parentNode.removeChild(previousTheme);
|
67
|
+
}
|
68
|
+
loadExternalResource(PRISM_THEME, 'css');
|
69
|
+
} else {
|
70
|
+
loadExternalResource(BLOG.PRISM_THEME_PREFIX_PATH, 'css');
|
71
|
+
}
|
72
|
+
};
|
73
|
+
|
74
|
+
/*
|
75
|
+
* 将代码块转为可折叠对象
|
76
|
+
*/
|
77
|
+
const renderCollapseCode = () => {
|
78
|
+
if (!JSON.parse(BLOG.CODE_COLLAPSE)) {
|
79
|
+
return;
|
80
|
+
}
|
81
|
+
const codeBlocks = document.querySelectorAll('.code-toolbar');
|
82
|
+
for (const codeBlock of codeBlocks) {
|
83
|
+
// 判断当前元素是否被包裹
|
84
|
+
if (codeBlock.closest('.collapse-wrapper')) {
|
85
|
+
continue; // 如果被包裹了,跳过当前循环
|
86
|
+
}
|
87
|
+
|
88
|
+
const code = codeBlock.querySelector('code');
|
89
|
+
const language = code.getAttribute('class').match(/language-(\w+)/)[1];
|
90
|
+
|
91
|
+
const collapseWrapper = document.createElement('div');
|
92
|
+
collapseWrapper.className = 'collapse-wrapper w-full py-2';
|
93
|
+
const panelWrapper = document.createElement('div');
|
94
|
+
panelWrapper.className =
|
95
|
+
'border dark:border-gray-600 rounded-md hover:border-indigo-500 duration-200 transition-colors';
|
96
|
+
|
97
|
+
const header = document.createElement('div');
|
98
|
+
header.className =
|
99
|
+
'flex justify-between items-center px-4 py-2 cursor-pointer select-none';
|
100
|
+
header.innerHTML = `<h3 class="text-lg font-medium">${language}</h3><svg class="transition-all duration-200 w-5 h-5 transform rotate-0" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M6.293 6.293a1 1 0 0 1 1.414 0L10 8.586l2.293-2.293a1 1 0 0 1 1.414 1.414l-3 3a1 1 0 0 1-1.414 0l-3-3a1 1 0 0 1 0-1.414z" clip-rule="evenodd"/></svg>`;
|
101
|
+
|
102
|
+
const panel = document.createElement('div');
|
103
|
+
panel.className =
|
104
|
+
'invisible h-0 transition-transform duration-200 border-t border-gray-300';
|
105
|
+
|
106
|
+
panelWrapper.appendChild(header);
|
107
|
+
panelWrapper.appendChild(panel);
|
108
|
+
collapseWrapper.appendChild(panelWrapper);
|
109
|
+
|
110
|
+
codeBlock.parentNode.insertBefore(collapseWrapper, codeBlock);
|
111
|
+
panel.appendChild(codeBlock);
|
112
|
+
|
113
|
+
header.addEventListener('click', () => {
|
114
|
+
panel.classList.toggle('invisible');
|
115
|
+
panel.classList.toggle('h-0');
|
116
|
+
panel.classList.toggle('h-auto');
|
117
|
+
header.querySelector('svg').classList.toggle('rotate-180');
|
118
|
+
panelWrapper.classList.toggle('border-gray-300');
|
119
|
+
});
|
120
|
+
}
|
121
|
+
};
|
122
|
+
|
123
|
+
/**
|
124
|
+
* 将mermaid语言 渲染成图片
|
125
|
+
*/
|
126
|
+
const renderMermaid = async () => {
|
127
|
+
const observer = new MutationObserver(async (mutationsList) => {
|
128
|
+
for (const m of mutationsList) {
|
129
|
+
if (m.target.className === 'notion-code language-mermaid') {
|
130
|
+
const chart = m.target.querySelector('code').textContent;
|
131
|
+
if (chart && !m.target.querySelector('.mermaid')) {
|
132
|
+
const mermaidChart = document.createElement('div');
|
133
|
+
mermaidChart.className = 'mermaid';
|
134
|
+
mermaidChart.innerHTML = chart;
|
135
|
+
m.target.appendChild(mermaidChart);
|
136
|
+
}
|
137
|
+
|
138
|
+
const mermaidsSvg = document.querySelectorAll('.mermaid');
|
139
|
+
if (mermaidsSvg) {
|
140
|
+
let needLoad = false;
|
141
|
+
for (const e of mermaidsSvg) {
|
142
|
+
if (e?.firstChild?.nodeName !== 'svg') {
|
143
|
+
needLoad = true;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
if (needLoad) {
|
147
|
+
loadExternalResource(BLOG.MERMAID_CDN, 'js').then(() => {
|
148
|
+
setTimeout(() => {
|
149
|
+
const mermaid = window.mermaid;
|
150
|
+
mermaid?.contentLoaded();
|
151
|
+
}, 100);
|
152
|
+
});
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
157
|
+
});
|
158
|
+
if (document.querySelector('#notion-article')) {
|
159
|
+
observer.observe(document.querySelector('#notion-article'), {
|
160
|
+
attributes: true,
|
161
|
+
subtree: true,
|
162
|
+
});
|
163
|
+
}
|
164
|
+
};
|
165
|
+
|
166
|
+
function renderPrismMac() {
|
167
|
+
const container = document?.getElementById('notion-article');
|
168
|
+
|
169
|
+
// Add line numbers
|
170
|
+
if (JSON.parse(BLOG.CODE_LINE_NUMBERS)) {
|
171
|
+
const codeBlocks = container?.getElementsByTagName('pre');
|
172
|
+
if (codeBlocks) {
|
173
|
+
Array.from(codeBlocks).forEach((item) => {
|
174
|
+
if (!item.classList.contains('line-numbers')) {
|
175
|
+
item.classList.add('line-numbers');
|
176
|
+
item.style.whiteSpace = 'pre-wrap';
|
177
|
+
}
|
178
|
+
});
|
179
|
+
}
|
180
|
+
}
|
181
|
+
// 重新渲染之前检查所有的多余text
|
182
|
+
|
183
|
+
try {
|
184
|
+
Prism.highlightAll();
|
185
|
+
} catch (err) {
|
186
|
+
console.log('代码渲染', err);
|
187
|
+
}
|
188
|
+
|
189
|
+
const codeToolBars = container?.getElementsByClassName('code-toolbar');
|
190
|
+
// Add pre-mac element for Mac Style UI
|
191
|
+
if (codeToolBars) {
|
192
|
+
Array.from(codeToolBars).forEach((item) => {
|
193
|
+
const existPreMac = item.getElementsByClassName('pre-mac');
|
194
|
+
if (existPreMac.length < codeToolBars.length) {
|
195
|
+
const preMac = document.createElement('div');
|
196
|
+
preMac.classList.add('pre-mac');
|
197
|
+
preMac.innerHTML = '<span></span><span></span><span></span>';
|
198
|
+
item?.appendChild(preMac, item);
|
199
|
+
}
|
200
|
+
});
|
201
|
+
}
|
202
|
+
|
203
|
+
// 折叠代码行号bug
|
204
|
+
if (JSON.parse(BLOG.CODE_LINE_NUMBERS)) {
|
205
|
+
fixCodeLineStyle();
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
/**
|
210
|
+
* 行号样式在首次渲染或被detail折叠后行高判断错误
|
211
|
+
* 在此手动resize计算
|
212
|
+
*/
|
213
|
+
const fixCodeLineStyle = () => {
|
214
|
+
const observer = new MutationObserver((mutationsList) => {
|
215
|
+
for (const m of mutationsList) {
|
216
|
+
if (m.target.nodeName === 'DETAILS') {
|
217
|
+
const preCodes = m.target.querySelectorAll('pre.notion-code');
|
218
|
+
for (const preCode of preCodes) {
|
219
|
+
Prism.plugins.lineNumbers.resize(preCode);
|
220
|
+
}
|
221
|
+
}
|
222
|
+
}
|
223
|
+
});
|
224
|
+
observer.observe(document.querySelector('#notion-article'), {
|
225
|
+
attributes: true,
|
226
|
+
subtree: true,
|
227
|
+
});
|
228
|
+
setTimeout(() => {
|
229
|
+
const preCodes = document.querySelectorAll('pre.notion-code');
|
230
|
+
for (const preCode of preCodes) {
|
231
|
+
Prism.plugins.lineNumbers.resize(preCode);
|
232
|
+
}
|
233
|
+
}, 10);
|
234
|
+
};
|
235
|
+
|
236
|
+
export default PrismMac;
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import BLOG from '@/blog.config';
|
2
|
+
import { loadExternalResource } from '@/lib/utils';
|
3
|
+
import { useEffect } from 'react';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* 二维码生成
|
7
|
+
*/
|
8
|
+
export default function QrCode({ value }) {
|
9
|
+
useEffect(() => {
|
10
|
+
let qrcode;
|
11
|
+
if (!value) {
|
12
|
+
return;
|
13
|
+
}
|
14
|
+
loadExternalResource(BLOG.QR_CODE_CDN, 'js').then(() => {
|
15
|
+
const QRCode = window.QRCode;
|
16
|
+
qrcode = new QRCode(document.getElementById('qrcode'), {
|
17
|
+
text: value,
|
18
|
+
width: 256,
|
19
|
+
height: 256,
|
20
|
+
colorDark: '#000000',
|
21
|
+
colorLight: '#ffffff',
|
22
|
+
correctLevel: QRCode.CorrectLevel.H,
|
23
|
+
});
|
24
|
+
// console.log('二维码', qrcode, value)
|
25
|
+
});
|
26
|
+
return () => {
|
27
|
+
if (qrcode) {
|
28
|
+
qrcode.clear(); // clear the code.
|
29
|
+
}
|
30
|
+
};
|
31
|
+
}, []);
|
32
|
+
|
33
|
+
return <div id="qrcode"></div>;
|
34
|
+
}
|