Merge branch 'main' into pr/emengweb/1007

This commit is contained in:
tangly1024.com
2023-05-23 16:03:18 +08:00
69 changed files with 1422 additions and 592 deletions

View File

@@ -3,6 +3,7 @@ import { ArticleLock } from './components/ArticleLock'
import NotionPage from '@/components/NotionPage'
import { ArticleInfo } from './components/ArticleInfo'
import Comment from '@/components/Comment'
import ShareBar from '@/components/ShareBar'
export const LayoutSlug = props => {
const { post, lock, validPassword } = props
@@ -17,10 +18,10 @@ export const LayoutSlug = props => {
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id="notion-article" className="px-2">
{post && <>
<ArticleInfo post={post} />
<NotionPage post={post} />
<ShareBar post={post} />
<Comment frontMatter={post}/>
</>}
</div>}

View File

@@ -4,6 +4,7 @@ import { useGlobal } from '@/lib/global'
import { useRouter } from 'next/router'
import Link from 'next/link'
import CONFIG_EXAMPLE from '../config_example'
import BlogPostCard from './BlogPostCard'
export const BlogListPage = props => {
const { page = 1, posts, postCount } = props
@@ -22,46 +23,8 @@ export const BlogListPage = props => {
<div className={`w-full ${showPageCover ? 'md:pr-2' : 'md:pr-12'}} mb-12`}>
<div id="container">
{posts?.map(p => (
<article key={p.id} className={`mb-12 ${showPageCover ? 'flex md:flex-row flex-col-reverse' : ''}`}>
<div className={`${showPageCover ? 'md:w-7/12' : ''}`}>
<h2 className="mb-4">
<Link
href={`/${p.slug}`}
className="text-black dark:text-gray-100 text-xl md:text-2xl no-underline hover:underline">
{p.title}
</Link>
</h2>
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
by <a href="#" className="text-gray-700 dark:text-gray-300">{BLOG.AUTHOR}</a> on {p.date?.start_date || p.createdTime}
<span className="font-bold mx-1"> | </span>
<a href={`/category${p.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{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 dark:text-gray-400 leading-normal p-3-lines">
{p.summary}
</p>
{/* 搜索结果 */}
{p.results && (
<p className="p-4-lines mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{p.results.map(r => (
<span key={r}>{r}</span>
))}
</p>
)}
</div>
{/* 图片封面 */}
{showPageCover && (
<div className="md:w-5/12 w-full overflow-hidden p-1">
<Link href={`${BLOG.SUB_PATH}/${p.slug}`} passHref legacyBehavior>
<div className='h-44 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${p?.page_cover}')` }} />
</Link>
</div>
)}
</article>
{posts?.map(post => (
<BlogPostCard key={post.id} post = {post}/>
))}
</div>

View File

@@ -1,8 +1,8 @@
import BLOG from '@/blog.config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import React from 'react'
import React, { useEffect } from 'react'
import throttle from 'lodash.throttle'
import BlogPostCard from './BlogPostCard'
import CONFIG_EXAMPLE from '../config_example'
export const BlogListScroll = props => {
@@ -35,8 +35,9 @@ export const BlogListScroll = props => {
handleGetMore()
}
}, 500))
const showPageCover = CONFIG_EXAMPLE.POST_LIST_COVER
React.useEffect(() => {
useEffect(() => {
window.addEventListener('scroll', scrollTrigger)
return () => {
@@ -44,60 +45,22 @@ export const BlogListScroll = props => {
}
})
const showPageCover = CONFIG_EXAMPLE.POST_LIST_COVER
return (
<div id="container" className="w-full md:pr-12 mb-12" ref={targetRef}>
{postsToShow.map(p => (
<article key={p.id} className={`mb-12 ${showPageCover ? 'flex md:flex-row flex-col-reverse' : ''}`}>
<div className={`${showPageCover ? 'md:w-7/12' : ''}`}>
<h2 className="mb-4">
<Link
href={`/${p.slug}`}
className="text-black dark:text-gray-100 text-xl md:text-2xl no-underline hover:underline">
{p.title}
</Link>
</h2>
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
by <a href="#" className="text-gray-700 dark:text-gray-300">{BLOG.AUTHOR}</a> on {p.date?.start_date || p.createdTime}
<span className="font-bold mx-1"> | </span>
<a href={`/category${p.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{p.category}</a>
{/* <span className="font-bold mx-1"> | </span> */}
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
</div>
<div className={`w-full ${showPageCover ? 'md:pr-2' : 'md:pr-12'}} mb-12`} ref={targetRef}>
<p className="text-gray-700 dark:text-gray-400 leading-normal p-3-lines">
{p.summary}
</p>
{/* 搜索结果 */}
{p.results && (
<p className="p-4-lines mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{p.results.map(r => (
<span key={r}>{r}</span>
))}
</p>
)}
</div>
{/* 图片封面 */}
{showPageCover && (
<div className="md:w-5/12 w-full overflow-hidden p-1">
<Link href={`${BLOG.SUB_PATH}/${p.slug}`} passHref legacyBehavior>
<div className='h-44 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${p?.page_cover}')` }} />
</Link>
</div>
)}
</article>
))}
{postsToShow?.map(post => (
<BlogPostCard key={post.id} post={post} />
))}
<div
onClick={handleGetMore}
className="w-full my-4 py-4 text-center cursor-pointer "
>
{' '}
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
</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>
</div>
)
}

View File

@@ -0,0 +1,51 @@
import BLOG from '@/blog.config'
import CONFIG_EXAMPLE from '../config_example'
import Link from 'next/link'
import TwikooCommentCount from '@/components/TwikooCommentCount'
const BlogPostCard = ({ post }) => {
const showPageCover = CONFIG_EXAMPLE.POST_LIST_COVER
return <article className={`mb-12 ${showPageCover ? 'flex md:flex-row flex-col-reverse' : ''}`}>
<div className={`${showPageCover ? 'md:w-7/12' : ''}`}>
<h2 className="mb-4">
<Link
href={`/${post.slug}`}
className="text-black dark:text-gray-100 text-xl md:text-2xl no-underline hover:underline">
{post.title}
</Link>
</h2>
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
by <a href="#" className="text-gray-700 dark:text-gray-300">{BLOG.AUTHOR}</a> on {post.date?.start_date || post.createdTime}
<TwikooCommentCount post={post} className='pl-1'/>
<span className="font-bold mx-1"> | </span>
<a href={`/category${post.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{post.category}</a>
{/* <span className="font-bold mx-1"> | </span> */}
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
</div>
<p className="text-gray-700 dark:text-gray-400 leading-normal p-3-lines">
{post.summary}
</p>
{/* 搜索结果 */}
{post.results && (
<p className="p-4-lines 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>
{/* 图片封面 */}
{showPageCover && (
<div className="md:w-5/12 w-full overflow-hidden p-1">
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
<div className='h-44 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${post?.page_cover}')` }} />
</Link>
</div>
)}
</article>
}
export default BlogPostCard

