diff --git a/blog.config.js b/blog.config.js
index c4b4c886..ba52c635 100644
--- a/blog.config.js
+++ b/blog.config.js
@@ -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/
}
diff --git a/components/BlogPostCard.js b/components/BlogPostCard.js
index b30cb5db..ae49f8d0 100644
--- a/components/BlogPostCard.js
+++ b/components/BlogPostCard.js
@@ -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 (
@@ -25,12 +25,14 @@ const BlogPostCard = ({ post }) => {
-
{post.category}
+
+ {post.category}
{post.date.start_date}
-
{post.tags.map(tag => ())}
+
{post.tagItems.map(tag => ())}
diff --git a/components/BlogPostListScroll.js b/components/BlogPostListScroll.js
index 5ff9f721..8d0d76c4 100644
--- a/components/BlogPostListScroll.js
+++ b/components/BlogPostListScroll.js
@@ -56,7 +56,7 @@ const BlogPostListScroll = ({ posts = [], tags, currentSearch, currentCategory,
{/* 文章列表 */}
{postsToShow.map(post => (
-
+
))}
diff --git a/components/TagGroups.js b/components/TagGroups.js
index ceed3ccb..45ea3c33 100644
--- a/components/TagGroups.js
+++ b/components/TagGroups.js
@@ -14,7 +14,7 @@ const TagGroups = ({ tags, currentTag }) => {
{
tags.map(tag => {
const selected = tag.name === currentTag
- return
+ return
})
}
diff --git a/components/TagItemMini.js b/components/TagItemMini.js
index 7fdc6abf..eb6e37e4 100644
--- a/components/TagItemMini.js
+++ b/components/TagItemMini.js
@@ -1,13 +1,13 @@
import Link from 'next/link'
-const TagItemMini = ({ tag, selected = false, count }) => {
- return
+const TagItemMini = ({ tag, selected = false }) => {
+ return
-
{tag + (count ? `(${count})` : '')}
+ ? '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 `}` }>
+
{tag.name + (tag.count ? `(${tag.count})` : '')}
}
diff --git a/layouts/BaseLayout.js b/layouts/BaseLayout.js
index addb3269..814f311b 100644
--- a/layouts/BaseLayout.js
+++ b/layouts/BaseLayout.js
@@ -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
diff --git a/lib/cache/cache_manager.js b/lib/cache/cache_manager.js
index 34b5fff7..b28c2c0f 100644
--- a/lib/cache/cache_manager.js
+++ b/lib/cache/cache_manager.js
@@ -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 {
diff --git a/lib/notion/getAllPosts.js b/lib/notion/getAllPosts.js
index 02aaab2a..becd9ca3 100644
--- a/lib/notion/getAllPosts.js
+++ b/lib/notion/getAllPosts.js
@@ -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}
+ * 获取所有文章列表
+ * @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 ''
-}
diff --git a/lib/notion/getAllTags.js b/lib/notion/getAllTags.js
index a3df72c4..aa0a6d9b 100644
--- a/lib/notion/getAllTags.js
+++ b/lib/notion/getAllTags.js
@@ -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) {
diff --git a/lib/notion/getNotionData.js b/lib/notion/getNotionData.js
new file mode 100644
index 00000000..a6cc5b0e
--- /dev/null
+++ b/lib/notion/getNotionData.js
@@ -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}
+ */
+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}
+ */
+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
+ }
+}
diff --git a/lib/notion/getPostBlocks.js b/lib/notion/getPostBlocks.js
index c9cbfa50..299d66d5 100644
--- a/lib/notion/getPostBlocks.js
+++ b/lib/notion/getPostBlocks.js
@@ -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
}
diff --git a/package.json b/package.json
index b487cab2..98e9ec54 100644
--- a/package.json
+++ b/package.json
@@ -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"
diff --git a/pages/article/[slug].js b/pages/article/[slug].js
index 92881f5e..b0bf47ef 100644
--- a/pages/article/[slug].js
+++ b/pages/article/[slug].js
@@ -30,7 +30,7 @@ const mapPageUrl = id => {
}
const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories }) => {
if (!post) {
- return
+ return
}
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
+ return
@@ -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 && (
-

)}
-
+
{/* 文章标题 */}
{post.title}
@@ -72,8 +73,9 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
分类:
-
- {post.category}
+
+ {post.category}
{post.type[0] !== 'Page' && (
@@ -88,10 +90,9 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
{/* 不蒜子 */}
@@ -113,7 +114,7 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
-
+
{/* 版权声明 */}
标签:
- {post.tags.map(tag => (
-
+ {post.tagItems.map(tag => (
+
))}
)}
@@ -143,33 +144,45 @@ const ArticleDetail = ({ post, blockMap, tags, prev, next, posts, categories })
-
+
-
{prev.title}
-
{next.title}
+
+
{prev.title}
+
+
+
{next.title}
+
{/* 评论互动 */}
-
- { drawerRight.current.handleSwitchVisible() }} />
+ {
+ drawerRight.current.handleSwitchVisible()
+ }} />
{/* 目录侧边栏 */}
-
+
}
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
diff --git a/pages/category/[category].js b/pages/category/[category].js
index 86e7d77d..eec3196a 100644
--- a/pages/category/[category].js
+++ b/pages/category/[category].js
@@ -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
}
}
diff --git a/pages/index.js b/pages/index.js
index b1a7ac78..f889b5fe 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -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 (
-
+
-
+
)
diff --git a/pages/tag/[tag].js b/pages/tag/[tag].js
index 3d493f79..603891a6 100644
--- a/pages/tag/[tag].js
+++ b/pages/tag/[tag].js
@@ -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
}
}