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.
Files changed (218) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.local +2 -0
  3. package/.eslintrc.json +15 -0
  4. package/.github/stale.yml +16 -0
  5. package/.github/workflows/codeql-analysis.yml +73 -0
  6. package/.github/workflows/docker-ghcr.yaml +59 -0
  7. package/.prettierrc +9 -0
  8. package/.vscode/launch.json +28 -0
  9. package/.vscode/settings.json +6 -0
  10. package/Dockerfile +38 -0
  11. package/LICENSE +21 -0
  12. package/README.md +16 -0
  13. package/blog.config.js +454 -0
  14. package/components/Ackee.js +83 -0
  15. package/components/AdBlockDetect.js +40 -0
  16. package/components/AlgoliaSearchModal.js +250 -0
  17. package/components/Artalk.js +30 -0
  18. package/components/Busuanzi.js +26 -0
  19. package/components/ChatBase.js +19 -0
  20. package/components/Collapse.tsx +134 -0
  21. package/components/Comment.js +161 -0
  22. package/components/CommonHead.tsx +101 -0
  23. package/components/CommonScript.js +125 -0
  24. package/components/CusdisComponent.js +35 -0
  25. package/components/CustomContextMenu.js +221 -0
  26. package/components/DebugPanel.js +134 -0
  27. package/components/DisableCopy.js +21 -0
  28. package/components/Draggable.js +167 -0
  29. package/components/Equation.js +31 -0
  30. package/components/ExternalPlugins.js +75 -0
  31. package/components/ExternalScript.js +29 -0
  32. package/components/FacebookMessenger.js +255 -0
  33. package/components/FacebookPage.js +34 -0
  34. package/components/Fireworks.js +210 -0
  35. package/components/FlipCard.js +56 -0
  36. package/components/FlutteringRibbon.js +322 -0
  37. package/components/FullScreenButton.js +48 -0
  38. package/components/Giscus.js +33 -0
  39. package/components/Gitalk.js +42 -0
  40. package/components/GoogleAdsense.js +111 -0
  41. package/components/Gtag.js +18 -0
  42. package/components/HeroIcons.tsx +321 -0
  43. package/components/KatexReact.js +53 -0
  44. package/components/LazyImage.js +95 -0
  45. package/components/Live2D.js +52 -0
  46. package/components/Loading.js +20 -0
  47. package/components/Mark.js +28 -0
  48. package/components/NProgress.ts +8 -0
  49. package/components/Nest.js +124 -0
  50. package/components/NotionIcon.js +20 -0
  51. package/components/NotionPage.tsx +206 -0
  52. package/components/Player.js +54 -0
  53. package/components/PrismMac.js +236 -0
  54. package/components/QrCode.js +34 -0
  55. package/components/Ribbon.js +98 -0
  56. package/components/Sakura.js +192 -0
  57. package/components/Select.js +40 -0
  58. package/components/ShareBar.js +29 -0
  59. package/components/ShareButtons.js +403 -0
  60. package/components/SideBarDrawer.js +50 -0
  61. package/components/StarrySky.js +130 -0
  62. package/components/Tabs.js +64 -0
  63. package/components/ThemeSwitch.js +67 -0
  64. package/components/Twikoo.js +27 -0
  65. package/components/TwikooCommentCount.js +22 -0
  66. package/components/TwikooCommentCounter.js +78 -0
  67. package/components/TwikooRecentComments.js +11 -0
  68. package/components/Utterances.js +35 -0
  69. package/components/VConsole.js +76 -0
  70. package/components/ValineComponent.js +59 -0
  71. package/components/ValineCount.js +6 -0
  72. package/components/ValinePanel.js +3 -0
  73. package/components/Vercel.tsx +54 -0
  74. package/components/WWAds.js +18 -0
  75. package/components/WalineComponent.js +83 -0
  76. package/components/WebMention.js +173 -0
  77. package/components/Webwhiz.js +17 -0
  78. package/components/WordCount.js +73 -0
  79. package/hooks/useToggleClickOutSide.ts +32 -0
  80. package/hooks/useWindowSize.ts +30 -0
  81. package/lib/algolia.js +108 -0
  82. package/lib/busuanzi.js +99 -0
  83. package/lib/cache/cacheManager.ts +49 -0
  84. package/lib/cache/localFileCache.ts +56 -0
  85. package/lib/cache/memoryMache.ts +20 -0
  86. package/lib/cache/mongoDbCache.ts +70 -0
  87. package/lib/cache/types.ts +5 -0
  88. package/lib/font.js +46 -0
  89. package/lib/global.tsx +129 -0
  90. package/lib/gtag.js +17 -0
  91. package/lib/mailchimp.js +49 -0
  92. package/lib/memorize.js +0 -0
  93. package/lib/mhchem.js +1696 -0
  94. package/lib/notion/getAllCategories.ts +51 -0
  95. package/lib/notion/getAllPageIds.ts +51 -0
  96. package/lib/notion/getAllPosts.js +68 -0
  97. package/lib/notion/getAllTags.ts +43 -0
  98. package/lib/notion/getNotionData.ts +340 -0
  99. package/lib/notion/getPageInfoOfPostPage.ts +58 -0
  100. package/lib/notion/getPageProperties.ts +203 -0
  101. package/lib/notion/getPageTableOfContents.ts +107 -0
  102. package/lib/notion/getPostBlocks.ts +147 -0
  103. package/lib/notion/mapImage.ts +130 -0
  104. package/lib/notion/types.ts +125 -0
  105. package/lib/notion.js +2 -0
  106. package/lib/robots.txt.js +25 -0
  107. package/lib/rss.js +63 -0
  108. package/lib/sitemap.xml.js +67 -0
  109. package/lib/utils.js +212 -0
  110. package/next-env.d.ts +5 -0
  111. package/next-i18next.config.js +7 -0
  112. package/next-sitemap.config.js +11 -0
  113. package/next.config.js +124 -0
  114. package/package.json +92 -0
  115. package/pages/404.tsx +40 -0
  116. package/pages/[prefix]/[slug].tsx +123 -0
  117. package/pages/[prefix]/index.tsx +223 -0
  118. package/pages/_app.js +59 -0
  119. package/pages/_document.js +42 -0
  120. package/pages/api/subscribe.js +22 -0
  121. package/pages/archive/index.tsx +79 -0
  122. package/pages/category/[category]/index.tsx +87 -0
  123. package/pages/category/[category]/page/[page].tsx +103 -0
  124. package/pages/category/index.tsx +43 -0
  125. package/pages/index.tsx +88 -0
  126. package/pages/page/[page].tsx +93 -0
  127. package/pages/search/[keyword]/index.tsx +162 -0
  128. package/pages/search/[keyword]/page/[page].tsx +166 -0
  129. package/pages/search/index.tsx +69 -0
  130. package/pages/sitemap.xml.js +70 -0
  131. package/pages/tag/[tag]/index.tsx +73 -0
  132. package/pages/tag/[tag]/page/[page].tsx +87 -0
  133. package/pages/tag/index.tsx +42 -0
  134. package/postcss.config.js +6 -0
  135. package/public/ads.txt +1 -0
  136. package/public/avatar.png +0 -0
  137. package/public/avatar.svg +11 -0
  138. package/public/bg_image.jpg +0 -0
  139. package/public/css/all.min.css +9 -0
  140. package/public/css/custom.css +8 -0
  141. package/public/css/img-shadow.css +5 -0
  142. package/public/css/prism-mac-style.css +58 -0
  143. package/public/favicon.ico +0 -0
  144. package/public/favicon.svg +9 -0
  145. package/public/js/cusdis.es.js +107 -0
  146. package/public/js/custom.js +1 -0
  147. package/public/locales/en/common.json +44 -0
  148. package/public/locales/en/menu.json +9 -0
  149. package/public/locales/en/nav.json +11 -0
  150. package/public/locales/zh-CN/common.json +44 -0
  151. package/public/locales/zh-CN/menu.json +9 -0
  152. package/public/locales/zh-CN/nav.json +9 -0
  153. package/public/webfonts/fa-brands-400.ttf +0 -0
  154. package/public/webfonts/fa-brands-400.woff2 +0 -0
  155. package/public/webfonts/fa-regular-400.ttf +0 -0
  156. package/public/webfonts/fa-regular-400.woff2 +0 -0
  157. package/public/webfonts/fa-solid-900.ttf +0 -0
  158. package/public/webfonts/fa-solid-900.woff2 +0 -0
  159. package/public/webfonts/fa-v4compatibility.ttf +0 -0
  160. package/public/webfonts/fa-v4compatibility.woff2 +0 -0
  161. package/styles/animate.css +503 -0
  162. package/styles/globals.css +183 -0
  163. package/styles/notion.css +2064 -0
  164. package/styles/nprogress.css +84 -0
  165. package/styles/prism-theme.css +119 -0
  166. package/styles/utility-patterns.css +79 -0
  167. package/tailwind.config.js +37 -0
  168. package/theme/index.ts +6 -0
  169. package/theme/types/@theme-components.d.ts +29 -0
  170. package/theme/useLayout.ts +41 -0
  171. package/theme/utils.ts +108 -0
  172. package/themes/innocent/package.json +7 -0
  173. package/themes/innocent/theme.config.js +1 -0
  174. package/themes/nobelium/components/Announcement.tsx +27 -0
  175. package/themes/nobelium/components/ArticleFooter.tsx +39 -0
  176. package/themes/nobelium/components/ArticleInfo.tsx +58 -0
  177. package/themes/nobelium/components/ArticleLock.tsx +86 -0
  178. package/themes/nobelium/components/BlogArchiveItem.js +41 -0
  179. package/themes/nobelium/components/BlogListBar.js +39 -0
  180. package/themes/nobelium/components/BlogListPage.tsx +67 -0
  181. package/themes/nobelium/components/BlogListScroll.tsx +96 -0
  182. package/themes/nobelium/components/BlogPost.tsx +33 -0
  183. package/themes/nobelium/components/DarkModeButton.tsx +50 -0
  184. package/themes/nobelium/components/ExampleRecentComments.js +35 -0
  185. package/themes/nobelium/components/Footer.tsx +35 -0
  186. package/themes/nobelium/components/JumpToTopButton.tsx +39 -0
  187. package/themes/nobelium/components/LanguageSwitchButton.tsx +58 -0
  188. package/themes/nobelium/components/MenuItemCollapse.tsx +92 -0
  189. package/themes/nobelium/components/MenuItemDrop.tsx +83 -0
  190. package/themes/nobelium/components/Nav/Nav.module.css +50 -0
  191. package/themes/nobelium/components/Nav/Nav.tsx +187 -0
  192. package/themes/nobelium/components/RandomPostButton.tsx +31 -0
  193. package/themes/nobelium/components/SearchButton.tsx +31 -0
  194. package/themes/nobelium/components/SearchInput.tsx +94 -0
  195. package/themes/nobelium/components/SearchNavBar.js +19 -0
  196. package/themes/nobelium/components/SideBar.js +83 -0
  197. package/themes/nobelium/components/SvgIcon.js +29 -0
  198. package/themes/nobelium/components/TagItem.js +13 -0
  199. package/themes/nobelium/components/Tags.tsx +44 -0
  200. package/themes/nobelium/components/Title.js +19 -0
  201. package/themes/nobelium/index.tsx +28 -0
  202. package/themes/nobelium/layout/LayoutBase.tsx +79 -0
  203. package/themes/nobelium/pages/Archive.tsx +30 -0
  204. package/themes/nobelium/pages/Category.tsx +43 -0
  205. package/themes/nobelium/pages/Home.tsx +22 -0
  206. package/themes/nobelium/pages/PageNotFound.tsx +15 -0
  207. package/themes/nobelium/pages/Post.tsx +34 -0
  208. package/themes/nobelium/pages/PostList.tsx +74 -0
  209. package/themes/nobelium/pages/Search.tsx +65 -0
  210. package/themes/nobelium/pages/Tag.tsx +42 -0
  211. package/themes/nobelium/providers/index.tsx +60 -0
  212. package/themes/nobelium/stores/index.tsx +42 -0
  213. package/themes/nobelium/theme.config.ts +17 -0
  214. package/themes/nobelium/types/index.ts +10 -0
  215. package/tsconfig.json +29 -0
  216. package/types/index.ts +1 -0
  217. package/types/page.ts +102 -0
  218. 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
+ }