theme-heo 博文列表分页

This commit is contained in:
tangly1024
2023-07-12 23:19:41 +08:00
parent 99bd4f3c99
commit 109c5d4c52
10 changed files with 182 additions and 129 deletions

View File

@@ -13,10 +13,14 @@ export default function FlipCard(props) {
}
return (
<div className={`flip-card ${isFlipped ? 'flipped' : ''}`} >
<div className={`flip-card-front ${props.className || ''}`} onMouseEnter={handleCardFlip}>{props.frontContent}</div>
<div className={`flip-card-back ${props.className || ''}`} onMouseLeave={handleCardFlip}>{props.backContent}</div>
<style jsx>{`
<div className={`flip-card ${isFlipped ? 'flipped' : ''}`} >
<div className={`flip-card-front ${props.className || ''}`} onMouseEnter={handleCardFlip}>
{props.frontContent}
</div>
<div className={`flip-card-back ${props.className || ''}`} onMouseOut={handleCardFlip}>
{props.backContent}
</div>
<style jsx>{`
.flip-card {
width: auto;
height: auto;
@@ -49,6 +53,6 @@ export default function FlipCard(props) {
transform: rotateY(180deg);
}
`}</style>
</div>
</div>
)
}

View File

@@ -45,6 +45,12 @@ export const ChevronRight = ({ className }) => {
</svg>
}
export const ChevronDoubleRight = ({ className }) => {
return <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className={className}>
<path strokeLinecap="round" strokeLinejoin="round" d="M11.25 4.5l7.5 7.5-7.5 7.5m-6-15l7.5 7.5-7.5 7.5" />
</svg>
}
export const InformationCircle = ({ className }) => {
return <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className={className}>
<path strokeLinecap="round" strokeLinejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />

View File

@@ -47,8 +47,8 @@ export default {
WORD_COUNT: '字数'
},
PAGINATION: {
PREV: '上页',
NEXT: '下页'
PREV: '上页',
NEXT: '下页'
},
SEARCH: {
ARTICLES: '搜索文章',

View File

@@ -1,34 +1,79 @@
import Link from 'next/link'
import React from 'react'
import React, { useState } from 'react'
import CONFIG from '../config'
import { BlogPostCardInfo } from './BlogPostCardInfo'
import BLOG from '@/blog.config'
import TagItemMini from './TagItemMini'
// import Image from 'next/image'
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
const showPreview = CONFIG.POST_LIST_PREVIEW && post.blockMap
const [onHover, setOnHover] = useState(false)
if (post && !post.pageCoverThumbnail && CONFIG.POST_LIST_COVER_DEFAULT) {
post.pageCoverThumbnail = siteInfo?.pageCover
}
const showPageCover = CONFIG.POST_LIST_COVER && post?.pageCoverThumbnail && !showPreview
console.log(post, post.pageCoverThumbnail)
return (
<div className={`${CONFIG.POST_LIST_COVER_HOVER_ENLARGE ? ' hover:scale-110 transition-all duration-150' : ''}`} >
<div className={`w-full border justify-between flex flex-col lg:h-96
overflow-hidden rounded-xl bg-white `}>
<div className={` ${CONFIG.POST_LIST_COVER_HOVER_ENLARGE ? ' hover:scale-110 transition-all duration-150' : ''}`} >
<div onMouseEnter={() => setOnHover(true)} onMouseLeave={() => setOnHover(false)} className={'w-full hover:border-indigo-600 duration-300 transition-colors border justify-between flex flex-col lg:h-96 overflow-hidden rounded-xl bg-white '}>
{/* 图片封面 */}
{showPageCover && (
<div className="flex-1 md:w-5/12 lg:w-full overflow-hidden">
<div className="flex-1 h-60 md:w-5/12 lg:w-full overflow-hidden">
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
<div className='h-56 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${post?.pageCoverThumbnail}')` }} />
<div className={`h-60 bg-center bg-cover ${onHover ? 'scale-105 brightness-75' : ''} transition-all duration-300`} style={{ backgroundImage: `url('${post?.pageCoverThumbnail}')` }} />
</Link>
</div>
)}
{/* 文字区块 */}
<BlogPostCardInfo index={index} post={post} showPageCover={showPageCover} showPreview={showPreview} showSummary={showSummary} />
{/* <BlogPostCardInfo index={index} post={post} onHover={onHover} showPageCover={showPageCover} showPreview={showPreview} showSummary={showSummary} /> */}
<div className={'flex flex-col justify-between lg:p-6 p-4 w-full'}>
<div>
{/* 分类 */}
{post?.category && <div className={`flex mb-1 items-center ${showPreview ? 'justify-center' : 'justify-start'} flex-wrap dark:text-gray-500 text-gray-600 `}>
<Link passHref href={`/category/${post.category}`}
className="cursor-pointer text-xs font-normal menu-link hover:text-indigo-700 dark:hover:text-indigo-400 transform">
{post.category}
</Link>
</div>}
{/* 标题 */}
<Link
href={`${BLOG.SUB_PATH}/${post.slug}`}
passHref
className={`${onHover ? 'text-indigo-700 dark:text-indigo-400' : ' text-black dark:text-gray-100'} line-clamp-2 replace cursor-pointer text-2xl font-extrabold leading-tight`}>
<span className='menu-link '>{post.title}</span>
</Link>
{/* 摘要 */}
{(!showPreview || showSummary) && !post.results && (
<p className="line-clamp-2 replace my-3 text-gray-700 dark:text-gray-300 text-sm font-light leading-tight">
{post.summary}
</p>
)}
{/* 搜索结果 */}
{post.results && (
<p className="line-clamp-2 mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.results.map(r => (
<span key={r}>{r}</span>
))}
</p>
)}
<div className="md:flex-nowrap flex-wrap md:justify-start inline-block">
<div>
{' '}
{post.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,60 +0,0 @@
import Link from 'next/link'
import TagItemMini from './TagItemMini'
import BLOG from '@/blog.config'
/**
* 博客列表的文字内容
* @param {*} param0
* @returns
*/
export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary }) => {
return <div className={'flex flex-col justify-between lg:p-6 p-4 w-full'}>
<div>
{/* 分类 */}
{post?.category && <div className={`flex mb-1 items-center ${showPreview ? 'justify-center' : 'justify-start'} flex-wrap dark:text-gray-500 text-gray-400 `}>
<Link passHref href={`/category/${post.category}`}
className="cursor-pointer font-light text-xs menu-link hover:text-indigo-700 dark:hover:text-indigo-400 transform">
{post.category}
</Link>
</div>}
{/* 标题 */}
<Link
href={`${BLOG.SUB_PATH}/${post.slug}`}
passHref
className={'line-clamp-2 replace cursor-pointer text-2xl font-extrabold leading-tight text-black dark:text-gray-100 hover:text-indigo-700 dark:hover:text-indigo-400'}>
<span className='menu-link '>{post.title}</span>
</Link>
{/* 摘要 */}
{(!showPreview || showSummary) && !post.results && (
<p className="line-clamp-2 replace my-3 text-gray-700 dark:text-gray-300 text-sm font-light leading-tight">
{post.summary}
</p>
)}
{/* 搜索结果 */}
{post.results && (
<p className="line-clamp-2 mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.results.map(r => (
<span key={r}>{r}</span>
))}
</p>
)}
<div className="md:flex-nowrap flex-wrap md:justify-start inline-block">
<div>
{' '}
{post.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>
</div>
</div>
</div>
}

