Merge pull request #7 from tangly1024/theme-Next

Theme next
This commit is contained in:
tangly1024
2022-01-04 16:35:50 +08:00
committed by GitHub
25 changed files with 302 additions and 135 deletions

View File

@@ -1,70 +1,58 @@
const BLOG = {
title: '小唐笔记',
author: 'tangly1024',
email: 'tlyong1992@hotmail.com',
link: 'https://tangly1024.com',
description: '分享编程技术与记录生活',
keywords: ['Notion', '写作', '博客'],
title: '小唐笔记', // 站点标题
description: '分享编程技术与记录生活', // 站点描述
author: 'tangly1024', // 作者
bio: '一个普通的干饭人🍚', // 作者简介
email: 'tlyong1992@hotmail.com', // 联系邮箱
link: 'https://tangly1024.com', // 网站地址
keywords: ['Notion', '写作', '博客'], // 网站关键词
home: { // 首页
showHomeBanner: false, // 首页是否显示大图及标语 [true,false]
homeBannerStrings: ['Hi我是一个程序员', 'Hi我是一个打工人', 'Hi我是一个干饭人', '欢迎来到我的博客🎉'], // 首页大图标语文字
homeBannerImage: './bg_image.jpg' // 首图
homeBannerImage: './bg_image.jpg' // 背景图地址
},
lang: 'zh-CN', // ['zh-CN','en-US'] default lang => see /lib/lang.js for more.
notionPageId: process.env.NOTION_PAGE_ID || 'bee1fccfa3bd47a1a7be83cc71372d83', // Important page_id
notionAccessToken: process.env.NOTION_ACCESS_TOKEN || '', // Useful if you prefer not to make your database public
appearance: 'auto', // ['light', 'dark', 'auto'],
font: 'font-sans tracking-wider subpixel-antialiased', // 文章字体 ['font-sans', 'font-serif', 'font-mono'] @see https://www.tailwindcss.cn/docs/font-family
lightBackground: '#ffffff', // use hex value, don't forget '#' e.g #fffefc
lightBackground: '#eeeeee', // use hex value, don't forget '#' e.g #fffefc
darkBackground: '#111827', // use hex value, don't forget '#'
path: '', // leave this empty unless you want to deploy in a folder
since: 2020, // if leave this empty, current year will be used.
postListStyle: 'page', // ['page','scroll] 文章列表样式:页码分页、单页滚动加载
postsPerPage: 6, // post counts per page
sortByDate: false,
autoCollapsedNavBar: true, // the automatically collapsed navigation bar
menu: { // menu config
showAbout: false,
showCategory: true,
showTag: true,
showArchive: true,
showSearch: true
menu: { // 菜单栏设置
showAbout: false, // 显示关于
showCategory: true, // 显示分类
showTag: true, // 显示标签
showArchive: true, // 显示归档
showSearch: true // 显示搜索
},
widget: {
widget: { // 挂件及组件设置
showPet: false, // 是否显示宠物挂件
petLink: 'https://cdn.jsdelivr.net/npm/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json', // 模型地址 @see https://github.com/xiazeyu/live2d-widget-models
showToTop: true,
showToBottom: true,
showDarkMode: true,
showToc: true,
showShareBar: false,
showRelatePosts: false,
showCopyRight: false,
showLatestPost: false,
showCategoryList: false,
showTagList: false
petLink: 'https://cdn.jsdelivr.net/npm/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json', // 挂件模型地址 @see https://github.com/xiazeyu/live2d-widget-models
showToTop: true, // 是否显示回顶
showToBottom: true, // 显示回底
showDarkMode: true, // 显示日间/夜间模式切换
showToc: true, // 移动端显示悬浮目录
showShareBar: false, // 文章分享功能
showRelatePosts: false, // 关联文章推荐
showCopyRight: false, // 显示版权声明
showLatestPost: false, // 右侧边栏显示最近更新
showCategoryList: false, // 右侧边栏显示文章分类列表
showTagList: false // 右侧边栏显示标签分类列表
},
socialLink: { // 社交链接
socialLink: { // 社交链接,如不需要展示可以留空白,例如 weibo:''
weibo: 'https://weibo.com/tangly1024',
twitter: 'https://twitter.com/troy1024_1',
github: 'https://github.com/tangly1024',
telegram: 'https://t.me/tangly_1024'
},
analytics: {
provider: 'ga', // Currently we support Google Analytics and Ackee, please fill with 'ga' or 'ackee', leave it empty to disable it.
ackeeConfig: {
tracker: '', // e.g 'https://ackee.tangly1024.net/tracker.js'
dataAckeeServer: '', // e.g https://ackee.tangly1024.net , don't end with a slash
domainId: '' // e.g '0e2257a8-54d4-4847-91a1-0311ea48cc7b'
},
gaConfig: {
measurementId: 'G-68EK0W049N' // e.g: G-XXXXXXXXXX
},
baiduAnalytics: 'f683ef76f06bb187cbed5546f6f28f28', // e.g only need xxxxx -> https://hm.baidu.com/hm.js?[xxxxx]
busuanzi: true, // 展示网站阅读量访问数 see http://busuanzi.ibruce.info/
cnzzAnalytics: '' // 站长统计id only need xxxxxxxx -> https://s9.cnzz.com/z_stat.php?id=[xxxxxxxx]&web_id=[xxxxxxx]
},
comment: { // support provider: gitalk, utterances, cusdis
provider: '', // leave it empty if you don't need any comment plugin
comment: { // 评论插件,支持 gitalk, utterances, cusdis
provider: '', // 不需要则留空白
gitalkConfig: {
repo: 'NotionNext', // The repository of store comments
owner: 'tangly1024',
@@ -84,6 +72,21 @@ const BLOG = {
DaoVoiceId: '', // DaoVoice http://dashboard.daovoice.io/get-started
TidioId: '' // https://www.tidio.com/
},
// --- 高级设置
analytics: { // 文章访问量统计
busuanzi: true, // 展示网站阅读量、访问数 see http://busuanzi.ibruce.info/
provider: 'ga', // 支持 Google Analytics and Ackee, please fill with 'ga' or 'ackee', leave it empty to disable it.
baiduAnalytics: 'f683ef76f06bb187cbed5546f6f28f28', // e.g only need xxxxx -> https://hm.baidu.com/hm.js?[xxxxx]
cnzzAnalytics: '', // 站长统计id only need xxxxxxxx -> https://s9.cnzz.com/z_stat.php?id=[xxxxxxxx]&web_id=[xxxxxxx]
gaConfig: {
measurementId: 'G-68EK0W049N' // e.g: G-XXXXXXXXXX
},
ackeeConfig: {
tracker: '', // e.g 'https://ackee.tangly1024.net/tracker.js'
dataAckeeServer: '', // e.g https://ackee.tangly1024.net , don't end with a slash
domainId: '' // e.g '0e2257a8-54d4-4847-91a1-0311ea48cc7b'
}
},
seo: {
googleSiteVerification: '' // Remove the value or replace it with your own google site verification code
},

View File

@@ -51,7 +51,7 @@ export default function ArticleDetail ({ post, blockMap, recommendPosts, prev, n
const attachZoomRef = attachZoom
return (<>
<div id="article-wrapper" ref={targetRef} className="shadow md:hover:shadow-2xl duration-300 overflow-x-auto flex-grow mx-auto w-screen md:w-full ">
<div id="container" ref={targetRef} className="shadow md:hover:shadow-2xl duration-300 overflow-x-auto flex-grow mx-auto w-screen md:w-full ">
<article itemScope itemType="https://schema.org/Movie"
className="subpixel-antialiased py-10 px-5 lg:pt-24 md:px-24 dark:border-gray-700 bg-white dark:bg-gray-800"
>

View File

@@ -1,5 +1,5 @@
import BlogPostCard from '@/components/BlogPostCard'
import Pagination from '@/components/Pagination'
import PaginationNumber from './PaginationNumber'
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
@@ -29,7 +29,7 @@ const BlogPostListPage = ({ page = 1, posts = [], tags }) => {
}
// 处理分页
const totalPages = Math.ceil(filteredBlogPosts.length / BLOG.postsPerPage)
const totalPage = Math.ceil(filteredBlogPosts.length / BLOG.postsPerPage)
const postsToShow = filteredBlogPosts.slice(
BLOG.postsPerPage * (page - 1),
BLOG.postsPerPage * page
@@ -43,28 +43,18 @@ const BlogPostListPage = ({ page = 1, posts = [], tags }) => {
if (!postsToShow || postsToShow.length === 0) {
return <BlogPostListEmpty />
} else {
return <div id='post-list-wrapper' className='pt-16 md:pt-28 px-2 md:px-20'>
{(!page || page === 1) && (<div className='py-5' />)}
{(page && page !== 1) && (
<div className='pb-5'>
<div className='dark:text-gray-200 flex justify-between py-1'>
{page && page !== 1 && (<span> {page} / {totalPages}</span>)}
</div>
</div>
)}
<div>
return (
<div id="container" className='mt-10'>
{/* 文章列表 */}
<div className='flex flex-wrap'>
<div className="flex flex-wrap space-y-8 mx-5 md:mx-0">
{postsToShow.map(post => (
<BlogPostCard key={post.id} post={post} tags={tags} />
))}
</div>
<Pagination page={page} showNext={showNext} />
<PaginationNumber page={page} showNext={showNext} totalPage={totalPage} />
</div>
</div>
)
}
}

View File

@@ -53,7 +53,7 @@ const BlogPostListScroll = ({ posts = [], tags, currentSearch, currentCategory,
if (!postsToShow || postsToShow.length === 0) {
return <BlogPostListEmpty currentSearch={currentSearch} />
} else {
return <div id='post-list-wrapper' className='mt-10 md:mt-0' ref={targetRef}>
return <div id='container' className='mt-10' ref={targetRef}>
{/* 文章列表 */}
<div className='flex flex-wrap space-y-8 mx-5 md:mx-0'>

View File

@@ -1,7 +1,7 @@
import Link from 'next/link'
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faFolder, faFolderOpen, faThList } from '@fortawesome/free-solid-svg-icons'
import { faFolder, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
import { useGlobal } from '@/lib/global'
const CategoryList = ({ currentCategory, categories }) => {
@@ -11,7 +11,7 @@ const CategoryList = ({ currentCategory, categories }) => {
const { locale } = useGlobal()
return <ul className='flex py-1 space-x-3'>
<li className='w-16 py-2 dark:text-gray-200 whitespace-nowrap'><FontAwesomeIcon className='mr-2' icon={faThList} />{locale.COMMON.CATEGORY}</li>
<li className='w-16 py-2 dark:text-gray-200 whitespace-nowrap'>{locale.COMMON.CATEGORY}</li>
{Object.keys(categories).map(category => {
const selected = category === currentCategory
return (

View File

@@ -9,7 +9,7 @@ const InfoCard = ({ postCount }) => {
<div className='flex flex-col items-center justify-center '>
<div className='hover:rotate-45 hover:scale-125 transform duration-200 cursor-pointer' onClick={ () => { Router.push('/about') }}>
<Image
alt={BLOG.title}
alt={BLOG.author}
width={120}
height={120}
loading='lazy'
@@ -17,8 +17,8 @@ const InfoCard = ({ postCount }) => {
className='rounded-full'
/>
</div>
<div className='text-3xl font-serif dark:text-white py-2 hover:scale-105 transform duration-200'>{BLOG.title}</div>
<div className='font-light dark:text-white py-2 hover:scale-105 transform duration-200'>{BLOG.description}</div>
<div className='text-2xl font-serif dark:text-white py-2 hover:scale-105 transform duration-200'>{BLOG.author}</div>
<div className='font-light dark:text-white py-2 hover:scale-105 transform duration-200'>{BLOG.bio}</div>
<SocialButton/>
</div>
</>

View File

@@ -3,7 +3,11 @@ import BLOG from '@/blog.config'
let hasLoad = false
export default function Live2D () {
if (BLOG.widget?.showPet && typeof window !== 'undefined' && !hasLoad) {
if (!BLOG.widget?.showPet) {
return <></>
}
if (typeof window !== 'undefined' && !hasLoad) {
initLive2D()
hasLoad = true
}

View File

@@ -4,10 +4,10 @@ import React from 'react'
const Logo = () => {
return <Link href='/' passHref>
<div title={BLOG.title} className='mx-auto border dark:border-gray-600 text-center cursor-pointer text-xl dark:text-gray-300 font-semibold dark:hover:bg-gray-600 text-white p-2 hover:scale-105 hover:shadow-2xl duration-200 transform'>
<span className='text-red-600'>Tangly</span>
<span className='text-blue-400'>1024</span>
</div>
<div className='flex flex-col justify-center items-center cursor-pointer bg-gray-800 space-y-3 h-32 font-bold mb-4'>
<div className='font-serif text-xl text-white'> {BLOG.title}</div>
<div className='text-sm text-gray-300 font-light'> {BLOG.description}</div>
</div>
</Link>
}
export default Logo

View File

@@ -20,9 +20,9 @@ const MenuButtonGroup = ({ allowCollapse = false }) => {
{links.map(link => {
if (link.show) {
const selected = (router.pathname === link.to) || (router.asPath === link.to)
return <Link key={link.id + link.icon} title={link.to} href={link.to} >
return <Link key={`${link.id}-${link.to}`} title={link.to} href={link.to} >
<a className={'py-1 my-1 px-5 mx-2 duration-300 text-base hover:bg-gray-500 hover:text-white hover:shadow-lg cursor-pointer font-light flex flex-nowrap items-center ' +
(selected ? 'bg-gray-700 text-white ' : ' ')} >
(selected ? 'bg-gray-200 text-black' : ' ')} >
<div className='my-auto justify-center flex '>
<FontAwesomeIcon icon={link.icon} />
</div>
@@ -30,7 +30,7 @@ const MenuButtonGroup = ({ allowCollapse = false }) => {
</a>
</Link>
} else {
return <></>
return null
}
})}
</nav>

View File

@@ -0,0 +1,95 @@
import BLOG from '@/blog.config'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'
/**
* 数字翻页插件
* @param page 当前页码
* @param showNext 是否有下一页
* @returns {JSX.Element}
* @constructor
*/
const PaginationNumber = ({ page, showNext, totalPage }) => {
const router = useRouter()
const currentPage = +page
const pages = generatePages(page, currentPage, totalPage)
return (
<div className='my-5 flex justify-center items-end font-medium text-black hover:shadow-xl duration-500 bg-white dark:bg-gray-700 dark:text-gray-300 py-3 shadow space-x-2'>
{/* 上一页 */}
<Link
href={ {
pathname: (currentPage - 1 === 1 ? `${BLOG.path || '/'}` : `/page/${currentPage - 1}`), query: router.query.s ? { s: router.query.s } : {}
} } passHref >
<div
rel='prev'
className={`${currentPage === 1 ? 'invisible' : 'block'} border-white dark:border-gray-700 hover:border-gray-400 dark:hover:border-gray-400 w-6 text-center cursor-pointer duration-200 hover:font-bold`}
>
<FontAwesomeIcon icon={faAngleLeft}/>
</div>
</Link>
{pages}
{/* 下一页 */}
<Link href={ { pathname: `/page/${currentPage + 1}`, query: router.query.s ? { s: router.query.s } : {} } } passHref>
<div
rel='next'
className={`${+showNext ? 'block' : 'invisible'} border-t-2 border-white dark:border-gray-700 hover:border-gray-400 dark:hover:border-gray-400 w-6 text-center cursor-pointer duration-500 hover:font-bold`}
>
<FontAwesomeIcon icon={faAngleRight}/>
</div>
</Link>
</div>
)
}
function getPageElement (page, currentPage) {
console.log(page, currentPage)
return <Link href={`/page/${page}`} key={page} passHref>
<div className={(page + '' === currentPage ? 'font-bold bg-gray-500 dark:bg-gray-400 text-white ' : 'border-t-2 duration-500 border-white hover:border-gray-400 ') +
' border-white dark:border-gray-700 dark:hover:border-gray-400 cursor-pointer w-6 text-center font-light hover:font-bold'}>
{page}
</div>
</Link>
}
function generatePages (page, currentPage, totalPage) {
const pages = []
const startPage = 1 // 分组开始页码
const groupCount = 5 // 页码分组
if (totalPage <= 10) {
for (let i = 1; i <= totalPage; i++) {
pages.push(getPageElement(i, page))
}
} else {
pages.push(getPageElement(1, page))
let pageLength = 0
if (groupCount + startPage > totalPage) {
pageLength = totalPage
} else {
pageLength = groupCount + startPage
}
if (currentPage >= groupCount) {
pages.push(<div key={-1}>... </div>)
}
for (let i = startPage; i < pageLength; i++) {
if (i <= totalPage - 1 && i > 1) {
pages.push(getPageElement(i, page))
}
}
if (totalPage - startPage >= groupCount + 1) {
pages.push(<div key={-2}>... </div>)
}
pages.push(getPageElement(totalPage, page))
}
return pages
}
export default PaginationNumber

View File

@@ -4,13 +4,13 @@ import { useRouter } from 'next/router'
import { useGlobal } from '@/lib/global'
/**
* 翻页插件
* 简易翻页插件
* @param page 当前页码
* @param showNext 是否有下一页
* @returns {JSX.Element}
* @constructor
*/
const Pagination = ({ page, showNext }) => {
const PaginationSimple = ({ page, showNext }) => {
const { locale } = useGlobal()
const router = useRouter()
const currentPage = +page
@@ -39,4 +39,4 @@ const Pagination = ({ page, showNext }) => {
)
}
export default Pagination
export default PaginationSimple

View File

@@ -21,7 +21,7 @@ const SearchDrawer = ({ cRef }) => {
return (
<div id='search-drawer-wrapper' ref={searchDrawer} className='hidden'>
<div className='flex absolute px-5 w-full h-full left-0 top-14 z-50 justify-center'>
<div className='md:max-w-3xl w-full mx-auto'>
<div className='md:max-w-3xl w-full mx-auto animate__animated animate__faster animate__fadeIn'>
<SearchInput cRef={searchInputRef} />
</div>
</div>

View File

@@ -7,6 +7,7 @@ import React from 'react'
import Analytics from './Analytics'
import Tabs from '@/components/Tabs'
import BLOG from '@/blog.config'
import Logo from './Logo'
/**
* 侧边平铺
@@ -26,16 +27,19 @@ const SideAreaLeft = ({ title, tags, currentTag, post, posts, categories, curren
const postCount = posts?.length || 0
return <aside id='left' className='hidden lg:block flex-col w-60 mr-4'>
<section className='sticky top-8 w-60'>
<section className='w-60'>
{/* 菜单 */}
<section className='shadow hidden lg:block mb-5 py-4 bg-white dark:bg-gray-800 hover:shadow-xl duration-200'>
<section className='shadow hidden lg:block mb-5 pb-4 bg-white dark:bg-gray-800 hover:shadow-xl duration-200'>
<Logo/>
<MenuButtonGroup allowCollapse={true} />
{BLOG.menu.showSearch && <div className='px-5 pt-2'>
<SearchInput currentTag={currentTag} currentSearch={currentSearch} />
</div>}
</section>
</section>
<section className='sticky top-4'>
<Tabs>
{showToc && (
<div key={locale.COMMON.TABLE_OF_CONTENTS} className='dark:text-gray-400 text-gray-600 bg-white dark:bg-gray-800 duration-200'>
@@ -48,7 +52,6 @@ const SideAreaLeft = ({ title, tags, currentTag, post, posts, categories, curren
<Analytics postCount={postCount}/>
</div>
</Tabs>
</section>
</aside>

View File

@@ -1,14 +1,13 @@
import React from 'react'
import MenuButtonGroup from '@/components/MenuButtonGroup'
import InfoCard from '@/components/InfoCard'
import TagGroups from '@/components/TagGroups'
import LatestPostsGroup from '@/components/LatestPostsGroup'
import CategoryGroup from '@/components/CategoryGroup'
import SearchInput from '@/components/SearchInput'
import Link from 'next/link'
import InfoCard from '@/components/InfoCard'
import LatestPostsGroup from '@/components/LatestPostsGroup'
import TagGroups from '@/components/TagGroups'
import { useGlobal } from '@/lib/global'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faAngleDoubleRight, faArchive, faTags, faThList } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import Link from 'next/link'
import React from 'react'
import Logo from './Logo'
/**
* 侧边栏
@@ -24,30 +23,15 @@ import { faAngleDoubleRight, faArchive, faTags, faThList } from '@fortawesome/fr
*/
const SideBar = ({ title, tags, currentTag, post, posts, categories, currentCategory, currentSearch }) => {
const { locale } = useGlobal()
return <aside id='sidebar' className='pt-5 bg-white dark:bg-gray-900 w-80 z-10 dark:border-gray-500 border-gray-200 scroll-hidden h-full'>
<InfoCard />
return <aside id='sidebar' className='bg-white dark:bg-gray-900 w-80 z-10 dark:border-gray-500 border-gray-200 scroll-hidden h-full'>
<div className={(!post ? 'sticky top-0' : '') + ' bg-white dark:bg-gray-900 pb-4'}>
<section className='hidden lg:block'>
<MenuButtonGroup allowCollapse={true} />
<section className='py-5'>
<InfoCard />
</section>
<section className='p-5'>
<SearchInput currentTag={currentTag} currentSearch={currentSearch} />
</section>
{/* 最新文章 */}
{posts && (
<section className='mt-4'>
<div className='text-sm pb-4 px-5 flex flex-nowrap justify-between'>
<div className='font-light text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faArchive} className='mr-2' />{locale.COMMON.LATEST_POSTS}</div>
</div>
<LatestPostsGroup posts={posts} />
</section>
)}
<Logo/>
{/* 分类 */}
{categories && (
<section className='mt-8'>
@@ -65,7 +49,7 @@ const SideBar = ({ title, tags, currentTag, post, posts, categories, currentCate
{/* 标签云 */}
{tags && (
<section className='mt-8'>
<section className='mt-4'>
<div className='text-sm py-2 px-5 flex flex-nowrap justify-between font-light dark:text-gray-200'>
<div className='text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faTags} className='mr-2'/>{locale.COMMON.TAGS}</div>
<Link href='/tag' passHref>
@@ -79,6 +63,16 @@ const SideBar = ({ title, tags, currentTag, post, posts, categories, currentCate
</div>
</section>
)}
{/* 最新文章 */}
{posts && (
<section className='mt-8'>
<div className='text-sm pb-4 px-5 flex flex-nowrap justify-between'>
<div className='font-light text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faArchive} className='mr-2' />{locale.COMMON.LATEST_POSTS}</div>
</div>
<LatestPostsGroup posts={posts} />
</section>
)}
</div>
<section className='bg-white dark:bg-gray-900'>

View File

@@ -1,5 +1,6 @@
import SideBar from '@/components/SideBar'
import React, { useEffect, useImperativeHandle, useState } from 'react'
import { useRouter } from 'next/router'
import React, { useEffect, useImperativeHandle } from 'react'
/**
* 侧边栏抽屉面板,可以从侧面拉出
@@ -10,7 +11,7 @@ const SideBarDrawer = ({ post, currentTag, cRef, tags, posts, categories, curren
// 暴露给父组件 通过cRef.current.handleMenuClick 调用
useImperativeHandle(cRef, () => {
return {
handleSwitchSideDrawerVisible: () => switchSideDrawerVisible()
handleSwitchSideDrawerVisible: () => switchSideDrawerVisible(true)
}
})
@@ -19,11 +20,19 @@ const SideBarDrawer = ({ post, currentTag, cRef, tags, posts, categories, curren
sideBarWrapperElement?.classList?.remove('hidden')
})
const router = useRouter()
useEffect(() => {
const sideBarDrawerRouteListener = url => {
switchSideDrawerVisible(false)
}
router.events.on('routeChangeComplete', sideBarDrawerRouteListener)
return () => {
router.events.off('routeChangeComplete', sideBarDrawerRouteListener)
}
}, [router.events])
// 点击按钮更改侧边抽屉状态
const [isShow, changeHiddenStatus] = useState(false)
const switchSideDrawerVisible = () => {
const showStatus = !isShow
changeHiddenStatus(showStatus)
const switchSideDrawerVisible = (showStatus) => {
if (window) {
const sideBarDrawer = window.document.getElementById('sidebar-drawer')
const sideBarDrawerBackground = window.document.getElementById('sidebar-drawer-background')
@@ -39,11 +48,11 @@ const SideBarDrawer = ({ post, currentTag, cRef, tags, posts, categories, curren
}
return <div id='sidebar-wrapper' className='hidden'>
<div id='sidebar-drawer' className='-ml-80 bg-white dark:bg-gray-900 flex flex-col duration-300 fixed h-full left-0 overflow-y-scroll scroll-hidden top-0 z-50'>
<div id='sidebar-drawer' className='-ml-80 bg-white dark:bg-gray-900 flex flex-col duration-300 fixed h-full left-0 overflow-y-scroll scroll-hidden top-0 z-50 shadow-2xl'>
<SideBar tags={tags} post={post} posts={posts} categories={categories} currentCategory={currentCategory} />
</div>
{/* 背景蒙版 */}
<div id='sidebar-drawer-background' onClick={switchSideDrawerVisible} className='hidden fixed top-0 left-0 z-30 w-full h-full bg-black bg-opacity-30'/>
<div id='sidebar-drawer-background' onClick={() => { switchSideDrawerVisible(false) }} className='hidden animate__animated animate__fadeIn fixed top-0 duration-300 left-0 z-30 w-full h-full glassmorphism'/>
</div>
}

View File

@@ -36,7 +36,7 @@ const StickyBar = ({ children }) => {
return (
<div id='sticky-bar' className='sticky flex-grow justify-center top-14 md:top-0 duration-500 z-10 pb-16'>
<div className='glassmorphism dark:border-gray-600 px-5 absolute rounded-none md:rounded-xl shadow-xl border w-full hidden-scroll'>
<div className='glassmorphism dark:border-gray-600 px-5 absolute shadow-xl border w-full hidden-scroll'>
<div id='tag-container' className="md:pl-3 overflow-x-auto">
{ children }
</div>

View File

@@ -12,12 +12,12 @@ const TagItem = ({ tag, selected }) => {
return (
<Link href={selected ? '/' : `/tag/${encodeURIComponent(tag.name)}`} passHref>
<li
className={`notion-${tag.color}_background list-none cursor-pointer rounded-md
className={`notion-${tag.color}_background dark:bg-gray-700 list-none cursor-pointer rounded-md
duration-200 mr-1 my-1 px-2 py-1 text-sm whitespace-nowrap
text-gray-600 hover:bg-gray-200 dark:hover:bg-gray-800 dark:hover:text-white`}>
<a>
hover:bg-gray-200 dark:hover:bg-gray-800 `}>
<div className='text-gray-600 dark:text-gray-300 dark:hover:text-white'>
{selected && <FontAwesomeIcon icon={faTag} className='mr-1'/>} {`${tag.name} `} {tag.count ? `(${tag.count})` : ''}
</a>
</div>
</li>
</Link>
)

View File

@@ -1,8 +1,5 @@
import React from 'react'
import TagItem from '@/components/TagItem'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTags } from '@fortawesome/free-solid-svg-icons'
/**
* 横向的标签列表
* @param tags
@@ -15,7 +12,7 @@ const TagList = ({ tags, currentTag }) => {
return <></>
}
return <ul className='flex py-1 space-x-3'>
<li className='w-20 py-2 dark:text-gray-200 whitespace-nowrap'><FontAwesomeIcon icon={faTags} className='mr-2'/>标签:</li>
<li className='w-20 py-2 dark:text-gray-200 whitespace-nowrap'>标签:</li>
{tags.map(tag => {
const selected = tag.name === currentTag
return <TagItem key={tag.name} tag={tag} selected={selected}/>

View File

@@ -53,7 +53,9 @@ const BaseLayout = ({
<>{headerSlot}</>
<main id='wrapper' className='flex justify-center flex-1 mx-auto md:pt-14 pb-12'>
<div className='h-0.5 w-full bg-gray-700 dark:bg-gray-600'></div>
<main id='wrapper' className='flex justify-center flex-1 mx-auto pb-12'>
<SideAreaLeft targetRef={targetRef} post={post} posts={totalPosts} tags={tags} currentSearch={currentSearch} currentTag={currentTag} categories={categories} currentCategory={currentCategory}/>
<section id='center' className='flex-grow mt-14 md:mt-0 max-w-5xl min-h-screen' ref={targetRef}>
{onLoading

View File

@@ -1,7 +1,7 @@
import cache from 'memory-cache'
import BLOG from 'blog.config'
const cacheTime = BLOG.isProd ? 60 : 60 * 60
const cacheTime = BLOG.isProd ? 20 : 120 * 60 // 120 minutes for dev,10 minutes for prod
export async function getCacheFromMemory (key, options) {
return cache.get(key)

View File

@@ -16,12 +16,12 @@ export default function Custom404 () {
// 延时3秒如果加载失败就返回首页
setTimeout(() => {
if (window) {
const article = document.getElementById('article-wrapper')
const article = document.getElementById('container')
if (!article) {
router.push('/')
}
}
}, 3000)
}, 30000000)
})
return <BaseLayout meta={{ title: `${BLOG.title} | 页面找不到啦` }}>

View File

@@ -18,7 +18,7 @@ class MyDocument extends Document {
<ThirdPartyScript />
</Head>
<body className='bg-gray-100 dark:bg-gray-900 duration-200'>
<body className='bg-day dark:bg-night duration-200'>
<Main />
<NextScript />
</body>

View File

@@ -4,6 +4,7 @@ import BaseLayout from '@/layouts/BaseLayout'
import BlogPostListScroll from '@/components/BlogPostListScroll'
import { getNotionPageData } from '@/lib/notion/getNotionData'
import Header from '@/components/Header'
import BlogPostListPage from '@/components/BlogPostListPage'
export async function getStaticProps () {
const from = 'index'
@@ -37,7 +38,11 @@ const Index = ({ allPosts, tags, meta, categories }) => {
totalPosts={allPosts}
categories={categories}
>
<BlogPostListScroll posts={allPosts} tags={tags} />
{BLOG.postListStyle !== 'page'
? (<BlogPostListScroll posts={allPosts} tags={tags} />)
: (<BlogPostListPage posts={allPosts} tags={tags} />)
}
</BaseLayout>
)
}

65
pages/page/[page].js Normal file
View File

@@ -0,0 +1,65 @@
import { getAllCategories, getAllPosts, getAllTags } from '@/lib/notion'
import BLOG from '@/blog.config'
import BaseLayout from '@/layouts/BaseLayout'
import { getNotionPageData } from '@/lib/notion/getNotionData'
import Header from '@/components/Header'
import Custom404 from '../404'
import BlogPostListPage from '@/components/BlogPostListPage'
const Page = ({ page, allPosts, tags, meta, categories }) => {
if (!meta || BLOG.postListStyle !== 'page') {
return <Custom404/>
}
return (
<BaseLayout
headerSlot={BLOG.home.showHomeBanner && <Header />}
meta={meta}
tags={tags}
totalPosts={allPosts}
categories={categories}
>
<BlogPostListPage page={page} posts={allPosts} tags={tags} />
</BaseLayout>
)
}
export async function getStaticPaths () {
const from = 'page'
const notionPageData = await getNotionPageData({ from })
const allPosts = await getAllPosts({ notionPageData, from })
const totalPages = Math.ceil(allPosts / BLOG.postsPerPage)
return {
// remove first page, we 're not gonna handle that.
paths: Array.from({ length: totalPages - 1 }, (_, i) => ({
params: { page: '' + (i + 2) }
})),
fallback: true
}
}
export async function getStaticProps ({ params: { page } }) {
const from = 'page'
const notionPageData = await getNotionPageData({ from })
const allPosts = await getAllPosts({ notionPageData, from })
const categories = await getAllCategories(allPosts)
const tagOptions = notionPageData.tagOptions
const tags = await getAllTags({ allPosts, tagOptions })
const meta = {
title: `${BLOG.title}`,
description: BLOG.description,
type: 'website'
}
return {
props: {
page,
allPosts,
tags,
categories,
meta
},
revalidate: 1
}
}
export default Page

View File

@@ -649,7 +649,7 @@ svg.notion-page-icon {
}
.notion-list li {
padding: 6px 0;
padding: 1px 0;
white-space: pre-wrap;
}