View File

@@ -1,6 +1,7 @@
import TagItemMini from './TagItemMini'
import Comment from '@/components/Comment'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import formatDate from '@/lib/formatDate'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
@@ -89,6 +90,11 @@ export default function ArticleDetail(props) {
{post && <NotionPage post={post} />}
</section>
<section>
{/* 分享 */}
<ShareBar post={post} />
</section>
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
{/* 文章内嵌广告 */}
<ins className="adsbygoogle"

View File

@@ -47,7 +47,7 @@ const PaginationSimple = ({ page, showNext }) => {
{locale.PAGINATION.NEXT}
</Link>
</div>
);
)
}
export default PaginationSimple

View File

@@ -11,6 +11,7 @@ import ArticleAdjacent from './components/ArticleAdjacent'
import ArticleCopyright from './components/ArticleCopyright'
import ArticleRecommend from './components/ArticleRecommend'
import { isBrowser } from '@/lib/utils'
import ShareBar from '@/components/ShareBar'
export const LayoutSlug = props => {
const { post, lock, validPassword } = props
@@ -68,6 +69,8 @@ export const LayoutSlug = props => {
data-ad-slot="3806269138" />
</section>
{/* 分享 */}
<ShareBar post={post} />
{post.type === 'Post' && <ArticleCopyright {...props} /> }
{post.type === 'Post' && <ArticleRecommend {...props} /> }
{post.type === 'Post' && <ArticleAdjacent {...props} /> }

View File

@@ -2,6 +2,7 @@ import BLOG from '@/blog.config'
import NotionPage from '@/components/NotionPage'
import Link from 'next/link'
import TagItemMini from './TagItemMini'
import TwikooCommentCount from '@/components/TwikooCommentCount'
/**
* 博客列表的文字内容
@@ -26,7 +27,7 @@ export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary
{/* 分类 */}
<div
className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'
} flex-wrap dark:text-gray-500 text-gray-400 hover:text-indigo-700 dark:hover:text-indigo-400`}
} flex-wrap dark:text-gray-500 text-gray-400 `}
>
<Link
href={`/category/${post.category}`}
@@ -37,6 +38,8 @@ export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary
{post.category}
</Link>
<TwikooCommentCount className='text-sm hover:text-indigo-700 dark:hover:text-indigo-400' post={post}/>
</div>
{/* 摘要 */}
@@ -80,7 +83,7 @@ export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary
<div className="md:flex-nowrap flex-wrap md:justify-start inline-block">
<div>
{' '}
{post.tagItems.map(tag => (
{post.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>

View File

@@ -4,6 +4,7 @@ import Typed from 'typed.js'
import CONFIG_HEXO from '../config_hexo'
import NavButtonGroup from './NavButtonGroup'
import throttle from 'lodash.throttle'
import { useGlobal } from '@/lib/global'
let wrapperTop = 0
let windowTop = 0
@@ -17,6 +18,7 @@ const enableAutoScroll = false // 是否开启自动吸附滚动
const Header = props => {
const [typed, changeType] = useState()
const { siteInfo } = props
const { locale } = useGlobal()
useEffect(() => {
updateHeaderHeight()
@@ -103,7 +105,7 @@ const Header = props => {
onClick={() => { window.scrollTo({ top: wrapperTop, behavior: 'smooth' }) }}
className="cursor-pointer w-full text-center py-4 text-3xl absolute bottom-10 text-white"
>
<div class="opacity-70 animate-bounce text-xs">点此继续</div>
<div className="opacity-70 animate-bounce text-xs">{locale.COMMON.START_READING}</div>
<i className='opacity-70 animate-bounce fas fa-angle-down' />
</div>
</header>

View File

@@ -25,21 +25,23 @@ const HexoRecentComments = (props) => {
}, [])
return (
<Card >
<div className=" mb-2 px-1 justify-between">
<i className="mr-2 fas fas fa-comment" />
{locale.COMMON.RECENT_COMMENTS}
</div>
<Card >
<div className=" mb-2 px-1 justify-between">
<i className="mr-2 fas fas fa-comment" />
{locale.COMMON.RECENT_COMMENTS}
</div>
{onLoading && <div>Loading...<i className='ml-2 fas fa-spinner animate-spin' /></div>}
{!onLoading && comments && comments.length === 0 && <div>No Comments</div>}
{!onLoading && comments && comments.length > 0 && comments.map((comment) => <div key={comment.objectId} className='pb-2 pl-1'>
<div className='dark:text-gray-200 text-sm waline-recent-content wl-content' dangerouslySetInnerHTML={{ __html: comment.comment }} />
<div className='dark:text-gray-400 text-gray-400 text-sm text-right cursor-pointer hover:text-red-500 hover:underline pt-1 pr-2'><Link href={{ pathname: comment.url, hash: comment.objectId, query: { target: 'comment' } }}>--{comment.nick}</Link></div>
</div>)}
{onLoading && <div>Loading...<i className='ml-2 fas fa-spinner animate-spin' /></div>}
{!onLoading && comments && comments.length === 0 && <div>No Comments</div>}
{!onLoading && comments && comments.length > 0 && comments.map((comment) => <div key={comment.objectId} className='pb-2 pl-1'>
<div className='dark:text-gray-200 text-sm waline-recent-content wl-content' dangerouslySetInnerHTML={{ __html: comment.comment }} />
<div className='dark:text-gray-400 text-gray-400 text-sm text-right cursor-pointer hover:text-red-500 hover:underline pt-1 pr-2'>
<Link href={{ pathname: comment.url, hash: comment.objectId, query: { target: 'comment' } }}>--{comment.nick}</Link>
</div>
</div>)}
</Card>
);
</Card>
)
}
export default HexoRecentComments

View File

@@ -47,7 +47,7 @@ const PaginationNumber = ({ page, totalPage }) => {
</Link>
</div>
);
)
}
function getPageElement(page, currentPage, pagePrefix) {
@@ -66,7 +66,7 @@ function getPageElement(page, currentPage, pagePrefix) {
{page}
</Link>)
);
)
}
function generatePages(pagePrefix, page, currentPage, totalPage) {

View File

@@ -51,9 +51,15 @@ const LayoutBase = props => {
{headerSlot}
<main id="wrapper" className="flex-1 w-full py-8 md:px-8 lg:px-24 relative">
{/* 嵌入区域 */}
<div id="container-slot" className={`w-full max-w-6xl ${props?.post && ' lg:max-w-3xl 2xl:max-w-4xl '} mt-6 px-3 mx-auto lg:flex lg:space-x-4 justify-center relative z-10`}>
{props.containerSlot}
</div>
<div id="container-inner" className="w-full max-w-6xl mx-auto lg:flex lg:space-x-4 justify-center relative z-10">
{onLoading ? <LoadingCover /> : children}
</div>
</main>
{/* 左下角悬浮 */}
@@ -61,15 +67,12 @@ const LayoutBase = props => {
<Live2D />
</div>
<div className="bottom-40 right-2 fixed justify-end z-20">
<FloatDarkModeButton />
</div>
{/* 右下角悬浮 */}
<div className={ (show ? ' opacity-100 fixed ' : ' hidden opacity-0 ') + ' transition-all duration-200 bottom-12 right-2 justify-end z-20' }>
<div className= ' justify-center flex flex-col items-center cursor-pointer '>
<JumpToTopButton />
</div>
<div className="bottom-40 right-2 fixed justify-end space-y-2 z-20">
<FloatDarkModeButton />
<JumpToTopButton />
{/* 可扩展的右下角悬浮 */}
{props.floatRightBottom}
</div>
<Footer title={siteInfo?.title || BLOG.TITLE} />

View File

@@ -5,9 +5,10 @@ import Header from './components/Header'
import CONFIG_MATERY from './config_matery'
import LayoutBase from './LayoutBase'
import React from 'react'
import Announcement from './components/Announcement'
export const LayoutIndex = (props) => {
return <LayoutBase {...props} headerSlot={CONFIG_MATERY.HOME_BANNER_ENABLE && <Header {...props} />}>
return <LayoutBase {...props} containerSlot={ <Announcement {...props}/>} headerSlot={CONFIG_MATERY.HOME_BANNER_ENABLE && <Header {...props} />}>
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
</LayoutBase>
}

View File

@@ -10,6 +10,8 @@ import { ArticleInfo } from './components/ArticleInfo'
import Catalog from './components/Catalog'
import JumpToCommentButton from './components/JumpToCommentButton'
import throttle from 'lodash.throttle'
import ShareBar from '@/components/ShareBar'
import Announcement from './components/Announcement'
export const LayoutSlug = props => {
const { post, lock, validPassword } = props
@@ -24,6 +26,7 @@ export const LayoutSlug = props => {
switchShow(shouldShow)
}
}, throttleMs))
useEffect(() => {
document.addEventListener('scroll', scrollListener)
return () => document.removeEventListener('scroll', scrollListener)
@@ -43,84 +46,82 @@ export const LayoutSlug = props => {
{...props}
showCategory={false}
showTag={false}
floatRightBottom={<JumpToCommentButton />}
>
<div id='inner-wrapper'>
<div className={'w-full lg:max-w-3xl 2xl:max-w-4xl'}>
<div className="-mt-32 rounded-md mx-3 lg:border lg:rounded-xl lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
{lock && <ArticleLock validPassword={validPassword} />}
<div id='inner-wrapper' className={'w-full lg:max-w-3xl 2xl:max-w-4xl'} >
{/* 文章主体卡片 */}
<div className="-mt-32 transition-all duration-300 rounded-md mx-3 lg:border lg:rounded-xl lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id="container" className="overflow-x-auto md:w-full px-3 ">
{post?.type && post?.type === 'Post' && <>
<div
data-aos="fade-down"
data-aos-duration="100"
data-aos-once="false"
data-aos-anchor-placement="top-center"
className='px-10'>
<ArticleInfo post={post} />
</div>
<hr />
</>}
<div className='lg:px-10 subpixel-antialiased'>
<article itemScope >
{/* Notion文章主体 */}
<section id='notion-article' className='justify-center mx-auto max-w-2xl lg:max-w-full'>
{post && <NotionPage post={post} />}
</section>
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
{/* 文章内嵌广告 */}
<ins className="adsbygoogle"
style={{ display: 'block', textAlign: 'center' }}
data-adtest="on"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-2708419466378217"
data-ad-slot="3806269138" />
</section>
{/* 文章版权说明 */}
{post.type === 'Post' && <ArticleCopyright {...props} />}
</article>
<hr className='border-dashed' />
{/* 评论互动 */}
<div className="overflow-x-auto dark:bg-hexo-black-gray px-3">
<Comment frontMatter={post} />
</div>
{!lock && <div id="container" className="overflow-x-auto md:w-full px-3 ">
{post?.type && post?.type === 'Post' && <>
<div
data-aos="fade-down"
data-aos-duration="100"
data-aos-once="false"
data-aos-anchor-placement="top-center"
className='px-10'>
<ArticleInfo post={post} />
</div>
<hr />
</>}
</div>}
</div>
<div className='lg:px-10 subpixel-antialiased'>
<article itemScope >
{/* Notion文章主体 */}
<section id='notion-article' className='justify-center mx-auto max-w-2xl lg:max-w-full'>
{post && <NotionPage post={post} />}
</section>
{/* 文章推荐 */}
{post.type === 'Post' && <ArticleAdjacent {...props} />}
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
{/* 文章内嵌广告 */}
<ins className="adsbygoogle"
style={{ display: 'block', textAlign: 'center' }}
data-adtest="on"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-2708419466378217"
data-ad-slot="3806269138" />
</section>
{/* 分享 */}
<ShareBar post={post} />
{/* 文章版权说明 */}
{post.type === 'Post' && <ArticleCopyright {...props} />}
{/* 文章目录 */}
{post?.toc?.length > 0 && <div id='toc-wrapper' style={{ zIndex: '-1' }} className='absolute top-0 w-full h-full xl:block hidden lg:max-w-3xl 2xl:max-w-4xl' >
<div data-aos-delay="200"
data-aos="fade-down"
data-aos-duration="200"
data-aos-once="true"
data-aos-anchor-placement="top-center"
className='relative h-full'>
<div className='float-right xl:-mr-72 xl:w-72 w-56 -mr-56 h-full mt-40'>
<div className='sticky top-24'>
<Catalog toc={post.toc} />
</div>
</article>
<hr className='border-dashed' />
{/* 评论互动 */}
<div className="overflow-x-auto dark:bg-hexo-black-gray px-3">
<Comment frontMatter={post} />
</div>
</div>
</div>}
</div>
<div className='fixed bottom-28 right-4'>
<JumpToCommentButton />
</div>
{/* 底部文章推荐 */}
{post.type === 'Post' && <ArticleAdjacent {...props} />}
<Announcement {...props}/>
{/* 右侧文章目录 */}
{post?.toc?.length > 0 && <div id='toc-wrapper' style={{ zIndex: '-1' }} className='absolute top-0 w-full h-full xl:block hidden lg:max-w-3xl 2xl:max-w-4xl' >
<div data-aos-delay="200"
data-aos="fade-down"
data-aos-duration="200"
data-aos-once="true"
data-aos-anchor-placement="top-center"
className='relative h-full'>
<div className='float-right xl:-mr-72 xl:w-72 w-56 -mr-56 h-full mt-40'>
<div className='sticky top-24'>
<Catalog toc={post.toc} />
</div>
</div>
</div>
</div>}
</div>

View File

@@ -0,0 +1,29 @@
import { useGlobal } from '@/lib/global'
import dynamic from 'next/dynamic'
const NotionPage = dynamic(() => import('@/components/NotionPage'))
const Announcement = ({ notice }) => {
const { locale } = useGlobal()
if (!notice) {
return <></>
}
return <div className="px-3 w-full">
<div
data-aos="zoom-in"
data-aos-duration="500"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className="mb-4 p-2 overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
<div className="text-sm flex flex-nowrap justify-between">
<div className="font-light text-gray-600 dark:text-gray-200">
<i className="mx-2 fas fa-bullhorn" />{locale.COMMON.ANNOUNCEMENT}
</div>
</div>
{notice && (<div id="announcement-content">
<NotionPage post={notice} className='text-center ' />
</div>)}
</div>
</div>
}
export default Announcement

View File

@@ -3,6 +3,7 @@ import Link from 'next/link'
import React from 'react'
import TagItemMini from './TagItemMini'
import CONFIG_MATERY from '../config_matery'
import TwikooCommentCount from '@/components/TwikooCommentCount'
// import Image from 'next/image'
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
@@ -14,84 +15,87 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
const showPageCover = CONFIG_MATERY.POST_LIST_COVER && post?.page_cover
const delay = (index % 3) * 300
return (
<div
data-aos="zoom-in"
data-aos-duration="500"
data-aos-delay={delay}
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className="w-full mb-4 overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
<div
data-aos="zoom-in"
data-aos-duration="500"
data-aos-delay={delay}
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className="w-full mb-4 overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
{/* 固定高度 ,空白用图片拉升填充 */}
<div className="flex flex-col h-80 justify-between">
{/* 固定高度 ,空白用图片拉升填充 */}
<div className="flex flex-col h-80 justify-between">
{/* 头部图片 填充卡片 */}
{showPageCover && (
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
<div
className="flex flex-grow w-full relative duration-200 bg-black rounded-t-md cursor-pointer transform overflow-hidden">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={post?.page_cover}
alt={post.title}
className="opacity-50 h-full w-full hover:scale-125 rounded-t-md transform object-cover duration-500"
/>
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace break-words w-full' > {post.title}</span>
</div>
</Link>
)}
{/* 头部图片 填充卡片 */}
{showPageCover && (
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
<div
className="flex flex-grow w-full relative duration-200 bg-black rounded-t-md cursor-pointer transform overflow-hidden">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={post?.page_cover}
alt={post.title}
className="opacity-50 h-full w-full hover:scale-125 rounded-t-md transform object-cover duration-500"
/>
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace break-words w-full' > {post.title}</span>
</div>
</Link>
)}
{/* 文字描述 */}
<div >
{/* 描述 */}
<div className="px-4 flex flex-col w-full text-gray-700 dark:text-gray-300">
{/* 文字描述 */}
<div >
{/* 描述 */}
<div className="px-4 flex flex-col w-full text-gray-700 dark:text-gray-300">
{(!showPreview || showSummary) && post.summary && (
<p style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '4', WebkitBoxOrient: 'vertical' }}
className="replace my-2 text-sm font-light leading-7">
{post.summary}
</p>
)}
{(!showPreview || showSummary) && post.summary && (
<p style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '4', WebkitBoxOrient: 'vertical' }}
className="replace my-2 text-sm font-light leading-7">
{post.summary}
</p>
)}
<div className='text-gray-800 justify-between flex my-2 dark:text-gray-300'>
<Link
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
passHref
className="font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
<div className='text-gray-800 justify-between flex my-2 dark:text-gray-300'>
<div>
<Link
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
passHref
className="font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
<i className="far fa-clock mr-1" />
{post.date?.start_date || post.lastEditedTime}
<i className="far fa-clock mr-1" />
{post.date?.start_date || post.lastEditedTime}
</Link>
<Link
href={`/category/${post.category}`}
passHref
className="cursor-pointer font-light text-sm hover:underline hover:text-indigo-700 dark:hover:text-indigo-400 transform">
</Link>
<TwikooCommentCount post={post} className='hover:underline cursor-pointer text-sm'/>
</div>
<Link
href={`/category/${post.category}`}
passHref
className="cursor-pointer font-light text-sm hover:underline hover:text-indigo-700 dark:hover:text-indigo-400 transform">
<i className="mr-1 far fa-folder" />
{post.category}
<i className="mr-1 far fa-folder" />
{post.category}
</Link>
</div>
</div>
</Link>
</div>
</div>
{post?.tagItems && post?.tagItems.length > 0 && (<>
<hr />
<div className="text-gray-400 justify-between flex px-5 py-3">
<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>
{post?.tagItems && post?.tagItems.length > 0 && (<>
<hr />
<div className="text-gray-400 justify-between flex px-5 py-3">
<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>
</div>
)
}

View File

@@ -21,7 +21,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
<div id="container" className='w-full'>
<div className='pt-6'></div>
{/* 文章列表 */}
<div className="pt-4 flex flex-wrap pb-24" >
<div className="pt-4 flex flex-wrap pb-12" >
{posts.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} /></div>
))}

View File

@@ -57,7 +57,7 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = CONFIG_MA
return <div id='container' ref={targetRef} className='w-full'>
{/* 文章列表 */}
<div className="pt-4 flex flex-wrap pb-24" >
<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} />

