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,111 @@
1
+ import BLOG from '@/blog.config';
2
+ import { loadExternalResource } from '@/lib/utils';
3
+ import { useRouter } from 'next/router';
4
+ import { useEffect } from 'react';
5
+
6
+ /**
7
+ * 初始化谷歌广告
8
+ * @returns
9
+ */
10
+ export default function GoogleAdsense() {
11
+ const initGoogleAdsense = () => {
12
+ loadExternalResource(
13
+ `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${BLOG.ADSENSE_GOOGLE_ID}`,
14
+ 'js',
15
+ ).then(() => {
16
+ setTimeout(() => {
17
+ const ads = document.getElementsByClassName('adsbygoogle');
18
+ const adsbygoogle = window.adsbygoogle;
19
+ if (ads.length > 0) {
20
+ for (let i = 0; i <= ads.length; i++) {
21
+ try {
22
+ adsbygoogle.push(ads[i]);
23
+ } catch (e) {
24
+ console.error(e);
25
+ }
26
+ }
27
+ }
28
+ }, 100);
29
+ });
30
+ };
31
+
32
+ const router = useRouter();
33
+ useEffect(() => {
34
+ // 延迟3秒加载
35
+ setTimeout(() => {
36
+ initGoogleAdsense();
37
+ }, 3000);
38
+ }, [router]);
39
+
40
+ return null;
41
+ }
42
+
43
+ /**
44
+ * 文章内嵌广告单元
45
+ * 请在GoogleAdsense后台配置创建对应广告,并且获取相应代码
46
+ * 修改下面广告单元中的 data-ad-slot data-ad-format data-ad-layout-key(如果有)
47
+ * 添加 可以在本地调试
48
+ */
49
+ const AdSlot = ({ type = 'show' }) => {
50
+ if (!BLOG.ADSENSE_GOOGLE_ID) {
51
+ return null;
52
+ }
53
+ // 文章内嵌广告
54
+ if (type === 'in-article') {
55
+ return (
56
+ <ins
57
+ className="adsbygoogle"
58
+ style={{ display: 'block', textAlign: 'center' }}
59
+ data-ad-layout="in-article"
60
+ data-ad-format="fluid"
61
+ data-adtest={BLOG.ADSENSE_GOOGLE_TEST ? 'on' : 'off'}
62
+ data-ad-client={BLOG.ADSENSE_GOOGLE_ID}
63
+ data-ad-slot={BLOG.ADSENSE_GOOGLE_SLOT_IN_ARTICLE}
64
+ ></ins>
65
+ );
66
+ }
67
+
68
+ // 信息流广告
69
+ if (type === 'flow') {
70
+ return (
71
+ <ins
72
+ className="adsbygoogle"
73
+ data-ad-format="fluid"
74
+ data-ad-layout-key="-5j+cz+30-f7+bf"
75
+ style={{ display: 'block' }}
76
+ data-adtest={BLOG.ADSENSE_GOOGLE_TEST ? 'on' : 'off'}
77
+ data-ad-client={BLOG.ADSENSE_GOOGLE_ID}
78
+ data-ad-slot={BLOG.ADSENSE_GOOGLE_SLOT_FLOW}
79
+ ></ins>
80
+ );
81
+ }
82
+
83
+ // 原生广告
84
+ if (type === 'native') {
85
+ return (
86
+ <ins
87
+ className="adsbygoogle"
88
+ style={{ display: 'block', textAlign: 'center' }}
89
+ data-ad-format="autorelaxed"
90
+ data-adtest={BLOG.ADSENSE_GOOGLE_TEST ? 'on' : 'off'}
91
+ data-ad-client={BLOG.ADSENSE_GOOGLE_ID}
92
+ data-ad-slot={BLOG.ADSENSE_GOOGLE_SLOT_NATIVE}
93
+ ></ins>
94
+ );
95
+ }
96
+
97
+ // 展示广告
98
+ return (
99
+ <ins
100
+ className="adsbygoogle"
101
+ style={{ display: 'block' }}
102
+ data-ad-client={BLOG.ADSENSE_GOOGLE_ID}
103
+ data-adtest={BLOG.ADSENSE_GOOGLE_TEST ? 'on' : 'off'}
104
+ data-ad-slot={BLOG.ADSENSE_GOOGLE_SLOT_AUTO}
105
+ data-ad-format="auto"
106
+ data-full-width-responsive="true"
107
+ ></ins>
108
+ );
109
+ };
110
+
111
+ export { AdSlot };
@@ -0,0 +1,18 @@
1
+ import { useEffect } from 'react'
2
+ import { useRouter } from 'next/router'
3
+ import * as gtag from '@/lib/gtag'
4
+
5
+ const Gtag = () => {
6
+ const router = useRouter()
7
+ useEffect(() => {
8
+ const gtagRouteChange = url => {
9
+ gtag.pageview(url)
10
+ }
11
+ router.events.on('routeChangeComplete', gtagRouteChange)
12
+ return () => {
13
+ router.events.off('routeChangeComplete', gtagRouteChange)
14
+ }
15
+ }, [router.events])
16
+ return null
17
+ }
18
+ export default Gtag
@@ -0,0 +1,321 @@
1
+ /**
2
+ * @see https://heroicons.com/
3
+ * @returns
4
+ */
5
+
6
+ export const Moon = () => {
7
+ return (
8
+ <svg
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ fill="none"
11
+ viewBox="0 0 24 24"
12
+ strokeWidth={2}
13
+ stroke="currentColor"
14
+ >
15
+ <path
16
+ strokeLinecap="round"
17
+ strokeLinejoin="round"
18
+ d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z"
19
+ />
20
+ </svg>
21
+ );
22
+ };
23
+
24
+ export const Sun = () => {
25
+ return (
26
+ <svg
27
+ xmlns="http://www.w3.org/2000/svg"
28
+ fill="none"
29
+ viewBox="0 0 24 24"
30
+ strokeWidth={2}
31
+ stroke="currentColor"
32
+ >
33
+ <path
34
+ strokeLinecap="round"
35
+ strokeLinejoin="round"
36
+ d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
37
+ />
38
+ </svg>
39
+ );
40
+ };
41
+
42
+ export const Home = ({ className = '' }) => {
43
+ return (
44
+ <svg
45
+ xmlns="http://www.w3.org/2000/svg"
46
+ fill="none"
47
+ viewBox="0 0 24 24"
48
+ strokeWidth={2}
49
+ stroke="currentColor"
50
+ className={className}
51
+ >
52
+ <path
53
+ strokeLinecap="round"
54
+ strokeLinejoin="round"
55
+ d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"
56
+ />
57
+ </svg>
58
+ );
59
+ };
60
+
61
+ export const User = ({ className = '' }) => {
62
+ return (
63
+ <svg
64
+ xmlns="http://www.w3.org/2000/svg"
65
+ fill="none"
66
+ viewBox="0 0 24 24"
67
+ strokeWidth={2}
68
+ stroke="currentColor"
69
+ className={className}
70
+ >
71
+ <path
72
+ strokeLinecap="round"
73
+ strokeLinejoin="round"
74
+ d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z"
75
+ />
76
+ </svg>
77
+ );
78
+ };
79
+
80
+ export const ArrowPath = ({ className = '' }) => {
81
+ return (
82
+ <svg
83
+ xmlns="http://www.w3.org/2000/svg"
84
+ fill="none"
85
+ viewBox="0 0 24 24"
86
+ strokeWidth={2}
87
+ stroke="currentColor"
88
+ className={className}
89
+ >
90
+ <path
91
+ strokeLinecap="round"
92
+ strokeLinejoin="round"
93
+ d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
94
+ />
95
+ </svg>
96
+ );
97
+ };
98
+
99
+ export const ChevronLeft = ({ className = '' }) => {
100
+ return (
101
+ <svg
102
+ xmlns="http://www.w3.org/2000/svg"
103
+ fill="none"
104
+ viewBox="0 0 24 24"
105
+ strokeWidth={2}
106
+ stroke="currentColor"
107
+ className={className}
108
+ >
109
+ <path
110
+ strokeLinecap="round"
111
+ strokeLinejoin="round"
112
+ d="M15.75 19.5L8.25 12l7.5-7.5"
113
+ />
114
+ </svg>
115
+ );
116
+ };
117
+
118
+ export const ChevronRight = ({ className = '' }) => {
119
+ return (
120
+ <svg
121
+ xmlns="http://www.w3.org/2000/svg"
122
+ fill="none"
123
+ viewBox="0 0 24 24"
124
+ strokeWidth={2}
125
+ stroke="currentColor"
126
+ className={className}
127
+ >
128
+ <path
129
+ strokeLinecap="round"
130
+ strokeLinejoin="round"
131
+ d="M8.25 4.5l7.5 7.5-7.5 7.5"
132
+ />
133
+ </svg>
134
+ );
135
+ };
136
+
137
+ export const ChevronDoubleLeft = ({ className = '' }) => {
138
+ return (
139
+ <svg
140
+ xmlns="http://www.w3.org/2000/svg"
141
+ fill="none"
142
+ viewBox="0 0 24 24"
143
+ strokeWidth={2}
144
+ stroke="currentColor"
145
+ className={className}
146
+ >
147
+ <path
148
+ strokeLinecap="round"
149
+ strokeLinejoin="round"
150
+ d="M18.75 19.5l-7.5-7.5 7.5-7.5m-6 15L5.25 12l7.5-7.5"
151
+ />
152
+ </svg>
153
+ );
154
+ };
155
+
156
+ export const ChevronDoubleRight = ({ className = '' }) => {
157
+ return (
158
+ <svg
159
+ xmlns="http://www.w3.org/2000/svg"
160
+ fill="none"
161
+ viewBox="0 0 24 24"
162
+ strokeWidth={2}
163
+ stroke="currentColor"
164
+ className={className}
165
+ >
166
+ <path
167
+ strokeLinecap="round"
168
+ strokeLinejoin="round"
169
+ d="M11.25 4.5l7.5 7.5-7.5 7.5m-6-15l7.5 7.5-7.5 7.5"
170
+ />
171
+ </svg>
172
+ );
173
+ };
174
+
175
+ export const InformationCircle = ({ className = '' }) => {
176
+ return (
177
+ <svg
178
+ xmlns="http://www.w3.org/2000/svg"
179
+ fill="none"
180
+ viewBox="0 0 24 24"
181
+ strokeWidth={2}
182
+ stroke="currentColor"
183
+ className={className}
184
+ >
185
+ <path
186
+ strokeLinecap="round"
187
+ strokeLinejoin="round"
188
+ d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"
189
+ />
190
+ </svg>
191
+ );
192
+ };
193
+
194
+ export const HashTag = ({ className = '' }) => {
195
+ return (
196
+ <svg
197
+ xmlns="http://www.w3.org/2000/svg"
198
+ fill="none"
199
+ viewBox="0 0 24 24"
200
+ strokeWidth={2}
201
+ stroke="currentColor"
202
+ className={className}
203
+ >
204
+ <path
205
+ strokeLinecap="round"
206
+ strokeLinejoin="round"
207
+ d="M5.25 8.25h15m-16.5 7.5h15m-1.8-13.5l-3.9 19.5m-2.1-19.5l-3.9 19.5"
208
+ />
209
+ </svg>
210
+ );
211
+ };
212
+
213
+ export const GlobeAlt = ({ className = '' }) => {
214
+ return (
215
+ <svg
216
+ xmlns="http://www.w3.org/2000/svg"
217
+ fill="none"
218
+ viewBox="0 0 24 24"
219
+ strokeWidth={2}
220
+ stroke="currentColor"
221
+ className={className}
222
+ >
223
+ <path
224
+ strokeLinecap="round"
225
+ strokeLinejoin="round"
226
+ d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418"
227
+ />
228
+ </svg>
229
+ );
230
+ };
231
+
232
+ export const ArrowRightCircle = ({ className = '' }) => {
233
+ return (
234
+ <svg
235
+ xmlns="http://www.w3.org/2000/svg"
236
+ fill="none"
237
+ viewBox="0 0 24 24"
238
+ strokeWidth={2}
239
+ stroke="currentColor"
240
+ className={className}
241
+ >
242
+ <path
243
+ strokeLinecap="round"
244
+ strokeLinejoin="round"
245
+ d="M12.75 15l3-3m0 0l-3-3m3 3h-7.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
246
+ />
247
+ </svg>
248
+ );
249
+ };
250
+
251
+ export const PlusSmall = ({ className = '' }) => {
252
+ return (
253
+ <svg
254
+ xmlns="http://www.w3.org/2000/svg"
255
+ fill="none"
256
+ viewBox="0 0 24 24"
257
+ strokeWidth={2}
258
+ stroke="currentColor"
259
+ className={className}
260
+ >
261
+ <path strokeLinecap="round" strokeLinejoin="round" d="M12 6v12m6-6H6" />
262
+ </svg>
263
+ );
264
+ };
265
+
266
+ export const ArrowSmallRight = ({ className = '' }) => {
267
+ return (
268
+ <svg
269
+ xmlns="http://www.w3.org/2000/svg"
270
+ fill="none"
271
+ viewBox="0 0 24 24"
272
+ strokeWidth={2}
273
+ stroke="currentColor"
274
+ className={className}
275
+ >
276
+ <path
277
+ strokeLinecap="round"
278
+ strokeLinejoin="round"
279
+ d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75"
280
+ />
281
+ </svg>
282
+ );
283
+ };
284
+
285
+ export const ArrowSmallUp = ({ className = '' }) => {
286
+ return (
287
+ <svg
288
+ xmlns="http://www.w3.org/2000/svg"
289
+ fill="none"
290
+ viewBox="0 0 24 24"
291
+ strokeWidth={2}
292
+ stroke="currentColor"
293
+ className={className}
294
+ >
295
+ <path
296
+ strokeLinecap="round"
297
+ strokeLinejoin="round"
298
+ d="M12 19.5v-15m0 0l-6.75 6.75M12 4.5l6.75 6.75"
299
+ />
300
+ </svg>
301
+ );
302
+ };
303
+
304
+ export const Language = ({ className = '' }) => {
305
+ return (
306
+ <svg
307
+ xmlns="http://www.w3.org/2000/svg"
308
+ fill="none"
309
+ viewBox="0 0 24 24"
310
+ strokeWidth={2}
311
+ stroke="currentColor"
312
+ className={className}
313
+ >
314
+ <path
315
+ strokeLinecap="round"
316
+ strokeLinejoin="round"
317
+ d="m10.5 21 5.25-11.25L21 21m-9-3h7.5M3 5.621a48.474 48.474 0 0 1 6-.371m0 0c1.12 0 2.233.038 3.334.114M9 5.25V3m3.334 2.364C11.176 10.658 7.69 15.08 3 17.502m9.334-12.138c.896.061 1.785.147 2.666.257m-4.589 8.495a18.023 18.023 0 0 1-3.827-5.802"
318
+ />
319
+ </svg>
320
+ );
321
+ };
@@ -0,0 +1,53 @@
1
+ import KaTeX from 'katex'
2
+ import React from 'react'
3
+
4
+ const TeX = ({
5
+ children,
6
+ math,
7
+ block,
8
+ errorColor,
9
+ renderError,
10
+ settings,
11
+ as: asComponent,
12
+ ...props
13
+ }) => {
14
+ const Component = asComponent || (block ? 'div' : 'span')
15
+ const content = (children ?? math)
16
+ const [state, setState] = React.useState({ innerHtml: '' })
17
+
18
+ React.useEffect(() => {
19
+ try {
20
+ const innerHtml = KaTeX.renderToString(content, {
21
+ displayMode: true,
22
+ errorColor,
23
+ throwOnError: !!renderError,
24
+ ...settings
25
+ })
26
+
27
+ setState({ innerHtml })
28
+ } catch (error) {
29
+ if (error instanceof KaTeX.ParseError || error instanceof TypeError) {
30
+ if (renderError) {
31
+ setState({ errorElement: renderError(error) })
32
+ } else {
33
+ setState({ innerHtml: error.message })
34
+ }
35
+ } else {
36
+ throw error
37
+ }
38
+ }
39
+ }, [block, content, errorColor, renderError, settings])
40
+
41
+ if ('errorElement' in state) {
42
+ return state.errorElement
43
+ }
44
+
45
+ return (
46
+ <Component
47
+ {...props}
48
+ dangerouslySetInnerHTML={{ __html: state.innerHtml }}
49
+ />
50
+ )
51
+ }
52
+
53
+ export default React.memo(TeX)
@@ -0,0 +1,95 @@
1
+ import BLOG from '@/blog.config'
2
+ import Head from 'next/head'
3
+ import React, { useEffect, useRef, useState } from 'react'
4
+
5
+ /**
6
+ * 图片懒加载
7
+ * @param {*} param0
8
+ * @returns
9
+ */
10
+ export default function LazyImage({
11
+ priority,
12
+ id,
13
+ src,
14
+ alt,
15
+ placeholderSrc = BLOG.IMG_LAZY_LOAD_PLACEHOLDER,
16
+ className,
17
+ width,
18
+ height,
19
+ title,
20
+ onLoad,
21
+ style
22
+ }) {
23
+ const imageRef = useRef(null)
24
+ const [imageLoaded, setImageLoaded] = useState(false)
25
+
26
+ const handleImageLoad = () => {
27
+ setImageLoaded(true)
28
+ if (typeof onLoad === 'function') {
29
+ onLoad() // 触发传递的onLoad回调函数
30
+ }
31
+ }
32
+
33
+ useEffect(() => {
34
+ const observer = new IntersectionObserver(
35
+ (entries) => {
36
+ entries.forEach((entry) => {
37
+ if (entry.isIntersecting) {
38
+ const lazyImage = entry.target
39
+ lazyImage.src = src
40
+ observer.unobserve(lazyImage)
41
+ }
42
+ })
43
+ },
44
+ { rootMargin: '50px 0px' } // Adjust the rootMargin as needed to trigger the loading earlier or later
45
+ )
46
+
47
+ if (imageRef.current) {
48
+ observer.observe(imageRef.current)
49
+ }
50
+
51
+ return () => {
52
+ if (imageRef.current) {
53
+ observer.unobserve(imageRef.current)
54
+ }
55
+ }
56
+ }, [src])
57
+
58
+ // 动态添加width、height和className属性,仅在它们为有效值时添加
59
+ const imgProps = {
60
+ ref: imageRef,
61
+ src: imageLoaded ? src : placeholderSrc,
62
+ alt: alt,
63
+ onLoad: handleImageLoad
64
+ }
65
+
66
+ if (id) {
67
+ imgProps.id = id
68
+ }
69
+
70
+ if (title) {
71
+ imgProps.title = title
72
+ }
73
+
74
+ if (width && width !== 'auto') {
75
+ imgProps.width = width
76
+ }
77
+
78
+ if (height && height !== 'auto') {
79
+ imgProps.height = height
80
+ }
81
+ if (className) {
82
+ imgProps.className = className
83
+ }
84
+ if (style) {
85
+ imgProps.style = style
86
+ }
87
+ return (<>
88
+ {/* eslint-disable-next-line @next/next/no-img-element */}
89
+ <img {...imgProps} />
90
+ {/* 预加载 */}
91
+ {priority && <Head>
92
+ <link rel='preload' as='image' src={src} />
93
+ </Head>}
94
+ </>)
95
+ }
@@ -0,0 +1,52 @@
1
+ /* eslint-disable no-undef */
2
+ import BLOG from '@/blog.config';
3
+ import { useGlobal } from '@/lib/global';
4
+ import { loadExternalResource } from '@/lib/utils';
5
+ import { useEffect } from 'react';
6
+
7
+ export default function Live2D() {
8
+ const { theme, switchTheme } = useGlobal();
9
+ const showPet = JSON.parse(BLOG.WIDGET_PET);
10
+
11
+ useEffect(() => {
12
+ if (showPet) {
13
+ Promise.all([
14
+ loadExternalResource(
15
+ 'https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/live2d.min.js',
16
+ 'js',
17
+ ),
18
+ ]).then(() => {
19
+ if (typeof window?.loadlive2d !== 'undefined') {
20
+ // https://github.com/xiazeyu/live2d-widget-models
21
+ try {
22
+ loadlive2d('live2d', BLOG.WIDGET_PET_LINK);
23
+ } catch (error) {
24
+ console.error('读取PET模型', error);
25
+ }
26
+ }
27
+ });
28
+ }
29
+ }, [theme]);
30
+
31
+ function handleClick() {
32
+ if (JSON.parse(BLOG.WIDGET_PET_SWITCH_THEME)) {
33
+ switchTheme();
34
+ }
35
+ }
36
+
37
+ if (!showPet) {
38
+ return <></>;
39
+ }
40
+
41
+ return (
42
+ <canvas
43
+ id="live2d"
44
+ width="280"
45
+ height="250"
46
+ onClick={handleClick}
47
+ className="cursor-grab"
48
+ onMouseDown={(e) => e.target.classList.add('cursor-grabbing')}
49
+ onMouseUp={(e) => e.target.classList.remove('cursor-grabbing')}
50
+ />
51
+ );
52
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 异步文件加载时的占位符
3
+ * @returns
4
+ */
5
+ const Loading = () => {
6
+ return (
7
+ <div
8
+ id="loading-container"
9
+ className="fixed left-0 top-0 -z-10 flex h-screen w-screen items-center justify-center"
10
+ >
11
+ <div id="loading-wrapper">
12
+ <div className="loading">
13
+ {' '}
14
+ <i className="fas fa-spinner animate-spin text-3xl " />
15
+ </div>
16
+ </div>
17
+ </div>
18
+ );
19
+ };
20
+ export default Loading;
@@ -0,0 +1,28 @@
1
+ import { loadExternalResource } from '@/lib/utils'
2
+
3
+ /**
4
+ * 将搜索结果的关键词高亮
5
+ */
6
+ export default async function replaceSearchResult({ doms, search, target }) {
7
+ if (!doms || !search || !target) {
8
+ return
9
+ }
10
+
11
+ try {
12
+ await loadExternalResource('https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/mark.min.js', 'js')
13
+ const Mark = window.Mark
14
+ if (doms instanceof HTMLCollection) {
15
+ for (const container of doms) {
16
+ const re = new RegExp(search, 'gim')
17
+ const instance = new Mark(container)
18
+ instance.markRegExp(re, target)
19
+ }
20
+ } else {
21
+ const re = new RegExp(search, 'gim')
22
+ const instance = new Mark(doms)
23
+ instance.markRegExp(re, target)
24
+ }
25
+ } catch (error) {
26
+ console.error('markjs 加载失败', error)
27
+ }
28
+ }
@@ -0,0 +1,8 @@
1
+ import NProgress from 'nprogress';
2
+
3
+ export function initNProgress() {
4
+ NProgress.configure({ showSpinner: false });
5
+ }
6
+
7
+ export const progressStart = NProgress.start;
8
+ export const progressDone = NProgress.done;