Files
NotionNext/pages/article/[slug].js
tangly bca62365d3 feature:
简化层级
2021-12-04 16:39:45 +08:00

212 lines
8.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { getAllCategories, getAllPosts, getAllTags, getPostBlocks } from '@/lib/notion'
import BLOG from '@/blog.config'
import { getPageTableOfContents } from 'notion-utils'
import { useRouter } from 'next/router'
import Progress from '@/components/Progress'
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 Comment from '@/components/Comment'
import BaseLayout from '@/layouts/BaseLayout'
import React, { useRef } from 'react'
import Custom404 from '@/pages/404'
import Link from 'next/link'
import Image from 'next/image'
import 'prismjs/themes/prism-okaidia.css'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-typescript'
import RecommendPosts from '@/components/RecommendPosts'
import TocDrawer from '@/components/TocDrawer'
import TocDrawerButton from '@/components/TocDrawerButton'
import { useGlobal } from '@/lib/global'
import { getNotionPageData } from '@/lib/notion/getNotionData'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faAngleDoubleLeft, faAngleDoubleRight, faEye, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
const ArticleDetail = ({ post, blockMap, tags, prev, next, allPosts, categories }) => {
if (!post) {
return <Custom404 />
}
const meta = {
title: `${post.title} | ${BLOG.title}`,
description: post.summary,
type: 'article',
tags: post.tags
}
const targetRef = useRef(null)
const drawerRight = useRef(null)
const url = BLOG.link + useRouter().asPath
const { locale } = useGlobal()
return <BaseLayout meta={meta} tags={tags} post={post} totalPosts={allPosts} categories={categories}>
<Progress targetRef={targetRef} />
<div id='article-wrapper' ref={targetRef} className='flex-grow dark:bg-black bg-gray-200'>
<div className='max-w-5xl mx-auto mt-16 xl:mt-32 w-screen md:w-full '>
{post.type && !post.type.includes('Page') && (<>
<header className='w-full h-60 lg:h-96 transform duration-200 md:flex-shrink-0'>
<Image src={(post.page_cover && post.page_cover.length > 1) ? post.page_cover : BLOG.defaultImgCover} loading='lazy' objectFit='cover' layout='fill' alt={post.title} />
</header>
</>)}
<article className='animate__fadeIn animate__animated subpixel-antialiased lg:pt-32 lg:px-44 px-5 py-2 dark:border-gray-700 bg-white dark:bg-gray-800'>
{/* 文章Title */}
<h1 className='font-bold text-3xl pt-5 text-black dark:text-white italic'> {post.title}</h1>
<hr className='mt-4' />
<section className='flex-nowrap flex mt-1 dark:text-white'>
<Link href={`/category/${post.category}`} passHref>
<div className='cursor-pointer text-md py-2 ml-1 mr-3 text-gray-500 dark:text-gray-300 hover:text-black dark:hover:text-white'>
<FontAwesomeIcon icon={faFolderOpen} className='mr-1' />{post.category}
</div>
</Link>
{post.type[0] !== 'Page' && (
<Link href='/archive' passHref>
<div className='pl-1 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 text-gray-400 dark:text-gray-400 leading-10'>
{formatDate(
post?.date?.start_date || post.createdTime,
BLOG.lang
)}
</div>
</Link>
)}
{/* 不蒜子 */}
<div id='busuanzi_container_page_pv' className='hidden'>
<FontAwesomeIcon icon={faEye} className='text-gray-500 dark:text-gray-400 mt-3 ml-2' />
&nbsp;<span id='busuanzi_value_page_pv' className='text-gray-500 dark:text-gray-400 leading-6'></span>
</div>
</section>
{/* Notion文章主体 */}
{blockMap && (
<NotionRenderer recordMap={blockMap} mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collectionRow: CollectionRow,
collection: Collection
}}
/>
)}
{/* 推荐文章 */}
<RecommendPosts currentPost={post} totalPosts={allPosts} />
{/* 版权声明 */}
<section className='text-sm overflow-auto dark:bg-gray-800 dark:text-gray-300 bg-gray-100 p-5 leading-8 border-l-4 border-red-500'>
<ul>
<li>本文作者: <Link href='/article/about'><a className='hover:underline'>{BLOG.author}</a></Link></li>
<li>本文链接: <a className='hover:underline' href={url}>{url}</a></li>
<li>版权声明: 本博客所有文章除特别声明外均采用 BY-NC-SA 许可协议转载请注明出处</li>
</ul>
</section>
{/* 标签列表 */}
<section className='md:flex md:justify-between'>
{post.tagItems && (
<div className='flex flex-nowrap leading-8 p-1 py-4 overflow-x-auto'>
<div className='hidden md:block dark:text-gray-300'>{locale.COMMON.TAGS}</div>
{post.tagItems.map(tag => (
<TagItem key={tag.name} tag={tag} />
))}
</div>
)}
<div>
<ShareBar post={post} />
</div>
</section>
</article>
<div className='w-screen md:w-full px-5 py-2 dark:border-gray-700 bg-white dark:bg-gray-800'>
<div className='py-10'>
<RewardButton />
</div>
</div>
<div className='text-gray-800 dark:text-gray-300 dark:bg-gray-900 bg-gray-50 px-5 '>
<div className='flex flex-wrap lg:flex-nowrap lg:space-x-10 justify-between py-2'>
<Link href={`/article/${prev.slug}`} passHref>
<div className='py-3 text-blue-500 text-lg hover:underline cursor-pointer'>
<FontAwesomeIcon icon={faAngleDoubleLeft} className='mr-1' />{prev.title}</div>
</Link>
<Link href={`/article/${next.slug}`} passHref>
<div className='flex py-3 text-blue-500 text-lg hover:underline cursor-pointer'>{next.title}
<FontAwesomeIcon icon={faAngleDoubleRight} className='ml-1 my-1' />
</div>
</Link>
</div>
</div>
{/* 评论互动 */}
<div
className='my-10 w-screen md:w-full overflow-x-auto dark:border-gray-700 bg-white dark:bg-gray-700'>
<Comment frontMatter={post} />
</div>
</div>
</div>
{/* 悬浮目录按钮 */}
<div className='block lg:hidden'>
<TocDrawerButton onClick={() => { drawerRight.current.handleSwitchVisible() }} />
{/* 目录侧边栏 */}
<TocDrawer post={post} cRef={drawerRight} />
</div>
</BaseLayout>
}
export async function getStaticPaths () {
let posts = []
if (BLOG.isProd) {
posts = await getAllPosts({ from: 'slug - paths', includePage: true })
}
return {
paths: posts.map(row => `${BLOG.path}/article/${row.slug}`),
fallback: true
}
}
export async function getStaticProps ({ params: { slug } }) {
const from = `slug-props-${slug}`
const notionPageData = await getNotionPageData({ from })
let allPosts = await getAllPosts({ notionPageData, from, includePage: true })
const post = allPosts.find(p => p.slug === slug)
if (!post) {
return { props: {}, revalidate: 1 }
}
const blockMap = await getPostBlocks(post.id, 'slug')
post.toc = []
if (blockMap) {
post.toc = getPageTableOfContents(post, blockMap)
}
allPosts = allPosts.filter(post => post.type[0] === 'Post')
const tagOptions = notionPageData.tagOptions
const tags = await getAllTags({ allPosts, tagOptions })
const categories = await getAllCategories(allPosts)
// 上一篇、下一篇文章关联
const index = allPosts.indexOf(post)
const prev = allPosts.slice(index - 1, index)[0] ?? allPosts.slice(-1)[0]
const next = allPosts.slice(index + 1, index + 2)[0] ?? allPosts[0]
return {
props: { post, blockMap, tags, prev, next, allPosts, categories },
revalidate: 1
}
}
export default ArticleDetail