文章分类功能
This commit is contained in:
tangly1024
2021-11-04 17:58:25 +08:00
parent 40db3aae2b
commit 979fa7777e
18 changed files with 202 additions and 67 deletions

View File

@@ -1,6 +1,6 @@
const BLOG = { const BLOG = {
title: '唐1024', title: '唐1024',
author: '唐哼哼', author: '唐',
email: 'tlyong1992@hotmail.com', email: 'tlyong1992@hotmail.com',
link: 'https://tangly1024.com', link: 'https://tangly1024.com',
description: '分享有趣的技术与思考', description: '分享有趣的技术与思考',
@@ -13,7 +13,7 @@ const BLOG = {
darkBackground: '#111827', // use hex value, don't forget '#' darkBackground: '#111827', // use hex value, don't forget '#'
path: '', // leave this empty unless you want to deploy in a folder path: '', // leave this empty unless you want to deploy in a folder
since: 2020, // if leave this empty, current year will be used. since: 2020, // if leave this empty, current year will be used.
postsPerPage: 8, // post counts per page postsPerPage: 6, // post counts per page
sortByDate: false, sortByDate: false,
showAbout: true, // WIP showAbout: true, // WIP
showArchive: true, // WIP showArchive: true, // WIP

View File

@@ -1,8 +1,9 @@
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import TagItemMini from '@/components/TagItemMini' import TagItemMini from '@/components/TagItemMini'
import Link from 'next/link' import Link from 'next/link'
import React from 'react'
const BlogPost = ({ post }) => { const BlogPostCard = ({ post }) => {
return ( return (
<div key={post.id} className='animate__animated animate__slideInUp animate__faster shadow-card inline-block border dark:border-gray-600 my-2 w-full 2xl:max-w-2xl bg-white bg-opacity-80 dark:bg-gray-800 dark:hover:bg-gray-700 overflow-hidden'> <div key={post.id} className='animate__animated animate__slideInUp animate__faster shadow-card inline-block border dark:border-gray-600 my-2 w-full 2xl:max-w-2xl bg-white bg-opacity-80 dark:bg-gray-800 dark:hover:bg-gray-700 overflow-hidden'>
{/* 封面图 */} {/* 封面图 */}
@@ -17,6 +18,9 @@ const BlogPost = ({ post }) => {
<div className='cursor-pointer my-3 text-2xl leading-tight font-bold text-black dark:text-gray-100 hover:underline'>{post.title}</div> <div className='cursor-pointer my-3 text-2xl leading-tight font-bold text-black dark:text-gray-100 hover:underline'>{post.title}</div>
</Link> </Link>
<div className='flex flex-nowrap'> <div className='flex flex-nowrap'>
<Link href={`/category/${post.category}`}>
<div className='cursor-pointer text-sm py-1.5 mr-2 hover:underline'><i className='fa fa-folder-open-o mr-1'/>{post.category}</div>
</Link>
{post.tags.map(tag => (<TagItemMini key={tag} tag={tag} />))} {post.tags.map(tag => (<TagItemMini key={tag} tag={tag} />))}
<span className='mt-2 mx-2 text-gray-500 dark:text-gray-300 text-sm leading-4'>{post.date.start_date}</span> <span className='mt-2 mx-2 text-gray-500 dark:text-gray-300 text-sm leading-4'>{post.date.start_date}</span>
</div> </div>
@@ -26,4 +30,4 @@ const BlogPost = ({ post }) => {
) )
} }
export default BlogPost export default BlogPostCard

View File

@@ -1,7 +1,7 @@
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import Link from 'next/link' import Link from 'next/link'
const BlogPostMini = ({ post }) => { const BlogPostCardMini = ({ post }) => {
return ( return (
<Link key={post.id} title={post.title} href={`${BLOG.path}/article/${post.slug}`} > <Link key={post.id} title={post.title} href={`${BLOG.path}/article/${post.slug}`} >
<div className='sm:flex w-full border dark:border-gray-800 my-2 duration-200 transform hover:scale-105 hover:shadow-2xl bg-white dark:bg-gray-800 dark:hover:bg-gray-700'> <div className='sm:flex w-full border dark:border-gray-800 my-2 duration-200 transform hover:scale-105 hover:shadow-2xl bg-white dark:bg-gray-800 dark:hover:bg-gray-700'>
@@ -22,4 +22,4 @@ const BlogPostMini = ({ post }) => {
) )
} }
export default BlogPostMini export default BlogPostCardMini

View File

@@ -1,4 +1,4 @@
import BlogPost from '@/components/BlogPost' import BlogPostCard from '@/components/BlogPostCard'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
@@ -58,7 +58,7 @@ const BlogPostListPage = ({ page = 1, posts = [], tags }) => {
{/* 文章列表 */} {/* 文章列表 */}
<div className='grid 3xl:grid-cols-4 2xl:grid-cols-3 md:grid-cols-2 grid-cols-1 gap-5'> <div className='grid 3xl:grid-cols-4 2xl:grid-cols-3 md:grid-cols-2 grid-cols-1 gap-5'>
{postsToShow.map(post => ( {postsToShow.map(post => (
<BlogPost key={post.id} post={post} tags={tags} /> <BlogPostCard key={post.id} post={post} tags={tags} />
))} ))}
</div> </div>

View File

@@ -1,7 +1,7 @@
import BlogPost from '@/components/BlogPost' import BlogPostCard from '@/components/BlogPostCard'
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import { useCallback, useEffect, useRef, useState } from 'react' import React, { useCallback, useEffect, useRef, useState } from 'react'
import throttle from 'lodash.throttle' import throttle from 'lodash.throttle'
import BlogPostListEmpty from '@/components/BlogPostListEmpty' import BlogPostListEmpty from '@/components/BlogPostListEmpty'
@@ -13,7 +13,7 @@ import BlogPostListEmpty from '@/components/BlogPostListEmpty'
* @returns {JSX.Element} * @returns {JSX.Element}
* @constructor * @constructor
*/ */
const BlogPostListScroll = ({ posts = [], tags, currentSearch }) => { const BlogPostListScroll = ({ posts = [], tags, currentSearch, currentCategory, currentTag }) => {
const postsPerPage = BLOG.postsPerPage const postsPerPage = BLOG.postsPerPage
const [page, updatePage] = useState(1) const [page, updatePage] = useState(1)
const postsToShow = getPostByPage(page, posts, postsPerPage) const postsToShow = getPostByPage(page, posts, postsPerPage)
@@ -52,10 +52,29 @@ const BlogPostListScroll = ({ posts = [], tags, currentSearch }) => {
return <BlogPostListEmpty /> return <BlogPostListEmpty />
} else { } else {
return <div id='post-list-wrapper' className='mt-28 md:mt-32 mx-2 md:mx-20' ref={targetRef}> return <div id='post-list-wrapper' className='mt-28 md:mt-32 mx-2 md:mx-20' ref={targetRef}>
{/* 文章列表 */}
{currentCategory && (
<div className='w-full p-1 bg-gray-100 dark:bg-gray-700'>
<div className='cursor-pointer py-1.5 mr-2 dark:text-gray-300 hover:underline'><i className='fa fa-folder-open-o mr-1'/>{currentCategory}</div>
</div>
)}
{currentSearch && (
<div className='w-full p-1 bg-gray-100 dark:bg-gray-700'>
<div className='cursor-pointer py-1.5 mr-2 dark:text-gray-300 hover:underline'><i className='fa fa-search mr-1'/>关键字{currentSearch}</div>
</div>
)}
{currentTag && (
<div className='w-full p-1 bg-gray-100 dark:bg-gray-700 flex'>
<div className='cursor-pointer py-1.5 mr-2 hover:underline bg-gray-200 dark:bg-gray-400 px-2 rounded'># {currentTag}</div>
</div>
)}
{/* 文章列表 */}
<div className='grid 3xl:grid-cols-3 md:grid-cols-2 grid-cols-1 gap-5'> <div className='grid 3xl:grid-cols-3 md:grid-cols-2 grid-cols-1 gap-5'>
{postsToShow.map(post => ( {postsToShow.map(post => (
<BlogPost key={post.id} post={post} tags={tags} /> <BlogPostCard key={post.id} post={post} tags={tags} />
))} ))}
</div> </div>

View File

@@ -20,16 +20,16 @@ const Drawer = ({ post, currentTag, cRef, tags, posts }) => {
handleMenuClick: () => handleMenuClick() handleMenuClick: () => handleMenuClick()
} }
}) })
const [showDrawer, switchShowDrawer] = useState(false) const [isHidden, changeHiddenStatus] = useState(true)
// 点击按钮更改侧边抽屉状态 // 点击按钮更改侧边抽屉状态
const handleMenuClick = () => { const handleMenuClick = () => {
switchShowDrawer(!showDrawer) changeHiddenStatus(!isHidden)
} }
return <> return <>
<div className='fixed top-0 left-0 z-50 h-screen shadow-2xl bg-white dark:bg-gray-800'> <div className='fixed top-0 left-0 z-50 h-screen shadow-2xl bg-white dark:bg-gray-800'>
{/* LOGO */} {/* LOGO */}
<div <div
className={(showDrawer ? '' : '-ml-72') + ' duration-200 w-72 border-r dark:border-gray-600'}> className={(isHidden ? '-ml-72' : '') + ' duration-200 w-72 border-r dark:border-gray-600'}>
<div className='w-72 flex space-x-4 px-5 py-1 dark:border-gray-500 '> <div className='w-72 flex space-x-4 px-5 py-1 dark:border-gray-500 '>
<div <div
className='z-10 py-2 duration-200 mr-2 text-gray-600 text-xl cursor-pointer dark:text-gray-300'> className='z-10 py-2 duration-200 mr-2 text-gray-600 text-xl cursor-pointer dark:text-gray-300'>
@@ -41,7 +41,7 @@ const Drawer = ({ post, currentTag, cRef, tags, posts }) => {
{/* 侧边菜单 */} {/* 侧边菜单 */}
<div <div
className={(showDrawer ? 'shadow-2xl' : '-ml-72') + ' overflow-y-scroll h-screen w-72 duration-200 overflow-y-auto'}> className={(isHidden ? '-ml-72' : 'shadow-2xl') + ' overflow-y-scroll h-screen w-72 duration-200 overflow-y-auto'}>
<div className='pb-56'> <div className='pb-56'>
{/* 搜索框 */} {/* 搜索框 */}
<div className='px-5 my-3 block md:hidden'> <div className='px-5 my-3 block md:hidden'>
@@ -79,7 +79,7 @@ const Drawer = ({ post, currentTag, cRef, tags, posts }) => {
</div> </div>
</div> </div>
{/* 背景蒙版 */} {/* 背景蒙版 */}
<div id='drawer-background' className={(showDrawer ? 'block' : 'hidden') + ' fixed top-0 left-0 z-30 w-full h-full bg-black bg-opacity-30'} <div id='drawer-background' className={(isHidden ? 'hidden' : 'block') + ' fixed top-0 left-0 z-30 w-full h-full bg-black bg-opacity-30'}
onClick={handleMenuClick} /> onClick={handleMenuClick} />
</> </>
} }

View File

@@ -24,7 +24,7 @@ const MenuButtonGroup = ({ allowCollapse = false }) => {
link => link =>
link.show && ( link.show && (
<Link key={link.id + link.icon} title={link.to} href={link.to} > <Link key={link.id + link.icon} title={link.to} href={link.to} >
<a className={(router.asPath === link.to ? 'bg-gray-200 dark:bg-black' : '') + ' py-2 px-5 hover:bg-gray-100 cursor-pointer dark:hover:bg-black duration-100 flex flex-nowrap align-middle'} > <a className={(router.asPath === link.to ? 'bg-gray-200 dark:bg-black' : '') + ' py-2 px-5 hover:bg-gray-100 cursor-pointer dark:hover:bg-gray-600 duration-100 flex flex-nowrap align-middle'} >
<div className='my-auto w-5 text-2xl justify-center flex'> <div className='my-auto w-5 text-2xl justify-center flex'>
<i className={'fa ' + link.icon} /> <i className={'fa ' + link.icon} />
</div> </div>

View File

@@ -0,0 +1,22 @@
import Link from 'next/link'
import React from 'react'
const PostsCategories = ({ currentCategory, categories }) => {
return <>
<section
className='text-sm font-bold py-3 px-5 text-gray-600 dark:text-gray-400 duration-100 flex flex-nowrap align-middle'>
<div className='w-32'>文章分类</div>
</section>
<div>
<div id='category-list' className='duration-500 dark:border-gray-600 dark:bg-gray-800 w-66'>
{Object.keys(categories).map(category => {
return <Link key={category} href={`/category/${category}`}>
<div className={(currentCategory === category ? 'bg-gray-200 dark:bg-black' : '') + ' dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}><i className='fa fa-folder-open-o mr-4'/>{category} {categories[category]}</div>
</Link>
})}
</div>
</div>
</>
}
export default PostsCategories

View File

@@ -3,8 +3,9 @@ import MenuButtonGroup from '@/components/MenuButtonGroup'
import InfoCard from '@/components/InfoCard' import InfoCard from '@/components/InfoCard'
import TagList from '@/components/TagList' import TagList from '@/components/TagList'
import LatestPosts from '@/components/LatestPosts' import LatestPosts from '@/components/LatestPosts'
import PostsCategories from '@/components/PostsCategories'
const SideBar = ({ tags, currentTag, post, posts }) => { const SideBar = ({ tags, currentTag, post, posts, categories, currentCategory }) => {
// 按时间排序 // 按时间排序
if (posts) { if (posts) {
posts = posts.sort((a, b) => { posts = posts.sort((a, b) => {
@@ -26,6 +27,13 @@ const SideBar = ({ tags, currentTag, post, posts }) => {
<hr className='dark:border-gray-700 my-2' /> <hr className='dark:border-gray-700 my-2' />
{/* 分类 */}
{categories && (
<div className='mt-2'>
<PostsCategories currentCategory={currentCategory} categories={categories}/>
</div>
)}
{/* 最新文章 */} {/* 最新文章 */}
{posts && ( {posts && (
<div className='mt-2'> <div className='mt-2'>

View File

@@ -3,7 +3,7 @@ import Link from 'next/link'
const TagItemMini = ({ tag, selected = false, count }) => ( const TagItemMini = ({ tag, selected = false, count }) => (
<Link key={tag} href={selected ? '/' : `/tag/${encodeURIComponent(tag)}`}> <Link key={tag} href={selected ? '/' : `/tag/${encodeURIComponent(tag)}`}>
<span <span
className={`cursor-pointer inline-block border hover:bg-gray-300 duration-200 mr-1 my-1 p-1 font-medium font-light text-xs whitespace-nowrap className={`cursor-pointer inline-block border rounded hover:bg-gray-300 duration-200 mr-1 my-1 p-1 font-medium font-light text-xs whitespace-nowrap
dark:text-gray-300 dark:hover:bg-gray-800 ${selected ? 'text-white bg-black dark:hover:bg-gray-900 dark:bg-black dark:border-gray-800' : 'bg-gray-200 text-gray-600 dark:bg-gray-600 dark:border-gray-600' dark:text-gray-300 dark:hover:bg-gray-800 ${selected ? 'text-white bg-black dark:hover:bg-gray-900 dark:bg-black dark:border-gray-800' : 'bg-gray-200 text-gray-600 dark:bg-gray-600 dark:border-gray-600'
}`} }`}
> >

View File

@@ -9,7 +9,7 @@ import SideBar from '@/components/SideBar'
import JumpToTop from '@/components/JumpToTop' import JumpToTop from '@/components/JumpToTop'
import { useGlobal } from '@/lib/global' import { useGlobal } from '@/lib/global'
const BaseLayout = ({ children, layout, fullWidth, tags, meta, post, totalPosts, currentSearch, ...customMeta }) => { const BaseLayout = ({ children, layout, fullWidth, tags, meta, post, totalPosts, currentSearch, currentCategory, categories, ...customMeta }) => {
let windowTop = 0 let windowTop = 0
const scrollTrigger = useCallback(throttle(() => { const scrollTrigger = useCallback(throttle(() => {
const scrollS = window.scrollY const scrollS = window.scrollY
@@ -40,7 +40,7 @@ const BaseLayout = ({ children, layout, fullWidth, tags, meta, post, totalPosts,
<TopNav tags={tags} post={post} posts={totalPosts} currentSearch={currentSearch} /> <TopNav tags={tags} post={post} posts={totalPosts} currentSearch={currentSearch} />
{/* Middle Wrapper */} {/* Middle Wrapper */}
<main className='flex dark:bg-black'> <main className='flex dark:bg-black'>
<SideBar tags={tags} post={post} posts={totalPosts} /> <SideBar tags={tags} post={post} posts={totalPosts} categories={categories} currentCategory={currentCategory} />
<div className='flex flex-grow' ref={targetRef}> <div className='flex flex-grow' ref={targetRef}>
{children} {children}
</div> </div>

View File

@@ -1,3 +1,4 @@
export { getAllPosts } from './notion/getAllPosts' export { getAllPosts } from './notion/getAllPosts'
export { getAllTags } from './notion/getAllTags' export { getAllTags } from './notion/getAllTags'
export { getPostBlocks } from './notion/getPostBlocks' export { getPostBlocks } from './notion/getPostBlocks'
export { getAllCategories } from './notion/getAllCategories'

View File

@@ -0,0 +1,22 @@
/**
* 获取所有文章的分类
* @param allPosts
* @returns {Promise<{}|*[]>}
*/
export async function getAllCategories (allPosts) {
if (!allPosts) {
return []
}
let categories = allPosts.map(p => p.category)
categories = [...categories.flat()]
const categoryObj = {}
categories.forEach(category => {
if (category in categoryObj) {
categoryObj[category]++
} else {
categoryObj[category] = 1
}
})
return categoryObj
}

View File

@@ -1,4 +1,4 @@
import { getAllPosts, getAllTags, getPostBlocks } from '@/lib/notion' import { getAllCategories, getAllPosts, getAllTags, getPostBlocks } from '@/lib/notion'
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import { getPageTableOfContents } from 'notion-utils' import { getPageTableOfContents } from 'notion-utils'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
@@ -9,11 +9,11 @@ import formatDate from '@/lib/formatDate'
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x' import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
import RewardButton from '@/components/RewardButton' import RewardButton from '@/components/RewardButton'
import ShareBar from '@/components/ShareBar' import ShareBar from '@/components/ShareBar'
import BlogPostMini from '@/components/BlogPostMini' import BlogPostCardMini from '@/components/BlogPostCardMini'
import Comment from '@/components/Comment' import Comment from '@/components/Comment'
import TocBar from '@/components/TocBar' import TocBar from '@/components/TocBar'
import BaseLayout from '@/layouts/BaseLayout' import BaseLayout from '@/layouts/BaseLayout'
import { useRef } from 'react' import React, { useRef } from 'react'
import Custom404 from '@/pages/404' import Custom404 from '@/pages/404'
import 'prismjs/themes/prism-okaidia.css' import 'prismjs/themes/prism-okaidia.css'
@@ -27,19 +27,19 @@ import 'prismjs/components/prism-typescript'
const mapPageUrl = id => { const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '') return 'https://www.notion.so/' + id.replace(/-/g, '')
} }
const ArticleDetail = ({ post, blockMap, tags, prev, next, posts }) => { const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories }) => {
if (!post) { if (!post) {
return <Custom404/> return <Custom404/>
} }
const meta = { const meta = {
title: post.title, title: `${post.title} | ${BLOG.title}`,
description: post.summary, description: post.summary,
type: 'article' type: 'article'
} }
const targetRef = useRef(null) const targetRef = useRef(null)
const url = BLOG.link + useRouter().asPath const url = BLOG.link + useRouter().asPath
return <BaseLayout meta={meta} tags={tags} post={post} totalPosts={posts} > return <BaseLayout meta={meta} tags={tags} post={post} totalPosts={posts} categories={categories} >
{/* 阅读进度条 */} {/* 阅读进度条 */}
<Progress targetRef={targetRef} /> <Progress targetRef={targetRef} />
@@ -65,25 +65,10 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts }) => {
{post.summary} {post.summary}
</h2> </h2>
{/* 文章信息 */} {/* 文章作者等关联信息 */}
<div className='justify-between flex flex-wrap bg-gray-50 p-2 dark:bg-gray-800 dark:text-white'> <div className='justify-between flex flex-wrap bg-gray-50 p-2 dark:bg-gray-800 dark:text-white'>
<div className='flex-nowrap flex'> <div className='flex-nowrap flex'>
<div className='cursor-pointer text-md py-2 mx-2 hover:underline'><i className='fa fa-folder-open-o mr-1'/>{post.category}</div>
{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' && ( {post.type[0] !== 'Page' && (
<div className='flex items-start text-gray-500 dark:text-gray-400 leading-10'> <div className='flex items-start text-gray-500 dark:text-gray-400 leading-10'>
@@ -93,6 +78,15 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts }) => {
)} )}
</div> </div>
)} )}
{post.tags && (
<div className='flex flex-nowrap leading-8 p-1'>
{post.tags.map(tag => (
<TagItem key={tag} tag={tag} />
))}
</div>
)}
</div> </div>
{/* 不蒜子 */} {/* 不蒜子 */}
@@ -141,10 +135,10 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts }) => {
</section> </section>
<div className='text-gray-800 my-5 dark:text-gray-300'> <div className='text-gray-800 my-5 dark:text-gray-300'>
<div className='mt-4 font-bold'>继续阅读</div> <div className='mt-4 font-bold'>其他文章</div>
<div className='flex flex-wrap lg:flex-nowrap lg:space-x-10 justify-between py-2'> <div className='flex flex-wrap lg:flex-nowrap lg:space-x-10 justify-between py-2'>
<BlogPostMini post={prev} /> <BlogPostCardMini post={prev} />
<BlogPostMini post={next} /> <BlogPostCardMini post={next} />
</div> </div>
</div> </div>
{/* 评论互动 */} {/* 评论互动 */}
@@ -198,13 +192,15 @@ export async function getStaticProps ({ params: { slug } }) {
} }
posts = posts.filter(post => post.type[0] === 'Post') posts = posts.filter(post => post.type[0] === 'Post')
const tags = await getAllTags(posts) const tags = await getAllTags(posts)
const categories = await getAllCategories(posts)
// 获取推荐文章 // 获取推荐文章
const index = posts.indexOf(post) const index = posts.indexOf(post)
const prev = posts.slice(index - 1, index)[0] ?? posts.slice(-1)[0] const prev = posts.slice(index - 1, index)[0] ?? posts.slice(-1)[0]
const next = posts.slice(index + 1, index + 2)[0] ?? posts[0] const next = posts.slice(index + 1, index + 2)[0] ?? posts[0]
return { return {
props: { post, blockMap, tags, prev, next, posts }, props: { post, blockMap, tags, prev, next, posts, categories },
revalidate: 1 revalidate: 1
} }
} }

View File

@@ -0,0 +1,56 @@
import { getAllCategories, getAllPosts, getAllTags } from '@/lib/notion'
import BLOG from '@/blog.config'
import TagsBar from '@/components/TagsBar'
import BaseLayout from '@/layouts/BaseLayout'
import BlogPostListScroll from '@/components/BlogPostListScroll'
export default function Category ({ tags, posts, category, categories }) {
const meta = {
title: `${BLOG.title} | ${category}`,
description: BLOG.description,
type: 'website'
}
return <BaseLayout meta={meta} tags={tags} currentCategory={category} totalPosts={posts} categories={categories}>
<div className='flex-grow bg-gray-200 dark:bg-black shadow-inner'>
<TagsBar tags={tags} />
<BlogPostListScroll posts={posts} tags={tags} currentCategory={category}/>
</div>
</BaseLayout>
}
export async function getStaticProps ({ params }) {
const category = params.category
let posts = await getAllPosts({ from: 'category-props' })
posts = posts.filter(
post => post.status[0] === 'Published' && post.type[0] === 'Post'
)
const tags = await getAllTags(posts)
const categories = await getAllCategories(posts)
const filteredPosts = posts.filter(
post => post && post.category && post.category.includes(category)
)
return {
props: {
tags,
posts: filteredPosts,
category,
categories
},
revalidate: 1
}
}
export async function getStaticPaths () {
if (BLOG.isProd) {
const tags = await getAllTags()
return {
paths: Object.keys(tags).map(tag => ({ params: { tag } })),
fallback: true
}
} else {
return {
paths: [],
fallback: true
}
}
}

View File

@@ -1,4 +1,4 @@
import { getAllPosts, getAllTags } from '@/lib/notion' import { getAllPosts, getAllTags, getAllCategories } from '@/lib/notion'
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import BaseLayout from '@/layouts/BaseLayout' import BaseLayout from '@/layouts/BaseLayout'
import TagsBar from '@/components/TagsBar' import TagsBar from '@/components/TagsBar'
@@ -10,6 +10,7 @@ export async function getStaticProps () {
post => post.status[0] === 'Published' && post.type[0] === 'Post' post => post.status[0] === 'Published' && post.type[0] === 'Post'
) )
const tags = await getAllTags(posts) const tags = await getAllTags(posts)
const categories = await getAllCategories(posts)
const meta = { const meta = {
title: `${BLOG.title} | ${BLOG.description} `, title: `${BLOG.title} | ${BLOG.description} `,
description: BLOG.description, description: BLOG.description,
@@ -19,15 +20,16 @@ export async function getStaticProps () {
props: { props: {
posts, posts,
tags, tags,
categories,
meta meta
}, },
revalidate: 1 revalidate: 1
} }
} }
const Index = ({ posts, tags, meta }) => { const Index = ({ posts, tags, meta, categories }) => {
return ( return (
<BaseLayout meta={meta} tags={tags} totalPosts={posts}> <BaseLayout meta={meta} tags={tags} totalPosts={posts} categories={categories}>
<div className='flex-grow bg-gray-200 dark:bg-black shadow-inner'> <div className='flex-grow bg-gray-200 dark:bg-black shadow-inner'>
<TagsBar tags={tags} /> <TagsBar tags={tags} />
<BlogPostListScroll posts={posts} tags={tags} /> <BlogPostListScroll posts={posts} tags={tags} />

View File

@@ -1,4 +1,4 @@
import { getAllPosts, getAllTags } from '@/lib/notion' import { getAllCategories, getAllPosts, getAllTags } from '@/lib/notion'
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import BaseLayout from '@/layouts/BaseLayout' import BaseLayout from '@/layouts/BaseLayout'
import TagsBar from '@/components/TagsBar' import TagsBar from '@/components/TagsBar'
@@ -11,6 +11,8 @@ export async function getStaticProps () {
post => post.status[0] === 'Published' && post.type[0] === 'Post' post => post.status[0] === 'Published' && post.type[0] === 'Post'
) )
const tags = await getAllTags(posts) const tags = await getAllTags(posts)
const categories = await getAllCategories(posts)
const meta = { const meta = {
title: `${BLOG.title} | ${BLOG.description} `, title: `${BLOG.title} | ${BLOG.description} `,
description: BLOG.description, description: BLOG.description,
@@ -20,13 +22,14 @@ export async function getStaticProps () {
props: { props: {
posts, posts,
tags, tags,
meta meta,
categories
}, },
revalidate: 1 revalidate: 1
} }
} }
const Search = ({ posts, tags, meta }) => { const Search = ({ posts, tags, meta, categories }) => {
// 处理查询过滤 支持标签、关键词过滤 // 处理查询过滤 支持标签、关键词过滤
let filteredPosts = [] let filteredPosts = []
const searchKey = getSearchKey() const searchKey = getSearchKey()
@@ -38,10 +41,10 @@ const Search = ({ posts, tags, meta }) => {
}) })
} }
return ( return (
<BaseLayout meta={meta} tags={tags} totalPosts={posts} currentSearch={searchKey}> <BaseLayout meta={meta} tags={tags} totalPosts={posts} currentSearch={searchKey} categories={categories}>
<div className='flex-grow bg-gray-200 dark:bg-black shadow-inner'> <div className='flex-grow bg-gray-200 dark:bg-black shadow-inner'>
<TagsBar tags={tags} /> <TagsBar tags={tags} />
<BlogPostListScroll posts={filteredPosts} tags={tags} /> <BlogPostListScroll posts={filteredPosts} tags={tags} currentSearch={searchKey} />
</div> </div>
</BaseLayout> </BaseLayout>
) )

View File

@@ -1,19 +1,19 @@
import { getAllPosts, getAllTags } from '@/lib/notion' import { getAllCategories, getAllPosts, getAllTags } from '@/lib/notion'
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import TagsBar from '@/components/TagsBar' import TagsBar from '@/components/TagsBar'
import BlogPostListPage from '@/components/BlogPostListPage'
import BaseLayout from '@/layouts/BaseLayout' import BaseLayout from '@/layouts/BaseLayout'
import BlogPostListScroll from '@/components/BlogPostListScroll'
export default function Tag ({ tags, posts, currentTag }) { export default function Tag ({ tags, posts, currentTag, categories }) {
const meta = { const meta = {
title: `${BLOG.title} | ${currentTag}`, title: `${BLOG.title} | #${currentTag}`,
description: BLOG.description, description: BLOG.description,
type: 'website' type: 'website'
} }
return <BaseLayout meta={meta} tags={tags} currentTag={currentTag}> return <BaseLayout meta={meta} tags={tags} currentTag={currentTag} categories={categories} totalPosts={posts}>
<div className='flex-grow'> <div className='flex-grow bg-gray-200 dark:bg-black shadow-inner'>
<TagsBar tags={tags} currentTag={currentTag}/> <TagsBar tags={tags} currentTag={currentTag}/>
<BlogPostListPage posts={posts} tags={tags}/> <BlogPostListScroll posts={posts} tags={tags} currentTag={currentTag}/>
</div> </div>
</BaseLayout> </BaseLayout>
} }
@@ -25,6 +25,7 @@ export async function getStaticProps ({ params }) {
post => post.status[0] === 'Published' && post.type[0] === 'Post' post => post.status[0] === 'Published' && post.type[0] === 'Post'
) )
const tags = await getAllTags(posts) const tags = await getAllTags(posts)
const categories = await getAllCategories(posts)
const filteredPosts = posts.filter( const filteredPosts = posts.filter(
post => post && post.tags && post.tags.includes(currentTag) post => post && post.tags && post.tags.includes(currentTag)
) )
@@ -32,7 +33,8 @@ export async function getStaticProps ({ params }) {
props: { props: {
tags, tags,
posts: filteredPosts, posts: filteredPosts,
currentTag currentTag,
categories
}, },
revalidate: 1 revalidate: 1
} }