From e9fc7b9ea362e39ba27cf6ff2b9c567abad950a3 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Sat, 24 Dec 2022 19:07:36 +0800 Subject: [PATCH 1/3] =?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 2/3] =?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 3/3] 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}