mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
Merge pull request #2414 from tangly1024/hotfix/NOTION-CONFIG-for-GITBOOK_AUTO_SORT
修复部分NOTION_CONFIG读取问题
This commit is contained in:
@@ -14,15 +14,38 @@ import { deepClone } from './utils'
|
||||
* @param {*} extendConfig ; 参考配置对象{key:val},如果notion中找不到优先尝试在这里面查找
|
||||
* @returns
|
||||
*/
|
||||
export const siteConfig = (key, defaultVal = null, extendConfig = null) => {
|
||||
let global = null
|
||||
export const siteConfig = (key, defaultVal = null, extendConfig = {}) => {
|
||||
if (!key) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 特殊配置处理;某些配置只在服务端生效;而Global的NOTION_CONFIG仅限前端组件使用,因此需要从extendConfig中读取
|
||||
switch (key) {
|
||||
case 'NEXT_REVALIDATE_SECOND':
|
||||
case 'POST_RECOMMEND_COUNT':
|
||||
case 'IMAGE_COMPRESS_WIDTH':
|
||||
case 'PSEUDO_STATIC':
|
||||
case 'POSTS_SORT_BY':
|
||||
case 'POSTS_PER_PAGE':
|
||||
case 'POST_PREVIEW_LINES':
|
||||
case 'POST_URL_PREFIX':
|
||||
case 'POST_LIST_STYLE':
|
||||
case 'POST_LIST_PREVIEW':
|
||||
case 'POST_URL_PREFIX_MAPPING_CATEGORY':
|
||||
return convertVal(extendConfig[key] || defaultVal || BLOG[key])
|
||||
default:
|
||||
}
|
||||
|
||||
let global = {}
|
||||
try {
|
||||
const isClient = typeof window !== 'undefined'
|
||||
// const isClient = typeof window !== 'undefined'
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
global = isClient ? useGlobal() : {}
|
||||
global = useGlobal()
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// global = useGlobal()
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
console.warn('SiteConfig警告', key, error)
|
||||
}
|
||||
|
||||
// 首先 配置最优先读取NOTION中的表格配置
|
||||
let val = null
|
||||
@@ -66,6 +89,16 @@ export const siteConfig = (key, defaultVal = null, extendConfig = null) => {
|
||||
}
|
||||
|
||||
// 从Notion_CONFIG读取的配置通常都是字符串,适当转义
|
||||
return convertVal(val)
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置默认都是string类型;
|
||||
* 识别配置的值是否数字、布尔、[]数组,若是则转成对应类型
|
||||
* @param {*} val
|
||||
* @returns
|
||||
*/
|
||||
export const convertVal = val => {
|
||||
if (typeof val === 'string') {
|
||||
// 解析布尔
|
||||
if (val === 'true' || val === 'false') {
|
||||
|
||||
@@ -236,12 +236,13 @@ function getCategoryOptions(schema) {
|
||||
* @param from
|
||||
* @returns {Promise<{title,description,pageCover,icon}>}
|
||||
*/
|
||||
function getSiteInfo({ collection, block, NOTION_CONFIG, pageId }) {
|
||||
const defaultTitle = siteConfig('TITLE', '', NOTION_CONFIG)
|
||||
const defaultDescription = siteConfig('DESCRIPTION', '', NOTION_CONFIG)
|
||||
const defaultPageCover = siteConfig('HOME_BANNER_IMAGE', '', NOTION_CONFIG)
|
||||
const defaultIcon = siteConfig('AVATAR', '', NOTION_CONFIG)
|
||||
const defaultLink = siteConfig('LINK', '', NOTION_CONFIG)
|
||||
function getSiteInfo({ collection, block, NOTION_CONFIG }) {
|
||||
const defaultTitle = NOTION_CONFIG?.TITLE || BLOG.TITLE
|
||||
const defaultDescription = NOTION_CONFIG?.DESCRIPTION || BLOG.DESCRIPTION
|
||||
const defaultPageCover =
|
||||
NOTION_CONFIG?.HOME_BANNER_IMAGE || BLOG.HOME_BANNER_IMAGE
|
||||
const defaultIcon = NOTION_CONFIG?.AVATAR || BLOG.AVATAR
|
||||
const defaultLink = NOTION_CONFIG?.LINK || BLOG.LINK
|
||||
if (!collection && !block) {
|
||||
return {
|
||||
title: defaultTitle,
|
||||
|
||||
@@ -186,7 +186,7 @@ export function adjustPageProperties(properties, NOTION_CONFIG) {
|
||||
}
|
||||
|
||||
// 开启伪静态路径
|
||||
if (siteConfig('PSEUDO_STATIC', false, NOTION_CONFIG)) {
|
||||
if (JSON.parse(NOTION_CONFIG?.PSEUDO_STATIC || BLOG.PSEUDO_STATIC)) {
|
||||
if (
|
||||
!properties?.href?.endsWith('.html') &&
|
||||
!properties?.href?.startsWith('http')
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import fs from 'fs'
|
||||
import { siteConfig } from './config'
|
||||
|
||||
export async function generateRobotsTxt(NOTION_CONFIG) {
|
||||
const LINK = siteConfig('LINK', '', NOTION_CONFIG)
|
||||
export async function generateRobotsTxt(props) {
|
||||
const { siteInfo } = props
|
||||
const LINK = siteInfo?.link
|
||||
const content = `
|
||||
# *
|
||||
User-agent: *
|
||||
|
||||
39
lib/rss.js
39
lib/rss.js
@@ -1,9 +1,9 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import NotionPage from '@/components/NotionPage'
|
||||
import { getPostBlocks } from '@/lib/db/getSiteData'
|
||||
import { Feed } from 'feed'
|
||||
import fs from 'fs'
|
||||
import ReactDOMServer from 'react-dom/server'
|
||||
import { siteConfig } from './config'
|
||||
|
||||
/**
|
||||
* 生成RSS内容
|
||||
@@ -25,30 +25,33 @@ const createFeedContent = async post => {
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateRss(NOTION_CONFIG, posts) {
|
||||
const link = siteConfig('LINK', '', NOTION_CONFIG)
|
||||
const author = siteConfig('AUTHOR', '', NOTION_CONFIG)
|
||||
const lang = siteConfig('LANG', '', NOTION_CONFIG)
|
||||
const subPath = siteConfig('SUB_PATH', '', NOTION_CONFIG)
|
||||
|
||||
export async function generateRss(props) {
|
||||
const { NOTION_CONFIG, siteInfo, latestPosts } = props
|
||||
const TITLE = siteInfo?.title
|
||||
const DESCRIPTION = siteInfo?.description
|
||||
const LINK = siteInfo?.link
|
||||
const AUTHOR = NOTION_CONFIG?.AUTHOR || BLOG.AUTHOR
|
||||
const LANG = NOTION_CONFIG?.LANG || BLOG.LANG
|
||||
const SUB_PATH = NOTION_CONFIG?.SUB_PATH || BLOG.SUB_PATH
|
||||
const CONTACT_EMAIL = NOTION_CONFIG?.CONTACT_EMAIL || BLOG.CONTACT_EMAIL
|
||||
const year = new Date().getFullYear()
|
||||
const feed = new Feed({
|
||||
title: siteConfig('TITLE', '', NOTION_CONFIG),
|
||||
description: siteConfig('DESCRIPTION', '', NOTION_CONFIG),
|
||||
link: `${link}/${subPath}`,
|
||||
language: lang,
|
||||
favicon: `${link}/favicon.png`,
|
||||
copyright: `All rights reserved ${year}, ${author}`,
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
link: `${LINK}/${SUB_PATH}`,
|
||||
language: LANG,
|
||||
favicon: `${LINK}/favicon.png`,
|
||||
copyright: `All rights reserved ${year}, ${AUTHOR}`,
|
||||
author: {
|
||||
name: author,
|
||||
email: siteConfig('CONTACT_EMAIL', '', NOTION_CONFIG),
|
||||
link: link
|
||||
name: AUTHOR,
|
||||
email: CONTACT_EMAIL,
|
||||
link: LINK
|
||||
}
|
||||
})
|
||||
for (const post of posts) {
|
||||
for (const post of latestPosts) {
|
||||
feed.addItem({
|
||||
title: post.title,
|
||||
link: `${link}/${post.slug}`,
|
||||
link: `${LINK}/${post.slug}`,
|
||||
description: post.summary,
|
||||
content: await createFeedContent(post),
|
||||
date: new Date(post?.publishDay)
|
||||
|
||||
@@ -37,7 +37,10 @@ export async function getStaticProps({ params: { category }, locale }) {
|
||||
if (siteConfig('POST_LIST_STYLE') === 'scroll') {
|
||||
// 滚动列表 给前端返回所有数据
|
||||
} else if (siteConfig('POST_LIST_STYLE') === 'page') {
|
||||
props.posts = props.posts?.slice(0, siteConfig('POSTS_PER_PAGE'))
|
||||
props.posts = props.posts?.slice(
|
||||
0,
|
||||
siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)
|
||||
)
|
||||
}
|
||||
|
||||
delete props.allPages
|
||||
|
||||
@@ -30,10 +30,11 @@ export async function getStaticProps({ params: { category, page } }) {
|
||||
.filter(post => post && post.category && post.category.includes(category))
|
||||
// 处理文章页数
|
||||
props.postCount = props.posts.length
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)
|
||||
// 处理分页
|
||||
props.posts = props.posts.slice(
|
||||
siteConfig('POSTS_PER_PAGE') * (page - 1),
|
||||
siteConfig('POSTS_PER_PAGE') * page
|
||||
POSTS_PER_PAGE * (page - 1),
|
||||
POSTS_PER_PAGE * page
|
||||
)
|
||||
|
||||
delete props.allPages
|
||||
@@ -53,7 +54,9 @@ export async function getStaticProps({ params: { category, page } }) {
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const from = 'category-paths'
|
||||
const { categoryOptions, allPages } = await getGlobalData({ from })
|
||||
const { categoryOptions, allPages, NOTION_CONFIG } = await getGlobalData({
|
||||
from
|
||||
})
|
||||
const paths = []
|
||||
|
||||
categoryOptions?.forEach(category => {
|
||||
@@ -65,7 +68,9 @@ export async function getStaticPaths() {
|
||||
)
|
||||
// 处理文章页数
|
||||
const postCount = categoryPosts.length
|
||||
const totalPages = Math.ceil(postCount / siteConfig('POSTS_PER_PAGE'))
|
||||
const totalPages = Math.ceil(
|
||||
postCount / siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
)
|
||||
if (totalPages > 1) {
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
paths.push({ params: { category: category.name, page: '' + i } })
|
||||
|
||||
@@ -28,7 +28,11 @@ export async function getStaticProps(req) {
|
||||
const { locale } = req
|
||||
const from = 'index'
|
||||
const props = await getGlobalData({ from, locale })
|
||||
|
||||
const POST_PREVIEW_LINES = siteConfig(
|
||||
'POST_PREVIEW_LINES',
|
||||
12,
|
||||
props?.NOTION_CONFIG
|
||||
)
|
||||
props.posts = props.allPages?.filter(
|
||||
page => page.type === 'Post' && page.status === 'Published'
|
||||
)
|
||||
@@ -37,29 +41,28 @@ export async function getStaticProps(req) {
|
||||
if (siteConfig('POST_LIST_STYLE') === 'scroll') {
|
||||
// 滚动列表默认给前端返回所有数据
|
||||
} else if (siteConfig('POST_LIST_STYLE') === 'page') {
|
||||
props.posts = props.posts?.slice(0, siteConfig('POSTS_PER_PAGE'))
|
||||
props.posts = props.posts?.slice(
|
||||
0,
|
||||
siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)
|
||||
)
|
||||
}
|
||||
|
||||
// 预览文章内容
|
||||
if (siteConfig('POST_LIST_PREVIEW')) {
|
||||
if (siteConfig('POST_LIST_PREVIEW', false, props?.NOTION_CONFIG)) {
|
||||
for (const i in props.posts) {
|
||||
const post = props.posts[i]
|
||||
if (post.password && post.password !== '') {
|
||||
continue
|
||||
}
|
||||
post.blockMap = await getPostBlocks(
|
||||
post.id,
|
||||
'slug',
|
||||
siteConfig('POST_PREVIEW_LINES')
|
||||
)
|
||||
post.blockMap = await getPostBlocks(post.id, 'slug', POST_PREVIEW_LINES)
|
||||
}
|
||||
}
|
||||
|
||||
// 生成robotTxt
|
||||
generateRobotsTxt(props?.NOTION_CONFIG)
|
||||
generateRobotsTxt(props)
|
||||
// 生成Feed订阅
|
||||
if (JSON.parse(BLOG.ENABLE_RSS)) {
|
||||
generateRss(props?.NOTION_CONFIG, props?.latestPosts || [])
|
||||
generateRss(props)
|
||||
}
|
||||
|
||||
// 生成全文索引 - 仅在 yarn build 时执行 && process.env.npm_lifecycle_event === 'build'
|
||||
|
||||
@@ -21,8 +21,10 @@ const Page = props => {
|
||||
|
||||
export async function getStaticPaths({ locale }) {
|
||||
const from = 'page-paths'
|
||||
const { postCount } = await getGlobalData({ from, locale })
|
||||
const totalPages = Math.ceil(postCount / siteConfig('POSTS_PER_PAGE'))
|
||||
const { postCount, NOTION_CONFIG } = await getGlobalData({ from, locale })
|
||||
const totalPages = Math.ceil(
|
||||
postCount / siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
)
|
||||
return {
|
||||
// remove first page, we 're not gonna handle that.
|
||||
paths: Array.from({ length: totalPages - 1 }, (_, i) => ({
|
||||
@@ -36,28 +38,31 @@ export async function getStaticProps({ params: { page } }) {
|
||||
const from = `page-${page}`
|
||||
const props = await getGlobalData({ from })
|
||||
const { allPages } = props
|
||||
const POST_PREVIEW_LINES = siteConfig(
|
||||
'POST_PREVIEW_LINES',
|
||||
12,
|
||||
props?.NOTION_CONFIG
|
||||
)
|
||||
|
||||
const allPosts = allPages?.filter(
|
||||
page => page.type === 'Post' && page.status === 'Published'
|
||||
)
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)
|
||||
// 处理分页
|
||||
props.posts = allPosts.slice(
|
||||
siteConfig('POSTS_PER_PAGE') * (page - 1),
|
||||
siteConfig('POSTS_PER_PAGE') * page
|
||||
POSTS_PER_PAGE * (page - 1),
|
||||
POSTS_PER_PAGE * page
|
||||
)
|
||||
props.page = page
|
||||
|
||||
// 处理预览
|
||||
if (siteConfig('POST_LIST_PREVIEW')) {
|
||||
if (siteConfig('POST_LIST_PREVIEW', false, props?.NOTION_CONFIG)) {
|
||||
for (const i in props.posts) {
|
||||
const post = props.posts[i]
|
||||
if (post.password && post.password !== '') {
|
||||
continue
|
||||
}
|
||||
post.blockMap = await getPostBlocks(
|
||||
post.id,
|
||||
'slug',
|
||||
siteConfig('POST_PREVIEW_LINES')
|
||||
)
|
||||
post.blockMap = await getPostBlocks(post.id, 'slug', POST_PREVIEW_LINES)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,18 @@ export async function getStaticProps({ params: { keyword }, locale }) {
|
||||
)
|
||||
props.posts = await filterByMemCache(allPosts, keyword)
|
||||
props.postCount = props.posts.length
|
||||
const POST_LIST_STYLE = siteConfig(
|
||||
'POST_LIST_STYLE',
|
||||
'Page',
|
||||
props?.NOTION_CONFIG
|
||||
)
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)
|
||||
|
||||
// 处理分页
|
||||
if (siteConfig('POST_LIST_STYLE') === 'scroll') {
|
||||
// 滚动列表 给前端返回所有数据
|
||||
} else if (siteConfig('POST_LIST_STYLE') === 'page') {
|
||||
props.posts = props.posts?.slice(0, siteConfig('POSTS_PER_PAGE'))
|
||||
if (POST_LIST_STYLE === 'scroll') {
|
||||
// 滚动列表默认给前端返回所有数据
|
||||
} else if (POST_LIST_STYLE) {
|
||||
props.posts = props.posts?.slice(0, POSTS_PER_PAGE)
|
||||
}
|
||||
props.keyword = keyword
|
||||
return {
|
||||
|
||||
@@ -34,10 +34,11 @@ export async function getStaticProps({ params: { keyword, page }, locale }) {
|
||||
)
|
||||
props.posts = await filterByMemCache(allPosts, keyword)
|
||||
props.postCount = props.posts.length
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)
|
||||
// 处理分页
|
||||
props.posts = props.posts.slice(
|
||||
siteConfig('POSTS_PER_PAGE') * (page - 1),
|
||||
siteConfig('POSTS_PER_PAGE') * page
|
||||
POSTS_PER_PAGE * (page - 1),
|
||||
POSTS_PER_PAGE * page
|
||||
)
|
||||
props.keyword = keyword
|
||||
props.page = page
|
||||
|
||||
@@ -35,7 +35,10 @@ export async function getStaticProps({ params: { tag }, locale }) {
|
||||
if (siteConfig('POST_LIST_STYLE') === 'scroll') {
|
||||
// 滚动列表 给前端返回所有数据
|
||||
} else if (siteConfig('POST_LIST_STYLE') === 'page') {
|
||||
props.posts = props.posts?.slice(0, siteConfig('POSTS_PER_PAGE'))
|
||||
props.posts = props.posts?.slice(
|
||||
0,
|
||||
siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)
|
||||
)
|
||||
}
|
||||
|
||||
props.tag = tag
|
||||
|
||||
@@ -22,10 +22,11 @@ export async function getStaticProps({ params: { tag, page }, locale }) {
|
||||
.filter(post => post && post?.tags && post?.tags.includes(tag))
|
||||
// 处理文章数
|
||||
props.postCount = props.posts.length
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)
|
||||
// 处理分页
|
||||
props.posts = props.posts.slice(
|
||||
siteConfig('POSTS_PER_PAGE') * (page - 1),
|
||||
siteConfig('POSTS_PER_PAGE') * page
|
||||
POSTS_PER_PAGE * (page - 1),
|
||||
POSTS_PER_PAGE * page
|
||||
)
|
||||
|
||||
props.tag = tag
|
||||
@@ -43,7 +44,7 @@ export async function getStaticProps({ params: { tag, page }, locale }) {
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const from = 'tag-page-static-path'
|
||||
const { tagOptions, allPages } = await getGlobalData({ from })
|
||||
const { tagOptions, allPages, NOTION_CONFIG } = await getGlobalData({ from })
|
||||
const paths = []
|
||||
tagOptions?.forEach(tag => {
|
||||
// 过滤状态类型
|
||||
@@ -52,7 +53,9 @@ export async function getStaticPaths() {
|
||||
.filter(post => post && post?.tags && post?.tags.includes(tag.name))
|
||||
// 处理文章页数
|
||||
const postCount = tagPosts.length
|
||||
const totalPages = Math.ceil(postCount / siteConfig('POSTS_PER_PAGE'))
|
||||
const totalPages = Math.ceil(
|
||||
postCount / siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
)
|
||||
if (totalPages > 1) {
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
paths.push({ params: { tag: tag.name, page: '' + i } })
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import ProductCard from './ProductCard'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
import ProductCard from './ProductCard'
|
||||
|
||||
/**
|
||||
* 文章列表分页表格
|
||||
@@ -12,20 +13,29 @@ import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const showPagination = postCount >= parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
const showPagination = postCount >= POSTS_PER_PAGE
|
||||
if (!posts || posts.length === 0 || page > totalPage) {
|
||||
return <BlogPostListEmpty />
|
||||
} else {
|
||||
return (
|
||||
<div id="container" className='w-full'>
|
||||
<div id='container' className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className="py-4 gap-4 grid grid-cols-3">
|
||||
<div className='py-4 gap-4 grid grid-cols-3'>
|
||||
{posts?.map(post => (
|
||||
<ProductCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo}/>
|
||||
<ProductCard
|
||||
index={posts.indexOf(post)}
|
||||
key={post.id}
|
||||
post={post}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{showPagination && <PaginationNumber page={page} totalPage={totalPage} />}
|
||||
{showPagination && (
|
||||
<PaginationNumber page={page} totalPage={totalPage} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import ProductCard from './ProductCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import CONFIG from '../config'
|
||||
import { getListByPage } from '@/lib/utils'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import ProductCard from './ProductCard'
|
||||
|
||||
/**
|
||||
* 博客列表滚动分页
|
||||
@@ -13,15 +13,22 @@ import { useEffect, useRef, useState } from 'react'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = CONFIG.POST_LIST_SUMMARY, siteInfo }) => {
|
||||
const postsPerPage = parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const BlogPostListScroll = ({
|
||||
posts = [],
|
||||
currentSearch,
|
||||
showSummary = CONFIG.POST_LIST_SUMMARY,
|
||||
siteInfo
|
||||
}) => {
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
|
||||
const [page, updatePage] = useState(1)
|
||||
const postsToShow = getListByPage(posts, page, postsPerPage)
|
||||
const postsToShow = getListByPage(posts, page, POSTS_PER_PAGE)
|
||||
|
||||
let hasMore = false
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * postsPerPage < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
|
||||
const handleGetMore = () => {
|
||||
@@ -33,7 +40,11 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = CONFIG.PO
|
||||
const scrollTrigger = () => {
|
||||
requestAnimationFrame(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
@@ -54,21 +65,32 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = CONFIG.PO
|
||||
if (!postsToShow || postsToShow.length === 0) {
|
||||
return <BlogPostListEmpty currentSearch={currentSearch} />
|
||||
} else {
|
||||
return <div id='container' ref={targetRef} className='w-full'>
|
||||
return (
|
||||
<div id='container' ref={targetRef} className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className='space-y-6 px-2'>
|
||||
{postsToShow.map(post => (
|
||||
<ProductCard
|
||||
key={post.id}
|
||||
post={post}
|
||||
showSummary={showSummary}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 文章列表 */}
|
||||
<div className="space-y-6 px-2">
|
||||
{postsToShow.map(post => (
|
||||
<ProductCard key={post.id} post={post} showSummary={showSummary} siteInfo={siteInfo}/>
|
||||
))}
|
||||
<div>
|
||||
<div
|
||||
onClick={() => {
|
||||
handleGetMore()
|
||||
}}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer rounded-xl dark:text-gray-200'>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE}`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div onClick={() => { handleGetMore() }}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer rounded-xl dark:text-gray-200'
|
||||
> {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE}`} </div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ import BlogItem from './BlogItem'
|
||||
*/
|
||||
export const BlogListPage = props => {
|
||||
const { page = 1, posts, postCount } = props
|
||||
const { locale } = useGlobal()
|
||||
const { locale, NOTION_CONFIG } = useGlobal()
|
||||
const router = useRouter()
|
||||
const totalPage = Math.ceil(
|
||||
postCount / parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
postCount / siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
)
|
||||
const currentPage = +page
|
||||
|
||||
|
||||
@@ -11,21 +11,18 @@ import BlogItem from './BlogItem'
|
||||
*/
|
||||
export const BlogListScroll = props => {
|
||||
const { posts } = props
|
||||
const { locale } = useGlobal()
|
||||
|
||||
const { locale, NOTION_CONFIG } = useGlobal()
|
||||
const [page, updatePage] = useState(1)
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
|
||||
let hasMore = false
|
||||
const postsToShow = posts
|
||||
? Object.assign(posts).slice(
|
||||
0,
|
||||
parseInt(siteConfig('POSTS_PER_PAGE')) * page
|
||||
)
|
||||
? Object.assign(posts).slice(0, POSTS_PER_PAGE * page)
|
||||
: []
|
||||
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * parseInt(siteConfig('POSTS_PER_PAGE')) < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
const handleGetMore = () => {
|
||||
if (!hasMore) return
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { AdSlot } from '@/components/GoogleAdsense'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { deepClone, isBrowser } from '@/lib/utils'
|
||||
import { debounce } from 'lodash'
|
||||
import { useEffect, useState } from 'react'
|
||||
import BlogCard from './BlogCard'
|
||||
import BlogPostListEmpty from './BlogListEmpty'
|
||||
import PaginationSimple from './PaginationSimple'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { debounce } from 'lodash'
|
||||
import { AdSlot } from '@/components/GoogleAdsense'
|
||||
/**
|
||||
* 文章列表分页表格
|
||||
* @param page 当前页
|
||||
@@ -15,7 +16,10 @@ import { AdSlot } from '@/components/GoogleAdsense'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const totalPage = Math.ceil(
|
||||
postCount / parseInt(siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG))
|
||||
)
|
||||
const showNext = page < totalPage
|
||||
|
||||
const [columns, setColumns] = useState(calculateColumns())
|
||||
@@ -53,18 +57,25 @@ const BlogListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
return (
|
||||
<div>
|
||||
{/* 文章列表 */}
|
||||
<div id="posts-wrapper" className='grid-container'>
|
||||
<div id='posts-wrapper' className='grid-container'>
|
||||
{filterPosts?.map((post, index) => (
|
||||
<div key={post.id} className='grid-item justify-center flex' style={{ breakInside: 'avoid' }}>
|
||||
<BlogCard index={index} key={post.id} post={post} siteInfo={siteInfo} />
|
||||
<div
|
||||
key={post.id}
|
||||
className='grid-item justify-center flex'
|
||||
style={{ breakInside: 'avoid' }}>
|
||||
<BlogCard
|
||||
index={index}
|
||||
key={post.id}
|
||||
post={post}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{siteConfig('ADSENSE_GOOGLE_ID') && (
|
||||
<div className='p-3'>
|
||||
<AdSlot type='flow'/>
|
||||
<AdSlot type='flow' />
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
<PaginationSimple page={page} showNext={showNext} />
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import BlogCard from './BlogCard'
|
||||
import BlogPostListEmpty from './BlogListEmpty'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
|
||||
/**
|
||||
* 文章列表分页表格
|
||||
@@ -14,19 +14,19 @@ import { useGlobal } from '@/lib/global'
|
||||
*/
|
||||
const BlogListScroll = props => {
|
||||
const { posts = [], siteInfo } = props
|
||||
const { locale } = useGlobal()
|
||||
const { locale, NOTION_CONFIG } = useGlobal()
|
||||
const targetRef = useRef(null)
|
||||
|
||||
const [page, updatePage] = useState(1)
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
|
||||
let hasMore = false
|
||||
const postsToShow = posts
|
||||
? Object.assign(posts).slice(0, parseInt(siteConfig('POSTS_PER_PAGE')) * page)
|
||||
? Object.assign(posts).slice(0, POSTS_PER_PAGE * page)
|
||||
: []
|
||||
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * parseInt(siteConfig('POSTS_PER_PAGE')) < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
const handleGetMore = () => {
|
||||
if (!hasMore) return
|
||||
@@ -37,7 +37,11 @@ const BlogListScroll = props => {
|
||||
const scrollTrigger = () => {
|
||||
requestAnimationFrame(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
@@ -55,20 +59,29 @@ const BlogListScroll = props => {
|
||||
return <BlogPostListEmpty />
|
||||
} else {
|
||||
return (
|
||||
<div id="posts-wrapper" ref={targetRef} className='grid-container' >
|
||||
{/* 文章列表 */}
|
||||
{postsToShow?.map(post => (
|
||||
<div key={post.id} className='grid-item justify-center flex' style={{ breakInside: 'avoid' }}>
|
||||
<BlogCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo} />
|
||||
</div>
|
||||
))}
|
||||
<div id='posts-wrapper' ref={targetRef} className='grid-container'>
|
||||
{/* 文章列表 */}
|
||||
{postsToShow?.map(post => (
|
||||
<div
|
||||
key={post.id}
|
||||
className='grid-item justify-center flex'
|
||||
style={{ breakInside: 'avoid' }}>
|
||||
<BlogCard
|
||||
index={posts.indexOf(post)}
|
||||
key={post.id}
|
||||
post={post}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="w-full my-4 py-4 text-center cursor-pointer "
|
||||
onClick={handleGetMore}>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className='w-full my-4 py-4 text-center cursor-pointer '
|
||||
onClick={handleGetMore}>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { GameListIndexCombine } from './GameListIndexCombine'
|
||||
import PaginationSimple from './PaginationSimple'
|
||||
/**
|
||||
@@ -8,9 +8,8 @@ import PaginationSimple from './PaginationSimple'
|
||||
*/
|
||||
export const BlogListPage = props => {
|
||||
const { page = 1, postCount } = props
|
||||
const totalPage = Math.ceil(
|
||||
postCount / parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
)
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const totalPage = Math.ceil(postCount / NOTION_CONFIG)
|
||||
const showNext = page < totalPage
|
||||
|
||||
return (
|
||||
|
||||
@@ -7,19 +7,19 @@ import { GameListIndexCombine } from './GameListIndexCombine'
|
||||
|
||||
export const BlogListScroll = props => {
|
||||
const { posts } = props
|
||||
const { locale } = useGlobal()
|
||||
|
||||
const { locale, NOTION_CONFIG } = useGlobal()
|
||||
const [page, updatePage] = useState(1)
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
|
||||
let hasMore = false
|
||||
const postsToShow =
|
||||
posts && Array.isArray(posts)
|
||||
? deepClone(posts).slice(0, parseInt(siteConfig('POSTS_PER_PAGE')) * page)
|
||||
? deepClone(posts).slice(0, POSTS_PER_PAGE * page)
|
||||
: []
|
||||
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * parseInt(siteConfig('POSTS_PER_PAGE')) < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
const handleGetMore = () => {
|
||||
if (!hasMore) return
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import NotionIcon from '@/components/NotionIcon'
|
||||
import NotionPage from '@/components/NotionPage'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import Link from 'next/link'
|
||||
|
||||
const BlogPost = ({ post }) => {
|
||||
const showPreview = siteConfig('POST_LIST_PREVIEW') && post.blockMap
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const showPreview =
|
||||
siteConfig('POST_LIST_PREVIEW', false, NOTION_CONFIG) && post?.blockMap
|
||||
|
||||
return (
|
||||
<Link href={post?.href}>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
|
||||
/**
|
||||
* 文章列表分页表格
|
||||
@@ -12,22 +13,31 @@ import { siteConfig } from '@/lib/config'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const showPagination = postCount >= parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
const showPagination = postCount >= POSTS_PER_PAGE
|
||||
if (!posts || posts.length === 0 || page > totalPage) {
|
||||
return <BlogPostListEmpty />
|
||||
} else {
|
||||
return (
|
||||
<div id="container" className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className="2xl:grid 2xl:grid-cols-2 grid-cols-1 gap-5">
|
||||
{posts?.map(post => (
|
||||
<BlogPostCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo} />
|
||||
))}
|
||||
</div>
|
||||
<div id='container' className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className='2xl:grid 2xl:grid-cols-2 grid-cols-1 gap-5'>
|
||||
{posts?.map(post => (
|
||||
<BlogPostCard
|
||||
index={posts.indexOf(post)}
|
||||
key={post.id}
|
||||
post={post}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{showPagination && <PaginationNumber page={page} totalPage={totalPage} />}
|
||||
</div>
|
||||
{showPagination && (
|
||||
<PaginationNumber page={page} totalPage={totalPage} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { getListByPage } from '@/lib/utils'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import { getListByPage } from '@/lib/utils'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
|
||||
/**
|
||||
* 博客列表滚动分页
|
||||
@@ -13,15 +13,21 @@ import { siteConfig } from '@/lib/config'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfig('HEO_POST_LIST_SUMMARY', null, CONFIG), siteInfo }) => {
|
||||
const postsPerPage = parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const BlogPostListScroll = ({
|
||||
posts = [],
|
||||
currentSearch,
|
||||
showSummary = siteConfig('HEO_POST_LIST_SUMMARY', null, CONFIG),
|
||||
siteInfo
|
||||
}) => {
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const [page, updatePage] = useState(1)
|
||||
const postsToShow = getListByPage(posts, page, postsPerPage)
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const postsToShow = getListByPage(posts, page, POSTS_PER_PAGE)
|
||||
|
||||
let hasMore = false
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * postsPerPage < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
|
||||
const handleGetMore = () => {
|
||||
@@ -33,7 +39,11 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
const scrollTrigger = () => {
|
||||
requestAnimationFrame(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
@@ -54,22 +64,33 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
if (!postsToShow || postsToShow.length === 0) {
|
||||
return <BlogPostListEmpty currentSearch={currentSearch} />
|
||||
} else {
|
||||
return <div id='container' ref={targetRef} className='w-full'>
|
||||
return (
|
||||
<div id='container' ref={targetRef} className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className='2xl:grid 2xl:grid-cols-2 grid-cols-1 gap-5'>
|
||||
{postsToShow.map(post => (
|
||||
<BlogPostCard
|
||||
key={post.id}
|
||||
post={post}
|
||||
showSummary={showSummary}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 文章列表 */}
|
||||
<div className="2xl:grid 2xl:grid-cols-2 grid-cols-1 gap-5">
|
||||
{postsToShow.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} showSummary={showSummary} siteInfo={siteInfo}/>
|
||||
))}
|
||||
{/* 更多按钮 */}
|
||||
<div>
|
||||
<div
|
||||
onClick={() => {
|
||||
handleGetMore()
|
||||
}}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer rounded-xl dark:text-gray-200'>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE}`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 更多按钮 */}
|
||||
<div>
|
||||
<div onClick={() => { handleGetMore() }}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer rounded-xl dark:text-gray-200'
|
||||
> {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE}`} </div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
|
||||
/**
|
||||
* 文章列表分页表格
|
||||
@@ -12,20 +13,29 @@ import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const showPagination = postCount >= parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
const showPagination = postCount >= POSTS_PER_PAGE
|
||||
if (!posts || posts.length === 0 || page > totalPage) {
|
||||
return <BlogPostListEmpty />
|
||||
} else {
|
||||
return (
|
||||
<div id="container" className='w-full'>
|
||||
<div id='container' className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className="space-y-6 px-2">
|
||||
<div className='space-y-6 px-2'>
|
||||
{posts?.map(post => (
|
||||
<BlogPostCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo}/>
|
||||
<BlogPostCard
|
||||
index={posts.indexOf(post)}
|
||||
key={post.id}
|
||||
post={post}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{showPagination && <PaginationNumber page={page} totalPage={totalPage} />}
|
||||
{showPagination && (
|
||||
<PaginationNumber page={page} totalPage={totalPage} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { getListByPage } from '@/lib/utils'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import { getListByPage } from '@/lib/utils'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
|
||||
/**
|
||||
* 博客列表滚动分页
|
||||
@@ -13,15 +13,21 @@ import { getListByPage } from '@/lib/utils'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfig('HEXO_POST_LIST_SUMMARY', null, CONFIG), siteInfo }) => {
|
||||
const postsPerPage = parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const BlogPostListScroll = ({
|
||||
posts = [],
|
||||
currentSearch,
|
||||
showSummary = siteConfig('HEXO_POST_LIST_SUMMARY', null, CONFIG),
|
||||
siteInfo
|
||||
}) => {
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const [page, updatePage] = useState(1)
|
||||
const postsToShow = getListByPage(posts, page, postsPerPage)
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const postsToShow = getListByPage(posts, page, POSTS_PER_PAGE)
|
||||
|
||||
let hasMore = false
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * postsPerPage < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
|
||||
const handleGetMore = () => {
|
||||
@@ -33,7 +39,11 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
const scrollTrigger = () => {
|
||||
requestAnimationFrame(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
@@ -54,21 +64,32 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
if (!postsToShow || postsToShow.length === 0) {
|
||||
return <BlogPostListEmpty currentSearch={currentSearch} />
|
||||
} else {
|
||||
return <div id='container' ref={targetRef} className='w-full'>
|
||||
return (
|
||||
<div id='container' ref={targetRef} className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className='space-y-6 px-2'>
|
||||
{postsToShow.map(post => (
|
||||
<BlogPostCard
|
||||
key={post.id}
|
||||
post={post}
|
||||
showSummary={showSummary}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 文章列表 */}
|
||||
<div className="space-y-6 px-2">
|
||||
{postsToShow.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} showSummary={showSummary} siteInfo={siteInfo}/>
|
||||
))}
|
||||
<div>
|
||||
<div
|
||||
onClick={() => {
|
||||
handleGetMore()
|
||||
}}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer rounded-xl dark:text-gray-200'>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE}`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div onClick={() => { handleGetMore() }}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer rounded-xl dark:text-gray-200'
|
||||
> {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE}`} </div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import PaginationSimple from './PaginationSimple'
|
||||
@@ -12,10 +13,10 @@ import PaginationSimple from './PaginationSimple'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
const totalPage = Math.ceil(
|
||||
postCount / parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
)
|
||||
const showPagination = postCount >= parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
const showPagination = postCount >= POSTS_PER_PAGE
|
||||
if (!posts || posts.length === 0 || page > totalPage) {
|
||||
return <BlogPostListEmpty />
|
||||
} else {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import { getListByPage } from '@/lib/utils'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
|
||||
/**
|
||||
* 博客列表滚动分页
|
||||
@@ -14,10 +14,16 @@ import throttle from 'lodash.throttle'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfig('MATERY_POST_LIST_SUMMARY', null, CONFIG), siteInfo }) => {
|
||||
const postsPerPage = parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const BlogPostListScroll = ({
|
||||
posts = [],
|
||||
currentSearch,
|
||||
showSummary = siteConfig('MATERY_POST_LIST_SUMMARY', null, CONFIG),
|
||||
siteInfo
|
||||
}) => {
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const [page, updatePage] = useState(1)
|
||||
const postsToShow = getListByPage(posts, page, postsPerPage)
|
||||
const postsToShow = getListByPage(posts, page, POSTS_PER_PAGE)
|
||||
// 监听滚动
|
||||
useEffect(() => {
|
||||
window.addEventListener('scroll', scrollTrigger)
|
||||
@@ -31,7 +37,7 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
let hasMore = false
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * postsPerPage < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
|
||||
const handleGetMore = () => {
|
||||
@@ -40,36 +46,52 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
}
|
||||
|
||||
const throttleMs = 200
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
})
|
||||
}, throttleMs))
|
||||
const scrollTrigger = useCallback(
|
||||
throttle(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
})
|
||||
}, throttleMs)
|
||||
)
|
||||
|
||||
if (!postsToShow || postsToShow.length === 0) {
|
||||
return <BlogPostListEmpty currentSearch={currentSearch} />
|
||||
} else {
|
||||
return <div id='container' ref={targetRef} className='w-full'>
|
||||
|
||||
{/* 文章列表 */}
|
||||
<div className="pt-4 flex flex-wrap pb-12" >
|
||||
{postsToShow.map(post => (
|
||||
return (
|
||||
<div id='container' ref={targetRef} className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className='pt-4 flex flex-wrap pb-12'>
|
||||
{postsToShow.map(post => (
|
||||
<div key={post.id} className='xl:w-1/3 md:w-1/2 w-full p-4'>
|
||||
<BlogPostCard index={posts.indexOf(post)} post={post} siteInfo={siteInfo} />
|
||||
<BlogPostCard
|
||||
index={posts.indexOf(post)}
|
||||
post={post}
|
||||
siteInfo={siteInfo}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div onClick={() => { handleGetMore() }}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer rounded-xl dark:text-gray-200'
|
||||
> {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE}`} </div>
|
||||
<div>
|
||||
<div
|
||||
onClick={() => {
|
||||
handleGetMore()
|
||||
}}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer rounded-xl dark:text-gray-200'>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE}`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import PaginationSimple from './PaginationSimple'
|
||||
|
||||
@@ -12,22 +13,24 @@ import PaginationSimple from './PaginationSimple'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return <BlogPostListEmpty />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='w-full justify-center'>
|
||||
<div id='posts-wrapper'>
|
||||
<div className='w-full justify-center'>
|
||||
<div id='posts-wrapper'>
|
||||
{/* 文章列表 */}
|
||||
{posts?.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} />
|
||||
))}
|
||||
</div>
|
||||
<PaginationSimple page={page} totalPage={totalPage} />
|
||||
</div>
|
||||
<PaginationSimple page={page} totalPage={totalPage} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
|
||||
/**
|
||||
* 博客列表滚动分页
|
||||
@@ -14,7 +14,8 @@ import { useRouter } from 'next/router'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListScroll = ({ posts = [], currentSearch }) => {
|
||||
const postsPerPage = parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const [page, updatePage] = useState(1)
|
||||
const router = useRouter()
|
||||
let filteredPosts = Object.assign(posts)
|
||||
@@ -26,12 +27,12 @@ const BlogPostListScroll = ({ posts = [], currentSearch }) => {
|
||||
return searchContent.toLowerCase().includes(searchKey.toLowerCase())
|
||||
})
|
||||
}
|
||||
const postsToShow = getPostByPage(page, filteredPosts, postsPerPage)
|
||||
const postsToShow = getPostByPage(page, filteredPosts, POSTS_PER_PAGE)
|
||||
|
||||
let hasMore = false
|
||||
if (filteredPosts) {
|
||||
const totalCount = filteredPosts.length
|
||||
hasMore = page * postsPerPage < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
|
||||
const handleGetMore = () => {
|
||||
@@ -40,13 +41,19 @@ const BlogPostListScroll = ({ posts = [], currentSearch }) => {
|
||||
}
|
||||
|
||||
// 监听滚动自动分页加载
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500))
|
||||
const scrollTrigger = useCallback(
|
||||
throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500)
|
||||
)
|
||||
|
||||
// 监听滚动
|
||||
useEffect(() => {
|
||||
@@ -62,23 +69,27 @@ const BlogPostListScroll = ({ posts = [], currentSearch }) => {
|
||||
if (!postsToShow || postsToShow.length === 0) {
|
||||
return <BlogPostListEmpty currentSearch={currentSearch} />
|
||||
} else {
|
||||
return <div id='posts-wrapper' ref={targetRef} className='w-full'>
|
||||
return (
|
||||
<div id='posts-wrapper' ref={targetRef} className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className='space-y-1 lg:space-y-4'>
|
||||
{postsToShow?.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} showSummary={true} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 文章列表 */}
|
||||
<div className='space-y-1 lg:space-y-4'>
|
||||
{postsToShow?.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} showSummary={true} />
|
||||
))}
|
||||
<div>
|
||||
<div
|
||||
onClick={() => {
|
||||
handleGetMore()
|
||||
}}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer dark:text-gray-200'>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div onClick={() => {
|
||||
handleGetMore()
|
||||
}}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer dark:text-gray-200'
|
||||
> {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`} </div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,14 +97,11 @@ const BlogPostListScroll = ({ posts = [], currentSearch }) => {
|
||||
* 获取从第1页到指定页码的文章
|
||||
* @param page 第几页
|
||||
* @param totalPosts 所有文章
|
||||
* @param postsPerPage 每页文章数量
|
||||
* @param POSTS_PER_PAGE 每页文章数量
|
||||
* @returns {*}
|
||||
*/
|
||||
const getPostByPage = function (page, totalPosts, postsPerPage) {
|
||||
return totalPosts.slice(
|
||||
0,
|
||||
postsPerPage * page
|
||||
)
|
||||
const getPostByPage = function (page, totalPosts, POSTS_PER_PAGE) {
|
||||
return totalPosts.slice(0, POSTS_PER_PAGE * page)
|
||||
}
|
||||
|
||||
export default BlogPostListScroll
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import CONFIG from '../config'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
|
||||
export const BlogListPage = props => {
|
||||
const { page = 1, posts, postCount } = props
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
|
||||
const showPageCover = siteConfig('MOVIE_POST_LIST_COVER', null, CONFIG)
|
||||
|
||||
|
||||
@@ -12,11 +12,18 @@ export const BlogListScroll = props => {
|
||||
const [page, updatePage] = useState(1)
|
||||
|
||||
let hasMore = false
|
||||
const postsToShow = posts ? Object.assign(posts).slice(0, parseInt(siteConfig('POSTS_PER_PAGE')) * page) : []
|
||||
const postsToShow = posts
|
||||
? Object.assign(posts).slice(
|
||||
0,
|
||||
parseInt(siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)) * page
|
||||
)
|
||||
: []
|
||||
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * parseInt(siteConfig('POSTS_PER_PAGE')) < totalCount
|
||||
hasMore =
|
||||
page * parseInt(siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)) <
|
||||
totalCount
|
||||
}
|
||||
const handleGetMore = () => {
|
||||
if (!hasMore) return
|
||||
@@ -29,7 +36,11 @@ export const BlogListScroll = props => {
|
||||
const scrollTrigger = useCallback(
|
||||
throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? targetRef.current.clientHeight : 0) : 0
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
@@ -46,12 +57,17 @@ export const BlogListScroll = props => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div id='posts-wrapper' className={`w-full ${showPageCover ? 'md:pr-2' : 'md:pr-12'}} mb-12`} ref={targetRef}>
|
||||
<div
|
||||
id='posts-wrapper'
|
||||
className={`w-full ${showPageCover ? 'md:pr-2' : 'md:pr-12'}} mb-12`}
|
||||
ref={targetRef}>
|
||||
{postsToShow?.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} />
|
||||
))}
|
||||
|
||||
<div onClick={handleGetMore} className='w-full my-4 py-4 text-center cursor-pointer '>
|
||||
<div
|
||||
onClick={handleGetMore}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer '>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import NavPostListEmpty from './NavPostListEmpty'
|
||||
import PaginationSimple from './PaginationSimple'
|
||||
@@ -11,22 +12,24 @@ import PaginationSimple from './PaginationSimple'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const totalPage = Math.ceil(
|
||||
postCount / parseInt(siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG))
|
||||
)
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return <NavPostListEmpty />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='w-full justify-center'>
|
||||
<div id='posts-wrapper'>
|
||||
<div className='w-full justify-center'>
|
||||
<div id='posts-wrapper'>
|
||||
{/* 文章列表 */}
|
||||
{posts?.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} />
|
||||
))}
|
||||
</div>
|
||||
<PaginationSimple page={page} totalPage={totalPage} />
|
||||
</div>
|
||||
<PaginationSimple page={page} totalPage={totalPage} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
const CONFIG = {
|
||||
|
||||
NAV_INDEX_PAGE: 'about', // 文档首页显示的文章,请确此路径包含在您的notion数据库中
|
||||
|
||||
NAV_AUTO_SORT: process.env.NEXT_PUBLIC_GITBOOK_AUTO_SORT || true, // 是否自动按分类名 归组排序文章;自动归组可能会打乱您Notion中的文章顺序
|
||||
NAV_AUTO_SORT: process.env.NEXT_PUBLIC_NAV_AUTO_SORT || true, // 是否自动按分类名 归组排序文章;自动归组可能会打乱您Notion中的文章顺序
|
||||
|
||||
NAV_SHOW_TITLE_TEXT: false, // 标题栏显示文本
|
||||
NAV_USE_CUSTOM_MENU: true, // 使用自定义菜单(可支持子菜单,支持自定义分类图标),若为true则显示所有的category分类
|
||||
@@ -14,7 +13,8 @@ const CONFIG = {
|
||||
NAV_MENU_SEARCH: true, // 显示搜索
|
||||
|
||||
// Widget
|
||||
NAV_WIDGET_REVOLVER_MAPS: process.env.NEXT_PUBLIC_WIDGET_REVOLVER_MAPS || 'false', // 地图插件
|
||||
NAV_WIDGET_REVOLVER_MAPS:
|
||||
process.env.NEXT_PUBLIC_WIDGET_REVOLVER_MAPS || 'false', // 地图插件
|
||||
NAV_WIDGET_TO_TOP: true // 跳回顶部
|
||||
}
|
||||
export default CONFIG
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import PaginationNumber from './PaginationNumber'
|
||||
|
||||
/**
|
||||
* 文章列表分页表格
|
||||
@@ -12,7 +13,9 @@ import { siteConfig } from '@/lib/config'
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return <BlogPostListEmpty />
|
||||
@@ -20,7 +23,9 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
|
||||
return (
|
||||
<div>
|
||||
{/* 文章列表 */}
|
||||
<div id="posts-wrapper" className="flex flex-wrap lg:space-y-4 space-y-1">
|
||||
<div
|
||||
id='posts-wrapper'
|
||||
className='flex flex-wrap lg:space-y-4 space-y-1'>
|
||||
{posts?.map((post, index) => (
|
||||
<BlogPostCard key={post.id} index={index} post={post} />
|
||||
))}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
|
||||
/**
|
||||
* 博客列表滚动分页
|
||||
@@ -13,15 +13,20 @@ import { siteConfig } from '@/lib/config'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfig('NEXT_POST_LIST_SUMMARY', null, CONFIG) }) => {
|
||||
const postsPerPage = parseInt(siteConfig('POSTS_PER_PAGE'))
|
||||
const BlogPostListScroll = ({
|
||||
posts = [],
|
||||
currentSearch,
|
||||
showSummary = siteConfig('NEXT_POST_LIST_SUMMARY', null, CONFIG)
|
||||
}) => {
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const [page, updatePage] = useState(1)
|
||||
const postsToShow = getPostByPage(page, posts, postsPerPage)
|
||||
const postsToShow = getPostByPage(page, posts, POSTS_PER_PAGE)
|
||||
|
||||
let hasMore = false
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * postsPerPage < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
|
||||
const handleGetMore = () => {
|
||||
@@ -30,13 +35,19 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
}
|
||||
|
||||
// 监听滚动自动分页加载
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500))
|
||||
const scrollTrigger = useCallback(
|
||||
throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500)
|
||||
)
|
||||
|
||||
// 监听滚动
|
||||
useEffect(() => {
|
||||
@@ -52,23 +63,29 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
if (!postsToShow || postsToShow.length === 0) {
|
||||
return <BlogPostListEmpty currentSearch={currentSearch} />
|
||||
} else {
|
||||
return <div ref={targetRef}>
|
||||
return (
|
||||
<div ref={targetRef}>
|
||||
{/* 文章列表 */}
|
||||
<div
|
||||
id='posts-wrapper'
|
||||
className='flex flex-wrap space-y-1 lg:space-y-4'>
|
||||
{postsToShow.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} showSummary={showSummary} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 文章列表 */}
|
||||
<div id='posts-wrapper' className='flex flex-wrap space-y-1 lg:space-y-4'>
|
||||
{postsToShow.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} showSummary={showSummary} />
|
||||
))}
|
||||
<div>
|
||||
<div
|
||||
onClick={() => {
|
||||
handleGetMore()
|
||||
}}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer glassmorphism shadow hover:shadow-xl duration-200 dark:text-gray-200'>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div onClick={() => {
|
||||
handleGetMore()
|
||||
}}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer glassmorphism shadow hover:shadow-xl duration-200 dark:text-gray-200'
|
||||
> {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`} </div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,13 +93,10 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = siteConfi
|
||||
* 获取从第1页到指定页码的文章
|
||||
* @param page 第几页
|
||||
* @param totalPosts 所有文章
|
||||
* @param postsPerPage 每页文章数量
|
||||
* @param POSTS_PER_PAGE 每页文章数量
|
||||
* @returns {*}
|
||||
*/
|
||||
const getPostByPage = function (page, totalPosts, postsPerPage) {
|
||||
return totalPosts.slice(
|
||||
0,
|
||||
postsPerPage * page
|
||||
)
|
||||
const getPostByPage = function (page, totalPosts, POSTS_PER_PAGE) {
|
||||
return totalPosts.slice(0, POSTS_PER_PAGE * page)
|
||||
}
|
||||
export default BlogPostListScroll
|
||||
|
||||
@@ -1,50 +1,58 @@
|
||||
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import BlogPost from './BlogPost'
|
||||
|
||||
export const BlogListPage = props => {
|
||||
const { page = 1, posts, postCount } = props
|
||||
const { locale } = useGlobal()
|
||||
const router = useRouter()
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
const currentPage = +page
|
||||
|
||||
const showPrev = currentPage > 1
|
||||
const showNext = currentPage < totalPage && posts?.length > 0
|
||||
const pagePrefix = router.asPath.split('?')[0].replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '')
|
||||
const pagePrefix = router.asPath
|
||||
.split('?')[0]
|
||||
.replace(/\/page\/[1-9]\d*/, '')
|
||||
.replace(/\/$/, '')
|
||||
|
||||
return (
|
||||
<div className="w-full md:pr-12 my-6">
|
||||
<div className='w-full md:pr-12 my-6'>
|
||||
<div id='posts-wrapper'>
|
||||
{posts?.map(post => (
|
||||
<BlogPost key={post.id} post={post} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div id="posts-wrapper">
|
||||
{posts?.map(post => (
|
||||
<BlogPost key={post.id} post={post}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between text-xs">
|
||||
<Link
|
||||
href={{ pathname: currentPage - 1 === 1 ? `${pagePrefix}/` : `${pagePrefix}/page/${currentPage - 1}`, query: router.query.s ? { s: router.query.s } : {} }}
|
||||
className={`${showPrev ? ' ' : ' invisible block pointer-events-none '}no-underline py-2 px-3 rounded`}>
|
||||
|
||||
<button rel="prev" className="block cursor-pointer">
|
||||
← {locale.PAGINATION.PREV}
|
||||
</button>
|
||||
|
||||
</Link>
|
||||
<Link
|
||||
href={{ pathname: `${pagePrefix}/page/${currentPage + 1}`, query: router.query.s ? { s: router.query.s } : {} }}
|
||||
className={`${showNext ? ' ' : 'invisible pointer-events-none '} no-underline py-2 px-3 rounded`}>
|
||||
|
||||
<button rel="next" className="block cursor-pointer">
|
||||
{locale.PAGINATION.NEXT} →
|
||||
</button>
|
||||
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex justify-between text-xs'>
|
||||
<Link
|
||||
href={{
|
||||
pathname:
|
||||
currentPage - 1 === 1
|
||||
? `${pagePrefix}/`
|
||||
: `${pagePrefix}/page/${currentPage - 1}`,
|
||||
query: router.query.s ? { s: router.query.s } : {}
|
||||
}}
|
||||
className={`${showPrev ? ' ' : ' invisible block pointer-events-none '}no-underline py-2 px-3 rounded`}>
|
||||
<button rel='prev' className='block cursor-pointer'>
|
||||
← {locale.PAGINATION.PREV}
|
||||
</button>
|
||||
</Link>
|
||||
<Link
|
||||
href={{
|
||||
pathname: `${pagePrefix}/page/${currentPage + 1}`,
|
||||
query: router.query.s ? { s: router.query.s } : {}
|
||||
}}
|
||||
className={`${showNext ? ' ' : 'invisible pointer-events-none '} no-underline py-2 px-3 rounded`}>
|
||||
<button rel='next' className='block cursor-pointer'>
|
||||
{locale.PAGINATION.NEXT} →
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import Link from 'next/link'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { deepClone } from '@/lib/utils'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { deepClone } from '@/lib/utils'
|
||||
import throttle from 'lodash.throttle'
|
||||
import Link from 'next/link'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
|
||||
export const BlogListScroll = props => {
|
||||
@@ -12,13 +12,20 @@ export const BlogListScroll = props => {
|
||||
const [page, updatePage] = useState(1)
|
||||
|
||||
let hasMore = false
|
||||
const postsToShow = posts && Array.isArray(posts)
|
||||
? deepClone(posts).slice(0, parseInt(siteConfig('POSTS_PER_PAGE')) * page)
|
||||
: []
|
||||
const postsToShow =
|
||||
posts && Array.isArray(posts)
|
||||
? deepClone(posts).slice(
|
||||
0,
|
||||
parseInt(siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)) *
|
||||
page
|
||||
)
|
||||
: []
|
||||
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * parseInt(siteConfig('POSTS_PER_PAGE')) < totalCount
|
||||
hasMore =
|
||||
page * parseInt(siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)) <
|
||||
totalCount
|
||||
}
|
||||
const handleGetMore = () => {
|
||||
if (!hasMore) return
|
||||
@@ -28,13 +35,19 @@ export const BlogListScroll = props => {
|
||||
const targetRef = useRef(null)
|
||||
|
||||
// 监听滚动自动分页加载
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500))
|
||||
const scrollTrigger = useCallback(
|
||||
throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500)
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('scroll', scrollTrigger)
|
||||
@@ -45,39 +58,41 @@ export const BlogListScroll = props => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div id="posts-wrapper" className="w-full md:pr-12 mb-12" ref={targetRef}>
|
||||
{postsToShow.map(p => (
|
||||
<article key={p.id} className="mb-12" >
|
||||
<h2 className="mb-4">
|
||||
<Link
|
||||
href={`/${p.slug}`}
|
||||
className="text-black text-xl md:text-2xl no-underline hover:underline">
|
||||
{p.title}
|
||||
</Link>
|
||||
</h2>
|
||||
|
||||
<div className="mb-4 text-sm text-gray-700">
|
||||
by <a href="#" className="text-gray-700">{siteConfig('AUTHOR')}</a> on {p.date?.start_date || p.createdTime}
|
||||
<span className="font-bold mx-1"> | </span>
|
||||
<a href="#" className="text-gray-700">{p.category}</a>
|
||||
<span className="font-bold mx-1"> | </span>
|
||||
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
|
||||
</div>
|
||||
|
||||
<p className="text-gray-700 leading-normal">
|
||||
{p.summary}
|
||||
</p>
|
||||
</article>
|
||||
))}
|
||||
|
||||
<div
|
||||
onClick={handleGetMore}
|
||||
className="w-full my-4 py-4 text-center cursor-pointer "
|
||||
>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
<div id='posts-wrapper' className='w-full md:pr-12 mb-12' ref={targetRef}>
|
||||
{postsToShow.map(p => (
|
||||
<article key={p.id} className='mb-12'>
|
||||
<h2 className='mb-4'>
|
||||
<Link
|
||||
href={`/${p.slug}`}
|
||||
className='text-black text-xl md:text-2xl no-underline hover:underline'>
|
||||
{p.title}
|
||||
</Link>
|
||||
</h2>
|
||||
|
||||
<div className='mb-4 text-sm text-gray-700'>
|
||||
by{' '}
|
||||
<a href='#' className='text-gray-700'>
|
||||
{siteConfig('AUTHOR')}
|
||||
</a>{' '}
|
||||
on {p.date?.start_date || p.createdTime}
|
||||
<span className='font-bold mx-1'> | </span>
|
||||
<a href='#' className='text-gray-700'>
|
||||
{p.category}
|
||||
</a>
|
||||
<span className='font-bold mx-1'> | </span>
|
||||
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
|
||||
</div>
|
||||
|
||||
<p className='text-gray-700 leading-normal'>{p.summary}</p>
|
||||
</article>
|
||||
))}
|
||||
|
||||
<div
|
||||
onClick={handleGetMore}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer '>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import NotionIcon from '@/components/NotionIcon'
|
||||
import NotionPage from '@/components/NotionPage'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import Link from 'next/link'
|
||||
|
||||
const BlogPost = ({ post }) => {
|
||||
const showPreview = siteConfig('POST_LIST_PREVIEW') && post.blockMap
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const showPreview =
|
||||
siteConfig('POST_LIST_PREVIEW', false, NOTION_CONFIG) && post?.blockMap
|
||||
|
||||
return (
|
||||
<Link href={post?.href}>
|
||||
|
||||
@@ -1,34 +1,41 @@
|
||||
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import BlogPost from './BlogPost'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import BlogPost from './BlogPost'
|
||||
|
||||
export const BlogListPage = props => {
|
||||
const { page = 1, posts, postCount } = props
|
||||
const { locale } = useGlobal()
|
||||
const router = useRouter()
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
const currentPage = +page
|
||||
|
||||
const showPrev = currentPage > 1
|
||||
const showNext = page < totalPage
|
||||
const pagePrefix = router.asPath.split('?')[0].replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '')
|
||||
const pagePrefix = router.asPath
|
||||
.split('?')[0]
|
||||
.replace(/\/page\/[1-9]\d*/, '')
|
||||
.replace(/\/$/, '')
|
||||
|
||||
const blogPostRefs = useRef([])
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.toggle('visible')
|
||||
}
|
||||
})
|
||||
}, {
|
||||
threshold: 0.1 // 调整阈值以达到最佳效果
|
||||
})
|
||||
const observer = new IntersectionObserver(
|
||||
entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.toggle('visible')
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
threshold: 0.1 // 调整阈值以达到最佳效果
|
||||
}
|
||||
)
|
||||
|
||||
blogPostRefs.current.forEach(ref => {
|
||||
observer.observe(ref)
|
||||
@@ -39,34 +46,47 @@ export const BlogListPage = props => {
|
||||
}
|
||||
}, [])
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className='w-full'>
|
||||
<div
|
||||
id='posts-wrapper'
|
||||
className='grid lg:grid-cols-3 grid-cols-1 md:grid-cols-2'>
|
||||
{posts?.map((post, index) => (
|
||||
<BlogPost
|
||||
index={index}
|
||||
key={post.id}
|
||||
className='blog-post'
|
||||
post={post}
|
||||
{...props}
|
||||
ref={el => blogPostRefs.current.push(el)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div id="posts-wrapper" className='grid lg:grid-cols-3 grid-cols-1 md:grid-cols-2'>
|
||||
{posts?.map((post, index) => (
|
||||
<BlogPost index={index} key={post.id} className="blog-post" post={post} {...props} ref={el => blogPostRefs.current.push(el)}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between text-xs">
|
||||
<Link
|
||||
href={{ pathname: currentPage - 1 === 1 ? `${pagePrefix}/` : `${pagePrefix}/page/${currentPage - 1}`, query: router.query.s ? { s: router.query.s } : {} }}
|
||||
className={`${showPrev ? ' ' : ' invisible block pointer-events-none '}no-underline py-2 px-3 rounded`}>
|
||||
|
||||
<button rel="prev" className="block cursor-pointer">
|
||||
← {locale.PAGINATION.PREV}
|
||||
</button>
|
||||
|
||||
</Link>
|
||||
<Link
|
||||
href={{ pathname: `${pagePrefix}/page/${currentPage + 1}`, query: router.query.s ? { s: router.query.s } : {} }}
|
||||
className={`${showNext ? ' ' : 'invisible pointer-events-none '} no-underline py-2 px-3 rounded`}>
|
||||
|
||||
<button rel="next" className="block cursor-pointer">
|
||||
{locale.PAGINATION.NEXT} →
|
||||
</button>
|
||||
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex justify-between text-xs'>
|
||||
<Link
|
||||
href={{
|
||||
pathname:
|
||||
currentPage - 1 === 1
|
||||
? `${pagePrefix}/`
|
||||
: `${pagePrefix}/page/${currentPage - 1}`,
|
||||
query: router.query.s ? { s: router.query.s } : {}
|
||||
}}
|
||||
className={`${showPrev ? ' ' : ' invisible block pointer-events-none '}no-underline py-2 px-3 rounded`}>
|
||||
<button rel='prev' className='block cursor-pointer'>
|
||||
← {locale.PAGINATION.PREV}
|
||||
</button>
|
||||
</Link>
|
||||
<Link
|
||||
href={{
|
||||
pathname: `${pagePrefix}/page/${currentPage + 1}`,
|
||||
query: router.query.s ? { s: router.query.s } : {}
|
||||
}}
|
||||
className={`${showNext ? ' ' : 'invisible pointer-events-none '} no-underline py-2 px-3 rounded`}>
|
||||
<button rel='next' className='block cursor-pointer'>
|
||||
{locale.PAGINATION.NEXT} →
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import throttle from 'lodash.throttle'
|
||||
import Link from 'next/link'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
|
||||
export const BlogListScroll = props => {
|
||||
const { posts } = props
|
||||
@@ -12,12 +12,17 @@ export const BlogListScroll = props => {
|
||||
|
||||
let hasMore = false
|
||||
const postsToShow = posts
|
||||
? Object.assign(posts).slice(0, parseInt(siteConfig('POSTS_PER_PAGE')) * page)
|
||||
? Object.assign(posts).slice(
|
||||
0,
|
||||
parseInt(siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)) * page
|
||||
)
|
||||
: []
|
||||
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * parseInt(siteConfig('POSTS_PER_PAGE')) < totalCount
|
||||
hasMore =
|
||||
page * parseInt(siteConfig('POSTS_PER_PAGE', 12, props?.NOTION_CONFIG)) <
|
||||
totalCount
|
||||
}
|
||||
const handleGetMore = () => {
|
||||
if (!hasMore) return
|
||||
@@ -27,13 +32,19 @@ export const BlogListScroll = props => {
|
||||
const targetRef = useRef(null)
|
||||
|
||||
// 监听滚动自动分页加载
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500))
|
||||
const scrollTrigger = useCallback(
|
||||
throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500)
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('scroll', scrollTrigger)
|
||||
@@ -44,39 +55,41 @@ export const BlogListScroll = props => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div id="posts-wrapper" className="w-full md:pr-12 mb-12" ref={targetRef}>
|
||||
{postsToShow.map(p => (
|
||||
<article key={p.id} className="mb-12" >
|
||||
<h2 className="mb-4">
|
||||
<Link
|
||||
href={`/${p.slug}`}
|
||||
className="text-black text-xl md:text-2xl no-underline hover:underline">
|
||||
{p.title}
|
||||
</Link>
|
||||
</h2>
|
||||
|
||||
<div className="mb-4 text-sm text-gray-700">
|
||||
by <a href="#" className="text-gray-700">{siteConfig('AUTHOR')}</a> on {p.date?.start_date || p.createdTime}
|
||||
<span className="font-bold mx-1"> | </span>
|
||||
<a href="#" className="text-gray-700">{p.category}</a>
|
||||
<span className="font-bold mx-1"> | </span>
|
||||
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
|
||||
</div>
|
||||
|
||||
<p className="text-gray-700 leading-normal">
|
||||
{p.summary}
|
||||
</p>
|
||||
</article>
|
||||
))}
|
||||
|
||||
<div
|
||||
onClick={handleGetMore}
|
||||
className="w-full my-4 py-4 text-center cursor-pointer "
|
||||
>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
<div id='posts-wrapper' className='w-full md:pr-12 mb-12' ref={targetRef}>
|
||||
{postsToShow.map(p => (
|
||||
<article key={p.id} className='mb-12'>
|
||||
<h2 className='mb-4'>
|
||||
<Link
|
||||
href={`/${p.slug}`}
|
||||
className='text-black text-xl md:text-2xl no-underline hover:underline'>
|
||||
{p.title}
|
||||
</Link>
|
||||
</h2>
|
||||
|
||||
<div className='mb-4 text-sm text-gray-700'>
|
||||
by{' '}
|
||||
<a href='#' className='text-gray-700'>
|
||||
{siteConfig('AUTHOR')}
|
||||
</a>{' '}
|
||||
on {p.date?.start_date || p.createdTime}
|
||||
<span className='font-bold mx-1'> | </span>
|
||||
<a href='#' className='text-gray-700'>
|
||||
{p.category}
|
||||
</a>
|
||||
<span className='font-bold mx-1'> | </span>
|
||||
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
|
||||
</div>
|
||||
|
||||
<p className='text-gray-700 leading-normal'>{p.summary}</p>
|
||||
</article>
|
||||
))}
|
||||
|
||||
<div
|
||||
onClick={handleGetMore}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer '>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,14 +3,17 @@ import NotionIcon from '@/components/NotionIcon'
|
||||
import NotionPage from '@/components/NotionPage'
|
||||
import TwikooCommentCount from '@/components/TwikooCommentCount'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { formatDateFmt } from '@/lib/utils/formatDate'
|
||||
import Link from 'next/link'
|
||||
import CONFIG from '../config'
|
||||
|
||||
export const BlogItem = props => {
|
||||
const { post } = props
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const showPageCover = siteConfig('SIMPLE_POST_COVER_ENABLE', false, CONFIG)
|
||||
const showPreview = siteConfig('POST_LIST_PREVIEW') && post.blockMap
|
||||
const showPreview =
|
||||
siteConfig('POST_LIST_PREVIEW', false, NOTION_CONFIG) && post.blockMap
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import { BlogItem } from './BlogItem'
|
||||
import { AdSlot } from '@/components/GoogleAdsense'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import CONFIG from '../config'
|
||||
import { BlogItem } from './BlogItem'
|
||||
|
||||
/**
|
||||
* 博客列表
|
||||
@@ -14,40 +14,60 @@ import CONFIG from '../config'
|
||||
export default function BlogListPage(props) {
|
||||
const { page = 1, posts, postCount } = props
|
||||
const router = useRouter()
|
||||
const totalPage = Math.ceil(postCount / parseInt(siteConfig('POSTS_PER_PAGE')))
|
||||
const { NOTION_CONFIG } = useGlobal()
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
|
||||
const currentPage = +page
|
||||
|
||||
// 博客列表嵌入广告
|
||||
const SIMPLE_POST_AD_ENABLE = siteConfig('SIMPLE_POST_AD_ENABLE', false, CONFIG)
|
||||
const SIMPLE_POST_AD_ENABLE = siteConfig(
|
||||
'SIMPLE_POST_AD_ENABLE',
|
||||
false,
|
||||
CONFIG
|
||||
)
|
||||
|
||||
const showPrev = currentPage > 1
|
||||
const showNext = page < totalPage
|
||||
const pagePrefix = router.asPath.split('?')[0].replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '')
|
||||
const pagePrefix = router.asPath
|
||||
.split('?')[0]
|
||||
.replace(/\/page\/[1-9]\d*/, '')
|
||||
.replace(/\/$/, '')
|
||||
|
||||
return (
|
||||
<div className="w-full md:pr-8 mb-12">
|
||||
<div className='w-full md:pr-8 mb-12'>
|
||||
<div id='posts-wrapper'>
|
||||
{posts?.map((p, index) => (
|
||||
<div key={p.id}>
|
||||
{SIMPLE_POST_AD_ENABLE && (index + 1) % 3 === 0 && (
|
||||
<AdSlot type='in-article' />
|
||||
)}
|
||||
{SIMPLE_POST_AD_ENABLE && index + 1 === 4 && <AdSlot type='flow' />}
|
||||
<BlogItem post={p} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div id="posts-wrapper">
|
||||
{posts?.map((p, index) => (<div key={p.id}>
|
||||
{SIMPLE_POST_AD_ENABLE && (index + 1) % 3 === 0 && <AdSlot type='in-article' />}
|
||||
{SIMPLE_POST_AD_ENABLE && (index + 1) === 4 && <AdSlot type='flow' />}
|
||||
<BlogItem post={p} />
|
||||
</div>))}
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between text-xs mt-1">
|
||||
<Link
|
||||
href={{ pathname: currentPage - 1 === 1 ? `${pagePrefix}/` : `${pagePrefix}/page/${currentPage - 1}`, query: router.query.s ? { s: router.query.s } : {} }}
|
||||
className={`${showPrev ? 'text-blue-600 border-b border-blue-400 visible ' : ' invisible bg-gray pointer-events-none '} no-underline pb-1 px-3`}>
|
||||
NEWER POSTS <i className="fa-solid fa-arrow-left"></i>
|
||||
</Link>
|
||||
<Link
|
||||
href={{ pathname: `${pagePrefix}/page/${currentPage + 1}`, query: router.query.s ? { s: router.query.s } : {} }}
|
||||
className={`${showNext ? 'text-blue-600 border-b border-blue-400 visible' : ' invisible bg-gray pointer-events-none '} no-underline pb-1 px-3`}>
|
||||
OLDER POSTS <i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex justify-between text-xs mt-1'>
|
||||
<Link
|
||||
href={{
|
||||
pathname:
|
||||
currentPage - 1 === 1
|
||||
? `${pagePrefix}/`
|
||||
: `${pagePrefix}/page/${currentPage - 1}`,
|
||||
query: router.query.s ? { s: router.query.s } : {}
|
||||
}}
|
||||
className={`${showPrev ? 'text-blue-600 border-b border-blue-400 visible ' : ' invisible bg-gray pointer-events-none '} no-underline pb-1 px-3`}>
|
||||
NEWER POSTS <i className='fa-solid fa-arrow-left'></i>
|
||||
</Link>
|
||||
<Link
|
||||
href={{
|
||||
pathname: `${pagePrefix}/page/${currentPage + 1}`,
|
||||
query: router.query.s ? { s: router.query.s } : {}
|
||||
}}
|
||||
className={`${showNext ? 'text-blue-600 border-b border-blue-400 visible' : ' invisible bg-gray pointer-events-none '} no-underline pb-1 px-3`}>
|
||||
OLDER POSTS <i className='fa-solid fa-arrow-right'></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { BlogItem } from './BlogItem'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { BlogItem } from './BlogItem'
|
||||
|
||||
/**
|
||||
* 滚动博客列表
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
export default function BlogListScroll (props) {
|
||||
export default function BlogListScroll(props) {
|
||||
const { posts } = props
|
||||
const { locale } = useGlobal()
|
||||
|
||||
const { locale, NOTION_CONFIG } = useGlobal()
|
||||
const [page, updatePage] = useState(1)
|
||||
|
||||
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
|
||||
let hasMore = false
|
||||
const postsToShow = posts
|
||||
? Object.assign(posts).slice(0, parseInt(siteConfig('POSTS_PER_PAGE')) * page)
|
||||
? Object.assign(posts).slice(0, POSTS_PER_PAGE * page)
|
||||
: []
|
||||
|
||||
if (posts) {
|
||||
const totalCount = posts.length
|
||||
hasMore = page * parseInt(siteConfig('POSTS_PER_PAGE')) < totalCount
|
||||
hasMore = page * POSTS_PER_PAGE < totalCount
|
||||
}
|
||||
const handleGetMore = () => {
|
||||
if (!hasMore) return
|
||||
@@ -32,13 +31,19 @@ export default function BlogListScroll (props) {
|
||||
const targetRef = useRef(null)
|
||||
|
||||
// 监听滚动自动分页加载
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef ? (targetRef.current ? (targetRef.current.clientHeight) : 0) : 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500))
|
||||
const scrollTrigger = useCallback(
|
||||
throttle(() => {
|
||||
const scrollS = window.scrollY + window.outerHeight
|
||||
const clientHeight = targetRef
|
||||
? targetRef.current
|
||||
? targetRef.current.clientHeight
|
||||
: 0
|
||||
: 0
|
||||
if (scrollS > clientHeight + 100) {
|
||||
handleGetMore()
|
||||
}
|
||||
}, 500)
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('scroll', scrollTrigger)
|
||||
@@ -49,17 +54,17 @@ export default function BlogListScroll (props) {
|
||||
})
|
||||
|
||||
return (
|
||||
<div id="posts-wrapper" className="w-full md:pr-8 mb-12" ref={targetRef}>
|
||||
{postsToShow.map(p => (
|
||||
<BlogItem key={p.id} post={p}/>
|
||||
))}
|
||||
<div id='posts-wrapper' className='w-full md:pr-8 mb-12' ref={targetRef}>
|
||||
{postsToShow.map(p => (
|
||||
<BlogItem key={p.id} post={p} />
|
||||
))}
|
||||
|
||||
<div onClick={handleGetMore}
|
||||
className="w-full my-4 py-4 text-center cursor-pointer ">
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div
|
||||
onClick={handleGetMore}
|
||||
className='w-full my-4 py-4 text-center cursor-pointer '>
|
||||
{' '}
|
||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user