mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
feature:
标签加入颜色
This commit is contained in:
@@ -7,6 +7,7 @@ const BLOG = {
|
||||
lang: 'zh-CN', // ['zh-CN','en-US']
|
||||
notionPageId: process.env.NOTION_PAGE_ID || 'bee1fccfa3bd47a1a7be83cc71372d83', // Important page_id!!!
|
||||
notionAccessToken: process.env.NOTION_ACCESS_TOKEN || '', // Useful if you prefer not to make your database public
|
||||
defaultImgCover: 'https://avatars.githubusercontent.com/u/15920488', // default image cover
|
||||
appearance: 'auto', // ['light', 'dark', 'auto'],
|
||||
font: 'font-serif', // ['font-sans', 'font-serif', 'font-mono']
|
||||
lightBackground: '#ffffff', // use hex value, don't forget '#' e.g #fffefc
|
||||
@@ -58,7 +59,7 @@ const BLOG = {
|
||||
}
|
||||
},
|
||||
isProd: process.env.VERCEL_ENV === 'production', // distinguish between development and production environment (ref: https://vercel.com/docs/environment-variables#system-environment-variables)
|
||||
googleAdsenseId: 'ca-pub-2708419466378217', //谷歌广告ID
|
||||
googleAdsenseId: 'ca-pub-2708419466378217', // 谷歌广告ID
|
||||
DaoVoiceId: '', // 在线聊天 DaoVoice http://dashboard.daovoice.io/get-started
|
||||
TidioId: '8lgekxyr9hr9m7archbs0a4a2gu9ckbg' // 在线聊天 https://www.tidio.com/
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import TagItemMini from '@/components/TagItemMini'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
const BlogPostCard = ({ post }) => {
|
||||
const BlogPostCard = ({ post, tags }) => {
|
||||
return (
|
||||
<div key={post.id}
|
||||
className='animate__animated animate__fadeIn animate__faster xl:flex shadow-card border dark:border-gray-600 mb-6 w-full bg-white bg-opacity-80 dark:bg-gray-800 dark:hover:bg-gray-700 overflow-hidden'>
|
||||
@@ -25,12 +25,14 @@ const BlogPostCard = ({ post }) => {
|
||||
<div className='flex md:flex-nowrap flex-wrap md:justify-start justify-between pt-5'>
|
||||
<div className='flex whitespace-nowrap'>
|
||||
<Link href={`/category/${post.category}`}>
|
||||
<div className='cursor-pointer dark:text-gray-200 text-gray-500 text-sm py-1.5 mr-1 underline hover:scale-105 transform duration-200'><i
|
||||
className='fa fa-folder-open-o mr-1' />{post.category}</div>
|
||||
<div
|
||||
className='cursor-pointer dark:text-gray-200 text-gray-500 text-sm py-1.5 mr-1 underline hover:scale-105 transform duration-200'>
|
||||
<i
|
||||
className='fa fa-folder-open-o mr-1' />{post.category}</div>
|
||||
</Link>
|
||||
<span className='mt-2 mx-2 text-gray-500 dark:text-gray-300 text-sm leading-4'>{post.date.start_date}</span>
|
||||
</div>
|
||||
<div className='flex ml-1'> {post.tags.map(tag => (<TagItemMini key={tag} tag={tag} />))}</div>
|
||||
<div className='flex ml-1'> {post.tagItems.map(tag => (<TagItemMini key={tag.name} tag={tag} />))}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -56,7 +56,7 @@ const BlogPostListScroll = ({ posts = [], tags, currentSearch, currentCategory,
|
||||
{/* 文章列表 */}
|
||||
<div className='flex flex-wrap'>
|
||||
{postsToShow.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} />
|
||||
<BlogPostCard key={post.id} post={post} tags={tags}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ const TagGroups = ({ tags, currentTag }) => {
|
||||
{
|
||||
tags.map(tag => {
|
||||
const selected = tag.name === currentTag
|
||||
return <TagItemMini key={tag.name} tag={tag.name} selected={selected} count={tag.count} />
|
||||
return <TagItemMini key={tag.name} tag={tag} selected={selected} />
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
const TagItemMini = ({ tag, selected = false, count }) => {
|
||||
return <Link key={tag} href={selected ? '/' : `/tag/${encodeURIComponent(tag)}`}>
|
||||
const TagItemMini = ({ tag, selected = false }) => {
|
||||
return <Link key={tag} href={selected ? '/' : `/tag/${encodeURIComponent(tag.name)}`}>
|
||||
<div className={`cursor-pointer inline-block border rounded hover:bg-gray-500 shadow-card
|
||||
mr-2 my-1 p-1 font-medium font-light text-xs whitespace-nowrap dark:text-gray-300
|
||||
mr-2 my-1 p-1 font-medium font-light text-xs whitespace-nowrap dark:text-gray-300
|
||||
${selected
|
||||
? 'text-white bg-gray-700 dark:hover:bg-gray-900 dark:bg-gray-500 border-gray-800'
|
||||
: 'bg-white text-gray-500 hover:shadow-xl hover:text-white border-gray-500 dark:bg-gray-800 dark:hover:bg-gray-600 dark:border-gray-600'}` }>
|
||||
<div> <i className='fa fa-tag mr-2 py-0.5'/>{tag + (count ? `(${count})` : '')} </div>
|
||||
? 'text-white bg-black dark:bg-black dark:border-gray-600 dark:hover:bg-gray-900 border-gray-800'
|
||||
: `text-gray-500 hover:shadow-xl hover:text-white border-gray-500 dark:hover:bg-gray-600 dark:border-gray-600 bg-${tag.color}-50 bg-gray-50 dark:bg-${tag.color}-700 dark:bg-gray-600 `}` }>
|
||||
<div> <i className='fa fa-tag mr-2 py-0.5'/>{tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||
</div>
|
||||
</Link>
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ const BaseLayout = ({
|
||||
let windowTop = 0
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY
|
||||
console.log(scrollS)
|
||||
if (scrollS >= windowTop && scrollS > 10) {
|
||||
handleScrollDown()
|
||||
windowTop = scrollS
|
||||
|
||||
13
lib/cache/cache_manager.js
vendored
13
lib/cache/cache_manager.js
vendored
@@ -1,12 +1,18 @@
|
||||
import { getCacheFromFile, setCacheToFile } from '@/lib/cache/local_file_cache'
|
||||
import { getCacheFromMemory, setCacheToMemory } from '@/lib/cache/memory_cache'
|
||||
import BLOG from '@/blog.config'
|
||||
// 关闭本地缓存
|
||||
const enableCache = true
|
||||
|
||||
/**
|
||||
* 为减少频繁接口请求,notion数据将被缓存
|
||||
* @param {*} key
|
||||
* @returns
|
||||
* @param {*} key
|
||||
* @returns
|
||||
*/
|
||||
export async function getDataFromCache (key) {
|
||||
if (!enableCache) {
|
||||
return null
|
||||
}
|
||||
let dataFromCache
|
||||
if (BLOG.isProd) {
|
||||
dataFromCache = await getCacheFromMemory(key)
|
||||
@@ -17,6 +23,9 @@ export async function getDataFromCache (key) {
|
||||
}
|
||||
|
||||
export async function setDataToCache (key, data) {
|
||||
if (!enableCache) {
|
||||
return
|
||||
}
|
||||
if (BLOG.isProd) {
|
||||
await setCacheToMemory(key, data)
|
||||
} else {
|
||||
|
||||
@@ -1,73 +1,62 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { idToUuid } from 'notion-utils'
|
||||
import getAllPageIds from './getAllPageIds'
|
||||
import getPageProperties from './getPageProperties'
|
||||
import { defaultMapImageUrl } from 'react-notion-x'
|
||||
import { getDataFromCache, setDataToCache } from '@/lib/cache/cache_manager'
|
||||
import { getPostBlocks } from '@/lib/notion/getPostBlocks'
|
||||
|
||||
export async function getAllPosts ({ from }) {
|
||||
// 尝试从缓存获取
|
||||
const data = await getDataFromCache('posts_list')
|
||||
if (data) return data
|
||||
const posts = await getPostsFromNotionAPI({ from })
|
||||
// 存入缓存
|
||||
if (posts) {
|
||||
await setDataToCache('posts_list', posts)
|
||||
}
|
||||
return posts || []
|
||||
}
|
||||
import { getNotionPageData } from '@/lib/notion/getNotionData'
|
||||
import TagItemMini from '@/components/TagItemMini'
|
||||
import React from 'react'
|
||||
|
||||
/**
|
||||
* 调用NotionAPI获取所有文章列表
|
||||
* @returns {Promise<JSX.Element|null|*>}
|
||||
* 获取所有文章列表
|
||||
* @param notionPageData
|
||||
* @param from
|
||||
* @param includePage 是否包含Page类型
|
||||
* @returns {Promise<*[]>}
|
||||
*/
|
||||
async function getPostsFromNotionAPI ({ from }) {
|
||||
let id = BLOG.notionPageId
|
||||
const pageRecordMap = await getPostBlocks(id, from)
|
||||
if (!pageRecordMap) {
|
||||
export async function getAllPosts ({ notionPageData, from, includePage = false }) {
|
||||
if (!notionPageData) {
|
||||
notionPageData = await getNotionPageData({ from })
|
||||
}
|
||||
if (!notionPageData) {
|
||||
return []
|
||||
}
|
||||
|
||||
id = idToUuid(id)
|
||||
const collection = Object.values(pageRecordMap.collection)[0]?.value
|
||||
const collectionQuery = pageRecordMap.collection_query
|
||||
const block = pageRecordMap.block
|
||||
const schema = collection?.schema
|
||||
const rawMetadata = block[id].value
|
||||
|
||||
// Check Type 兼容Page-Database和Inline-Database
|
||||
if (rawMetadata?.type !== 'collection_view_page' && rawMetadata?.type !== 'collection_view') {
|
||||
console.warn(`pageId "${id}" is not a database`)
|
||||
return null
|
||||
}
|
||||
const pageBlock = notionPageData.block
|
||||
const schema = notionPageData.schema
|
||||
const tagOptions = notionPageData.tagOptions
|
||||
const collectionQuery = notionPageData.collectionQuery
|
||||
|
||||
// 获取每篇文章信息
|
||||
const data = []
|
||||
const pageIds = getAllPageIds(collectionQuery)
|
||||
for (let i = 0; i < pageIds.length; i++) {
|
||||
const id = pageIds[i]
|
||||
const properties = (await getPageProperties(id, block, schema)) || null
|
||||
properties.createdTime = new Date(
|
||||
block[id].value?.created_time
|
||||
).toString()
|
||||
properties.lastEditedTime = new Date(
|
||||
block[id].value?.last_edited_time
|
||||
).toString()
|
||||
properties.fullWidth = block[id].value?.format?.page_full_width ?? false
|
||||
properties.page_cover = getPostCover(id, block, pageRecordMap) ?? getContentFirstImage(id, block, pageRecordMap)
|
||||
properties.content = block[id].value?.content ?? []
|
||||
const properties = (await getPageProperties(id, pageBlock, schema)) || null
|
||||
const tagItems = properties?.tags?.map(tag => { return { name: tag, color: tagOptions.find(t => t.value === tag).color } }) || ['默认']
|
||||
properties.createdTime = new Date(pageBlock[id].value?.created_time).toString()
|
||||
properties.lastEditedTime = new Date(pageBlock[id].value?.last_edited_time).toString()
|
||||
properties.fullWidth = pageBlock[id].value?.format?.page_full_width ?? false
|
||||
properties.page_cover = getPostCover(id, pageBlock) ?? BLOG.defaultImgCover
|
||||
properties.content = pageBlock[id].value?.content ?? []
|
||||
properties.tagItems = tagItems
|
||||
data.push(properties)
|
||||
}
|
||||
|
||||
// remove all the the items doesn't meet requirements
|
||||
const posts = data.filter(post => {
|
||||
return (
|
||||
post.title &&
|
||||
post.slug &&
|
||||
post?.status?.[0] === 'Published' &&
|
||||
(post?.type?.[0] === 'Post' || post?.type?.[0] === 'Page')
|
||||
)
|
||||
if (includePage) {
|
||||
return (
|
||||
post.title && post.slug &&
|
||||
post?.status?.[0] === 'Published' &&
|
||||
(post?.type?.[0] === 'Post' || post?.type?.[0] === 'Page')
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
post.title && post.slug &&
|
||||
post?.status?.[0] === 'Published' &&
|
||||
(post?.type?.[0] === 'Post')
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
// Sort by date
|
||||
@@ -82,30 +71,10 @@ async function getPostsFromNotionAPI ({ from }) {
|
||||
}
|
||||
|
||||
// 从Block获取封面图;优先取PageCover,否则取内容图片
|
||||
function getPostCover (id, block, pageRecordMap) {
|
||||
function getPostCover (id, block) {
|
||||
const pageCover = block[id].value?.format?.page_cover
|
||||
if (pageCover) {
|
||||
if (pageCover.startsWith('/')) return 'https://www.notion.so' + pageCover
|
||||
if (pageCover.startsWith('http')) return defaultMapImageUrl(pageCover, block[id].value)
|
||||
}
|
||||
}
|
||||
|
||||
// 取文章的第一个图片内容作为封面
|
||||
function getContentFirstImage (id, block, pageRecordMap) {
|
||||
const pageBlock = block[id]?.value
|
||||
|
||||
const contentBlockId = pageBlock?.content?.find((blockId) => {
|
||||
const block = pageRecordMap.block[blockId]?.value
|
||||
if (block?.type === 'image') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
if (contentBlockId) {
|
||||
const contentBlock = pageRecordMap.block[contentBlockId]?.value
|
||||
const source = contentBlock.properties?.source?.[0]?.[0] ??
|
||||
contentBlock.format?.display_source
|
||||
return defaultMapImageUrl(source, contentBlock)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
* 获取所有文章的标签
|
||||
* @param allPosts
|
||||
* @param sliceCount 默认截取数量为12,若为0则返回全部
|
||||
* @param tagOptions tags的下拉选项
|
||||
* @returns {Promise<{}|*[]>}
|
||||
*/
|
||||
export async function getAllTags (allPosts, sliceCount = 12) {
|
||||
export async function getAllTags ({ allPosts, sliceCount = 12, tagOptions }) {
|
||||
if (!allPosts) {
|
||||
return []
|
||||
}
|
||||
@@ -24,8 +25,9 @@ export async function getAllTags (allPosts, sliceCount = 12) {
|
||||
})
|
||||
|
||||
// 按照标签数量排序
|
||||
const list = Object.keys(tagObj).map((index) => {
|
||||
return { name: index, count: tagObj[index] }
|
||||
const list = Object.keys(tagObj).map((tag) => {
|
||||
const color = tagOptions.find(option => option.value === tag).color
|
||||
return { name: tag, count: tagObj[tag], color }
|
||||
})
|
||||
list.sort((a, b) => b.count - a.count)
|
||||
if (sliceCount) {
|
||||
|
||||
66
lib/notion/getNotionData.js
Normal file
66
lib/notion/getNotionData.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { idToUuid } from 'notion-utils'
|
||||
import { getDataFromCache, setDataToCache } from '@/lib/cache/cache_manager'
|
||||
import { getPostBlocks } from '@/lib/notion/getPostBlocks'
|
||||
|
||||
/**
|
||||
* 获取指定notion的collection数据
|
||||
* @param pageId
|
||||
* @param from 请求来源
|
||||
* @returns {Promise<JSX.Element|*|*[]>}
|
||||
*/
|
||||
export async function getNotionPageData ({ pageId = BLOG.notionPageId, from }) {
|
||||
// 尝试从缓存获取
|
||||
const data = await getDataFromCache('page_record_map_' + pageId)
|
||||
if (data) return data
|
||||
const pageRecordMap = await getPageRecordMapByNotionAPI({ pageId, from })
|
||||
// 存入缓存
|
||||
if (pageRecordMap) {
|
||||
await setDataToCache('page_record_map', pageRecordMap)
|
||||
}
|
||||
return pageRecordMap
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签选项
|
||||
* @param schema
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function getTagOptions (schema) {
|
||||
const tagSchema = Object.values(schema).find(e => e.name === 'tags')
|
||||
return tagSchema?.options || {}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用NotionAPI获取Page数据
|
||||
* @returns {Promise<JSX.Element|null|*>}
|
||||
*/
|
||||
async function getPageRecordMapByNotionAPI ({ pageId, from }) {
|
||||
const pageRecordMap = await getPostBlocks(pageId, from)
|
||||
if (!pageRecordMap) {
|
||||
return []
|
||||
}
|
||||
|
||||
pageId = idToUuid(pageId)
|
||||
const collection = Object.values(pageRecordMap.collection)[0]?.value
|
||||
const collectionQuery = pageRecordMap.collection_query
|
||||
const block = pageRecordMap.block
|
||||
const schema = collection?.schema
|
||||
const rawMetadata = block[pageId].value
|
||||
const tagOptions = getTagOptions(schema)
|
||||
|
||||
// Check Type Page-Database和Inline-Database
|
||||
if (rawMetadata?.type !== 'collection_view_page' && rawMetadata?.type !== 'collection_view') {
|
||||
console.warn(`pageId "${pageId}" is not a database`)
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
collection,
|
||||
collectionQuery,
|
||||
block,
|
||||
schema,
|
||||
tagOptions,
|
||||
rawMetadata
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,11 @@ export async function getPostBlocks (id, from) {
|
||||
const authToken = BLOG.notionAccessToken || null
|
||||
const api = new NotionAPI({ authToken })
|
||||
try {
|
||||
console.log(id, '向Notion请求数据:', from)
|
||||
console.log('[请求API]:', `from:${from}`, `id:${id}`)
|
||||
pageBlock = await api.getPage(id)
|
||||
console.log(id, '请求成功:', from)
|
||||
console.log('[请求成功]', `from:${from}`, `id:${id}`)
|
||||
} catch (error) {
|
||||
console.error(id, '请求失败:', from, error)
|
||||
console.error('[请求失败]', `from:${from}`, `id:${id}`, `error:${error}`)
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev-mac": "NODE_OPTIONS='--inspect' next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"postbuild": "next-sitemap --config next-sitemap.config.js"
|
||||
|
||||
@@ -30,7 +30,7 @@ const mapPageUrl = id => {
|
||||
}
|
||||
const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories }) => {
|
||||
if (!post) {
|
||||
return <Custom404/>
|
||||
return <Custom404 />
|
||||
}
|
||||
const meta = {
|
||||
title: `${post.title} | ${BLOG.title}`,
|
||||
@@ -42,7 +42,7 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
|
||||
const drawerRight = useRef(null)
|
||||
const url = BLOG.link + useRouter().asPath
|
||||
|
||||
return <BaseLayout meta={meta} tags={tags} post={post} totalPosts={posts} categories={categories} >
|
||||
return <BaseLayout meta={meta} tags={tags} post={post} totalPosts={posts} categories={categories}>
|
||||
<Progress targetRef={targetRef} />
|
||||
|
||||
<div id='article-wrapper' ref={targetRef} className='flex-grow bg-gray-200 dark:bg-black'>
|
||||
@@ -51,12 +51,13 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
|
||||
className='hover:shadow-2xl hover:scale-105 transform duration-200 mx-auto max-w-5xl mt-16 mb-2 lg:mt-32 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' }} loading="lazy"
|
||||
<img className='bg-center object-cover w-full' style={{ maxHeight: '40rem' }} loading='lazy'
|
||||
src={post.page_cover} alt={post.title} />
|
||||
)}
|
||||
</header>
|
||||
|
||||
<article className='hover:shadow-2xl duration-200 shadow-card mb-20 w-screen md:w-full overflow-x-auto md:px-10 px-5 pt-10 max-w-5xl mx-auto dark:border-gray-700 bg-white dark:bg-gray-900'>
|
||||
<article
|
||||
className='hover:shadow-2xl duration-200 shadow-card mb-20 w-screen md:w-full overflow-x-auto md:px-10 px-5 pt-10 max-w-5xl mx-auto dark:border-gray-700 bg-white dark:bg-gray-900'>
|
||||
{/* 文章标题 */}
|
||||
<h1 className='font-bold text-4xl text-black my-5 dark:text-white animate__animated animate__fadeIn'>
|
||||
{post.title}
|
||||
@@ -72,8 +73,9 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
|
||||
<div className='py-2 opacity-50'>
|
||||
分类:
|
||||
</div>
|
||||
<Link href={`/category/${post.category}`}>
|
||||
<div className='cursor-pointer text-md py-2 mx-3 hover:underline'><i className='fa fa-folder-open-o mr-1'/>{post.category}</div>
|
||||
<Link href={`/category/${post.category}`} passHref>
|
||||
<div className='cursor-pointer text-md py-2 mx-3 hover:underline'><i
|
||||
className='fa fa-folder-open-o mr-1' />{post.category}</div>
|
||||
</Link>
|
||||
|
||||
{post.type[0] !== 'Page' && (
|
||||
@@ -88,10 +90,9 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
|
||||
|
||||
{/* 不蒜子 */}
|
||||
<div id='busuanzi_container_page_pv' className='hidden'>
|
||||
<a href='/#'
|
||||
className='fa fa-eye text-gray-500 text-sm leading-none py-1 px-2'>
|
||||
<div 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>
|
||||
</div>
|
||||
|
||||
@@ -113,7 +114,7 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
|
||||
<RewardButton />
|
||||
</div>
|
||||
|
||||
<RecommendPosts currentPost={post} totalPosts={posts}/>
|
||||
<RecommendPosts currentPost={post} totalPosts={posts} />
|
||||
|
||||
{/* 版权声明 */}
|
||||
<section
|
||||
@@ -130,8 +131,8 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
|
||||
{post.tags && (
|
||||
<div className='flex flex-nowrap leading-8 p-1 py-4 overflow-x-auto'>
|
||||
<div className='hidden md:block dark:text-gray-300'>标签:</div>
|
||||
{post.tags.map(tag => (
|
||||
<TagItem key={tag} tag={tag} />
|
||||
{post.tagItems.map(tag => (
|
||||
<TagItem key={tag.name} tag={tag} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
@@ -143,33 +144,45 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
|
||||
</section>
|
||||
|
||||
<div className='text-gray-800 my-5 dark:text-gray-300'>
|
||||
<hr/>
|
||||
<hr />
|
||||
<div className='flex flex-wrap lg:flex-nowrap lg:space-x-10 justify-between py-2'>
|
||||
<Link href={`/article/${prev.slug}`}><div className='py-3 text-blue-500 text-lg hover:underline cursor-pointer'><i className='fa fa-angle-double-left mr-1'/>{prev.title}</div></Link>
|
||||
<Link href={`/article/${next.slug}`}><div className='flex py-3 text-blue-500 text-lg hover:underline cursor-pointer'>{next.title}<i className='fa fa-angle-double-right ml-1'/></div></Link>
|
||||
<Link href={`/article/${prev.slug}`}>
|
||||
<div className='py-3 text-blue-500 text-lg hover:underline cursor-pointer'><i
|
||||
className='fa fa-angle-double-left mr-1' />{prev.title}</div>
|
||||
</Link>
|
||||
<Link href={`/article/${next.slug}`}>
|
||||
<div className='flex py-3 text-blue-500 text-lg hover:underline cursor-pointer'>{next.title}<i
|
||||
className='fa fa-angle-double-right ml-1' /></div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
{/* 评论互动 */}
|
||||
<div className='shadow-card mb-20 w-screen md:w-full overflow-x-auto md:px-10 px-5 py-10 max-w-5xl mx-auto dark:border-gray-700 bg-white dark:bg-gray-700'>
|
||||
<div
|
||||
className='shadow-card mb-20 w-screen md:w-full overflow-x-auto md:px-10 px-5 py-10 max-w-5xl mx-auto dark:border-gray-700 bg-white dark:bg-gray-700'>
|
||||
<Comment frontMatter={post} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className='block lg:hidden'>
|
||||
<TocDrawerButton onClick={() => { drawerRight.current.handleSwitchVisible() }} />
|
||||
<TocDrawerButton onClick={() => {
|
||||
drawerRight.current.handleSwitchVisible()
|
||||
}} />
|
||||
{/* 目录侧边栏 */}
|
||||
<TocDrawer post={post} cRef={ drawerRight }/>
|
||||
<TocDrawer post={post} cRef={drawerRight} />
|
||||
</div>
|
||||
|
||||
</BaseLayout>
|
||||
}
|
||||
|
||||
export async function getStaticPaths () {
|
||||
let posts = await getAllPosts({ from: 'slug - paths' })
|
||||
posts = posts.filter(post => post.status[0] === 'Published')
|
||||
let posts = []
|
||||
if (BLOG.isProd) {
|
||||
posts = await getAllPosts({ from: 'slug - paths', includePage: true })
|
||||
posts = posts.filter(post => post.status[0] === 'Published')
|
||||
}
|
||||
return {
|
||||
paths: posts.map(row => `${BLOG.path}/article/${row.slug}`),
|
||||
fallback: true
|
||||
|
||||
@@ -5,6 +5,7 @@ import BaseLayout from '@/layouts/BaseLayout'
|
||||
import BlogPostListScroll from '@/components/BlogPostListScroll'
|
||||
import React from 'react'
|
||||
import CategoryList from '@/components/CategoryList'
|
||||
import { getNotionPageData } from '@/lib/notion/getNotionData'
|
||||
|
||||
export default function Category ({ tags, posts, category, categories }) {
|
||||
const meta = {
|
||||
@@ -23,14 +24,14 @@ export default function Category ({ tags, posts, category, categories }) {
|
||||
}
|
||||
|
||||
export async function getStaticProps ({ params }) {
|
||||
const from = 'category-props'
|
||||
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(
|
||||
const notionPageData = await getNotionPageData({ from })
|
||||
const allPosts = await getAllPosts({ notionPageData, from })
|
||||
const categories = await getAllCategories(allPosts)
|
||||
const tagOptions = notionPageData.tagOptions
|
||||
const tags = await getAllTags({ allPosts, tagOptions })
|
||||
const filteredPosts = allPosts.filter(
|
||||
post => post && post.category && post.category.includes(category)
|
||||
)
|
||||
return {
|
||||
@@ -45,16 +46,14 @@ export async function getStaticProps ({ params }) {
|
||||
}
|
||||
|
||||
export async function getStaticPaths () {
|
||||
let posts = []
|
||||
let categories = []
|
||||
if (BLOG.isProd) {
|
||||
const tags = await getAllTags()
|
||||
return {
|
||||
paths: Object.keys(tags).map(tag => ({ params: { tag } })),
|
||||
fallback: true
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: true
|
||||
}
|
||||
posts = await getAllPosts({ from: 'category-path' })
|
||||
categories = await getAllCategories(posts)
|
||||
}
|
||||
return {
|
||||
paths: Object.keys(categories).map(category => ({ params: { category } })),
|
||||
fallback: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,15 @@ import { getAllCategories, getAllPosts, getAllTags } from '@/lib/notion'
|
||||
import BLOG from '@/blog.config'
|
||||
import BaseLayout from '@/layouts/BaseLayout'
|
||||
import BlogPostListScroll from '@/components/BlogPostListScroll'
|
||||
import { getNotionPageData } from '@/lib/notion/getNotionData'
|
||||
|
||||
export async function getStaticProps () {
|
||||
let posts = await getAllPosts({ from: 'index' })
|
||||
posts = posts.filter(
|
||||
post => post.status[0] === 'Published' && post.type[0] === 'Post'
|
||||
)
|
||||
const tags = await getAllTags(posts)
|
||||
const categories = await getAllCategories(posts)
|
||||
const from = 'index'
|
||||
const notionPageData = await getNotionPageData({ from })
|
||||
const allPosts = await getAllPosts({ notionPageData, from })
|
||||
const categories = await getAllCategories(allPosts)
|
||||
const tagOptions = notionPageData.tagOptions
|
||||
const tags = await getAllTags({ allPosts, tagOptions })
|
||||
const meta = {
|
||||
title: `${BLOG.title} | ${BLOG.description} `,
|
||||
description: BLOG.description,
|
||||
@@ -17,7 +18,7 @@ export async function getStaticProps () {
|
||||
}
|
||||
return {
|
||||
props: {
|
||||
posts,
|
||||
allPosts,
|
||||
tags,
|
||||
categories,
|
||||
meta
|
||||
@@ -26,11 +27,11 @@ export async function getStaticProps () {
|
||||
}
|
||||
}
|
||||
|
||||
const Index = ({ posts, tags, meta, categories }) => {
|
||||
const Index = ({ allPosts, tags, meta, categories }) => {
|
||||
return (
|
||||
<BaseLayout meta={meta} tags={tags} totalPosts={posts} categories={categories}>
|
||||
<BaseLayout meta={meta} tags={tags} totalPosts={allPosts} categories={categories}>
|
||||
<div className='flex-grow bg-gray-200 dark:bg-black shadow-inner'>
|
||||
<BlogPostListScroll posts={posts} tags={tags} />
|
||||
<BlogPostListScroll posts={allPosts} tags={tags} />
|
||||
</div>
|
||||
</BaseLayout>
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import StickyBar from '@/components/StickyBar'
|
||||
import BaseLayout from '@/layouts/BaseLayout'
|
||||
import BlogPostListScroll from '@/components/BlogPostListScroll'
|
||||
import TagList from '@/components/TagList'
|
||||
import { getNotionPageData } from '@/lib/notion/getNotionData'
|
||||
|
||||
export default function Tag ({ tags, posts, currentTag, categories }) {
|
||||
const meta = {
|
||||
@@ -23,13 +24,13 @@ export default function Tag ({ tags, posts, currentTag, categories }) {
|
||||
|
||||
export async function getStaticProps ({ params }) {
|
||||
const currentTag = params.tag
|
||||
let posts = await getAllPosts({ from: 'tag-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(
|
||||
const from = 'tag-props'
|
||||
const notionPageData = await getNotionPageData({ from })
|
||||
const allPosts = await getAllPosts({ notionPageData, from })
|
||||
const categories = await getAllCategories(allPosts)
|
||||
const tagOptions = notionPageData.tagOptions
|
||||
const tags = await getAllTags({ allPosts, tagOptions })
|
||||
const filteredPosts = allPosts.filter(
|
||||
post => post && post.tags && post.tags.includes(currentTag)
|
||||
)
|
||||
return {
|
||||
@@ -44,16 +45,14 @@ export async function getStaticProps ({ params }) {
|
||||
}
|
||||
|
||||
export async function getStaticPaths () {
|
||||
let posts = []
|
||||
let tags = []
|
||||
if (BLOG.isProd) {
|
||||
const tags = await getAllTags()
|
||||
return {
|
||||
paths: Object.keys(tags).map(tag => ({ params: { tag } })),
|
||||
fallback: true
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: true
|
||||
}
|
||||
posts = await getAllPosts({ from: 'tag-props' })
|
||||
tags = await getAllTags(posts)
|
||||
}
|
||||
return {
|
||||
paths: Object.keys(tags).map(tag => ({ params: { tag } })),
|
||||
fallback: true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user