View File

@@ -11,8 +11,8 @@ export default function CategoryBar(props) {
const { categoryOptions } = props
const { locale } = useGlobal()
return <div id='category-bar' className="h-12 mb-2 space-x-2 w-full bg-white border
flex justify-between py-2 px-4 items-center rounded-xl hover:border hover:border-indigo-600 transition-colors duration-200">
return <div id='category-bar' className="flex justify-between items-center h-12 mb-4 space-x-2 w-full bg-white border
py-2 px-4 rounded-xl hover:border hover:border-indigo-600 transition-colors duration-200">
<div id='category-bar-items' className='flex justify-start space-x-2'>
<MenuItem href='/' name={locale.NAV.INDEX} />
@@ -26,7 +26,7 @@ export default function CategoryBar(props) {
</div>
<div id='category-bar-next' className='flex'>
<Link href='/category' className='font-bold transition-colors duration-200 hover:text-indigo-600'>
<Link href='/category' className='font-bold text-gray-900 transition-colors duration-200 hover:text-indigo-600'>
{locale.COMMON.MORE}
</Link>
</div>
@@ -41,7 +41,7 @@ export default function CategoryBar(props) {
const MenuItem = ({ href, name }) => {
const router = useRouter()
const selected = router.pathname === href
return <div className={`duration-200 transition-all font-bold px-2 py-0.5 rounded-md hover:text-white hover:bg-indigo-600 ${selected ? 'text-white bg-indigo-600' : ''}`}>
return <div className={`duration-200 transition-all font-bold px-2 py-0.5 rounded-md text-gray-900 hover:text-white hover:bg-indigo-600 ${selected ? 'text-white bg-indigo-600' : ''}`}>
<Link href={href}>{name}</Link>
</div>
}

View File

@@ -36,13 +36,21 @@ export function InfoCard(props) {
<div className='bg-indigo-400 p-2 rounded-full hover:bg-white hover:text-black transition-colors duration-200'><Link href='/about'><GlobeAlt className={'w-6 h-6'} /></Link></div>
<div className='bg-indigo-400 p-2 rounded-full w-10 items-center flex justify-center hover:bg-white hover:text-black transition-colors duration-200'><Link href='https://github.com/tangly1024/NotionNext'><i className='fab fa-github text-xl'></i></Link></div>
</div>
<Link href='/about'>
<div className='flex items-center hover:bg-white hover:text-black transition-colors duration-200 bg-indigo-400 py-2 px-3 rounded-full space-x-1'>
<ArrowRightCircle className={'w-6 h-6 stroke-indigo-400 fill-white'} />
<div className='font-bold'>了解更多</div>
</div>
</Link>
<MoreButton />
</div>
</Card>
)
}
/**
* 了解更多按鈕
* @returns
*/
function MoreButton() {
return <Link href='/about'>
<div className={'group bg-indigo-400 hover:bg-white hover:text-black flex items-center transition-colors duration-200 py-2 px-3 rounded-full space-x-1'}>
<ArrowRightCircle className={'group-hover:stroke-black w-6 h-6 transition-all duration-100'} />
<div className='font-bold'>了解更多</div>
</div>
</Link>
}

View File

@@ -1,5 +1,8 @@
import { ChevronDoubleRight } from '@/components/HeroIcons'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useState } from 'react'
/**
* 数字翻页插件
@@ -10,65 +13,113 @@ import { useRouter } from 'next/router'
*/
const PaginationNumber = ({ page, totalPage }) => {
const router = useRouter()
const { locale } = useGlobal()
const currentPage = +page
const showNext = page < totalPage
const pagePrefix = router.asPath.split('?')[0].replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '')
const pages = generatePages(pagePrefix, page, currentPage, totalPage)
const [value, setValue] = useState('')
const handleInputChange = (event) => {
const newValue = event.target.value.replace(/[^0-9]/g, '')
setValue(newValue)
}
/**
* 调到指定页
*/
const jumpToPage = () => {
router.push(value === 1 ? `${pagePrefix}/` : `${pagePrefix}/page/${value}`)
}
return (
<div className="mt-10 mb-5 flex justify-center items-end font-medium text-black duration-500 dark:text-gray-300 py-3 space-x-2">
{/* 上一页 */}
<Link
href={{
pathname: currentPage === 2
? `${pagePrefix}/`
: `${pagePrefix}/page/${currentPage - 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
rel="prev"
className={`${currentPage === 1 ? 'invisible' : 'block'} pb-0.5 border-white dark:border-indigo-700 hover:border-indigo-400 dark:hover:border-indigo-400 w-6 text-center cursor-pointer duration-200 hover:font-bold`}>
<div className="mt-10 mb-5 flex justify-between items-end font-medium text-black duration-500 dark:text-gray-300 py-3 space-x-2">
{/* 上一页 */}
<Link
href={{
pathname: currentPage === 2 ? `${pagePrefix}/` : `${pagePrefix}/page/${currentPage - 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
rel="prev"
className={`${currentPage === 1 ? 'invisible' : 'block'}`}>
<div className="relative w-24 h-10 flex items-center transition-all duration-200 justify-center py-2 px-2 bg-white border rounded-lg cursor-pointer group">
<i className="fas fa-angle-left mr-2 transition-all duration-200 transform group-hover:-translate-x-4" />
<div className="absolute translate-x-4 ml-2 opacity-0 transition-all duration-200 group-hover:opacity-100 group-hover:translate-x-0">
{locale.PAGINATION.PREV}
</div>
</div>
<i className="fas fa-angle-left" />
</Link>
</Link>
{/* 分页 */}
<div className='flex items-center space-x-2'>
{pages}
{pages}
{/* 跳转页码 */}
<div className='bg-white hover:bg-gray-100 h-10 border flex justify-center items-center rounded-lg group hover:border-indigo-600 transition-all duration-200'>
<input value={value} className='w-0 group-hover:w-20 group-hover:px-3 transition-all duration-200 bg-gray-100 border-none outline-none h-full rounded-lg' onInput={handleInputChange}></input>
<div onClick={jumpToPage} className='cursor-pointer hover:bg-indigo-600 hover:text-white px-4 py-2 group-hover:px-2 group-hover:mx-1 group-hover:rounded bg-white'>
<ChevronDoubleRight className={'w-4 h-4'} />
</div>
</div>
</div>
{/* 下一页 */}
<Link
href={{
pathname: `${pagePrefix}/page/${currentPage + 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
rel="next"
className={`${+showNext ? 'block' : 'invisible'} pb-0.5 border-b border-indigo-300 dark:border-indigo-700 hover:border-indigo-400 dark:hover:border-indigo-400 w-6 text-center cursor-pointer duration-500 hover:font-bold`}>
{/* 下一页 */}
<Link
href={{
pathname: `${pagePrefix}/page/${currentPage + 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
rel="next"
className={`${+showNext ? 'block' : 'invisible'} `}>
<i className="fas fa-angle-right" />
</Link>
</div>
<div className="relative w-24 h-10 flex items-center transition-all duration-200 justify-center py-2 px-2 bg-white border rounded-lg cursor-pointer group">
<i className="fas fa-angle-right mr-2 transition-all duration-200 transform group-hover:translate-x-6" />
<div className="absolute -translate-x-10 ml-2 opacity-0 transition-all duration-200 group-hover:opacity-100 group-hover:-translate-x-2">
{locale.PAGINATION.NEXT}
</div>
</div>
</Link>
</div>
)
}
/**
* 页码按钮
* @param {*} page
* @param {*} currentPage
* @param {*} pagePrefix
* @returns
*/
function getPageElement(page, currentPage, pagePrefix) {
const selected = page + '' === currentPage + ''
return (
(<Link
href={page === 1 ? `${pagePrefix}/` : `${pagePrefix}/page/${page}`}
key={page}
passHref
className={
(page + '' === currentPage + ''
? 'font-bold bg-indigo-400 dark:bg-indigo-500 text-white '
: 'border-b duration-500 border-indigo-300 hover:border-indigo-400 ') +
' border-white dark:border-indigo-700 dark:hover:border-indigo-400 cursor-pointer pb-0.5 w-6 text-center font-light hover:font-bold'
}>
href={page === 1 ? `${pagePrefix}/` : `${pagePrefix}/page/${page}`}
key={page}
passHref
className={
(selected
? 'bg-indigo-600 dark:bg-indigo-500 text-white '
: 'bg-white') +
' hover:border-indigo-600 px-4 border py-2 rounded-lg drop-shadow-sm duration-200 transition-colors'
}>
{page}
{page}
</Link>)
</Link>)
)
}
/**
* 获取所有页码
* @param {*} pagePrefix
* @param {*} page
* @param {*} currentPage
* @param {*} totalPage
* @returns
*/
function generatePages(pagePrefix, page, currentPage, totalPage) {
const pages = []
const groupCount = 7 // 最多显示页签数
@@ -87,7 +138,7 @@ function generatePages(pagePrefix, page, currentPage, totalPage) {
startPage = totalPage - dynamicGroupCount
}
if (startPage > 2) {
pages.push(<div key={-1}>... </div>)
pages.push(<div key={-1} className='-mt-2 mx-1'>... </div>)
}
for (let i = 0; i < dynamicGroupCount; i++) {

View File

@@ -7,8 +7,8 @@ const TagItemMini = ({ tag, selected = false }) => {
key={tag}
href={selected ? '/' : `/tag/${encodeURIComponent(tag.name)}`}
passHref
className={'cursor-pointer inline-block hover:text-blue-600 duration-200 py-0.5 px-1 text-sm whitespace-nowrap ' }>
<div className='font-light flex items-center'><HashTag className='text-gray-500 w-3 h-3'/> {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
className={'cursor-pointer inline-block hover:text-indigo-600 duration-200 py-0.5 px-1 text-sm whitespace-nowrap ' }>
<div className='font-light flex items-center'><HashTag className='text-gray-500 stroke-2 mr-0.5 w-3 h-3'/> {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
</Link>
)

View File

@@ -113,8 +113,7 @@ const LayoutBase = props => {
* @returns
*/
const LayoutIndex = (props) => {
const headerSlot = CONFIG.HOME_BANNER_ENABLE && <Hero {...props} />
return <LayoutPostList {...props} headerSlot={headerSlot}/>
return <LayoutPostList {...props}/>
}
/**
@@ -123,7 +122,7 @@ const LayoutIndex = (props) => {
* @returns
*/
const LayoutPostList = (props) => {
return <LayoutBase {...props}>
return <LayoutBase {...props} headerSlot={<Hero {...props} />}>
<CategoryBar {...props} />
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
</LayoutBase>