View File

@@ -21,9 +21,8 @@ export default function FloatDarkModeButton() {
return (
<div className={'justify-center items-center text-center' } onClick={handleChangeDarkMode}>
<i id="darkModeButton"
className={`${isDarkMode ? 'fa-sun' : 'fa-moon'} fas transform hover:scale-105 duration-200
text-2xl text-white bg-indigo-700 px-3 py-2.5 rounded-full dark:bg-black cursor-pointer`} />
<i id="darkModeButton" className={`${isDarkMode ? 'fa-sun' : 'fa-moon'} fas transform hover:scale-105 duration-200
text-white bg-indigo-700 w-10 h-10 py-2.5 rounded-full dark:bg-black cursor-pointer`} />
</div>
)
}

View File

@@ -3,6 +3,7 @@ import { useCallback, useEffect, useState } from 'react'
import Typed from 'typed.js'
import CONFIG_MATERY from '../config_matery'
import throttle from 'lodash.throttle'
import { useGlobal } from '@/lib/global'
let wrapperTop = 0
let windowTop = 0
@@ -17,6 +18,8 @@ const throttleMs = 200
const Header = props => {
const [typed, changeType] = useState()
const { siteInfo } = props
const { locale } = useGlobal()
useEffect(() => {
scrollTrigger()
updateHeaderHeight()
@@ -96,8 +99,8 @@ const Header = props => {
<span id='typed' />
</div>
<div onClick={() => { window.scrollTo({ top: wrapperTop, behavior: 'smooth' }) }}
className="mt-12 border cursor-pointer w-40 text-center pt-4 pb-3 text-md text-white hover:bg-orange-600 duration-300 rounded-3xl">
<i className='animate-bounce fas fa-angle-double-down' /> <span>开始阅读</span>
className="mt-12 border cursor-pointer w-40 text-center pt-4 pb-3 text-md text-white hover:bg-orange-600 duration-300 rounded-3xl z-40">
<i className='animate-bounce fas fa-angle-double-down' /> <span>{locale.COMMON.START_READING}</span>
</div>
</div>

View File

@@ -17,11 +17,10 @@ const JumpToCommentButton = () => {
}
}
return (<div
onClick={navToComment}
className='flex space-x-1 items-center justify-center cursor-pointer transform hover:scale-105 duration-200 w-7 h-7 text-center'>
<i className='fas fa-comments text-xl text-white bg-indigo-700 py-3 px-2 rounded-full' />
</div>)
return <div className={'justify-center items-center text-center'} onClick={navToComment}>
<i id="darkModeButton" className={`fas fa-comments transform hover:scale-105 duration-200 text-white
text-sm bg-indigo-700 w-10 h-10 rounded-full dark:bg-black cursor-pointer py-3`} />
</div>
}
export default JumpToCommentButton

View File

@@ -16,11 +16,14 @@ const JumpToTopButton = ({ showPercent = true, percent }) => {
if (!CONFIG_MATERY.WIDGET_TO_TOP) {
return <></>
}
return (<div className=' drop-shadow-md space-x-1 items-center justify-center transform hover:scale-105 duration-200 px-3 py-2 text-center text-white bg-indigo-700 dark:bg-hexo-black-gray rounded-full'
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
<div title={locale.POST.TOP} ><i className='fas fa-arrow-up text-2xl rounded-full' /></div>
{showPercent && (<div className='text-md hidden lg:block'>{percent}</div>)}
</div>)
return <div data-aos="fade-left"
data-aos-duration="300"
data-aos-anchor-placement="top-center"
className={'justify-center items-center text-center'} onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
<i id="darkModeButton" title={locale.POST.TOP} className={`fas fa-arrow-up transform hover:scale-105 duration-200 text-white
bg-indigo-700 w-10 h-10 rounded-full dark:bg-black cursor-pointer py-2.5`} />
</div>
}
export default JumpToTopButton

View File

@@ -1,4 +1,3 @@
import BLOG from '@/blog.config'
import Link from 'next/link'
import { useRouter } from 'next/router'
@@ -13,6 +12,7 @@ const PaginationSimple = ({ page, totalPage }) => {
const router = useRouter()
const currentPage = +page
const showNext = currentPage < totalPage
const pagePrefix = router.asPath.replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '')
return (
<div className="my-10 mx-6 flex justify-between font-medium text-black dark:text-gray-100 space-x-2">
@@ -20,8 +20,8 @@ const PaginationSimple = ({ page, totalPage }) => {
href={{
pathname:
currentPage - 1 === 1
? `${BLOG.SUB_PATH || '/'}`
: `/page/${currentPage - 1}`,
? `${pagePrefix}/`
: `${pagePrefix}/page/${currentPage - 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
passHref
@@ -36,7 +36,7 @@ const PaginationSimple = ({ page, totalPage }) => {
</Link>
<Link
href={{
pathname: `/page/${currentPage + 1}`,
pathname: `${pagePrefix}/page/${currentPage + 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
passHref

View File

@@ -13,6 +13,7 @@ import ArticleAround from './components/ArticleAround'
import TocDrawer from './components/TocDrawer'
import CategoryItem from './components/CategoryItem'
import TagItemMini from './components/TagItemMini'
import ShareBar from '@/components/ShareBar'
export const LayoutSlug = props => {
const { post, prev, next, siteInfo, lock, validPassword } = props
@@ -85,12 +86,17 @@ export const LayoutSlug = props => {
</section>
<section>
{/* 分享 */}
<ShareBar post={post} />
{/* 文章分类和标签信息 */}
<div className='flex justify-between'>
{CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category && <CategoryItem category={post.category} />}
<div>
{CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
</div>
</div>
{post.type === 'Post' && <ArticleAround prev={prev} next={next} />}
<Comment frontMatter={post} />
</section>

View File

@@ -6,6 +6,7 @@ import React from 'react'
import CONFIG_MEDIUM from '../config_medium'
import CategoryItem from './CategoryItem'
import TagItemMini from './TagItemMini'
import TwikooCommentCount from '@/components/TwikooCommentCount'
const BlogPostCard = ({ post, showSummary }) => {
const showPreview = CONFIG_MEDIUM.POST_LIST_PREVIEW && post.blockMap
@@ -43,13 +44,9 @@ const BlogPostCard = ({ post, showSummary }) => {
}
>
<div className="text-sm py-1">{post.date?.start_date}</div>
{CONFIG_MEDIUM.POST_LIST_CATEGORY && (
<CategoryItem category={post.category} />
)}
{CONFIG_MEDIUM.POST_LIST_TAG &&
post?.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
{CONFIG_MEDIUM.POST_LIST_CATEGORY && <CategoryItem category={post.category} />}
{CONFIG_MEDIUM.POST_LIST_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
<TwikooCommentCount post={post} className='hover:underline'/>
</div>
<div className="flex"></div>

View File

@@ -48,7 +48,7 @@ const PaginationSimple = ({ page, totalPage }) => {
{locale.PAGINATION.NEXT}
</Link>
</div>
);
)
}
export default PaginationSimple

View File

@@ -8,8 +8,7 @@ import SideAreaLeft from './components/SideAreaLeft'
import SideAreaRight from './components/SideAreaRight'
import TopNav from './components/TopNav'
import { useGlobal } from '@/lib/global'
import PropTypes from 'prop-types'
import React from 'react'
import { useEffect, useRef, useState } from 'react'
import CONFIG_NEXT from './config_next'
import Live2D from '@/components/Live2D'
import BLOG from '@/blog.config'
@@ -22,12 +21,13 @@ import BLOG from '@/blog.config'
const LayoutBase = (props) => {
const { children, headerSlot, meta, sideBarSlot, floatSlot, rightAreaSlot, siteInfo } = props
const { onLoading } = useGlobal()
const targetRef = React.useRef(null)
const floatButtonGroup = React.useRef(null)
const targetRef = useRef(null)
const floatButtonGroup = useRef(null)
const leftAreaSlot = <Live2D/>
const [show, switchShow] = React.useState(false)
const [percent, changePercent] = React.useState(0) // 页面阅读百分比
const [showRightFloat, switchShow] = useState(false)
const [percent, changePercent] = useState(0) // 页面阅读百分比
const scrollListener = () => {
const targetRef = document.getElementById('wrapper')
const clientHeight = targetRef?.clientHeight
@@ -37,13 +37,13 @@ const LayoutBase = (props) => {
if (per > 100) per = 100
const shouldShow = scrollY > 100 && per > 0
if (shouldShow !== show) {
if (shouldShow !== showRightFloat) {
switchShow(shouldShow)
}
changePercent(per)
}
React.useEffect(() => {
useEffect(() => {
// facebook messenger 插件需要调整右下角悬浮按钮的高度
const fb = document.getElementsByClassName('fb-customerchat')
if (fb.length === 0) {
@@ -54,7 +54,7 @@ const LayoutBase = (props) => {
document.addEventListener('scroll', scrollListener)
return () => document.removeEventListener('scroll', scrollListener)
}, [show])
}, [showRightFloat])
return (<div id='theme-next'>
@@ -78,7 +78,7 @@ const LayoutBase = (props) => {
{/* 右下角悬浮 */}
<div ref={floatButtonGroup} className='right-8 bottom-12 lg:right-2 fixed justify-end z-20 font-sans'>
<div className={(show ? 'animate__animated ' : 'hidden') + ' animate__fadeInUp rounded-md glassmorphism justify-center duration-500 animate__faster flex space-x-2 items-center cursor-pointer '}>
<div className={(showRightFloat ? 'animate__animated ' : 'hidden') + ' animate__fadeInUp rounded-md glassmorphism justify-center duration-500 animate__faster flex space-x-2 items-center cursor-pointer '}>
<JumpToTopButton percent={percent}/>
<JumpToBottomButton />
<FloatDarkModeButton/>
@@ -91,8 +91,4 @@ const LayoutBase = (props) => {
)
}
LayoutBase.propTypes = {
children: PropTypes.node
}
export default LayoutBase

View File

@@ -14,7 +14,11 @@ const Announcement = ({ post, className }) => {
<i className="mr-2 fas fa-bullhorn" />{locale.COMMON.ANNOUNCEMENT}
</div>
</div>
{post && (<div id="announcement-content">
{post && (<div id="announcement-content" data-aos="fade-down"
data-aos-duration="500"
data-aos-delay="200"
data-aos-once="true"
data-aos-anchor-placement="top-bottom">
<NotionPage post={post} className='text-center ' />
</div>)}
</>

View File

@@ -2,7 +2,7 @@ import BLOG from '@/blog.config'
import BlogAround from './BlogAround'
import Comment from '@/components/Comment'
import RecommendPosts from './RecommendPosts'
import ShareBar from './ShareBar'
import ShareBar from '@/components/ShareBar'
import TagItem from './TagItem'
import formatDate from '@/lib/formatDate'
import { useGlobal } from '@/lib/global'
@@ -94,6 +94,10 @@ export default function ArticleDetail(props) {
</section>
{showArticleInfo && <>
{/* 分享 */}
<ShareBar post={post} />
{/* 版权声明 */}
{post.type === 'Post' && <ArticleCopyright author={BLOG.AUTHOR} url={url} />}
@@ -124,7 +128,6 @@ export default function ArticleDetail(props) {
))}
</div>
)}
<ShareBar post={post} />
</>
)}
</section>

View File

@@ -8,6 +8,7 @@ import TagItemMini from './TagItemMini'
import CONFIG_NEXT from '../config_next'
import NotionPage from '@/components/NotionPage'
import NotionIcon from '@/components/NotionIcon'
import TwikooCommentCount from '@/components/TwikooCommentCount'
const BlogPostCard = ({ post, showSummary }) => {
const { locale } = useGlobal()
@@ -22,6 +23,10 @@ const BlogPostCard = ({ post, showSummary }) => {
<Link
href={`${BLOG.SUB_PATH}/${post.slug}`}
passHref
data-aos="fade-down"
data-aos-duration="500"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className={`cursor-pointer hover:underline text-3xl ${showPreview ? 'text-center' : ''
} leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400`}>
@@ -29,17 +34,20 @@ const BlogPostCard = ({ post, showSummary }) => {
</Link>
<div
className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'
} flex-wrap dark:text-gray-500 text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 `}
>
<div data-aos="fade-down"
data-aos-duration="500"
data-aos-delay="100"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'} flex-wrap dark:text-gray-500 text-gray-400 `}>
<div>
{post.category && (
<>
<Link
href={`/category/${post.category}`}
passHref
className="cursor-pointer font-light text-sm hover:underline transform">
className="hover:text-blue-500 dark:hover:text-blue-400 cursor-pointer font-light text-sm hover:underline transform">
<i className="mr-1 fas fa-folder" />
{post.category}
@@ -48,27 +56,29 @@ const BlogPostCard = ({ post, showSummary }) => {
<span className="mx-2">|</span>
</>
)}
<Link
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
passHref
className="font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
{post.date?.start_date}
</Link>
<Link
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
passHref
className="hover:text-blue-500 dark:hover:text-blue-400 font-light hover:underline cursor-pointer text-sm leading-4 mr-3">
{post.date?.start_date}
</Link>
</div>
<div className="md:flex-nowrap flex-wrap md:justify-start inline-block">
<div>
{' '}
{post.tagItems.map(tag => (
<TwikooCommentCount post={post} className='hover:text-blue-500 dark:hover:text-blue-400 hover:underline text-sm'/>
<div className="hover:text-blue-500 dark:hover:text-blue-400 md:flex-nowrap flex-wrap md:justify-start inline-block">
{post.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>
</div>
</div>
{(!showPreview || showSummary) && !post.results && (
<p className="mt-4 mb-24 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
<p data-aos="fade-down"
data-aos-duration="500"
data-aos-delay="100"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className="mt-4 mb-12 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.summary}
</p>
)}
@@ -83,7 +93,11 @@ const BlogPostCard = ({ post, showSummary }) => {
)}
{showPreview && post?.blockMap && (
<div className="overflow-ellipsis truncate">
<div data-aos="fade-down"
data-aos-duration="500"
data-aos-delay="100"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"className="overflow-ellipsis truncate">
<NotionPage post={post} />
</div>
)}

View File

@@ -1,10 +1,6 @@
const Card = ({ children, headerSlot, className }) => {
return <div
data-aos="fade-down"
data-aos-duration="300"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className={className}>
const Card = (props) => {
const { children, headerSlot } = props
return <div {...props}>
<>{headerSlot}</>
<section className="shadow px-2 py-4 bg-white dark:bg-hexo-black-gray hover:shadow-xl duration-200">
{children}

View File

@@ -4,12 +4,21 @@ import React from 'react'
const Logo = props => {
const { siteInfo, className } = props
return (
<Link href='/' passHref legacyBehavior>
<div className={'flex flex-col justify-center items-center cursor-pointer bg-black dark:bg-gray-800 space-y-3 font-bold ' + className}>
<div className='font-serif text-xl text-white'> {siteInfo?.title}</div>
<div className='text-sm text-gray-300 font-light text-center'> {siteInfo?.description}</div>
</div>
</Link>
);
<Link href='/' passHref legacyBehavior>
<div className={'flex flex-col justify-center items-center cursor-pointer bg-black dark:bg-gray-800 space-y-3 font-bold ' + className}>
<div data-aos="fade-down"
data-aos-duration="500"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className='font-serif text-xl text-white'> {siteInfo?.title}</div>
<div data-aos="fade-down"
data-aos-duration="500"
data-aos-delay="300"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className='text-sm text-gray-300 font-light text-center'> {siteInfo?.description}</div>
</div>
</Link>
)
}
export default Logo

View File

@@ -34,7 +34,12 @@ export const MenuList = (props) => {
return (
<>
{/* 大屏模式菜单 */}
<nav id='nav' className='hidden md:block leading-8 text-gray-500 dark:text-gray-400 font-sans'>
<nav id='nav' data-aos="fade-down"
data-aos-duration="500"
data-aos-delay="400"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className='hidden md:block leading-8 text-gray-500 dark:text-gray-400 font-sans'>
{links.map(link => link && link.show && <MenuItemDrop key={link?.to} link={link} />)}
</nav>

View File

@@ -1,4 +1,3 @@
import BLOG from '@/blog.config'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useGlobal } from '@/lib/global'
@@ -14,6 +13,8 @@ const PaginationSimple = ({ page, showNext }) => {
const { locale } = useGlobal()
const router = useRouter()
const currentPage = +page
const pagePrefix = router.asPath.replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '')
return (
<div
data-aos="fade-down"
@@ -25,8 +26,8 @@ const PaginationSimple = ({ page, showNext }) => {
href={{
pathname:
currentPage - 1 === 1
? `${BLOG.SUB_PATH || '/'}`
: `/page/${currentPage - 1}`,
? `${pagePrefix}/`
: `${pagePrefix}/page/${currentPage - 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
passHref

View File

@@ -41,11 +41,11 @@ const SearchInput = ({ currentTag, currentSearch, cRef }) => {
searchInputRef.current.value = ''
setShowClean(false)
}
function lockSearchInput () {
function lockSearchInput() {
lock = true
}
function unLockSearchInput () {
function unLockSearchInput() {
lock = false
}
const [showClean, setShowClean] = useState(false)
@@ -61,31 +61,36 @@ const SearchInput = ({ currentTag, currentSearch, cRef }) => {
}
}
return <div className='flex w-full bg-gray-100'>
<input
ref={searchInputRef}
type='text'
placeholder={currentTag ? `${locale.SEARCH.TAGS} #${currentTag}` : `${locale.SEARCH.ARTICLES}`}
className={'outline-none w-full text-sm pl-4 transition focus:shadow-lg font-light leading-10 text-black bg-gray-100 dark:bg-gray-800 dark:text-white'}
onKeyUp={handleKeyUp}
onCompositionStart={lockSearchInput}
onCompositionUpdate={lockSearchInput}
onCompositionEnd={unLockSearchInput}
onChange={e => updateSearchKey(e.target.value)}
defaultValue={currentSearch || ''}
/>
return <div data-aos="fade-down"
data-aos-duration="500"
data-aos-delay="200"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
className='flex w-full bg-gray-100'>
<input
ref={searchInputRef}
type='text'
placeholder={currentTag ? `${locale.SEARCH.TAGS} #${currentTag}` : `${locale.SEARCH.ARTICLES}`}
className={'outline-none w-full text-sm pl-4 transition focus:shadow-lg font-light leading-10 text-black bg-gray-100 dark:bg-gray-800 dark:text-white'}
onKeyUp={handleKeyUp}
onCompositionStart={lockSearchInput}
onCompositionUpdate={lockSearchInput}
onCompositionEnd={unLockSearchInput}
onChange={e => updateSearchKey(e.target.value)}
defaultValue={currentSearch || ''}
/>
<div className='-ml-8 cursor-pointer float-right items-center justify-center py-2'
onClick={handleSearch}>
<i className={`hover:text-black transform duration-200 text-gray-500 cursor-pointer fas ${onLoading ? 'fa-spinner animate-spin' : 'fa-search'}`} />
</div>
<div className='-ml-8 cursor-pointer float-right items-center justify-center py-2'
onClick={handleSearch}>
<i className={`hover:text-black transform duration-200 text-gray-500 cursor-pointer fas ${onLoading ? 'fa-spinner animate-spin' : 'fa-search'}`} />
</div>
{(showClean &&
<div className='-ml-12 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
<i className='hover:text-black transform duration-200 text-gray-400 cursor-pointer fas fa-times' onClick={cleanSearch} />
{(showClean &&
<div className='-ml-12 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
<i className='hover:text-black transform duration-200 text-gray-400 cursor-pointer fas fa-times' onClick={cleanSearch} />
</div>
)}
</div>
)}
</div>
}
export default SearchInput

View File

@@ -1,88 +0,0 @@
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
import React from 'react'
import { createPopper } from '@popperjs/core'
import copy from 'copy-to-clipboard'
import QRCode from 'qrcode.react'
import { useGlobal } from '@/lib/global'
import CONFIG_NEXT from '../config_next'
const ShareBar = ({ post }) => {
const router = useRouter()
const [qrCodeShow, setQrCodeShow] = React.useState(false)
const { locale } = useGlobal()
if (!CONFIG_NEXT.ARTICLE_SHARE) {
return <></>
}
const shareUrl = BLOG.LINK + router.asPath
// 二维码悬浮
const btnRef = React.createRef()
const popoverRef = React.createRef()
const openPopover = () => {
createPopper(btnRef.current, popoverRef.current, {
placement: 'top'
})
setQrCodeShow(true)
}
const closePopover = () => {
setQrCodeShow(false)
}
const copyUrl = () => {
copy(shareUrl)
alert(locale.COMMON.URL_COPIED)
}
return <>
<div
className='py-2 text-gray-500 text-center space-x-2 flex my-1 dark:text-gray-200 overflow-visible'>
<div className='hidden md:block text-gray-800 dark:text-gray-300 mr-2 my-2 whitespace-nowrap'>{locale.COMMON.SHARE}:</div>
<div className='text-3xl cursor-pointer'>
<a className='text-blue-700' href={`https://www.facebook.com/sharer.php?u=${shareUrl}`} >
<i className='fab fa-facebook-square'/>
</a>
</div>
<div className='text-3xl cursor-pointer'>
<a className='text-blue-400' target='_blank' rel='noreferrer' href={`https://twitter.com/intent/tweet?title=${post.title}&url${shareUrl}`} >
<i className='fab fa-twitter-square'/>
</a>
</div>
<div className='text-3xl cursor-pointer'>
<a className='text-blue-500' href={`https://telegram.me/share/url?url=${shareUrl}&text=${post.title}`} >
<i className='fab fa-telegram'/>
</a>
</div>
<div className='cursor-pointer text-2xl'>
<a className='text-green-600' ref={btnRef} onMouseEnter={openPopover} onMouseLeave={closePopover}>
<i className='fab fa-weixin'/>
<div ref={popoverRef} className={(qrCodeShow ? 'opacity-100 ' : 'invisible opacity-0') + ' transition-all duration-200 text-center py-2'}>
<div className='p-2 bg-white border-0 duration-200 transform block z-40 font-normal shadow-xl mr-10'>
<QRCode value={shareUrl} fgColor='#000000' />
</div>
<span className='bg-white text-black font-semibold p-1 mb-0 rounded-t-lg text-sm mx-auto mr-10'>
{locale.COMMON.SCAN_QR_CODE}
</span>
</div>
</a>
</div>
<div className='cursor-pointer text-2xl'>
<a className='text-red-600' target='_blank' rel='noreferrer' href={`https://service.weibo.com/share/share.php?url=${shareUrl}&title=${post.title}`} >
<i className='fab fa-weibo'/>
</a>
</div>
<div className='cursor-pointer text-2xl'>
<a className='text-blue-400' target='_blank' rel='noreferrer' href={`http://connect.qq.com/widget/shareqq/index.html?url=${shareUrl}&sharesource=qzone&title=${post.title}&desc=${post.summary}`} >
<i className='fab fa-qq'/>
</a>
</div>
<div className='cursor-pointer text-2xl'>
<a className='text-yellow-600' onClick={copyUrl} >
<i className='fas fa-link'/>
</a>
</div>
</div>
</>
}
export default ShareBar

View File

@@ -1,34 +0,0 @@
import React from 'react'
import ShareBar from './ShareBar'
/**
* 悬浮在屏幕右下角,分享按钮
* @returns {JSX.Element}
* @constructor
*/
const ShareButton = ({ post }) => {
const [popoverShow, setPopoverShow] = React.useState(false)
const btnRef = React.createRef()
const openPopover = () => {
setPopoverShow(true)
}
const closePopover = () => {
setPopoverShow(false)
}
return (
<div className='my-2'
onMouseEnter={() => { openPopover() }}
onMouseLeave={() => { closePopover() }}>
<div className={(popoverShow ? 'opacity-100' : 'opacity-0') + ' duration-200 ease-in-out font-normal'}>
<ShareBar post={post}/>
</div>
<div ref={btnRef}
className='z-20 border dark:border-gray-500 dark:bg-gray-600 bg-white cursor-pointer text-md hover:shadow-2xl shadow-lg'>
<i className='fas fa-share-alt-square transform duration-200 hover:scale-150 dark:text-gray-200 p-4' title='share' />
</div>
</div>
)
}
export default ShareButton

View File

@@ -26,14 +26,10 @@ const SideAreaLeft = props => {
return <aside id='left' className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'ml-4' : 'mr-4') + ' hidden lg:block flex-col w-60 z-20 relative'}>
<section
data-aos="fade-down"
data-aos-duration="300"
data-aos-once="false"
data-aos-anchor-placement="top-bottom"
className='w-60'>
{/* 菜单 */}
<section className='shadow hidden lg:block mb-5 pb-4 bg-white dark:bg-hexo-black-gray hover:shadow-xl duration-200'>
<Logo {...props} className='h-32' />
<Logo className='h-32' {...props} />
<div className='pt-2 px-2 font-sans'>
<MenuList allowCollapse={true} {...props} />
</div>

View File

@@ -43,6 +43,7 @@ const SideAreaRight = (props) => {
</Card>}
<div className="sticky top-0 space-y-4 w-full">
{announcementVisible && <Card>
<Announcement post={notice} />
</Card>}

View File

@@ -30,7 +30,6 @@ const CONFIG_NEXT = {
WIDGET_DARK_MODE: false, // 显示日间/夜间模式切换
WIDGET_TOC: true, // 移动端显示悬浮目录
ARTICLE_SHARE: process.env.NEXT_PUBLIC_ARTICLE_SHARE || false, // 文章分享功能
ARTICLE_RELATE_POSTS: true, // 相关文章推荐
ARTICLE_COPYRIGHT: true // 文章版权声明

View File

@@ -1,5 +1,6 @@
import BLOG from '@/blog.config'
import Announcement from './components/Announcement'
import { BlogListPage } from './components/BlogListPage'
import { BlogListScroll } from './components/BlogListScroll'
import LayoutBase from './LayoutBase'
@@ -7,6 +8,7 @@ import LayoutBase from './LayoutBase'
export const LayoutIndex = props => {
return (
<LayoutBase {...props}>
<Announcement {...props} />
{BLOG.POST_LIST_STYLE === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />}
</LayoutBase>
)

View File

@@ -4,6 +4,7 @@ import NotionPage from '@/components/NotionPage'
import { ArticleInfo } from './components/ArticleInfo'
import Comment from '@/components/Comment'
import { ArticleFooter } from './components/ArticleFooter'
import ShareBar from '@/components/ShareBar'
export const LayoutSlug = props => {
const { post, lock, validPassword } = props
@@ -21,6 +22,7 @@ export const LayoutSlug = props => {
{post && <>
<ArticleInfo post={post} />
<NotionPage post={post} />
<ShareBar post={post} />
<Comment frontMatter={post}/>
<ArticleFooter />
</>}

View File

@@ -0,0 +1,18 @@
import dynamic from 'next/dynamic'
const NotionPage = dynamic(() => import('@/components/NotionPage'))
const Announcement = ({ notice, className }) => {
if (notice?.blockMap) {
return <div className={className}>
<section id='announcement-wrapper' className='mb-10'>
{notice && (<div id="announcement-content">
<NotionPage post={notice} className='text-center ' />
</div>)}
</section>
</div>
} else {
return null
}
}
export default Announcement

View File

@@ -4,6 +4,7 @@ import NotionPage from '@/components/NotionPage'
import { ArticleInfo } from './components/ArticleInfo'
import Comment from '@/components/Comment'
import ArticleAround from './components/ArticleAround'
import ShareBar from '@/components/ShareBar'
export const LayoutSlug = props => {
const { post, lock, validPassword, prev, next } = props
@@ -22,6 +23,8 @@ export const LayoutSlug = props => {
{post && <>
<ArticleInfo post={post} />
<NotionPage post={post} />
{/* 分享 */}
<ShareBar post={post} />
{post.type === 'Post' && <ArticleAround prev={prev} next={next} />}
<Comment frontMatter={post}/>
</>}

View File

@@ -1,6 +1,7 @@
import BLOG from '@/blog.config'
import Link from 'next/link'
import CONFIG_SIMPLE from '../config_simple'
import TwikooCommentCount from '@/components/TwikooCommentCount'
export const BlogItem = props => {
const { post } = props
@@ -18,6 +19,7 @@ export const BlogItem = props => {
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
<span> <i className="fa-regular fa-user"></i> <a href={CONFIG_SIMPLE.AUTHOR_LINK}>{BLOG.AUTHOR}</a></span>
<span> - <i className="fa-regular fa-clock"></i> {post.date?.start_date || post.createdTime}</span>
<span> - <TwikooCommentCount post={post}/></span>
{post.category && <span> - <i className="fa-regular fa-folder"></i> <a href={`/category/${post.category}`} className="hover:text-red-400 transition-all duration-200">{post.category}</a></span>}
{post.tags && post.tags?.length > 0 && post.tags.map(t => <span key={t}> / <Link href={`/tag/${t}`}><span className=' hover:text-red-400 transition-all duration-200'>{t}</span></Link></span>)}
</div>