mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
封装Layout组件
This commit is contained in:
@@ -73,6 +73,7 @@
|
||||
|
||||
## 页面样式主题
|
||||
- 仿照 [fukasawa](https://andersnoren.se/themes/fukasawa)
|
||||
- 仿照 [youtube](https://youtube.com)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import BlogPostListEmpty from '@/components/BlogPostListEmpty'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListScrollPagination = ({ posts = [], tags, targetRef }) => {
|
||||
const BlogPostListScroll = ({ posts = [], tags }) => {
|
||||
let filteredBlogPosts = posts
|
||||
|
||||
// 处理查询过滤 支持标签、关键词过滤
|
||||
@@ -61,10 +61,12 @@ const BlogPostListScrollPagination = ({ posts = [], tags, targetRef }) => {
|
||||
}
|
||||
})
|
||||
|
||||
const targetRef = useRef(null)
|
||||
|
||||
if (!postsToShow || postsToShow.length === 0) {
|
||||
return <BlogPostListEmpty />
|
||||
} else {
|
||||
return <div id='post-list-wrapper' className='pt-16 md:pt-28 px-2 md:px-20'>
|
||||
return <div id='post-list-wrapper' className='pt-16 md:pt-28 px-2 md:px-20' ref={targetRef}>
|
||||
<div>
|
||||
{/* 文章列表 */}
|
||||
<div className='grid 2xl:grid-cols-4 xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2 grid-cols-1 gap-3'>
|
||||
@@ -100,4 +102,4 @@ const getPostByPage = function (page, totalPosts, postsPerPage) {
|
||||
postsPerPage * page
|
||||
)
|
||||
}
|
||||
export default BlogPostListScrollPagination
|
||||
export default BlogPostListScroll
|
||||
@@ -26,11 +26,11 @@ const DrawerRight = ({ post, cRef }) => {
|
||||
className={(showDrawer ? 'shadow-2xl' : '-mr-72') + ' overflow-y-auto duration-200 w-72 h-full bg-white dark:bg-gray-700 border-r dark:border-gray-600'}>
|
||||
{/* LOGO */}
|
||||
<div className='sticky top-0 z-20 bg-white w-72 flex space-x-4 px-5 py-3.5 dark:border-gray-500 border-b dark:bg-gray-900 '>
|
||||
<div className='flex text-lg justify-center font-bold font-semibold px-2 py-1 duration-200 dark:text-gray-300'>文章目录
|
||||
<div className='text-lg font-bold font-semibold px-2 py-1 duration-200 dark:text-gray-300'>文章目录
|
||||
</div>
|
||||
<div
|
||||
className='z-10 p-1 duration-200 mr-2 absolute right-6 text-gray-600 text-xl cursor-pointer dark:text-gray-300'>
|
||||
<i className='fa hover:scale-125 transform duration-200 fa-bookmark-o ' onClick={handleMenuClick} />
|
||||
<i className='fa hover:scale-125 transform duration-200 fa-bookmark ' onClick={handleMenuClick} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,11 +4,11 @@ import InfoCard from '@/components/InfoCard'
|
||||
import TagList from '@/components/TagList'
|
||||
|
||||
const SideBar = ({ tags, currentTag, post }) => {
|
||||
return <aside className='z-10 dark:border-gray-500 border-gray-200 bg-white hidden md:block'>
|
||||
return <aside className='z-10 dark:border-gray-500 border-gray-200 bg-white hidden lg:block'>
|
||||
<div
|
||||
className='dark:bg-gray-800 border-r dark:border-gray-700 h-full scroll-hidden left-0 duration-500 ease-in-out min-h-screen'>
|
||||
<div id='sidebar' className='hidden md:block sticky top-20 duration-500'>
|
||||
<div className={post ? 'block' : 'hidden xl:block'}>
|
||||
<div >
|
||||
<InfoCard />
|
||||
<hr className='dark:border-gray-700' />
|
||||
<MenuButtonGroup allowCollapse={true} />
|
||||
|
||||
@@ -41,9 +41,11 @@ const TopNav = ({ tags, currentTag, post }) => {
|
||||
{/* 右侧功能 */}
|
||||
<div className='flex flex-nowrap space-x-1'>
|
||||
<DarkModeButton />
|
||||
{post && <div className='block xl:hidden z-10 p-1 duration-200 mr-2 h-12 text-xl cursor-pointer dark:text-gray-300 '>
|
||||
<i className='fa p-2.5 hover:scale-125 transform duration-200 fa-bookmark' onClick={() => { drawerRight.current.handleMenuClick() }}/>
|
||||
</div>}
|
||||
{post && (
|
||||
<div className='block xl:hidden z-10 p-1 duration-200 mr-2 h-12 text-xl cursor-pointer dark:text-gray-300 '>
|
||||
<i className='fa p-2.5 hover:scale-125 transform duration-200 fa-bookmark-o' onClick={() => { drawerRight.current.handleMenuClick() }}/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
import TagItem from '@/components/TagItem'
|
||||
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
|
||||
import BLOG from '@/blog.config'
|
||||
import formatDate from '@/lib/formatDate'
|
||||
import 'gitalk/dist/gitalk.css'
|
||||
import Comment from '@/components/Comment'
|
||||
import Progress from '@/components/Progress'
|
||||
import React, { useRef } from 'react'
|
||||
import Image from 'next/image'
|
||||
import RewardButton from '@/components/RewardButton'
|
||||
import BlogPostMini from '@/components/BlogPostMini'
|
||||
import { useRouter } from 'next/router'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
import SideBar from '@/components/SideBar'
|
||||
import Footer from '@/components/Footer'
|
||||
import Container from '@/components/Container'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import TopNav from '@/components/TopNav'
|
||||
import ShareBar from '@/components/ShareBar'
|
||||
|
||||
const mapPageUrl = id => {
|
||||
return 'https://www.notion.so/' + id.replace(/-/g, '')
|
||||
}
|
||||
|
||||
const ArticleLayout = ({
|
||||
children,
|
||||
blockMap,
|
||||
post,
|
||||
emailHash,
|
||||
fullWidth = true,
|
||||
tags,
|
||||
prev,
|
||||
next
|
||||
}) => {
|
||||
const meta = {
|
||||
title: post.title,
|
||||
description: post.summary,
|
||||
type: 'article'
|
||||
}
|
||||
const targetRef = useRef(null)
|
||||
const url = BLOG.link + useRouter().asPath
|
||||
|
||||
return (
|
||||
<Container meta={meta} tags={tags}>
|
||||
|
||||
{/* live2d 看板娘 */}
|
||||
{/* <script async src='https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js' /> */}
|
||||
|
||||
<Progress targetRef={targetRef} />
|
||||
|
||||
<TopNav tags={tags} post={post} />
|
||||
|
||||
{/* Wrapper */}
|
||||
<div className='flex justify-between bg-gray-100'>
|
||||
|
||||
<SideBar tags={tags} post={post} />
|
||||
|
||||
{/* 主体区块 */}
|
||||
<main className='bg-gray-100 w-full dark:bg-gray-800' ref={targetRef}>
|
||||
{/* 中央区域 wrapper */}
|
||||
<header
|
||||
className='hover:scale-105 hover:shadow-2xl duration-200 transform mx-auto max-w-5xl mt-16 lg:mt-20 md:flex-shrink-0 animate__fadeIn animate__animated'>
|
||||
{/* 封面图 */}
|
||||
{post.page_cover && post.page_cover.length > 1 && (
|
||||
<img className='bg-center object-cover w-full' style={{ maxHeight: '40rem' }}
|
||||
src={post.page_cover} alt={post.title} />
|
||||
)}
|
||||
</header>
|
||||
|
||||
<article
|
||||
className='overflow-x-auto md:px-10 px-5 py-10 max-w-5xl mx-auto bg-white dark:border-gray-700 dark:bg-gray-700'>
|
||||
{/* 文章标题 */}
|
||||
<h1 className='font-bold text-4xl text-black my-5 dark:text-white animate__animated animate__fadeIn'>
|
||||
{post.title}
|
||||
</h1>
|
||||
|
||||
{/* 文章信息 */}
|
||||
<div className='justify-between flex flex-wrap bg-gray-50 p-2 dark:bg-gray-700 dark:text-white'>
|
||||
<div className='flex-nowrap flex'>
|
||||
|
||||
{post.slug !== 'about' && (<>
|
||||
<a
|
||||
className='hidden md:block duration-200 px-1' href='/article/about'
|
||||
>
|
||||
<Image alt={BLOG.author} width={33} height={33} src='/avatar.svg'
|
||||
className='rounded-full cursor-pointer transform hover:scale-125 duration-200' />
|
||||
</a>
|
||||
</>)}
|
||||
{post.tags && (
|
||||
<div className='flex flex-nowrap leading-8 p-1'>
|
||||
{post.tags.map(tag => (
|
||||
<TagItem key={tag} tag={tag} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{post.type[0] !== 'Page' && (
|
||||
<div className='flex items-start text-gray-500 dark:text-gray-400 leading-10'>
|
||||
{formatDate(
|
||||
post?.date?.start_date || post.createdTime,
|
||||
BLOG.lang
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 不蒜子 */}
|
||||
<div id='busuanzi_container_page_pv' className='hidden'>
|
||||
<a href='https://analytics.google.com/analytics/web/#/p273013569/reports/reportinghub'
|
||||
className='fa fa-eye text-gray-500 text-sm leading-none py-1 px-2'>
|
||||
<span id='busuanzi_value_page_pv' className='leading-6'></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Notion文章主体 */}
|
||||
{blockMap && (
|
||||
<NotionRenderer recordMap={blockMap} mapPageUrl={mapPageUrl}
|
||||
components={{
|
||||
equation: Equation,
|
||||
code: Code,
|
||||
collectionRow: CollectionRow,
|
||||
collection: Collection
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className='flex justify-center pt-5'>
|
||||
<RewardButton />
|
||||
</div>
|
||||
<p className='flex justify-center py-5 dark:text-gray-200'>
|
||||
- 💖 本 文 结 束 😚 感 谢 您 的 阅 读 💖 -
|
||||
</p>
|
||||
|
||||
{/* 版权声明 */}
|
||||
<section
|
||||
className='overflow-auto dark:bg-gray-700 dark:text-gray-300 bg-gray-100 p-5 leading-8 border-l-4 border-red-500'>
|
||||
<ul>
|
||||
<li><strong>本文作者:</strong>{BLOG.author}</li>
|
||||
<li><strong>本文链接:</strong> <a href={url}>{url}</a> 《{post.title}》</li>
|
||||
<li><strong>版权声明:</strong> 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className='flex'>
|
||||
<div className='text-gray-800 my-5 dark:text-gray-300 font-bold my-5 mr-2'>分享本文 </div>
|
||||
<ShareBar post={post} />
|
||||
</section>
|
||||
|
||||
<div className='text-gray-800 my-5 dark:text-gray-300'>
|
||||
<div className='mt-4 font-bold'>继续阅读</div>
|
||||
<div className='flex flex-wrap lg:flex-nowrap lg:space-x-10 justify-between py-2'>
|
||||
<BlogPostMini post={prev} />
|
||||
<BlogPostMini post={next} />
|
||||
</div>
|
||||
</div>
|
||||
{/* 评论互动 */}
|
||||
<Comment frontMatter={post} />
|
||||
</article>
|
||||
|
||||
</main>
|
||||
|
||||
{/* 右侧目录 */}
|
||||
<aside className='dark:bg-gray-800 bg-white'>
|
||||
<section className='h-full xl:static xl:block hidden top-0 right-0 fixed h-full w-52 dark:bg-gray-800 duration-500'>
|
||||
<div id='right-toc' className='sticky top-16 duration-500'>
|
||||
<div
|
||||
className='border-t dark:border-gray-600 border-b text-2xl bg-white font-bold text-black dark:bg-gray-900 dark:text-white py-6 px-6'>
|
||||
文章目录
|
||||
</div>
|
||||
<TocBar toc={post.toc} />
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
{/* 下方菜单组 */}
|
||||
<div
|
||||
className='right-0 space-x-2 fixed flex bottom-24 px-5 py-1 duration-500'>
|
||||
<div className='flex-wrap'>
|
||||
{/* 分享按钮 */}
|
||||
{/* <ShareButton post={post} /> */}
|
||||
{/* 跳回顶部 */}
|
||||
<JumpToTop targetRef={targetRef} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default ArticleLayout
|
||||
@@ -1,11 +1,15 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
import React, { useCallback, useEffect, useRef } from 'react'
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
import throttle from 'lodash.throttle'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useTheme } from '@/lib/theme'
|
||||
import TopNav from '@/components/TopNav'
|
||||
import Footer from '@/components/Footer'
|
||||
import SideBar from '@/components/SideBar'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
|
||||
const Container = ({ children, layout, fullWidth, tags, meta, ...customMeta }) => {
|
||||
const BaseLayout = ({ children, layout, fullWidth, tags, meta, post, ...customMeta }) => {
|
||||
let windowTop = 0
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY
|
||||
@@ -36,16 +40,30 @@ const Container = ({ children, layout, fullWidth, tags, meta, ...customMeta }) =
|
||||
}
|
||||
})
|
||||
const { theme } = useTheme()
|
||||
const targetRef = useRef(null)
|
||||
|
||||
return (
|
||||
<div className={[BLOG.font, theme].join(' ')}>
|
||||
<div id='wrapper' className={[BLOG.font, theme].join(' ')}>
|
||||
<CommonHead meta={meta} />
|
||||
{children}
|
||||
|
||||
<TopNav tags={tags} post={post} />
|
||||
{/* Middle Wrapper */}
|
||||
<main className='flex bg-gray-100'>
|
||||
<SideBar tags={tags} post={post} />
|
||||
<div className='flex flex-grow' ref={targetRef} >
|
||||
{children}
|
||||
</div>
|
||||
<JumpToTop targetRef={targetRef} showPercent={false} />
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Container.propTypes = {
|
||||
BaseLayout.propTypes = {
|
||||
children: PropTypes.node
|
||||
}
|
||||
|
||||
export default Container
|
||||
export default BaseLayout
|
||||
@@ -1,38 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import BLOG from '@/blog.config'
|
||||
import TagsBar from '@/components/TagsBar'
|
||||
import Footer from '@/components/Footer'
|
||||
import React, { useRef } from 'react'
|
||||
import Container from '@/components/Container'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
import SideBar from '@/components/SideBar'
|
||||
import TopNav from '@/components/TopNav'
|
||||
import BlogPostListScrollPagination from '@/components/BlogPostListScrollPagination'
|
||||
|
||||
const IndexLayout = ({ tags, posts, page, currentTag, meta, ...customMeta }) => {
|
||||
const targetRef = useRef(null)
|
||||
|
||||
return (
|
||||
<Container id='wrapper' meta={meta} tags={tags}>
|
||||
<TopNav tags={tags} />
|
||||
|
||||
{/* middle */}
|
||||
<div ref={targetRef} className={`${BLOG.font} flex justify-between bg-gray-100 dark:bg-black min-h-screen`}>
|
||||
<SideBar />
|
||||
<main className='flex-grow'>
|
||||
<TagsBar tags={tags} currentTag={currentTag} />
|
||||
<BlogPostListScrollPagination posts={posts} tags={tags} targetRef={targetRef} />
|
||||
<JumpToTop targetRef={targetRef} showPercent={false} />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
IndexLayout.propTypes = {
|
||||
posts: PropTypes.array.isRequired,
|
||||
tags: PropTypes.object.isRequired,
|
||||
currentTag: PropTypes.string
|
||||
}
|
||||
export default IndexLayout
|
||||
@@ -1,39 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import BLOG from '@/blog.config'
|
||||
import TagsBar from '@/components/TagsBar'
|
||||
import Footer from '@/components/Footer'
|
||||
import React, { useRef } from 'react'
|
||||
import Container from '@/components/Container'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
import SideBar from '@/components/SideBar'
|
||||
import TopNav from '@/components/TopNav'
|
||||
import BlogPostList from '@/components/BlogPostList'
|
||||
|
||||
const PageLayout = ({ tags, posts, page, currentTag, meta, ...customMeta }) => {
|
||||
const targetRef = useRef(null)
|
||||
|
||||
return (
|
||||
<Container id='wrapper' meta={meta} tags={tags}>
|
||||
<TopNav tags={tags} />
|
||||
|
||||
{/* middle */}
|
||||
<div ref={targetRef} className={`${BLOG.font} flex justify-between bg-gray-100 dark:bg-black min-h-screen`}>
|
||||
<SideBar />
|
||||
|
||||
<main className='flex-grow'>
|
||||
<TagsBar tags={tags} currentTag={currentTag} />
|
||||
<BlogPostList posts={posts} tags={tags} page={page} />
|
||||
</main>
|
||||
<JumpToTop targetRef={targetRef} showPercent={false} />
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
PageLayout.propTypes = {
|
||||
posts: PropTypes.array.isRequired,
|
||||
tags: PropTypes.object.isRequired,
|
||||
currentTag: PropTypes.string
|
||||
}
|
||||
export default PageLayout
|
||||
17
pages/404.js
17
pages/404.js
@@ -7,18 +7,11 @@ import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export default function Custom404 () {
|
||||
const route = useRouter()
|
||||
if (route.asPath.indexOf('/article') < 0 && route.asPath.indexOf('/404') < 0) {
|
||||
// article 重定向,处理旧文章链接迁移。
|
||||
const redirectUrl = '/article' + route.asPath
|
||||
route.push(redirectUrl)
|
||||
} else {
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
window.location.href = '/'
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
window.location.href = '/'
|
||||
}, 3000)
|
||||
})
|
||||
|
||||
return <div
|
||||
className='text-black bg-white h-screen text-center justify-center content-center items-center flex flex-col'>
|
||||
|
||||
@@ -1,24 +1,173 @@
|
||||
import ArticleLayout from '@/layouts/ArticleLayout'
|
||||
import { getAllPosts, getAllTags, getPostBlocks } from '@/lib/notion'
|
||||
import BLOG from '@/blog.config'
|
||||
import { createHash } from 'crypto'
|
||||
import { getPageTableOfContents } from 'notion-utils'
|
||||
import Custom404 from '@/pages/404'
|
||||
import { useRouter } from 'next/router'
|
||||
import Progress from '@/components/Progress'
|
||||
import Image from 'next/image'
|
||||
import TagItem from '@/components/TagItem'
|
||||
import formatDate from '@/lib/formatDate'
|
||||
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
|
||||
import RewardButton from '@/components/RewardButton'
|
||||
import ShareBar from '@/components/ShareBar'
|
||||
import BlogPostMini from '@/components/BlogPostMini'
|
||||
import Comment from '@/components/Comment'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
import BaseLayout from '@/layouts/BaseLayout'
|
||||
import { useRef } from 'react'
|
||||
|
||||
const mapPageUrl = id => {
|
||||
return 'https://www.notion.so/' + id.replace(/-/g, '')
|
||||
}
|
||||
const BlogPost = ({ post, blockMap, emailHash, tags, prev, next }) => {
|
||||
if (!post) {
|
||||
return <Custom404 />
|
||||
return <>空白页</>
|
||||
}
|
||||
return (
|
||||
<ArticleLayout
|
||||
blockMap={blockMap}
|
||||
post={post}
|
||||
emailHash={emailHash}
|
||||
tags={tags}
|
||||
prev={prev}
|
||||
next={next}
|
||||
></ArticleLayout>
|
||||
)
|
||||
const meta = {
|
||||
title: post.title,
|
||||
description: post.summary,
|
||||
type: 'article'
|
||||
}
|
||||
const targetRef = useRef(null)
|
||||
const url = BLOG.link + useRouter().asPath
|
||||
|
||||
return <BaseLayout meta={meta} tags={tags} post={post}>
|
||||
{/* 阅读进度条 */}
|
||||
<Progress targetRef={targetRef} />
|
||||
|
||||
{/* 主体区块 */}
|
||||
<div ref={targetRef} className='flex flex-grow'>
|
||||
<div id='article-wrapper' className='flex-grow bg-gray-100 dark:bg-gray-800'>
|
||||
{/* 中央区域 wrapper */}
|
||||
<header
|
||||
className='hover:scale-105 hover:shadow-2xl duration-200 transform mx-auto max-w-5xl mt-16 lg:mt-20 md:flex-shrink-0 animate__fadeIn animate__animated'>
|
||||
{/* 封面图 */}
|
||||
{post.page_cover && post.page_cover.length > 1 && (
|
||||
<img className='bg-center object-cover w-full' style={{ maxHeight: '40rem' }}
|
||||
src={post.page_cover} alt={post.title} />
|
||||
)}
|
||||
</header>
|
||||
|
||||
<article
|
||||
className='overflow-x-auto md:px-10 px-5 py-10 max-w-5xl mx-auto bg-white dark:border-gray-700 dark:bg-gray-700'>
|
||||
{/* 文章标题 */}
|
||||
<h1 className='font-bold text-4xl text-black my-5 dark:text-white animate__animated animate__fadeIn'>
|
||||
{post.title}
|
||||
</h1>
|
||||
|
||||
{/* 文章信息 */}
|
||||
<div className='justify-between flex flex-wrap bg-gray-50 p-2 dark:bg-gray-700 dark:text-white'>
|
||||
<div className='flex-nowrap flex'>
|
||||
|
||||
{post.slug !== 'about' && (<>
|
||||
<a
|
||||
className='hidden md:block duration-200 px-1' href='/article/about'
|
||||
>
|
||||
<Image alt={BLOG.author} width={33} height={33} src='/avatar.svg'
|
||||
className='rounded-full cursor-pointer transform hover:scale-125 duration-200' />
|
||||
</a>
|
||||
</>)}
|
||||
{post.tags && (
|
||||
<div className='flex flex-nowrap leading-8 p-1'>
|
||||
{post.tags.map(tag => (
|
||||
<TagItem key={tag} tag={tag} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{post.type[0] !== 'Page' && (
|
||||
<div className='flex items-start text-gray-500 dark:text-gray-400 leading-10'>
|
||||
{formatDate(
|
||||
post?.date?.start_date || post.createdTime,
|
||||
BLOG.lang
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 不蒜子 */}
|
||||
<div id='busuanzi_container_page_pv' className='hidden'>
|
||||
<a href='https://analytics.google.com/analytics/web/#/p273013569/reports/reportinghub'
|
||||
className='fa fa-eye text-gray-500 text-sm leading-none py-1 px-2'>
|
||||
<span id='busuanzi_value_page_pv' className='leading-6'></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Notion文章主体 */}
|
||||
{blockMap && (
|
||||
<NotionRenderer recordMap={blockMap} mapPageUrl={mapPageUrl}
|
||||
components={{
|
||||
equation: Equation,
|
||||
code: Code,
|
||||
collectionRow: CollectionRow,
|
||||
collection: Collection
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className='flex justify-center pt-5'>
|
||||
<RewardButton />
|
||||
</div>
|
||||
<p className='flex justify-center py-5 dark:text-gray-200'>
|
||||
- 💖 本 文 结 束 😚 感 谢 您 的 阅 读 💖 -
|
||||
</p>
|
||||
|
||||
{/* 版权声明 */}
|
||||
<section
|
||||
className='overflow-auto dark:bg-gray-700 dark:text-gray-300 bg-gray-100 p-5 leading-8 border-l-4 border-red-500'>
|
||||
<ul>
|
||||
<li><strong>本文作者:</strong>{BLOG.author}</li>
|
||||
<li><strong>本文链接:</strong> <a href={url}>{url}</a> 《{post.title}》</li>
|
||||
<li><strong>版权声明:</strong> 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className='flex'>
|
||||
<div className='text-gray-800 my-5 dark:text-gray-300 font-bold my-5 mr-2'>分享本文 </div>
|
||||
<ShareBar post={post} />
|
||||
</section>
|
||||
|
||||
<div className='text-gray-800 my-5 dark:text-gray-300'>
|
||||
<div className='mt-4 font-bold'>继续阅读</div>
|
||||
<div className='flex flex-wrap lg:flex-nowrap lg:space-x-10 justify-between py-2'>
|
||||
<BlogPostMini post={prev} />
|
||||
<BlogPostMini post={next} />
|
||||
</div>
|
||||
</div>
|
||||
{/* 评论互动 */}
|
||||
<Comment frontMatter={post} />
|
||||
</article>
|
||||
|
||||
</div>
|
||||
|
||||
{/* 右侧目录 */}
|
||||
<aside className='dark:bg-gray-800 bg-white'>
|
||||
<section
|
||||
className='h-full xl:static xl:block hidden top-0 right-0 fixed h-full w-52 dark:bg-gray-800 duration-500'>
|
||||
<div id='right-toc' className='sticky top-16 duration-500'>
|
||||
<div
|
||||
className='border-t dark:border-gray-600 border-b text-2xl bg-white font-bold text-black dark:bg-gray-900 dark:text-white py-6 px-6'>
|
||||
文章目录
|
||||
</div>
|
||||
<TocBar toc={post.toc} />
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
{/* 右下角悬浮菜单 */}
|
||||
<div className='right-0 space-x-2 fixed flex bottom-24 px-5 py-1 duration-500'>
|
||||
<div className='flex-wrap'>
|
||||
{/* 分享按钮 */}
|
||||
{/* <ShareButton post={post} /> */}
|
||||
{/* 跳回顶部 */}
|
||||
<JumpToTop targetRef={targetRef} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</BaseLayout>
|
||||
}
|
||||
|
||||
export async function getStaticPaths () {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { getAllPosts, getAllTags } from '@/lib/notion'
|
||||
import IndexLayout from '@/layouts/IndexLayout'
|
||||
import BLOG from '@/blog.config'
|
||||
import BaseLayout from '@/layouts/BaseLayout'
|
||||
import TagsBar from '@/components/TagsBar'
|
||||
import BlogPostListScroll from '@/components/BlogPostListScroll'
|
||||
|
||||
export async function getStaticProps () {
|
||||
let posts = await getAllPosts()
|
||||
@@ -15,7 +17,6 @@ export async function getStaticProps () {
|
||||
}
|
||||
return {
|
||||
props: {
|
||||
page: 1, // current page is 1
|
||||
posts,
|
||||
tags,
|
||||
meta
|
||||
@@ -24,9 +25,14 @@ export async function getStaticProps () {
|
||||
}
|
||||
}
|
||||
|
||||
const index = ({ posts, page, tags, meta }) => {
|
||||
const index = ({ posts, tags, meta }) => {
|
||||
return (
|
||||
<IndexLayout tags={tags} posts={posts} page={page} meta={meta} />
|
||||
<BaseLayout meta={meta} tags={tags}>
|
||||
<div className='flex-grow'>
|
||||
<TagsBar tags={tags} />
|
||||
<BlogPostListScroll posts={posts} tags={tags} />
|
||||
</div>
|
||||
</BaseLayout>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,49 +1,36 @@
|
||||
import { getAllPosts, getAllTags } from '@/lib/notion'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useRouter } from 'next/router'
|
||||
import PageLayout from '@/layouts/PageLayout'
|
||||
import BaseLayout from '@/layouts/BaseLayout'
|
||||
import TagsBar from '@/components/TagsBar'
|
||||
import BlogPostList from '@/components/BlogPostList'
|
||||
|
||||
const Page = ({ posts, tags, page }) => {
|
||||
let filteredBlogPosts = posts
|
||||
if (posts) {
|
||||
const router = useRouter()
|
||||
if (router.query && router.query.s) {
|
||||
filteredBlogPosts = posts.filter(post => {
|
||||
const tagContent = post.tags ? post.tags.join(' ') : ''
|
||||
const searchContent = post.title + post.summary + tagContent
|
||||
return searchContent.toLowerCase().includes(router.query.s.toLowerCase())
|
||||
})
|
||||
}
|
||||
}
|
||||
const meta = {
|
||||
title: `${BLOG.title} | 博客列表`,
|
||||
description: BLOG.description,
|
||||
type: 'website'
|
||||
}
|
||||
return <PageLayout tags={tags} posts={filteredBlogPosts} page={page} meta={meta} />
|
||||
return <BaseLayout meta={meta} tags={tags}>
|
||||
<div className='flex-grow'>
|
||||
<TagsBar tags={tags} />
|
||||
<BlogPostList posts={posts} tags={tags} page={page} />
|
||||
</div>
|
||||
</BaseLayout>
|
||||
}
|
||||
|
||||
export async function getStaticPaths () {
|
||||
if (BLOG.isProd) {
|
||||
// 预渲染
|
||||
let posts = await getAllPosts()
|
||||
posts = posts.filter(
|
||||
post => post.status[0] === 'Published' && post.type[0] === 'Post'
|
||||
)
|
||||
const totalPosts = posts.length
|
||||
const totalPages = Math.ceil(totalPosts / BLOG.postsPerPage)
|
||||
return {
|
||||
// remove first page, we 're not gonna handle that.
|
||||
paths: Array.from({ length: totalPages - 1 }, (_, i) => ({
|
||||
params: { page: '' + (i + 2) }
|
||||
})),
|
||||
fallback: true
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: true
|
||||
}
|
||||
let posts = await getAllPosts()
|
||||
posts = posts.filter(
|
||||
post => post.status[0] === 'Published' && post.type[0] === 'Post'
|
||||
)
|
||||
const totalPosts = posts.length
|
||||
const totalPages = Math.ceil(totalPosts / BLOG.postsPerPage)
|
||||
return {
|
||||
// remove first page, we 're not gonna handle that.
|
||||
paths: Array.from({ length: totalPages - 1 }, (_, i) => ({
|
||||
params: { page: '' + (i + 2) }
|
||||
})),
|
||||
fallback: true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { getAllPosts, getAllTags } from '@/lib/notion'
|
||||
import BLOG from '@/blog.config'
|
||||
import PageLayout from '@/layouts/PageLayout'
|
||||
import TagsBar from '@/components/TagsBar'
|
||||
import BlogPostList from '@/components/BlogPostList'
|
||||
import BaseLayout from '@/layouts/BaseLayout'
|
||||
|
||||
export default function Tag ({ tags, posts, currentTag }) {
|
||||
const meta = {
|
||||
@@ -8,7 +10,12 @@ export default function Tag ({ tags, posts, currentTag }) {
|
||||
description: BLOG.description,
|
||||
type: 'website'
|
||||
}
|
||||
return <PageLayout tags={tags} posts={posts} currentTag={currentTag} meta={meta} />
|
||||
return <BaseLayout meta={meta} tags={tags} currentTag={currentTag}>
|
||||
<div className='flex-grow'>
|
||||
<TagsBar tags={tags} currentTag={currentTag}/>
|
||||
<BlogPostList posts={posts} tags={tags}/>
|
||||
</div>
|
||||
</BaseLayout>
|
||||
}
|
||||
|
||||
export async function getStaticProps ({ params }) {
|
||||
@@ -33,7 +40,6 @@ export async function getStaticProps ({ params }) {
|
||||
|
||||
export async function getStaticPaths () {
|
||||
if (BLOG.isProd) {
|
||||
// 预渲染
|
||||
const tags = await getAllTags()
|
||||
return {
|
||||
paths: Object.keys(tags).map(tag => ({ params: { tag } })),
|
||||
|
||||
Reference in New Issue
Block a user