From 7524fc325677654a1bf4d80eecb4c92f870bb511 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 13:09:12 +0800 Subject: [PATCH 01/24] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/NotionPage.js | 3 +++ components/PrismMac.js | 3 ++- components/WalineComponent.js | 1 + pages/_app.js | 9 ++------- styles/notion.css | 21 ++++++++++++++++++++- styles/prism-mac-style.css | 26 +++++--------------------- 6 files changed, 33 insertions(+), 30 deletions(-) diff --git a/components/NotionPage.js b/components/NotionPage.js index 8739917f..7f46e6f6 100644 --- a/components/NotionPage.js +++ b/components/NotionPage.js @@ -7,6 +7,9 @@ import Image from 'next/image' import Link from 'next/link' import { Code } from 'react-notion-x/build/third-party/code' +import 'prism-themes/themes/prism-material-light.css' +import 'katex/dist/katex.min.css' + const Equation = dynamic(() => import('react-notion-x/build/third-party/equation').then(async (m) => { // 化学方程式 diff --git a/components/PrismMac.js b/components/PrismMac.js index 956e9f73..11673d46 100644 --- a/components/PrismMac.js +++ b/components/PrismMac.js @@ -1,6 +1,7 @@ import React from 'react' import Prism from 'prismjs' import 'prismjs/plugins/toolbar/prism-toolbar' +import 'prismjs/plugins/toolbar/prism-toolbar.min.css' import 'prismjs/plugins/show-language/prism-show-language' import 'prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard' import 'prismjs/plugins/line-numbers/prism-line-numbers' @@ -70,7 +71,6 @@ const renderMermaid = async() => { function renderPrismMac() { const container = document?.getElementById('container-inner') - const codeToolBars = container?.getElementsByClassName('code-toolbar') // Add line numbers const codeBlocks = container?.getElementsByTagName('pre') @@ -93,6 +93,7 @@ function renderPrismMac() { console.log('代码渲染', err) } + const codeToolBars = container?.getElementsByClassName('code-toolbar') // Add pre-mac element for Mac Style UI if (codeToolBars) { Array.from(codeToolBars).forEach(item => { diff --git a/components/WalineComponent.js b/components/WalineComponent.js index c3da56ab..22d6ceee 100644 --- a/components/WalineComponent.js +++ b/components/WalineComponent.js @@ -2,6 +2,7 @@ import React from 'react' import { init } from '@waline/client' import BLOG from '@/blog.config' import { useRouter } from 'next/router' +import '@waline/client/dist/waline.css' const path = '' let waline = null diff --git a/pages/_app.js b/pages/_app.js index 200a6b43..6148cc1a 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -9,15 +9,10 @@ import '@/styles/notion.css' // 重写部分样式 // used for collection views (optional) // import 'rc-dropdown/assets/index.css' // import 'prismjs/themes/prism-tomorrow.min.css' -import 'prism-themes/themes/prism-one-dark.css' +// import 'prism-themes/themes/prism-one-dark.css' +// import 'prism-themes/themes/prism-one-light.css' import '@/styles/prism-mac-style.css' // 將 Prism 加入 mac 視窗樣式 -// import 'react-notion-x/build/third-party/equation.css' -import 'katex/dist/katex.min.css' - -// waline 评论插件 -import '@waline/client/dist/waline.css' - import dynamic from 'next/dynamic' import { GlobalContextProvider } from '@/lib/global' import { DebugPanel } from '@/components/DebugPanel' diff --git a/styles/notion.css b/styles/notion.css index d55d8456..5663f15a 100644 --- a/styles/notion.css +++ b/styles/notion.css @@ -737,7 +737,8 @@ svg.notion-page-icon { width: 100%; padding: 30px 16px 30px 20px; margin: 4px 0; - border-radius: 10px; + border-bottom-right-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; tab-size: 2; display: block; box-sizing: border-box; @@ -1996,4 +1997,22 @@ thead, tbody tr { .notion-collection-card{ @apply dark:hover:text-gray-200 +} + +.notion-code-copy{ + display: none; +} + + +pre[class*="language-mermaid"] { + @apply bg-gray-50 dark:bg-gray-200 !important; +} + +/* mermaid 原文隐藏 */ +code.language-mermaid { + display:none +} + +pre.notion-code.line-numbers{ + margin-bottom: 0 !important } \ No newline at end of file diff --git a/styles/prism-mac-style.css b/styles/prism-mac-style.css index ff2472a7..9498191a 100644 --- a/styles/prism-mac-style.css +++ b/styles/prism-mac-style.css @@ -3,9 +3,10 @@ **/ .code-toolbar { position: relative; - box-shadow: 0 10px 30px 0 rgba(0, 0, 0, .4); + /* box-shadow: 0 10px 30px 0 rgba(0, 0, 0, .4); */ padding-bottom: 0 !important; - @apply mb-8 mt-4 pt-6 w-full rounded-lg bg-black + /* @apply mb-8 mt-4 pt-6 w-full rounded-lg bg-black */ + @apply w-full rounded-lg } .toolbar { @@ -27,10 +28,10 @@ margin-top: -0.1rem; } -.notion-code > code[class*='language-'], +/* .notion-code > code[class*='language-'], pre[class*='language-'] { background: black; -} +} */ .pre-mac { position: absolute; @@ -55,20 +56,3 @@ pre[class*='language-'] { .pre-mac > span:nth-child(3) { background: limegreen; } - -.notion-code-copy{ - display: none; -} - -pre[class*="language-mermaid"] { - @apply bg-gray-50 dark:bg-gray-200 !important; -} - -/* mermaid 原文隐藏 */ -code.language-mermaid { - display:none -} - -pre.notion-code.line-numbers{ - margin-bottom: 0 !important -} \ No newline at end of file From adf962fea59d690c647cbc403895b0dd794d4ead Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 13:32:55 +0800 Subject: [PATCH 02/24] fix.live2d --- components/Live2D.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/Live2D.js b/components/Live2D.js index cb53df89..2e2011b6 100644 --- a/components/Live2D.js +++ b/components/Live2D.js @@ -8,9 +8,11 @@ export default function Live2D() { const { switchTheme } = useGlobal() React.useEffect(() => { - window.addEventListener('scroll', initLive2D) - return () => { - window.removeEventListener('scroll', initLive2D) + if (BLOG.WIDGET_PET) { + window.addEventListener('scroll', initLive2D) + return () => { + window.removeEventListener('scroll', initLive2D) + } } }, []) From d6c77bbbafc9d5de5d8f5133f7747b6d07340aa6 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 17:08:36 +0800 Subject: [PATCH 03/24] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/NotionPage.js | 1 - pages/_app.js | 17 ++++++------ styles/notion.css | 53 +++++++------------------------------- styles/prism-mac-style.css | 25 +++++------------- 4 files changed, 23 insertions(+), 73 deletions(-) diff --git a/components/NotionPage.js b/components/NotionPage.js index 7f46e6f6..429a6853 100644 --- a/components/NotionPage.js +++ b/components/NotionPage.js @@ -7,7 +7,6 @@ import Image from 'next/image' import Link from 'next/link' import { Code } from 'react-notion-x/build/third-party/code' -import 'prism-themes/themes/prism-material-light.css' import 'katex/dist/katex.min.css' const Equation = dynamic(() => diff --git a/pages/_app.js b/pages/_app.js index 6148cc1a..451296f2 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,24 +1,23 @@ import BLOG from 'blog.config' +import React from 'react' +import dynamic from 'next/dynamic' + import 'animate.css' import '@/styles/globals.css' -// custom + // core styles shared by all of react-notion-x (required) import 'react-notion-x/src/styles.css' import '@/styles/notion.css' // 重写部分样式 -// used for collection views (optional) -// import 'rc-dropdown/assets/index.css' -// import 'prismjs/themes/prism-tomorrow.min.css' -// import 'prism-themes/themes/prism-one-dark.css' -// import 'prism-themes/themes/prism-one-light.css' -import '@/styles/prism-mac-style.css' // 將 Prism 加入 mac 視窗樣式 +// 代码样式 更多样式参考: https://github.com/PrismJS/prism-themes +import 'prism-themes/themes/prism-material-light.css' + +// import '@/styles/prism-mac-style.css' // code 左上角显示mac的红黄绿图标 -import dynamic from 'next/dynamic' import { GlobalContextProvider } from '@/lib/global' import { DebugPanel } from '@/components/DebugPanel' import { ThemeSwitch } from '@/components/ThemeSwitch' import { Fireworks } from '@/components/Fireworks' -import React from 'react' import { loadExternalResource } from '@/lib/utils' const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false }) diff --git a/styles/notion.css b/styles/notion.css index 5663f15a..e7ab6173 100644 --- a/styles/notion.css +++ b/styles/notion.css @@ -733,19 +733,25 @@ svg.notion-page-icon { font-size: 85%; } +pre[class*='language-'] { + line-height: inherit; +} + +code[class*='language-'] { + background: unset !important; +} + .notion-code { - width: 100%; padding: 30px 16px 30px 20px; - margin: 4px 0; border-bottom-right-radius: 0.5rem; border-bottom-left-radius: 0.5rem; tab-size: 2; display: block; box-sizing: border-box; overflow: auto; - background: #272822; font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; + @apply w-full mb-4 dark:bg-black; } .notion-column { @@ -1666,14 +1672,6 @@ svg + .notion-page-title-text { @apply dark:text-black } -.notion-code > code { - color: unset; -} - -pre[class*='language-'] { - line-height: inherit; -} - .notion-bookmark:hover { @apply border-blue-400; } @@ -1911,35 +1909,6 @@ pre[class*='language-'] { width: 100% !important; } -.pre-mac { - position: relative; - margin-top: -7px; - top: 21px; - left: 10px; - width: 100px; - z-index: 99; -} - -.pre-mac > span { - float: left; - width: 10px; - height: 10px; - border-radius: 50%; - margin-right: 5px; -} - -.pre-mac > span:nth-child(1) { - background: red; -} - -.pre-mac > span:nth-child(2) { - background: sandybrown; -} - -.pre-mac > span:nth-child(3) { - background: limegreen; -} - .notion-asset-wrapper-pdf > div { display: block !important; } @@ -2012,7 +1981,3 @@ pre[class*="language-mermaid"] { code.language-mermaid { display:none } - -pre.notion-code.line-numbers{ - margin-bottom: 0 !important -} \ No newline at end of file diff --git a/styles/prism-mac-style.css b/styles/prism-mac-style.css index 9498191a..09e8dcfa 100644 --- a/styles/prism-mac-style.css +++ b/styles/prism-mac-style.css @@ -3,23 +3,11 @@ **/ .code-toolbar { position: relative; - /* box-shadow: 0 10px 30px 0 rgba(0, 0, 0, .4); */ + padding-top: 0 !important; padding-bottom: 0 !important; - /* @apply mb-8 mt-4 pt-6 w-full rounded-lg bg-black */ @apply w-full rounded-lg } -.toolbar { - position: absolute; - margin-left: 100%; - top: 8px; - right: 4px; - display: flex; - flex-direction: row; - font-size: 0.8rem; - line-height: 1rem; -} - .toolbar-item{ @apply whitespace-nowrap } @@ -28,18 +16,17 @@ margin-top: -0.1rem; } -/* .notion-code > code[class*='language-'], pre[class*='language-'] { - background: black; -} */ + @apply mt-0 mb-2 pt-6 !important; +} .pre-mac { - position: absolute; - left: 15px; - @apply z-10 top-4 left-3 + @apply left-5 top-2 z-10 absolute } .pre-mac > span { + width: 10px; + height: 10px; border-radius: 50%; margin-right: 5px; @apply float-left From 678ca279ce4ef8f4278d25a674ac3eaaf033bbec Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 18:53:49 +0800 Subject: [PATCH 04/24] =?UTF-8?q?Nobelium=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.local | 27 +++- components/Vercel.js | 42 ++++++ styles/globals.css | 10 +- themes/index.js | 5 +- themes/nobelium/Layout404.js | 7 + themes/nobelium/LayoutArchive.js | 62 +++++++++ themes/nobelium/LayoutBase.js | 41 ++++++ themes/nobelium/LayoutCategory.js | 10 ++ themes/nobelium/LayoutCategoryIndex.js | 19 +++ themes/nobelium/LayoutIndex.js | 13 ++ themes/nobelium/LayoutPage.js | 10 ++ themes/nobelium/LayoutSearch.js | 54 ++++++++ themes/nobelium/LayoutSlug.js | 31 +++++ themes/nobelium/LayoutTag.js | 57 ++++++++ themes/nobelium/LayoutTagIndex.js | 21 +++ themes/nobelium/components/ArticleFooter.js | 34 +++++ themes/nobelium/components/ArticleInfo.js | 63 +++++++++ themes/nobelium/components/ArticleLock.js | 38 ++++++ themes/nobelium/components/BlogListPage.js | 44 ++++++ themes/nobelium/components/BlogListScroll.js | 78 +++++++++++ themes/nobelium/components/BlogPost.js | 29 ++++ .../components/ExampleRecentComments.js | 35 +++++ themes/nobelium/components/Footer.js | 34 +++++ themes/nobelium/components/Header.js | 128 ++++++++++++++++++ themes/nobelium/components/JumpToTopButton.js | 19 +++ themes/nobelium/components/Nav.js | 39 ++++++ themes/nobelium/components/SearchInput.js | 87 ++++++++++++ themes/nobelium/components/SideBar.js | 55 ++++++++ themes/nobelium/components/TagItem.js | 13 ++ themes/nobelium/components/Tags.js | 38 ++++++ themes/nobelium/components/Title.js | 19 +++ themes/nobelium/config_nobelium.js | 4 + themes/nobelium/index.js | 25 ++++ 33 files changed, 1187 insertions(+), 4 deletions(-) create mode 100644 components/Vercel.js create mode 100644 themes/nobelium/Layout404.js create mode 100644 themes/nobelium/LayoutArchive.js create mode 100644 themes/nobelium/LayoutBase.js create mode 100644 themes/nobelium/LayoutCategory.js create mode 100644 themes/nobelium/LayoutCategoryIndex.js create mode 100644 themes/nobelium/LayoutIndex.js create mode 100644 themes/nobelium/LayoutPage.js create mode 100644 themes/nobelium/LayoutSearch.js create mode 100644 themes/nobelium/LayoutSlug.js create mode 100644 themes/nobelium/LayoutTag.js create mode 100644 themes/nobelium/LayoutTagIndex.js create mode 100644 themes/nobelium/components/ArticleFooter.js create mode 100644 themes/nobelium/components/ArticleInfo.js create mode 100644 themes/nobelium/components/ArticleLock.js create mode 100644 themes/nobelium/components/BlogListPage.js create mode 100644 themes/nobelium/components/BlogListScroll.js create mode 100644 themes/nobelium/components/BlogPost.js create mode 100644 themes/nobelium/components/ExampleRecentComments.js create mode 100644 themes/nobelium/components/Footer.js create mode 100644 themes/nobelium/components/Header.js create mode 100644 themes/nobelium/components/JumpToTopButton.js create mode 100644 themes/nobelium/components/Nav.js create mode 100644 themes/nobelium/components/SearchInput.js create mode 100644 themes/nobelium/components/SideBar.js create mode 100644 themes/nobelium/components/TagItem.js create mode 100644 themes/nobelium/components/Tags.js create mode 100644 themes/nobelium/components/Title.js create mode 100644 themes/nobelium/config_nobelium.js create mode 100644 themes/nobelium/index.js diff --git a/.env.local b/.env.local index 7b9c9266..92dfcd73 100644 --- a/.env.local +++ b/.env.local @@ -1,2 +1,27 @@ # 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables -NEXT_PUBLIC_VERSION=3.6.8 \ No newline at end of file +NEXT_PUBLIC_VERSION=3.6.8 + + + +NEXT_PUBLIC_WALINE_SERVER_URL=https://waline.tangly1024.com/ +NEXT_PUBLIC_NOTION_PROPERTY_PASSWORD=密码 +NEXT_PUBLIC_NOTION_PROPERTY_TYPE=类型 +NEXT_PUBLIC_NOTION_PROPERTY_TITLE=标题 +NEXT_PUBLIC_NOTION_PROPERTY_STATUS=状态 +NEXT_PUBLIC_NOTION_PROPERTY_SUMMARY=摘要 +NEXT_PUBLIC_NOTION_PROPERTY_SLUG=链接 +NEXT_PUBLIC_NOTION_PROPERTY_CATEGORY=分类 +NEXT_PUBLIC_NOTION_PROPERTY_DATE=日期 +NEXT_PUBLIC_NOTION_PROPERTY_TAGS=标签 +NEXT_PUBLIC_NOTION_PROPERTY_ICON=图标 +NOTION_PAGE_ID=29d5a78b858e4a3bbc13e51b5400fb82 +#影院前线NOTION_PAGE_ID=c7c08fdeb087414584a7912b92081c75 +NEXT_PUBLIC_THEME_SWITCH=true +NEXT_PUBLIC_WALINE_SERVER_URL=https://preview-waline.tangly1024.com +NEXT_PUBLIC_WALINE_RECENT=true +NEXT_PUBLIC_THEME=medium +#VERCEL_ENV=production +ENABLE_CACHE=true + + +NEXT_PUBLIC_COMMENT_ENV_ID=https://twikoo.tangly1024.com \ No newline at end of file diff --git a/components/Vercel.js b/components/Vercel.js new file mode 100644 index 00000000..c7013fe1 --- /dev/null +++ b/components/Vercel.js @@ -0,0 +1,42 @@ +const Vercel = () => { + return ( + + + + + + + + + + + + + + + + ) +} + +export default Vercel diff --git a/styles/globals.css b/styles/globals.css index f2f180e8..d7b7ed75 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -197,4 +197,12 @@ nav { -webkit-box-orient: vertical; word-wrap: break-word; word-break: break-all; -} \ No newline at end of file +} + +.nobelium{ + @apply flex flex-col justify-between +} + +.nobelium .notion-code{ + @apply max-w-2xl; +} diff --git a/themes/index.js b/themes/index.js index e13cd4b3..f8540101 100644 --- a/themes/index.js +++ b/themes/index.js @@ -5,7 +5,8 @@ import * as next from './next' import * as fukasawa from './fukasawa' import * as hexo from './hexo' import * as medium from './medium' +import * as nobelium from './nobelium' import * as example from './example' -export const ALL_THEME = ['hexo', 'next', 'medium', 'fukasawa', 'example'] -export { hexo, next, medium, fukasawa, example } +export const ALL_THEME = ['hexo', 'next', 'medium', 'fukasawa', 'nobelium', 'example'] +export { hexo, next, medium, fukasawa, nobelium, example } diff --git a/themes/nobelium/Layout404.js b/themes/nobelium/Layout404.js new file mode 100644 index 00000000..5f92f0cc --- /dev/null +++ b/themes/nobelium/Layout404.js @@ -0,0 +1,7 @@ +import LayoutBase from './LayoutBase' + +export const Layout404 = (props) => { + return + 404 Not found. + +} diff --git a/themes/nobelium/LayoutArchive.js b/themes/nobelium/LayoutArchive.js new file mode 100644 index 00000000..b85860e0 --- /dev/null +++ b/themes/nobelium/LayoutArchive.js @@ -0,0 +1,62 @@ +import BLOG from '@/blog.config' +import Link from 'next/link' +import LayoutBase from './LayoutBase' + +export const LayoutArchive = props => { + const { posts } = props + const postsSortByDate = Object.create(posts) + + postsSortByDate.sort((a, b) => { + const dateA = new Date(a?.date?.start_date || a.createdTime) + const dateB = new Date(b?.date?.start_date || b.createdTime) + return dateB - dateA + }) + + const archivePosts = {} + + postsSortByDate.forEach(post => { + const date = post.date?.start_date.slice(0, 7) + if (archivePosts[date]) { + archivePosts[date].push(post) + } else { + archivePosts[date] = [post] + } + }) + return ( + +
+ {Object.keys(archivePosts).map(archiveTitle => ( +
+
+ {archiveTitle} +
+ +
    + {archivePosts[archiveTitle].map(post => ( +
  • +
    + + {post.date?.start_date} + {' '} +   + + + {post.title} + + +
    +
  • + ))} +
+
+ ))} +
+
+ ) +} diff --git a/themes/nobelium/LayoutBase.js b/themes/nobelium/LayoutBase.js new file mode 100644 index 00000000..245705b0 --- /dev/null +++ b/themes/nobelium/LayoutBase.js @@ -0,0 +1,41 @@ +import CommonHead from '@/components/CommonHead' +import React from 'react' +import Header from './components/Header' +import { Footer } from './components/Footer' +import JumpToTopButton from './components/JumpToTopButton' +/** + * 基础布局 采用左右两侧布局,移动端使用顶部导航栏 + + * @returns {JSX.Element} + * @constructor + */ +const LayoutBase = props => { + const { children, meta, post } = props + + const fullWidth = post?.fullWidth ?? false + + return ( +
+ + + {/* 顶栏LOGO */} +
+ +
+ + {children} + +
+ +
+ +
+ +
+
+ ) +} + +export default LayoutBase diff --git a/themes/nobelium/LayoutCategory.js b/themes/nobelium/LayoutCategory.js new file mode 100644 index 00000000..6d819185 --- /dev/null +++ b/themes/nobelium/LayoutCategory.js @@ -0,0 +1,10 @@ +import BLOG from '@/blog.config' +import { BlogListPage } from './components/BlogListPage' +import { BlogListScroll } from './components/BlogListScroll' +import LayoutBase from './LayoutBase' + +export const LayoutCategory = props => { + return + {BLOG.POST_LIST_STYLE === 'page' ? : } + +} diff --git a/themes/nobelium/LayoutCategoryIndex.js b/themes/nobelium/LayoutCategoryIndex.js new file mode 100644 index 00000000..28b98b6e --- /dev/null +++ b/themes/nobelium/LayoutCategoryIndex.js @@ -0,0 +1,19 @@ +import Link from 'next/link' +import LayoutBase from './LayoutBase' + +export const LayoutCategoryIndex = (props) => { + const { categories } = props + + return +
+ {categories && categories.map(category => { + return +
+ {category.name}({category.count}) +
+ + })} +
+
+} diff --git a/themes/nobelium/LayoutIndex.js b/themes/nobelium/LayoutIndex.js new file mode 100644 index 00000000..94eaac2f --- /dev/null +++ b/themes/nobelium/LayoutIndex.js @@ -0,0 +1,13 @@ + +import BLOG from '@/blog.config' +import { BlogListPage } from './components/BlogListPage' +import { BlogListScroll } from './components/BlogListScroll' +import LayoutBase from './LayoutBase' + +export const LayoutIndex = props => { + return ( + + {BLOG.POST_LIST_STYLE === 'page' ? : } + + ) +} diff --git a/themes/nobelium/LayoutPage.js b/themes/nobelium/LayoutPage.js new file mode 100644 index 00000000..15355018 --- /dev/null +++ b/themes/nobelium/LayoutPage.js @@ -0,0 +1,10 @@ +import { BlogListPage } from './components/BlogListPage' +import LayoutBase from './LayoutBase' + +export const LayoutPage = props => { + return ( + + + + ) +} diff --git a/themes/nobelium/LayoutSearch.js b/themes/nobelium/LayoutSearch.js new file mode 100644 index 00000000..23b10b7a --- /dev/null +++ b/themes/nobelium/LayoutSearch.js @@ -0,0 +1,54 @@ +import BLOG from '@/blog.config' +import { BlogListPage } from './components/BlogListPage' +import { BlogListScroll } from './components/BlogListScroll' +import { useRouter } from 'next/router' +import { useEffect } from 'react' +import SearchInput from './components/SearchInput' +import Mark from 'mark.js' +import LayoutBase from './LayoutBase' +import { isBrowser } from '@/lib/utils' + +export const LayoutSearch = props => { + const { keyword } = props + const router = useRouter() + + useEffect(() => { + setTimeout(() => { + const container = isBrowser() && document.getElementById('container') + if (container && container.innerHTML) { + const re = new RegExp(keyword, 'gim') + const instance = new Mark(container) + instance.markRegExp(re, { + element: 'span', + className: 'text-red-500 border-b border-dashed' + }) + } + }, 100) + }, [router.events]) + + useEffect(() => { + setTimeout(() => { + if (keyword) { + const targets = document.getElementsByClassName('replace') + for (const container of targets) { + if (container && container.innerHTML) { + const re = new RegExp(`${keyword}`, 'gim') + container.innerHTML = container.innerHTML.replace( + re, + `${keyword}` + ) + } + } + } + }, 100) + }, []) + + return +
+ +
+ + {BLOG.POST_LIST_STYLE === 'page' ? : } + +
+} diff --git a/themes/nobelium/LayoutSlug.js b/themes/nobelium/LayoutSlug.js new file mode 100644 index 00000000..d60062a0 --- /dev/null +++ b/themes/nobelium/LayoutSlug.js @@ -0,0 +1,31 @@ +import LayoutBase from './LayoutBase' +import { ArticleLock } from './components/ArticleLock' +import NotionPage from '@/components/NotionPage' +import { ArticleInfo } from './components/ArticleInfo' +import Comment from '@/components/Comment' +import { ArticleFooter } from './components/ArticleFooter' + +export const LayoutSlug = props => { + const { post, lock, validPassword } = props + + if (!post) { + return + } + + return ( + + + {lock && } + + {!lock &&
+ {post && <> + + + + + } +
} + +
+ ) +} diff --git a/themes/nobelium/LayoutTag.js b/themes/nobelium/LayoutTag.js new file mode 100644 index 00000000..2f0ef119 --- /dev/null +++ b/themes/nobelium/LayoutTag.js @@ -0,0 +1,57 @@ +import React from 'react' +import BlogPost from './components/BlogPost' +import Tags from './components/Tags' +import LayoutBase from './LayoutBase' + +export const LayoutTag = props => { + const { currentTag } = props + const [searchValue, setSearchValue] = React.useState('') + let filteredBlogPosts = [] + const { posts } = props + + if (posts) { + filteredBlogPosts = posts.filter(post => { + const tagContent = post.tags ? post.tags.join(' ') : '' + const searchContent = post.title + post.summary + tagContent + return searchContent.toLowerCase().includes(searchValue.toLowerCase()) + }) + } + + return + +
+ setSearchValue(e.target.value)} + /> + + + +
+ + +
+ {!filteredBlogPosts.length && ( +

No posts found.

+ )} + {filteredBlogPosts.slice(0, 20).map(post => ( + + ))} +
+
+} diff --git a/themes/nobelium/LayoutTagIndex.js b/themes/nobelium/LayoutTagIndex.js new file mode 100644 index 00000000..6a89e168 --- /dev/null +++ b/themes/nobelium/LayoutTagIndex.js @@ -0,0 +1,21 @@ +import Link from 'next/link' +import LayoutBase from './LayoutBase' + +export const LayoutTagIndex = (props) => { + const { tags } = props + return +
+
+ {tags.map(tag => { + return + })} +
+
+} diff --git a/themes/nobelium/components/ArticleFooter.js b/themes/nobelium/components/ArticleFooter.js new file mode 100644 index 00000000..87cf7baf --- /dev/null +++ b/themes/nobelium/components/ArticleFooter.js @@ -0,0 +1,34 @@ +import BLOG from '@/blog.config' +import { useRouter } from 'next/router' +import { useGlobal } from '@/lib/global' + +/** + * 加密文章校验组件 + * @param {password, validPassword} props + * @param password 正确的密码 + * @param validPassword(bool) 回调函数,校验正确回调入参为true + * @returns + */ +export const ArticleFooter = props => { + const router = useRouter() + const { locale } = useGlobal() + + return +} diff --git a/themes/nobelium/components/ArticleInfo.js b/themes/nobelium/components/ArticleInfo.js new file mode 100644 index 00000000..64c1cf8c --- /dev/null +++ b/themes/nobelium/components/ArticleInfo.js @@ -0,0 +1,63 @@ + +import formatDate from '@/lib/formatDate' +import Image from 'next/image' +import BLOG from '@/blog.config' +import TagItem from './TagItem' +import { createHash } from 'crypto' + +export const ArticleInfo = (props) => { + const { post } = props + + const emailHash = createHash('md5') + .update(BLOG.CONTACT_EMAIL) + .digest('hex') + .trim() + .toLowerCase() + + return
+
+ +
+ {post.title} +
+ + {post?.type !== 'Page' && <> + + } + +
+ +
+} diff --git a/themes/nobelium/components/ArticleLock.js b/themes/nobelium/components/ArticleLock.js new file mode 100644 index 00000000..43b6647e --- /dev/null +++ b/themes/nobelium/components/ArticleLock.js @@ -0,0 +1,38 @@ +import { useGlobal } from '@/lib/global' + +/** + * 加密文章校验组件 + * @param {password, validPassword} props + * @param password 正确的密码 + * @param validPassword(bool) 回调函数,校验正确回调入参为true + * @returns + */ +export const ArticleLock = props => { + const { validPassword } = props + const { locale } = useGlobal() + + const submitPassword = () => { + const p = document.getElementById('password') + if (!validPassword(p?.value)) { + const tips = document.getElementById('tips') + if (tips) { + tips.innerHTML = '' + tips.innerHTML = `
${locale.COMMON.PASSWORD_ERROR}
` + } + } + } + + return
+
+
{locale.COMMON.ARTICLE_LOCK_TIPS}
+
+ +
+  {locale.COMMON.SUBMIT} +
+
+
+
+
+
+} diff --git a/themes/nobelium/components/BlogListPage.js b/themes/nobelium/components/BlogListPage.js new file mode 100644 index 00000000..266d14e3 --- /dev/null +++ b/themes/nobelium/components/BlogListPage.js @@ -0,0 +1,44 @@ + +import BLOG from '@/blog.config' +import { useGlobal } from '@/lib/global' +import { useRouter } from 'next/router' +import Link from 'next/link' +import BlogPost from './BlogPost' + +export const BlogListPage = props => { + const { page = 1, posts, postCount } = props + const { locale } = useGlobal() + const router = useRouter() + const totalPage = Math.ceil(postCount / BLOG.POSTS_PER_PAGE) + const currentPage = +page + + const showPrev = currentPage > 1 + const showNext = page < totalPage + const pagePrefix = router.asPath.replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '') + + return
+ +
+ {posts?.map(post => ( + + ))} +
+ + +
+} diff --git a/themes/nobelium/components/BlogListScroll.js b/themes/nobelium/components/BlogListScroll.js new file mode 100644 index 00000000..c9859c0b --- /dev/null +++ b/themes/nobelium/components/BlogListScroll.js @@ -0,0 +1,78 @@ +import BLOG from '@/blog.config' +import { useGlobal } from '@/lib/global' +import Link from 'next/link' +import React from 'react' +import throttle from 'lodash.throttle' + +export const BlogListScroll = props => { + const { posts } = props + const { locale } = useGlobal() + + const [page, updatePage] = React.useState(1) + + let hasMore = false + const postsToShow = posts + ? Object.assign(posts).slice(0, BLOG.POSTS_PER_PAGE * page) + : [] + + if (posts) { + const totalCount = posts.length + hasMore = page * BLOG.POSTS_PER_PAGE < totalCount + } + const handleGetMore = () => { + if (!hasMore) return + updatePage(page + 1) + } + + const targetRef = React.useRef(null) + + // 监听滚动自动分页加载 + const scrollTrigger = React.useCallback(throttle(() => { + const scrollS = window.scrollY + window.outerHeight + const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0 + if (scrollS > clientHeight + 100) { + handleGetMore() + } + }, 500)) + + React.useEffect(() => { + window.addEventListener('scroll', scrollTrigger) + + return () => { + window.removeEventListener('scroll', scrollTrigger) + } + }) + + return
+ {postsToShow.map(p => ( + + ))} + +
+ {' '} + {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '} +
+ +
+} diff --git a/themes/nobelium/components/BlogPost.js b/themes/nobelium/components/BlogPost.js new file mode 100644 index 00000000..b0a99330 --- /dev/null +++ b/themes/nobelium/components/BlogPost.js @@ -0,0 +1,29 @@ +import Link from 'next/link' +import BLOG from '@/blog.config' +import formatDate from '@/lib/formatDate' + +const BlogPost = ({ post }) => { + return ( + + +
+
+

+ {post.title} +

+ +
+
+

+ {post.summary} +

+
+
+
+ + ) +} + +export default BlogPost diff --git a/themes/nobelium/components/ExampleRecentComments.js b/themes/nobelium/components/ExampleRecentComments.js new file mode 100644 index 00000000..e1fe86ca --- /dev/null +++ b/themes/nobelium/components/ExampleRecentComments.js @@ -0,0 +1,35 @@ +import React from 'react' +import BLOG from '@/blog.config' +import Link from 'next/link' +import { RecentComments } from '@waline/client' + +/** + * @see https://waline.js.org/guide/get-started.html + * @param {*} props + * @returns + */ +const ExampleRecentComments = (props) => { + const [comments, updateComments] = React.useState([]) + const [onLoading, changeLoading] = React.useState(true) + React.useEffect(() => { + RecentComments({ + serverURL: BLOG.COMMENT_WALINE_SERVER_URL, + count: 5 + }).then(({ comments }) => { + changeLoading(false) + updateComments(comments) + }) + }, []) + + return <> + {onLoading &&
Loading...
} + {!onLoading && comments && comments.length === 0 &&
No Comments
} + {!onLoading && comments && comments.length > 0 && comments.map((comment) =>
+ )} + + +} + +export default ExampleRecentComments diff --git a/themes/nobelium/components/Footer.js b/themes/nobelium/components/Footer.js new file mode 100644 index 00000000..131a29a6 --- /dev/null +++ b/themes/nobelium/components/Footer.js @@ -0,0 +1,34 @@ +import BLOG from '@/blog.config' +import DarkModeButton from '@/components/DarkModeButton' +import Vercel from '@/components/Vercel' + +export const Footer = (props) => { + const d = new Date() + const currentYear = d.getFullYear() + const { post } = props + const fullWidth = post?.fullWidth ?? false + + const copyrightDate = (function() { + if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) { + return BLOG.SINCE + '-' + currentYear + } + return currentYear + })() + + return
+ +
+
+
+

+ © {BLOG.author} {copyrightDate} +

+ +
+
+
+} diff --git a/themes/nobelium/components/Header.js b/themes/nobelium/components/Header.js new file mode 100644 index 00000000..8d4df936 --- /dev/null +++ b/themes/nobelium/components/Header.js @@ -0,0 +1,128 @@ +import { useEffect, useRef } from 'react' +import Link from 'next/link' +import BLOG from '@/blog.config' +import { useGlobal } from '@/lib/global' + +const NavBar = (props) => { + const { customNav } = props + + const { locale } = useGlobal() + let links = [ + { id: 2, name: locale.NAV.RSS, to: '/feed', show: true }, + { icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: true }, + { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: true }, + { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: false }, + { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: true } + ] + if (customNav) { + links = links.concat(customNav) + } + return ( +
+
    + {links.map( + link => + link.show && ( +
  • + + {link.name} + +
  • + ) + )} +
+
+ ) +} + +const Header = ({ navBarTitle, fullWidth }) => { + const useSticky = !BLOG.autoCollapsedNavBar + const navRef = useRef(null) + const sentinalRef = useRef([]) + const handler = ([entry]) => { + if (navRef && navRef.current && useSticky) { + if (!entry.isIntersecting && entry !== undefined) { + navRef.current?.classList.add('sticky-nav-full') + } else { + navRef.current?.classList.remove('sticky-nav-full') + } + } else { + navRef.current?.classList.add('remove-sticky') + } + } + useEffect(() => { + const obvserver = new window.IntersectionObserver(handler) + obvserver.observe(sentinalRef.current) + // Don't touch this, I have no idea how it works XD + // return () => { + // if (sentinalRef.current) obvserver.unobserve(sentinalRef.current) + // } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [sentinalRef]) + return ( + <> +
+ + + ) +} + +export default Header diff --git a/themes/nobelium/components/JumpToTopButton.js b/themes/nobelium/components/JumpToTopButton.js new file mode 100644 index 00000000..30e684a8 --- /dev/null +++ b/themes/nobelium/components/JumpToTopButton.js @@ -0,0 +1,19 @@ +import { useGlobal } from '@/lib/global' +import React from 'react' + +/** + * 跳转到网页顶部 + * 当屏幕下滑500像素后会出现该控件 + * @param targetRef 关联高度的目标html标签 + * @param showPercent 是否显示百分比 + * @returns {JSX.Element} + * @constructor + */ +const JumpToTopButton = () => { + const { locale } = useGlobal() + return
window.scrollTo({ top: 0, behavior: 'smooth' })} + > +
+} + +export default JumpToTopButton diff --git a/themes/nobelium/components/Nav.js b/themes/nobelium/components/Nav.js new file mode 100644 index 00000000..26610035 --- /dev/null +++ b/themes/nobelium/components/Nav.js @@ -0,0 +1,39 @@ +import { useGlobal } from '@/lib/global' +import Link from 'next/link' + +/** + * 菜单导航 + * @param {*} props + * @returns + */ +export const Nav = (props) => { + const { customNav } = props + const { locale } = useGlobal() + let links = [ + { icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search' }, + { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive' }, + { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category' }, + { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag' } + ] + + if (customNav) { + links = links.concat(customNav) + } + + return +} diff --git a/themes/nobelium/components/SearchInput.js b/themes/nobelium/components/SearchInput.js new file mode 100644 index 00000000..6a95ba01 --- /dev/null +++ b/themes/nobelium/components/SearchInput.js @@ -0,0 +1,87 @@ +import { useRouter } from 'next/router' +import { useGlobal } from '@/lib/global' +import { useImperativeHandle, useRef, useState } from 'react' + +let lock = false + +const SearchInput = ({ currentTag, currentSearch, cRef }) => { + const { locale } = useGlobal() + const router = useRouter() + const searchInputRef = useRef(null) + useImperativeHandle(cRef, () => { + return { + focus: () => { + searchInputRef?.current?.focus() + } + } + }) + const handleSearch = () => { + const key = searchInputRef.current.value + if (key && key !== '') { + router.push({ pathname: '/search/' + key }).then(r => { + console.log('搜索', key) + }) + } else { + router.push({ pathname: '/' }).then(r => { + }) + } + } + const handleKeyUp = (e) => { + if (e.keyCode === 13) { // 回车 + handleSearch(searchInputRef.current.value) + } else if (e.keyCode === 27) { // ESC + cleanSearch() + } + } + const cleanSearch = () => { + searchInputRef.current.value = '' + setShowClean(false) + } + function lockSearchInput () { + lock = true + } + + function unLockSearchInput () { + lock = false + } + const [showClean, setShowClean] = useState(false) + const updateSearchKey = (val) => { + if (lock) { + return + } + searchInputRef.current.value = val + if (val) { + setShowClean(true) + } else { + setShowClean(false) + } + } + + return
+ updateSearchKey(e.target.value)} + defaultValue={currentSearch || ''} + /> + +
+ +
+ + {(showClean && +
+ +
+ )} +
+} + +export default SearchInput diff --git a/themes/nobelium/components/SideBar.js b/themes/nobelium/components/SideBar.js new file mode 100644 index 00000000..ea45f851 --- /dev/null +++ b/themes/nobelium/components/SideBar.js @@ -0,0 +1,55 @@ +import BLOG from '@/blog.config' +import Live2D from '@/components/Live2D' +import { useGlobal } from '@/lib/global' +import Link from 'next/link' +import dynamic from 'next/dynamic' +const ExampleRecentComments = dynamic(() => import('./ExampleRecentComments')) + +export const SideBar = (props) => { + const { locale } = useGlobal() + const { latestPosts, categories } = props + return
+ + + + + + {BLOG.COMMENT_WALINE_SERVER_URL && BLOG.COMMENT_WALINE_RECENT && } + + + +
+} diff --git a/themes/nobelium/components/TagItem.js b/themes/nobelium/components/TagItem.js new file mode 100644 index 00000000..6841f911 --- /dev/null +++ b/themes/nobelium/components/TagItem.js @@ -0,0 +1,13 @@ +import Link from 'next/link' + +const TagItem = ({ tag }) => ( + + +

+ {tag} +

+
+ +) + +export default TagItem diff --git a/themes/nobelium/components/Tags.js b/themes/nobelium/components/Tags.js new file mode 100644 index 00000000..4555bfae --- /dev/null +++ b/themes/nobelium/components/Tags.js @@ -0,0 +1,38 @@ +import Link from 'next/link' + +const Tags = (props) => { + const { tags, tag } = props + const currentTag = tag + if (!tags) return null + return ( +
+ +
+ ) +} + +export default Tags diff --git a/themes/nobelium/components/Title.js b/themes/nobelium/components/Title.js new file mode 100644 index 00000000..e57e2347 --- /dev/null +++ b/themes/nobelium/components/Title.js @@ -0,0 +1,19 @@ +import BLOG from '@/blog.config' + +/** + * 标题栏 + * @param {*} props + * @returns + */ +export const Title = (props) => { + const { siteInfo, post } = props + const title = post?.title || siteInfo?.description + const description = post?.description || BLOG.AUTHOR + + return
+

{title}

+

+ {description} +

+
+} diff --git a/themes/nobelium/config_nobelium.js b/themes/nobelium/config_nobelium.js new file mode 100644 index 00000000..9f1ac567 --- /dev/null +++ b/themes/nobelium/config_nobelium.js @@ -0,0 +1,4 @@ +const CONFIG_EMPTY = { + TEST_CONFIG: 'TESET' +} +export default CONFIG_EMPTY diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js new file mode 100644 index 00000000..4e36cdf9 --- /dev/null +++ b/themes/nobelium/index.js @@ -0,0 +1,25 @@ +import CONFIG_EMPTY from './config_nobelium' +import { LayoutIndex } from './LayoutIndex' +import { LayoutSearch } from './LayoutSearch' +import { LayoutArchive } from './LayoutArchive' +import { LayoutSlug } from './LayoutSlug' +import { Layout404 } from './Layout404' +import { LayoutCategory } from './LayoutCategory' +import { LayoutCategoryIndex } from './LayoutCategoryIndex' +import { LayoutPage } from './LayoutPage' +import { LayoutTag } from './LayoutTag' +import { LayoutTagIndex } from './LayoutTagIndex' + +export { + CONFIG_EMPTY as THEME_CONFIG, + LayoutIndex, + LayoutSearch, + LayoutArchive, + LayoutSlug, + Layout404, + LayoutCategory, + LayoutCategoryIndex, + LayoutPage, + LayoutTag, + LayoutTagIndex +} From e9fc7b9ea362e39ba27cf6ff2b9c567abad950a3 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 19:07:36 +0800 Subject: [PATCH 05/24] =?UTF-8?q?Nobelium=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Vercel.js | 42 ++++++ styles/globals.css | 10 +- themes/index.js | 5 +- themes/nobelium/Layout404.js | 7 + themes/nobelium/LayoutArchive.js | 62 +++++++++ themes/nobelium/LayoutBase.js | 41 ++++++ themes/nobelium/LayoutCategory.js | 10 ++ themes/nobelium/LayoutCategoryIndex.js | 19 +++ themes/nobelium/LayoutIndex.js | 13 ++ themes/nobelium/LayoutPage.js | 10 ++ themes/nobelium/LayoutSearch.js | 54 ++++++++ themes/nobelium/LayoutSlug.js | 31 +++++ themes/nobelium/LayoutTag.js | 57 ++++++++ themes/nobelium/LayoutTagIndex.js | 21 +++ themes/nobelium/components/ArticleFooter.js | 34 +++++ themes/nobelium/components/ArticleInfo.js | 63 +++++++++ themes/nobelium/components/ArticleLock.js | 38 ++++++ themes/nobelium/components/BlogListPage.js | 44 ++++++ themes/nobelium/components/BlogListScroll.js | 78 +++++++++++ themes/nobelium/components/BlogPost.js | 29 ++++ .../components/ExampleRecentComments.js | 35 +++++ themes/nobelium/components/Footer.js | 34 +++++ themes/nobelium/components/Header.js | 128 ++++++++++++++++++ themes/nobelium/components/JumpToTopButton.js | 19 +++ themes/nobelium/components/Nav.js | 39 ++++++ themes/nobelium/components/SearchInput.js | 87 ++++++++++++ themes/nobelium/components/SideBar.js | 55 ++++++++ themes/nobelium/components/TagItem.js | 13 ++ themes/nobelium/components/Tags.js | 38 ++++++ themes/nobelium/components/Title.js | 19 +++ themes/nobelium/config_nobelium.js | 4 + themes/nobelium/index.js | 25 ++++ 32 files changed, 1161 insertions(+), 3 deletions(-) create mode 100644 components/Vercel.js create mode 100644 themes/nobelium/Layout404.js create mode 100644 themes/nobelium/LayoutArchive.js create mode 100644 themes/nobelium/LayoutBase.js create mode 100644 themes/nobelium/LayoutCategory.js create mode 100644 themes/nobelium/LayoutCategoryIndex.js create mode 100644 themes/nobelium/LayoutIndex.js create mode 100644 themes/nobelium/LayoutPage.js create mode 100644 themes/nobelium/LayoutSearch.js create mode 100644 themes/nobelium/LayoutSlug.js create mode 100644 themes/nobelium/LayoutTag.js create mode 100644 themes/nobelium/LayoutTagIndex.js create mode 100644 themes/nobelium/components/ArticleFooter.js create mode 100644 themes/nobelium/components/ArticleInfo.js create mode 100644 themes/nobelium/components/ArticleLock.js create mode 100644 themes/nobelium/components/BlogListPage.js create mode 100644 themes/nobelium/components/BlogListScroll.js create mode 100644 themes/nobelium/components/BlogPost.js create mode 100644 themes/nobelium/components/ExampleRecentComments.js create mode 100644 themes/nobelium/components/Footer.js create mode 100644 themes/nobelium/components/Header.js create mode 100644 themes/nobelium/components/JumpToTopButton.js create mode 100644 themes/nobelium/components/Nav.js create mode 100644 themes/nobelium/components/SearchInput.js create mode 100644 themes/nobelium/components/SideBar.js create mode 100644 themes/nobelium/components/TagItem.js create mode 100644 themes/nobelium/components/Tags.js create mode 100644 themes/nobelium/components/Title.js create mode 100644 themes/nobelium/config_nobelium.js create mode 100644 themes/nobelium/index.js diff --git a/components/Vercel.js b/components/Vercel.js new file mode 100644 index 00000000..c7013fe1 --- /dev/null +++ b/components/Vercel.js @@ -0,0 +1,42 @@ +const Vercel = () => { + return ( + + + + + + + + + + + + + + + + ) +} + +export default Vercel diff --git a/styles/globals.css b/styles/globals.css index f2f180e8..d7b7ed75 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -197,4 +197,12 @@ nav { -webkit-box-orient: vertical; word-wrap: break-word; word-break: break-all; -} \ No newline at end of file +} + +.nobelium{ + @apply flex flex-col justify-between +} + +.nobelium .notion-code{ + @apply max-w-2xl; +} diff --git a/themes/index.js b/themes/index.js index e13cd4b3..f8540101 100644 --- a/themes/index.js +++ b/themes/index.js @@ -5,7 +5,8 @@ import * as next from './next' import * as fukasawa from './fukasawa' import * as hexo from './hexo' import * as medium from './medium' +import * as nobelium from './nobelium' import * as example from './example' -export const ALL_THEME = ['hexo', 'next', 'medium', 'fukasawa', 'example'] -export { hexo, next, medium, fukasawa, example } +export const ALL_THEME = ['hexo', 'next', 'medium', 'fukasawa', 'nobelium', 'example'] +export { hexo, next, medium, fukasawa, nobelium, example } diff --git a/themes/nobelium/Layout404.js b/themes/nobelium/Layout404.js new file mode 100644 index 00000000..5f92f0cc --- /dev/null +++ b/themes/nobelium/Layout404.js @@ -0,0 +1,7 @@ +import LayoutBase from './LayoutBase' + +export const Layout404 = (props) => { + return + 404 Not found. + +} diff --git a/themes/nobelium/LayoutArchive.js b/themes/nobelium/LayoutArchive.js new file mode 100644 index 00000000..b85860e0 --- /dev/null +++ b/themes/nobelium/LayoutArchive.js @@ -0,0 +1,62 @@ +import BLOG from '@/blog.config' +import Link from 'next/link' +import LayoutBase from './LayoutBase' + +export const LayoutArchive = props => { + const { posts } = props + const postsSortByDate = Object.create(posts) + + postsSortByDate.sort((a, b) => { + const dateA = new Date(a?.date?.start_date || a.createdTime) + const dateB = new Date(b?.date?.start_date || b.createdTime) + return dateB - dateA + }) + + const archivePosts = {} + + postsSortByDate.forEach(post => { + const date = post.date?.start_date.slice(0, 7) + if (archivePosts[date]) { + archivePosts[date].push(post) + } else { + archivePosts[date] = [post] + } + }) + return ( + +
+ {Object.keys(archivePosts).map(archiveTitle => ( +
+
+ {archiveTitle} +
+ +
    + {archivePosts[archiveTitle].map(post => ( +
  • +
    + + {post.date?.start_date} + {' '} +   + + + {post.title} + + +
    +
  • + ))} +
+
+ ))} +
+
+ ) +} diff --git a/themes/nobelium/LayoutBase.js b/themes/nobelium/LayoutBase.js new file mode 100644 index 00000000..245705b0 --- /dev/null +++ b/themes/nobelium/LayoutBase.js @@ -0,0 +1,41 @@ +import CommonHead from '@/components/CommonHead' +import React from 'react' +import Header from './components/Header' +import { Footer } from './components/Footer' +import JumpToTopButton from './components/JumpToTopButton' +/** + * 基础布局 采用左右两侧布局,移动端使用顶部导航栏 + + * @returns {JSX.Element} + * @constructor + */ +const LayoutBase = props => { + const { children, meta, post } = props + + const fullWidth = post?.fullWidth ?? false + + return ( +
+ + + {/* 顶栏LOGO */} +
+ +
+ + {children} + +
+ +
+ +
+ +
+
+ ) +} + +export default LayoutBase diff --git a/themes/nobelium/LayoutCategory.js b/themes/nobelium/LayoutCategory.js new file mode 100644 index 00000000..6d819185 --- /dev/null +++ b/themes/nobelium/LayoutCategory.js @@ -0,0 +1,10 @@ +import BLOG from '@/blog.config' +import { BlogListPage } from './components/BlogListPage' +import { BlogListScroll } from './components/BlogListScroll' +import LayoutBase from './LayoutBase' + +export const LayoutCategory = props => { + return + {BLOG.POST_LIST_STYLE === 'page' ? : } + +} diff --git a/themes/nobelium/LayoutCategoryIndex.js b/themes/nobelium/LayoutCategoryIndex.js new file mode 100644 index 00000000..28b98b6e --- /dev/null +++ b/themes/nobelium/LayoutCategoryIndex.js @@ -0,0 +1,19 @@ +import Link from 'next/link' +import LayoutBase from './LayoutBase' + +export const LayoutCategoryIndex = (props) => { + const { categories } = props + + return +
+ {categories && categories.map(category => { + return +
+ {category.name}({category.count}) +
+ + })} +
+
+} diff --git a/themes/nobelium/LayoutIndex.js b/themes/nobelium/LayoutIndex.js new file mode 100644 index 00000000..94eaac2f --- /dev/null +++ b/themes/nobelium/LayoutIndex.js @@ -0,0 +1,13 @@ + +import BLOG from '@/blog.config' +import { BlogListPage } from './components/BlogListPage' +import { BlogListScroll } from './components/BlogListScroll' +import LayoutBase from './LayoutBase' + +export const LayoutIndex = props => { + return ( + + {BLOG.POST_LIST_STYLE === 'page' ? : } + + ) +} diff --git a/themes/nobelium/LayoutPage.js b/themes/nobelium/LayoutPage.js new file mode 100644 index 00000000..15355018 --- /dev/null +++ b/themes/nobelium/LayoutPage.js @@ -0,0 +1,10 @@ +import { BlogListPage } from './components/BlogListPage' +import LayoutBase from './LayoutBase' + +export const LayoutPage = props => { + return ( + + + + ) +} diff --git a/themes/nobelium/LayoutSearch.js b/themes/nobelium/LayoutSearch.js new file mode 100644 index 00000000..23b10b7a --- /dev/null +++ b/themes/nobelium/LayoutSearch.js @@ -0,0 +1,54 @@ +import BLOG from '@/blog.config' +import { BlogListPage } from './components/BlogListPage' +import { BlogListScroll } from './components/BlogListScroll' +import { useRouter } from 'next/router' +import { useEffect } from 'react' +import SearchInput from './components/SearchInput' +import Mark from 'mark.js' +import LayoutBase from './LayoutBase' +import { isBrowser } from '@/lib/utils' + +export const LayoutSearch = props => { + const { keyword } = props + const router = useRouter() + + useEffect(() => { + setTimeout(() => { + const container = isBrowser() && document.getElementById('container') + if (container && container.innerHTML) { + const re = new RegExp(keyword, 'gim') + const instance = new Mark(container) + instance.markRegExp(re, { + element: 'span', + className: 'text-red-500 border-b border-dashed' + }) + } + }, 100) + }, [router.events]) + + useEffect(() => { + setTimeout(() => { + if (keyword) { + const targets = document.getElementsByClassName('replace') + for (const container of targets) { + if (container && container.innerHTML) { + const re = new RegExp(`${keyword}`, 'gim') + container.innerHTML = container.innerHTML.replace( + re, + `${keyword}` + ) + } + } + } + }, 100) + }, []) + + return +
+ +
+ + {BLOG.POST_LIST_STYLE === 'page' ? : } + +
+} diff --git a/themes/nobelium/LayoutSlug.js b/themes/nobelium/LayoutSlug.js new file mode 100644 index 00000000..d60062a0 --- /dev/null +++ b/themes/nobelium/LayoutSlug.js @@ -0,0 +1,31 @@ +import LayoutBase from './LayoutBase' +import { ArticleLock } from './components/ArticleLock' +import NotionPage from '@/components/NotionPage' +import { ArticleInfo } from './components/ArticleInfo' +import Comment from '@/components/Comment' +import { ArticleFooter } from './components/ArticleFooter' + +export const LayoutSlug = props => { + const { post, lock, validPassword } = props + + if (!post) { + return + } + + return ( + + + {lock && } + + {!lock &&
+ {post && <> + + + + + } +
} + +
+ ) +} diff --git a/themes/nobelium/LayoutTag.js b/themes/nobelium/LayoutTag.js new file mode 100644 index 00000000..2f0ef119 --- /dev/null +++ b/themes/nobelium/LayoutTag.js @@ -0,0 +1,57 @@ +import React from 'react' +import BlogPost from './components/BlogPost' +import Tags from './components/Tags' +import LayoutBase from './LayoutBase' + +export const LayoutTag = props => { + const { currentTag } = props + const [searchValue, setSearchValue] = React.useState('') + let filteredBlogPosts = [] + const { posts } = props + + if (posts) { + filteredBlogPosts = posts.filter(post => { + const tagContent = post.tags ? post.tags.join(' ') : '' + const searchContent = post.title + post.summary + tagContent + return searchContent.toLowerCase().includes(searchValue.toLowerCase()) + }) + } + + return + +
+ setSearchValue(e.target.value)} + /> + + + +
+ + +
+ {!filteredBlogPosts.length && ( +

No posts found.

+ )} + {filteredBlogPosts.slice(0, 20).map(post => ( + + ))} +
+
+} diff --git a/themes/nobelium/LayoutTagIndex.js b/themes/nobelium/LayoutTagIndex.js new file mode 100644 index 00000000..6a89e168 --- /dev/null +++ b/themes/nobelium/LayoutTagIndex.js @@ -0,0 +1,21 @@ +import Link from 'next/link' +import LayoutBase from './LayoutBase' + +export const LayoutTagIndex = (props) => { + const { tags } = props + return +
+
+ {tags.map(tag => { + return + })} +
+
+} diff --git a/themes/nobelium/components/ArticleFooter.js b/themes/nobelium/components/ArticleFooter.js new file mode 100644 index 00000000..87cf7baf --- /dev/null +++ b/themes/nobelium/components/ArticleFooter.js @@ -0,0 +1,34 @@ +import BLOG from '@/blog.config' +import { useRouter } from 'next/router' +import { useGlobal } from '@/lib/global' + +/** + * 加密文章校验组件 + * @param {password, validPassword} props + * @param password 正确的密码 + * @param validPassword(bool) 回调函数,校验正确回调入参为true + * @returns + */ +export const ArticleFooter = props => { + const router = useRouter() + const { locale } = useGlobal() + + return +} diff --git a/themes/nobelium/components/ArticleInfo.js b/themes/nobelium/components/ArticleInfo.js new file mode 100644 index 00000000..64c1cf8c --- /dev/null +++ b/themes/nobelium/components/ArticleInfo.js @@ -0,0 +1,63 @@ + +import formatDate from '@/lib/formatDate' +import Image from 'next/image' +import BLOG from '@/blog.config' +import TagItem from './TagItem' +import { createHash } from 'crypto' + +export const ArticleInfo = (props) => { + const { post } = props + + const emailHash = createHash('md5') + .update(BLOG.CONTACT_EMAIL) + .digest('hex') + .trim() + .toLowerCase() + + return
+
+ +
+ {post.title} +
+ + {post?.type !== 'Page' && <> + + } + +
+ +
+} diff --git a/themes/nobelium/components/ArticleLock.js b/themes/nobelium/components/ArticleLock.js new file mode 100644 index 00000000..43b6647e --- /dev/null +++ b/themes/nobelium/components/ArticleLock.js @@ -0,0 +1,38 @@ +import { useGlobal } from '@/lib/global' + +/** + * 加密文章校验组件 + * @param {password, validPassword} props + * @param password 正确的密码 + * @param validPassword(bool) 回调函数,校验正确回调入参为true + * @returns + */ +export const ArticleLock = props => { + const { validPassword } = props + const { locale } = useGlobal() + + const submitPassword = () => { + const p = document.getElementById('password') + if (!validPassword(p?.value)) { + const tips = document.getElementById('tips') + if (tips) { + tips.innerHTML = '' + tips.innerHTML = `
${locale.COMMON.PASSWORD_ERROR}
` + } + } + } + + return
+
+
{locale.COMMON.ARTICLE_LOCK_TIPS}
+
+ +
+  {locale.COMMON.SUBMIT} +
+
+
+
+
+
+} diff --git a/themes/nobelium/components/BlogListPage.js b/themes/nobelium/components/BlogListPage.js new file mode 100644 index 00000000..266d14e3 --- /dev/null +++ b/themes/nobelium/components/BlogListPage.js @@ -0,0 +1,44 @@ + +import BLOG from '@/blog.config' +import { useGlobal } from '@/lib/global' +import { useRouter } from 'next/router' +import Link from 'next/link' +import BlogPost from './BlogPost' + +export const BlogListPage = props => { + const { page = 1, posts, postCount } = props + const { locale } = useGlobal() + const router = useRouter() + const totalPage = Math.ceil(postCount / BLOG.POSTS_PER_PAGE) + const currentPage = +page + + const showPrev = currentPage > 1 + const showNext = page < totalPage + const pagePrefix = router.asPath.replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '') + + return
+ +
+ {posts?.map(post => ( + + ))} +
+ + +
+} diff --git a/themes/nobelium/components/BlogListScroll.js b/themes/nobelium/components/BlogListScroll.js new file mode 100644 index 00000000..c9859c0b --- /dev/null +++ b/themes/nobelium/components/BlogListScroll.js @@ -0,0 +1,78 @@ +import BLOG from '@/blog.config' +import { useGlobal } from '@/lib/global' +import Link from 'next/link' +import React from 'react' +import throttle from 'lodash.throttle' + +export const BlogListScroll = props => { + const { posts } = props + const { locale } = useGlobal() + + const [page, updatePage] = React.useState(1) + + let hasMore = false + const postsToShow = posts + ? Object.assign(posts).slice(0, BLOG.POSTS_PER_PAGE * page) + : [] + + if (posts) { + const totalCount = posts.length + hasMore = page * BLOG.POSTS_PER_PAGE < totalCount + } + const handleGetMore = () => { + if (!hasMore) return + updatePage(page + 1) + } + + const targetRef = React.useRef(null) + + // 监听滚动自动分页加载 + const scrollTrigger = React.useCallback(throttle(() => { + const scrollS = window.scrollY + window.outerHeight + const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0 + if (scrollS > clientHeight + 100) { + handleGetMore() + } + }, 500)) + + React.useEffect(() => { + window.addEventListener('scroll', scrollTrigger) + + return () => { + window.removeEventListener('scroll', scrollTrigger) + } + }) + + return
+ {postsToShow.map(p => ( + + ))} + +
+ {' '} + {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '} +
+ +
+} diff --git a/themes/nobelium/components/BlogPost.js b/themes/nobelium/components/BlogPost.js new file mode 100644 index 00000000..b0a99330 --- /dev/null +++ b/themes/nobelium/components/BlogPost.js @@ -0,0 +1,29 @@ +import Link from 'next/link' +import BLOG from '@/blog.config' +import formatDate from '@/lib/formatDate' + +const BlogPost = ({ post }) => { + return ( + + +
+
+

+ {post.title} +

+ +
+
+

+ {post.summary} +

+
+
+
+ + ) +} + +export default BlogPost diff --git a/themes/nobelium/components/ExampleRecentComments.js b/themes/nobelium/components/ExampleRecentComments.js new file mode 100644 index 00000000..e1fe86ca --- /dev/null +++ b/themes/nobelium/components/ExampleRecentComments.js @@ -0,0 +1,35 @@ +import React from 'react' +import BLOG from '@/blog.config' +import Link from 'next/link' +import { RecentComments } from '@waline/client' + +/** + * @see https://waline.js.org/guide/get-started.html + * @param {*} props + * @returns + */ +const ExampleRecentComments = (props) => { + const [comments, updateComments] = React.useState([]) + const [onLoading, changeLoading] = React.useState(true) + React.useEffect(() => { + RecentComments({ + serverURL: BLOG.COMMENT_WALINE_SERVER_URL, + count: 5 + }).then(({ comments }) => { + changeLoading(false) + updateComments(comments) + }) + }, []) + + return <> + {onLoading &&
Loading...
} + {!onLoading && comments && comments.length === 0 &&
No Comments
} + {!onLoading && comments && comments.length > 0 && comments.map((comment) =>
+ )} + + +} + +export default ExampleRecentComments diff --git a/themes/nobelium/components/Footer.js b/themes/nobelium/components/Footer.js new file mode 100644 index 00000000..131a29a6 --- /dev/null +++ b/themes/nobelium/components/Footer.js @@ -0,0 +1,34 @@ +import BLOG from '@/blog.config' +import DarkModeButton from '@/components/DarkModeButton' +import Vercel from '@/components/Vercel' + +export const Footer = (props) => { + const d = new Date() + const currentYear = d.getFullYear() + const { post } = props + const fullWidth = post?.fullWidth ?? false + + const copyrightDate = (function() { + if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) { + return BLOG.SINCE + '-' + currentYear + } + return currentYear + })() + + return
+ +
+
+
+

+ © {BLOG.author} {copyrightDate} +

+ +
+
+
+} diff --git a/themes/nobelium/components/Header.js b/themes/nobelium/components/Header.js new file mode 100644 index 00000000..8d4df936 --- /dev/null +++ b/themes/nobelium/components/Header.js @@ -0,0 +1,128 @@ +import { useEffect, useRef } from 'react' +import Link from 'next/link' +import BLOG from '@/blog.config' +import { useGlobal } from '@/lib/global' + +const NavBar = (props) => { + const { customNav } = props + + const { locale } = useGlobal() + let links = [ + { id: 2, name: locale.NAV.RSS, to: '/feed', show: true }, + { icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: true }, + { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: true }, + { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: false }, + { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: true } + ] + if (customNav) { + links = links.concat(customNav) + } + return ( +
+
    + {links.map( + link => + link.show && ( +
  • + + {link.name} + +
  • + ) + )} +
+
+ ) +} + +const Header = ({ navBarTitle, fullWidth }) => { + const useSticky = !BLOG.autoCollapsedNavBar + const navRef = useRef(null) + const sentinalRef = useRef([]) + const handler = ([entry]) => { + if (navRef && navRef.current && useSticky) { + if (!entry.isIntersecting && entry !== undefined) { + navRef.current?.classList.add('sticky-nav-full') + } else { + navRef.current?.classList.remove('sticky-nav-full') + } + } else { + navRef.current?.classList.add('remove-sticky') + } + } + useEffect(() => { + const obvserver = new window.IntersectionObserver(handler) + obvserver.observe(sentinalRef.current) + // Don't touch this, I have no idea how it works XD + // return () => { + // if (sentinalRef.current) obvserver.unobserve(sentinalRef.current) + // } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [sentinalRef]) + return ( + <> +
+ + + ) +} + +export default Header diff --git a/themes/nobelium/components/JumpToTopButton.js b/themes/nobelium/components/JumpToTopButton.js new file mode 100644 index 00000000..30e684a8 --- /dev/null +++ b/themes/nobelium/components/JumpToTopButton.js @@ -0,0 +1,19 @@ +import { useGlobal } from '@/lib/global' +import React from 'react' + +/** + * 跳转到网页顶部 + * 当屏幕下滑500像素后会出现该控件 + * @param targetRef 关联高度的目标html标签 + * @param showPercent 是否显示百分比 + * @returns {JSX.Element} + * @constructor + */ +const JumpToTopButton = () => { + const { locale } = useGlobal() + return
window.scrollTo({ top: 0, behavior: 'smooth' })} + > +
+} + +export default JumpToTopButton diff --git a/themes/nobelium/components/Nav.js b/themes/nobelium/components/Nav.js new file mode 100644 index 00000000..26610035 --- /dev/null +++ b/themes/nobelium/components/Nav.js @@ -0,0 +1,39 @@ +import { useGlobal } from '@/lib/global' +import Link from 'next/link' + +/** + * 菜单导航 + * @param {*} props + * @returns + */ +export const Nav = (props) => { + const { customNav } = props + const { locale } = useGlobal() + let links = [ + { icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search' }, + { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive' }, + { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category' }, + { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag' } + ] + + if (customNav) { + links = links.concat(customNav) + } + + return +} diff --git a/themes/nobelium/components/SearchInput.js b/themes/nobelium/components/SearchInput.js new file mode 100644 index 00000000..6a95ba01 --- /dev/null +++ b/themes/nobelium/components/SearchInput.js @@ -0,0 +1,87 @@ +import { useRouter } from 'next/router' +import { useGlobal } from '@/lib/global' +import { useImperativeHandle, useRef, useState } from 'react' + +let lock = false + +const SearchInput = ({ currentTag, currentSearch, cRef }) => { + const { locale } = useGlobal() + const router = useRouter() + const searchInputRef = useRef(null) + useImperativeHandle(cRef, () => { + return { + focus: () => { + searchInputRef?.current?.focus() + } + } + }) + const handleSearch = () => { + const key = searchInputRef.current.value + if (key && key !== '') { + router.push({ pathname: '/search/' + key }).then(r => { + console.log('搜索', key) + }) + } else { + router.push({ pathname: '/' }).then(r => { + }) + } + } + const handleKeyUp = (e) => { + if (e.keyCode === 13) { // 回车 + handleSearch(searchInputRef.current.value) + } else if (e.keyCode === 27) { // ESC + cleanSearch() + } + } + const cleanSearch = () => { + searchInputRef.current.value = '' + setShowClean(false) + } + function lockSearchInput () { + lock = true + } + + function unLockSearchInput () { + lock = false + } + const [showClean, setShowClean] = useState(false) + const updateSearchKey = (val) => { + if (lock) { + return + } + searchInputRef.current.value = val + if (val) { + setShowClean(true) + } else { + setShowClean(false) + } + } + + return
+ updateSearchKey(e.target.value)} + defaultValue={currentSearch || ''} + /> + +
+ +
+ + {(showClean && +
+ +
+ )} +
+} + +export default SearchInput diff --git a/themes/nobelium/components/SideBar.js b/themes/nobelium/components/SideBar.js new file mode 100644 index 00000000..ea45f851 --- /dev/null +++ b/themes/nobelium/components/SideBar.js @@ -0,0 +1,55 @@ +import BLOG from '@/blog.config' +import Live2D from '@/components/Live2D' +import { useGlobal } from '@/lib/global' +import Link from 'next/link' +import dynamic from 'next/dynamic' +const ExampleRecentComments = dynamic(() => import('./ExampleRecentComments')) + +export const SideBar = (props) => { + const { locale } = useGlobal() + const { latestPosts, categories } = props + return
+ + + + + + {BLOG.COMMENT_WALINE_SERVER_URL && BLOG.COMMENT_WALINE_RECENT && } + + + +
+} diff --git a/themes/nobelium/components/TagItem.js b/themes/nobelium/components/TagItem.js new file mode 100644 index 00000000..6841f911 --- /dev/null +++ b/themes/nobelium/components/TagItem.js @@ -0,0 +1,13 @@ +import Link from 'next/link' + +const TagItem = ({ tag }) => ( + + +

+ {tag} +

+
+ +) + +export default TagItem diff --git a/themes/nobelium/components/Tags.js b/themes/nobelium/components/Tags.js new file mode 100644 index 00000000..4555bfae --- /dev/null +++ b/themes/nobelium/components/Tags.js @@ -0,0 +1,38 @@ +import Link from 'next/link' + +const Tags = (props) => { + const { tags, tag } = props + const currentTag = tag + if (!tags) return null + return ( +
+ +
+ ) +} + +export default Tags diff --git a/themes/nobelium/components/Title.js b/themes/nobelium/components/Title.js new file mode 100644 index 00000000..e57e2347 --- /dev/null +++ b/themes/nobelium/components/Title.js @@ -0,0 +1,19 @@ +import BLOG from '@/blog.config' + +/** + * 标题栏 + * @param {*} props + * @returns + */ +export const Title = (props) => { + const { siteInfo, post } = props + const title = post?.title || siteInfo?.description + const description = post?.description || BLOG.AUTHOR + + return
+

{title}

+

+ {description} +

+
+} diff --git a/themes/nobelium/config_nobelium.js b/themes/nobelium/config_nobelium.js new file mode 100644 index 00000000..9f1ac567 --- /dev/null +++ b/themes/nobelium/config_nobelium.js @@ -0,0 +1,4 @@ +const CONFIG_EMPTY = { + TEST_CONFIG: 'TESET' +} +export default CONFIG_EMPTY diff --git a/themes/nobelium/index.js b/themes/nobelium/index.js new file mode 100644 index 00000000..4e36cdf9 --- /dev/null +++ b/themes/nobelium/index.js @@ -0,0 +1,25 @@ +import CONFIG_EMPTY from './config_nobelium' +import { LayoutIndex } from './LayoutIndex' +import { LayoutSearch } from './LayoutSearch' +import { LayoutArchive } from './LayoutArchive' +import { LayoutSlug } from './LayoutSlug' +import { Layout404 } from './Layout404' +import { LayoutCategory } from './LayoutCategory' +import { LayoutCategoryIndex } from './LayoutCategoryIndex' +import { LayoutPage } from './LayoutPage' +import { LayoutTag } from './LayoutTag' +import { LayoutTagIndex } from './LayoutTagIndex' + +export { + CONFIG_EMPTY as THEME_CONFIG, + LayoutIndex, + LayoutSearch, + LayoutArchive, + LayoutSlug, + Layout404, + LayoutCategory, + LayoutCategoryIndex, + LayoutPage, + LayoutTag, + LayoutTagIndex +} From ef4daf4cf65b442cb01105e7933e9257d7651356 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 19:08:10 +0800 Subject: [PATCH 06/24] =?UTF-8?q?=E4=B8=BB=E9=A2=98=EF=BC=8C=E5=8A=A0?= =?UTF-8?q?=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/notion/getPageProperties.js | 8 ++++++-- package.json | 1 - pages/[...slug].js | 7 +++++-- themes/example/components/ArticleLock.js | 2 +- themes/fukasawa/components/ArticleLock.js | 2 +- themes/hexo/components/ArticleLock.js | 2 +- themes/medium/components/ArticleLock.js | 2 +- themes/next/components/ArticleLock.js | 2 +- 8 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index ef93f84b..52452c52 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -3,7 +3,7 @@ import { NotionAPI } from 'notion-client' import BLOG from '@/blog.config' import formatDate from '../formatDate' import { defaultMapImageUrl } from 'react-notion-x' -import md5 from 'js-md5' +import { createHash } from 'crypto' export default async function getPageProperties(id, block, schema, authToken, tagOptions, siteInfo) { const rawProperties = Object.entries(block?.[id]?.value?.properties || []) @@ -90,7 +90,11 @@ export default async function getPageProperties(id, block, schema, authToken, ta properties.pageIcon = getImageUrl(block[id].value?.format?.page_icon, block[id].value) ?? '' properties.page_cover = getImageUrl(block[id].value?.format?.page_cover, block[id].value) ?? siteInfo?.pageCover properties.content = value.content ?? [] - properties.password = properties.password ? md5(properties.slug + properties.password) : '' + properties.password = properties.password + ? createHash('md5') + .update(properties.slug + properties.password) + .digest('hex').trim().toLowerCase() + : '' properties.tagItems = properties?.tags?.map(tag => { return { name: tag, color: tagOptions?.find(t => t.value === tag)?.color || 'gray' } }) || [] diff --git a/package.json b/package.json index d35fc0a4..ad6de107 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "eslint-plugin-react-hooks": "^4.6.0", "feed": "^4.2.2", "gitalk": "^1.7.2", - "js-md5": "^0.7.3", "localStorage": "^1.0.4", "lodash.throttle": "^4.1.1", "mark.js": "^8.11.1", diff --git a/pages/[...slug].js b/pages/[...slug].js index 6ca98c93..b4e1d47e 100644 --- a/pages/[...slug].js +++ b/pages/[...slug].js @@ -8,8 +8,8 @@ import { idToUuid } from 'notion-utils' import Router from 'next/router' import { isBrowser } from '@/lib/utils' import { getNotion } from '@/lib/notion/getNotion' -import md5 from 'js-md5' import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents' +import { createHash } from 'crypto' /** * 根据notion的slug访问页面 @@ -59,7 +59,10 @@ const Slug = props => { * @param {*} result */ const validPassword = passInput => { - if (passInput && md5(post.slug + passInput) === post.password) { + const encrypt = createHash('md5') + .update(post.slug + passInput) + .digest('hex').trim().toLowerCase() + if (passInput && encrypt === post.password) { setLock(false) return true } diff --git a/themes/example/components/ArticleLock.js b/themes/example/components/ArticleLock.js index 43b6647e..6e90f7b2 100644 --- a/themes/example/components/ArticleLock.js +++ b/themes/example/components/ArticleLock.js @@ -25,7 +25,7 @@ export const ArticleLock = props => { return
{locale.COMMON.ARTICLE_LOCK_TIPS}
-
+
 {locale.COMMON.SUBMIT} diff --git a/themes/fukasawa/components/ArticleLock.js b/themes/fukasawa/components/ArticleLock.js index 8ae18a4e..1dedba16 100644 --- a/themes/fukasawa/components/ArticleLock.js +++ b/themes/fukasawa/components/ArticleLock.js @@ -27,7 +27,7 @@ export const ArticleLock = props => {
{locale.COMMON.ARTICLE_LOCK_TIPS}
-
+
{ return
{locale.COMMON.ARTICLE_LOCK_TIPS}
-
+
 {locale.COMMON.SUBMIT} diff --git a/themes/medium/components/ArticleLock.js b/themes/medium/components/ArticleLock.js index 1e1bb228..aa870ac5 100644 --- a/themes/medium/components/ArticleLock.js +++ b/themes/medium/components/ArticleLock.js @@ -25,7 +25,7 @@ export const ArticleLock = props => { return
{locale.COMMON.ARTICLE_LOCK_TIPS}
-
+
 {locale.COMMON.SUBMIT} diff --git a/themes/next/components/ArticleLock.js b/themes/next/components/ArticleLock.js index 3e4a2019..1f1c6b6b 100644 --- a/themes/next/components/ArticleLock.js +++ b/themes/next/components/ArticleLock.js @@ -27,7 +27,7 @@ export const ArticleLock = props => {
{locale.COMMON.ARTICLE_LOCK_TIPS}
-
+
Date: Sat, 24 Dec 2022 19:13:32 +0800 Subject: [PATCH 07/24] nobelium-author --- themes/nobelium/components/Footer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/nobelium/components/Footer.js b/themes/nobelium/components/Footer.js index 131a29a6..3ba3d2c9 100644 --- a/themes/nobelium/components/Footer.js +++ b/themes/nobelium/components/Footer.js @@ -25,7 +25,7 @@ export const Footer = (props) => {

- © {BLOG.author} {copyrightDate} + © {BLOG.AUTHOR} {copyrightDate}

From ccc49abce90aacc6039164055f8a860b846fd908 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 19:26:38 +0800 Subject: [PATCH 08/24] =?UTF-8?q?fix=20=E9=87=8D=E5=A4=8D=E7=9A=84css?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/next/LayoutBase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/next/LayoutBase.js b/themes/next/LayoutBase.js index e178da0f..f9d2580d 100644 --- a/themes/next/LayoutBase.js +++ b/themes/next/LayoutBase.js @@ -79,7 +79,7 @@ const LayoutBase = (props) => { {/* 右下角悬浮 */} -
+
From 2aea439e1321ceebd9d18e9cd5b836c4b50ebb98 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 20:00:21 +0800 Subject: [PATCH 09/24] =?UTF-8?q?=E5=8D=87=E7=BA=A7tailwindCSS=203.2.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 6 +++--- tailwind.config.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ad6de107..e7b1d90c 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ }, "devDependencies": { "@waline/client": "^2.5.1", - "autoprefixer": "^10.2.5", + "autoprefixer": "^10.4.13", "eslint": "^7.26.0", "eslint-config-next": "^11.0.0", "eslint-config-standard": "^16.0.2", @@ -67,8 +67,8 @@ "eslint-plugin-promise": "^5.1.0", "eslint-plugin-react": "^7.23.2", "next-sitemap": "^1.6.203", - "postcss": "^8.2.15", - "tailwindcss": "^2.1.2", + "postcss": "^8.4.20", + "tailwindcss": "^3.2.4", "webpack-bundle-analyzer": "^4.5.0" }, "resolutions": { diff --git a/tailwind.config.js b/tailwind.config.js index 5079e173..0c5e4a68 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -2,7 +2,7 @@ const BLOG = require('./blog.config') const { fontFamilies } = require('./lib/font') module.exports = { - purge: ['./pages/**/*.js', './components/**/*.js', './layouts/**/*.js', './themes/**/*.js'], + content: ['./pages/**/*.js', './components/**/*.js', './layouts/**/*.js', './themes/**/*.js'], darkMode: BLOG.APPEARANCE === 'class' ? 'media' : 'class', // or 'media' or 'class' theme: { fontFamily: fontFamilies, From b2351f43197b8ea2422ffc73d03a7ee089813439 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 21:58:24 +0800 Subject: [PATCH 10/24] theme-matery --- components/Live2D.js | 18 +- components/SideBarDrawer.js | 19 +-- themes/hexo/components/BlogPostCard.js | 2 +- themes/hexo/components/Card.js | 2 +- themes/hexo/components/TopNav.js | 2 +- themes/index.js | 5 +- themes/matery/Layout404.js | 32 ++++ themes/matery/LayoutArchive.js | 53 ++++++ themes/matery/LayoutBase.js | 87 ++++++++++ themes/matery/LayoutCategory.js | 15 ++ themes/matery/LayoutCategoryIndex.js | 35 ++++ themes/matery/LayoutIndex.js | 13 ++ themes/matery/LayoutPage.js | 9 + themes/matery/LayoutSearch.js | 99 +++++++++++ themes/matery/LayoutSlug.js | 92 ++++++++++ themes/matery/LayoutTag.js | 26 +++ themes/matery/LayoutTagIndex.js | 28 +++ themes/matery/components/AnalyticsCard.js | 30 ++++ themes/matery/components/ArticleAdjacent.js | 25 +++ themes/matery/components/ArticleCopyright.js | 39 +++++ themes/matery/components/ArticleLock.js | 37 ++++ themes/matery/components/ArticleRecommend.js | 66 ++++++++ themes/matery/components/BlogPostArchive.js | 46 +++++ themes/matery/components/BlogPostCard.js | 93 ++++++++++ themes/matery/components/BlogPostListEmpty.js | 14 ++ themes/matery/components/BlogPostListPage.js | 35 ++++ .../matery/components/BlogPostListScroll.js | 74 ++++++++ themes/matery/components/Card.js | 9 + themes/matery/components/Catalog.js | 91 ++++++++++ themes/matery/components/CategoryGroup.js | 25 +++ themes/matery/components/Collapse.js | 75 +++++++++ .../matery/components/FloatDarkModeButton.js | 30 ++++ themes/matery/components/Footer.js | 37 ++++ themes/matery/components/Header.js | 95 +++++++++++ themes/matery/components/HeaderArticle.js | 69 ++++++++ .../matery/components/HexoRecentComments.js | 43 +++++ themes/matery/components/InfoCard.js | 24 +++ .../matery/components/JumpToCommentButton.js | 29 ++++ themes/matery/components/JumpToTopButton.js | 26 +++ themes/matery/components/LatestPostsGroup.js | 66 ++++++++ themes/matery/components/LoadingCover.js | 8 + themes/matery/components/Logo.js | 13 ++ .../matery/components/MenuButtonGroupTop.js | 38 +++++ themes/matery/components/MenuGroupCard.js | 36 ++++ themes/matery/components/MenuList.js | 44 +++++ themes/matery/components/NavButtonGroup.js | 24 +++ themes/matery/components/PaginationNumber.js | 101 +++++++++++ themes/matery/components/PaginationSimple.js | 57 +++++++ themes/matery/components/Progress.js | 44 +++++ themes/matery/components/SearchDrawer.js | 36 ++++ themes/matery/components/SearchInput.js | 106 ++++++++++++ themes/matery/components/SideBar.js | 61 +++++++ themes/matery/components/SideRight.js | 60 +++++++ themes/matery/components/SocialButton.js | 36 ++++ themes/matery/components/TagGroups.js | 27 +++ themes/matery/components/TagItemMini.js | 12 ++ themes/matery/components/TocDrawer.js | 42 +++++ themes/matery/components/TocDrawerButton.js | 22 +++ themes/matery/components/TopNav.js | 159 ++++++++++++++++++ themes/matery/config_matery.js | 28 +++ themes/matery/index.js | 25 +++ themes/nobelium/LayoutBase.js | 6 +- themes/nobelium/components/Header.js | 128 -------------- themes/nobelium/components/Nav.js | 147 ++++++++++++---- themes/nobelium/config_nobelium.js | 4 +- themes/nobelium/index.js | 4 +- 66 files changed, 2694 insertions(+), 189 deletions(-) create mode 100644 themes/matery/Layout404.js create mode 100644 themes/matery/LayoutArchive.js create mode 100644 themes/matery/LayoutBase.js create mode 100644 themes/matery/LayoutCategory.js create mode 100644 themes/matery/LayoutCategoryIndex.js create mode 100644 themes/matery/LayoutIndex.js create mode 100644 themes/matery/LayoutPage.js create mode 100644 themes/matery/LayoutSearch.js create mode 100644 themes/matery/LayoutSlug.js create mode 100644 themes/matery/LayoutTag.js create mode 100644 themes/matery/LayoutTagIndex.js create mode 100644 themes/matery/components/AnalyticsCard.js create mode 100644 themes/matery/components/ArticleAdjacent.js create mode 100644 themes/matery/components/ArticleCopyright.js create mode 100644 themes/matery/components/ArticleLock.js create mode 100644 themes/matery/components/ArticleRecommend.js create mode 100644 themes/matery/components/BlogPostArchive.js create mode 100644 themes/matery/components/BlogPostCard.js create mode 100644 themes/matery/components/BlogPostListEmpty.js create mode 100644 themes/matery/components/BlogPostListPage.js create mode 100644 themes/matery/components/BlogPostListScroll.js create mode 100644 themes/matery/components/Card.js create mode 100644 themes/matery/components/Catalog.js create mode 100644 themes/matery/components/CategoryGroup.js create mode 100644 themes/matery/components/Collapse.js create mode 100644 themes/matery/components/FloatDarkModeButton.js create mode 100644 themes/matery/components/Footer.js create mode 100644 themes/matery/components/Header.js create mode 100644 themes/matery/components/HeaderArticle.js create mode 100644 themes/matery/components/HexoRecentComments.js create mode 100644 themes/matery/components/InfoCard.js create mode 100644 themes/matery/components/JumpToCommentButton.js create mode 100644 themes/matery/components/JumpToTopButton.js create mode 100644 themes/matery/components/LatestPostsGroup.js create mode 100644 themes/matery/components/LoadingCover.js create mode 100644 themes/matery/components/Logo.js create mode 100644 themes/matery/components/MenuButtonGroupTop.js create mode 100644 themes/matery/components/MenuGroupCard.js create mode 100644 themes/matery/components/MenuList.js create mode 100644 themes/matery/components/NavButtonGroup.js create mode 100644 themes/matery/components/PaginationNumber.js create mode 100644 themes/matery/components/PaginationSimple.js create mode 100644 themes/matery/components/Progress.js create mode 100644 themes/matery/components/SearchDrawer.js create mode 100644 themes/matery/components/SearchInput.js create mode 100644 themes/matery/components/SideBar.js create mode 100644 themes/matery/components/SideRight.js create mode 100644 themes/matery/components/SocialButton.js create mode 100644 themes/matery/components/TagGroups.js create mode 100644 themes/matery/components/TagItemMini.js create mode 100644 themes/matery/components/TocDrawer.js create mode 100644 themes/matery/components/TocDrawerButton.js create mode 100644 themes/matery/components/TopNav.js create mode 100644 themes/matery/config_matery.js create mode 100644 themes/matery/index.js delete mode 100644 themes/nobelium/components/Header.js diff --git a/components/Live2D.js b/components/Live2D.js index 2e2011b6..74522cc2 100644 --- a/components/Live2D.js +++ b/components/Live2D.js @@ -36,14 +36,14 @@ function initLive2D() { window.removeEventListener('scroll', initLive2D) setTimeout(() => { // 加载 waifu.css live2d.min.js waifu-tips.js - if (screen.width >= 768) { - Promise.all([ - // loadExternalResource('https://cdn.zhangxinxu.com/sp/demo/live2d/live2d/js/live2d.js', 'js') - loadExternalResource('https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/live2d.min.js', 'js') - ]).then((e) => { - // https://github.com/xiazeyu/live2d-widget-models - loadlive2d('live2d', BLOG.WIDGET_PET_LINK) - }) - } + // if (screen.width >= 768) { + Promise.all([ + // loadExternalResource('https://cdn.zhangxinxu.com/sp/demo/live2d/live2d/js/live2d.js', 'js') + loadExternalResource('https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/live2d.min.js', 'js') + ]).then((e) => { + // https://github.com/xiazeyu/live2d-widget-models + loadlive2d('live2d', BLOG.WIDGET_PET_LINK) + }) + // } }, 300) } diff --git a/components/SideBarDrawer.js b/components/SideBarDrawer.js index ad988503..dac43d75 100644 --- a/components/SideBarDrawer.js +++ b/components/SideBarDrawer.js @@ -9,10 +9,6 @@ import React from 'react' const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => { const router = useRouter() React.useEffect(() => { - // 页面渲染后删除hidden属性 - // const sideBarWrapperElement = document.getElementById('sidebar-wrapper') - // sideBarWrapperElement?.classList?.remove('hidden') - const sideBarDrawerRouteListener = () => { switchSideDrawerVisible(false) } @@ -25,29 +21,30 @@ const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => { // 点击按钮更改侧边抽屉状态 const switchSideDrawerVisible = (showStatus) => { if (showStatus) { - onOpen() + onOpen && onOpen() } else { - onClose() + onClose && onClose() } const sideBarDrawer = window.document.getElementById('sidebar-drawer') const sideBarDrawerBackground = window.document.getElementById('sidebar-drawer-background') if (showStatus) { - sideBarDrawer.classList.replace('-ml-80', 'ml-0') + sideBarDrawer.classList.replace('-ml-56', 'ml-0') sideBarDrawerBackground.classList.replace('hidden', 'block') } else { - sideBarDrawer.classList.replace('ml-0', '-ml-80') + sideBarDrawer.classList.replace('ml-0', '-ml-56') sideBarDrawerBackground.classList.replace('block', 'hidden') } } - return