mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-07 07:26:46 +00:00
example主题调整
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
|
import LayoutBase from './LayoutBase'
|
||||||
|
|
||||||
export const Layout404 = () => {
|
export const Layout404 = (props) => {
|
||||||
return <div>
|
return <LayoutBase {...props}>
|
||||||
404 Not found.
|
404 Not found.
|
||||||
</div>
|
</LayoutBase>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,15 +24,13 @@ export const LayoutArchive = props => {
|
|||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<LayoutBase {...props}>
|
<LayoutBase {...props}>
|
||||||
<div className="mb-10 pb-20 md:p-12 p-3 min-h-full">
|
<div className="mb-10 pb-20 md:p-12 p-3 min-h-screen w-full">
|
||||||
{Object.keys(archivePosts).map(archiveTitle => (
|
{Object.keys(archivePosts).map(archiveTitle => (
|
||||||
<div key={archiveTitle}>
|
<div key={archiveTitle}>
|
||||||
<div
|
<div id={archiveTitle} className="pt-16 pb-4 text-3xl dark:text-gray-300" >
|
||||||
className="pt-16 pb-4 text-3xl dark:text-gray-300"
|
|
||||||
id={archiveTitle}
|
|
||||||
>
|
|
||||||
{archiveTitle}
|
{archiveTitle}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{archivePosts[archiveTitle].map(post => (
|
{archivePosts[archiveTitle].map(post => (
|
||||||
<li
|
<li
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import CommonHead from '@/components/CommonHead'
|
import CommonHead from '@/components/CommonHead'
|
||||||
import Live2D from '@/components/Live2D'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import BLOG from '@/blog.config'
|
import { Header } from './components/Header'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { Nav } from './components/Nav'
|
||||||
|
import { Footer } from './components/Footer'
|
||||||
|
import { Title } from './components/Title'
|
||||||
|
import { SideBar } from './components/SideBar'
|
||||||
|
import JumpToTopButton from './components/JumpToTopButton'
|
||||||
/**
|
/**
|
||||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||||
|
|
||||||
@@ -11,116 +13,37 @@ import { useGlobal } from '@/lib/global'
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const LayoutBase = props => {
|
const LayoutBase = props => {
|
||||||
const { children, meta, customNav, siteInfo } = props
|
const { children, meta } = props
|
||||||
const { locale } = useGlobal()
|
|
||||||
const d = new Date()
|
|
||||||
const currentYear = d.getFullYear()
|
|
||||||
const startYear = BLOG.SINCE && BLOG.SINCE !== currentYear && BLOG.SINCE + '-'
|
|
||||||
|
|
||||||
let links = [
|
|
||||||
{ icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search' },
|
|
||||||
{ icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive' },
|
|
||||||
{ icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category' },
|
|
||||||
{ icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag' }
|
|
||||||
]
|
|
||||||
|
|
||||||
if (customNav) {
|
|
||||||
links = links.concat(customNav)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='dark:text-gray-300'>
|
<div className='dark:text-gray-300'>
|
||||||
<CommonHead meta={meta} />
|
<CommonHead meta={meta} />
|
||||||
{/* 导航菜单 */}
|
{/* 顶栏LOGO */}
|
||||||
<div className="w-full flex justify-center my-2 text-xs md:text-base px-5">
|
<Header {...props} />
|
||||||
<div className="max-w-6xl justify-between w-full flex">
|
|
||||||
<section>
|
|
||||||
<Link title={siteInfo.title} href={'/'}>
|
|
||||||
<a className={'cursor-pointer flex items-center hover:underline'}>
|
|
||||||
<i className={'fas fa-home mr-1'} />
|
|
||||||
<div className="text-center">{siteInfo.title} </div>
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
<nav className="space-x-3 flex flex-nowrap overflow-x-auto">
|
|
||||||
{links.map(link => {
|
|
||||||
if (link) {
|
|
||||||
return (
|
|
||||||
<Link key={`${link.to}`} title={link.to} href={link.to}>
|
|
||||||
<a
|
|
||||||
className={
|
|
||||||
'cursor-pointer flex whitespace-nowrap items-center hover:underline'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<i className={`${link.icon} mr-1`} />
|
|
||||||
<div className="text-center">{link.name}</div>
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 内容主体 */}
|
{/* 菜单 */}
|
||||||
<main id="wrapper" className="flex justify-center flex-1 pb-12">
|
<Nav {...props} />
|
||||||
<div className="max-w-4xl w-full px-3">{children}</div>
|
|
||||||
<div className='hidden md:block'>
|
|
||||||
<div className="sticky top-0 z-40">
|
|
||||||
<Live2D />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
{/* 页脚 */}
|
{/* 主体 */}
|
||||||
<footer className="font-sans dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-sm p-6">
|
<div className="w-full bg-white">
|
||||||
<i className="fas fa-copyright" /> {`${startYear}${currentYear}`}{' '}
|
|
||||||
<span>
|
<Title {...props} />
|
||||||
<i className="mx-1 animate-pulse fas fa-heart" />{' '}
|
|
||||||
<a
|
<div className="container max-w-4xl mx-auto md:flex items-start py-8 px-12 md:px-0">
|
||||||
href={BLOG.LINK}
|
|
||||||
className="underline dark:text-gray-300 "
|
<div className='px-2 w-full flex-grow'>{children}</div>
|
||||||
>
|
|
||||||
{BLOG.AUTHOR}
|
<SideBar {...props} />
|
||||||
</a>
|
|
||||||
.
|
</div>
|
||||||
</span>
|
|
||||||
{BLOG.BEI_AN && (
|
</div>
|
||||||
<>
|
|
||||||
<br />
|
<Footer {...props} />
|
||||||
<i className="fas fa-shield-alt" />{' '}
|
|
||||||
<a href="https://beian.miit.gov.cn/" className="mr-2">
|
<div className='fixed right-4 bottom-4'>
|
||||||
{BLOG.BEI_AN}
|
<JumpToTopButton />
|
||||||
</a>
|
</div>
|
||||||
<br />
|
</div>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<br />
|
|
||||||
<span className="hidden busuanzi_container_site_pv">
|
|
||||||
<i className="fas fa-eye" />
|
|
||||||
<span className="px-1 busuanzi_value_site_pv"> </span>{' '}
|
|
||||||
</span>
|
|
||||||
<span className="pl-2 hidden busuanzi_container_site_uv">
|
|
||||||
<i className="fas fa-users" />{' '}
|
|
||||||
<span className="px-1 busuanzi_value_site_uv"> </span>{' '}
|
|
||||||
</span>
|
|
||||||
<br />
|
|
||||||
<h1>{meta?.title || siteInfo.title}</h1>
|
|
||||||
<span className='text-xs font-serif'>
|
|
||||||
Powered by{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/tangly1024/NotionNext"
|
|
||||||
className="underline dark:text-gray-300"
|
|
||||||
>
|
|
||||||
NotionNext {BLOG.VERSION}
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</span>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,26 +23,39 @@ export const LayoutCategory = props => {
|
|||||||
updatePage(page + 1)
|
updatePage(page + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <LayoutBase {...props}>
|
||||||
<LayoutBase {...props}>
|
<div className='w-full'>
|
||||||
Category - {category}
|
<div className='pb-12'>{category}</div>
|
||||||
{postsToShow.map(p => (
|
|
||||||
<div key={p.id} className="border my-12">
|
{postsToShow.map(p => (
|
||||||
<Link href={`/article/${p.slug}`}>
|
<article key={p.id} className="mb-12" >
|
||||||
<a className="underline cursor-pointer">{p.title}</a>
|
<h2 className="mb-4">
|
||||||
</Link>
|
<Link href={`/article/${p.slug}`}>
|
||||||
<div>{p.summary}</div>
|
<a className="text-black text-xl md:text-2xl no-underline hover:underline"> {p.title}</a>
|
||||||
|
</Link>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className="mb-4 text-sm text-gray-700">
|
||||||
|
by <a href="#" className="text-gray-700">{BLOG.AUTHOR}</a> on {p.date?.start_date || p.createdTime}
|
||||||
|
<span className="font-bold mx-1"> | </span>
|
||||||
|
<a href="#" className="text-gray-700">{p.category}</a>
|
||||||
|
<span className="font-bold mx-1"> | </span>
|
||||||
|
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-gray-700 leading-normal">
|
||||||
|
{p.summary}
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div
|
||||||
|
onClick={handleGetMore}
|
||||||
|
className="w-full my-4 py-4 text-center cursor-pointer "
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
</LayoutBase >
|
||||||
<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>
|
|
||||||
</LayoutBase>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const LayoutCategoryIndex = (props) => {
|
|||||||
const { categories } = props
|
const { categories } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
return <LayoutBase {...props}>
|
return <LayoutBase {...props}>
|
||||||
<div className=' p-10'>
|
<div className=' p-10 w-full'>
|
||||||
<div className='dark:text-gray-200 mb-5'>
|
<div className='dark:text-gray-200 mb-5'>
|
||||||
<i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}:
|
<i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}:
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,74 +1,11 @@
|
|||||||
import BLOG from '@/blog.config'
|
|
||||||
import { useGlobal } from '@/lib/global'
|
import { BlogList } from './components/BlogList'
|
||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
|
|
||||||
export const LayoutIndex = props => {
|
export const LayoutIndex = props => {
|
||||||
const { posts, postCount } = props
|
|
||||||
|
|
||||||
const { locale } = useGlobal()
|
|
||||||
const router = useRouter()
|
|
||||||
const totalPage = Math.ceil(postCount / BLOG.POSTS_PER_PAGE)
|
|
||||||
|
|
||||||
const page = 1
|
|
||||||
const showNext =
|
|
||||||
page < totalPage &&
|
|
||||||
posts.length === BLOG.POSTS_PER_PAGE &&
|
|
||||||
posts.length < postCount
|
|
||||||
|
|
||||||
const currentPage = +page
|
|
||||||
return (
|
return (
|
||||||
<LayoutBase {...props}>
|
<LayoutBase {...props}>
|
||||||
{posts.map(p => (
|
<BlogList {...props} />
|
||||||
<div
|
|
||||||
key={p.id}
|
|
||||||
className="border dark:border-hexo-black-gray p-4 my-12"
|
|
||||||
>
|
|
||||||
<Link href={`/article/${p.slug}`}>
|
|
||||||
<a className="underline cursor-pointer">{p.title}</a>
|
|
||||||
</Link>
|
|
||||||
<div>{p.summary}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<div className="my-10 flex justify-between font-medium text-black dark:text-gray-100 space-x-2">
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname:
|
|
||||||
currentPage === 2
|
|
||||||
? `${BLOG.SUB_PATH || '/'}`
|
|
||||||
: `/page/${currentPage - 1}`,
|
|
||||||
query: router.query.s ? { s: router.query.s } : {}
|
|
||||||
}}
|
|
||||||
passHref
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
rel="prev"
|
|
||||||
className={`${
|
|
||||||
currentPage === 1 ? 'invisible' : 'visible'
|
|
||||||
} text-center w-full duration-200 px-4 py-2 hover:border-black border-b-2 hover:font-bold`}
|
|
||||||
>
|
|
||||||
← {locale.PAGINATION.PREV}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname: `/page/${currentPage + 1}`,
|
|
||||||
query: router.query.s ? { s: router.query.s } : {}
|
|
||||||
}}
|
|
||||||
passHref
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
rel="next"
|
|
||||||
className={`${
|
|
||||||
showNext ? 'visible' : 'invisible'
|
|
||||||
} text-center w-full duration-200 px-4 py-2 hover:border-black border-b-2 hover:font-bold`}
|
|
||||||
>
|
|
||||||
{locale.PAGINATION.NEXT} →
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</LayoutBase>
|
</LayoutBase>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,28 +33,58 @@ export const LayoutSearch = props => {
|
|||||||
if (!hasMore) return
|
if (!hasMore) return
|
||||||
updatePage(page + 1)
|
updatePage(page + 1)
|
||||||
}
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (keyword) {
|
||||||
|
const targets = document.getElementsByClassName('replace')
|
||||||
|
for (const container of targets) {
|
||||||
|
if (container && container.innerHTML) {
|
||||||
|
const re = new RegExp(`${keyword}`, 'gim')
|
||||||
|
container.innerHTML = container.innerHTML.replace(
|
||||||
|
re,
|
||||||
|
`<span class='text-red-500 border-b border-dashed'>${keyword}</span>`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return <LayoutBase {...props}>
|
||||||
<LayoutBase {...props}>
|
<div className='py-2'>
|
||||||
<h2>Search - {keyword}</h2>
|
<SearchInput {...props} />
|
||||||
<SearchInput {...props} />
|
|
||||||
{postsToShow?.map(p => (
|
|
||||||
<div key={p.id} className="border my-12">
|
|
||||||
<Link href={`/article/${p.slug}`}>
|
|
||||||
<a className="underline cursor-pointer">{p.title}</a>
|
|
||||||
</Link>
|
|
||||||
<div>{p.summary}</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
<div>
|
{postsToShow.map(p => (
|
||||||
<div
|
<article key={p.id} className="mb-12" >
|
||||||
onClick={handleGetMore}
|
<h2 className="mb-4">
|
||||||
className="w-full my-4 py-4 text-center cursor-pointer "
|
<Link href={`/article/${p.slug}`}>
|
||||||
>
|
<a className="text-black text-xl md:text-2xl no-underline hover:underline replace"> {p.title}</a>
|
||||||
{' '}
|
</Link>
|
||||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
</h2>
|
||||||
|
|
||||||
|
<div className="mb-4 text-sm text-gray-700">
|
||||||
|
by <a href="#" className="text-gray-700">{BLOG.AUTHOR}</a> on {p.date?.start_date || p.createdTime}
|
||||||
|
<span className="font-bold mx-1"> | </span>
|
||||||
|
<a href="#" className="text-gray-700">{p.category}</a>
|
||||||
|
<span className="font-bold mx-1"> | </span>
|
||||||
|
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-gray-700 leading-normal replace">
|
||||||
|
{p.summary}
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<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>
|
||||||
</div>
|
|
||||||
</LayoutBase>
|
</LayoutBase>
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import { getPageTableOfContents } from 'notion-utils'
|
|||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import { ArticleLock } from './components/ArticleLock'
|
import { ArticleLock } from './components/ArticleLock'
|
||||||
import NotionPage from '@/components/NotionPage'
|
import NotionPage from '@/components/NotionPage'
|
||||||
import Link from 'next/link'
|
import { ArticleInfo } from './components/ArticleInfo'
|
||||||
import { useGlobal } from '@/lib/global'
|
import Comment from '@/components/Comment'
|
||||||
import formatDate from '@/lib/formatDate'
|
|
||||||
|
|
||||||
export const LayoutSlug = props => {
|
export const LayoutSlug = props => {
|
||||||
const { post, lock, validPassword } = props
|
const { post, lock, validPassword } = props
|
||||||
@@ -18,57 +17,20 @@ export const LayoutSlug = props => {
|
|||||||
post.toc = getPageTableOfContents(post, post.blockMap)
|
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { locale } = useGlobal()
|
|
||||||
const date = formatDate(post?.date?.start_date || post?.createdTime, locale.LOCALE)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutBase {...props}>
|
<LayoutBase {...props}>
|
||||||
<div>
|
|
||||||
<h2>{post?.title}</h2>
|
|
||||||
|
|
||||||
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
|
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
|
||||||
|
|
||||||
{!lock && <section id="notion-article" className="px-1">
|
{!lock && <div id="notion-article" className="px-2">
|
||||||
<section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8">
|
|
||||||
<div>
|
|
||||||
<Link href={`/category/${post.category}`} passHref>
|
|
||||||
<a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
|
|
||||||
<i className="mr-1 fas fa-folder-open" />
|
|
||||||
{post.category}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
<span className='mr-2'>|</span>
|
|
||||||
|
|
||||||
{post?.type[0] !== 'Page' && (<>
|
{post && <>
|
||||||
<Link
|
<ArticleInfo post={post} />
|
||||||
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
<NotionPage post={post} />
|
||||||
passHref
|
<Comment frontMatter={post}/>
|
||||||
>
|
</>}
|
||||||
<a className="pl-1 mr-2 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 border-b dark:border-gray-500 border-dashed">
|
</div>}
|
||||||
{date}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
<span className='mr-2'>|</span>
|
|
||||||
<span className='mx-2 text-gray-400 dark:text-gray-500'>
|
|
||||||
{locale.COMMON.LAST_EDITED_TIME}: {post.lastEditedTime}
|
|
||||||
</span>
|
|
||||||
<span className='mr-2'>|</span>
|
|
||||||
|
|
||||||
</>)}
|
</LayoutBase>
|
||||||
|
|
||||||
<span className="hidden busuanzi_container_page_pv font-light mr-2">
|
|
||||||
<i className='mr-1 fas fa-eye' />
|
|
||||||
|
|
||||||
<span className="mr-2 busuanzi_value_page_pv" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{post && <NotionPage post={post} />}
|
|
||||||
</section>}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</LayoutBase>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useState } from 'react'
|
|||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
|
|
||||||
export const LayoutTag = props => {
|
export const LayoutTag = props => {
|
||||||
const { tag, posts } = props
|
const { posts } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
const [page, updatePage] = useState(1)
|
const [page, updatePage] = useState(1)
|
||||||
@@ -24,26 +24,36 @@ export const LayoutTag = props => {
|
|||||||
updatePage(page + 1)
|
updatePage(page + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <LayoutBase>
|
||||||
<LayoutBase>
|
{postsToShow.map(p => (
|
||||||
Tag - {tag}
|
<article key={p.id} className="mb-12" >
|
||||||
{postsToShow.map(p => (
|
<h2 className="mb-4">
|
||||||
<div key={p.id} className="border my-12">
|
<Link href={`/article/${p.slug}`}>
|
||||||
<Link href={`/article/${p.slug}`}>
|
<a className="text-black text-xl md:text-2xl no-underline hover:underline"> {p.title}</a>
|
||||||
<a className="underline cursor-pointer">{p.title}</a>
|
</Link>
|
||||||
</Link>
|
</h2>
|
||||||
<div>{p.summary}</div>
|
|
||||||
</div>
|
<div className="mb-4 text-sm text-gray-700">
|
||||||
))}
|
by <a href="#" className="text-gray-700">{BLOG.AUTHOR}</a> on {p.date?.start_date || p.createdTime}
|
||||||
<div>
|
<span className="font-bold mx-1"> | </span>
|
||||||
|
<a href="#" className="text-gray-700">{p.category}</a>
|
||||||
|
<span className="font-bold mx-1"> | </span>
|
||||||
|
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-gray-700 leading-normal">
|
||||||
|
{p.summary}
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
onClick={handleGetMore}
|
onClick={handleGetMore}
|
||||||
className="w-full my-4 py-4 text-center cursor-pointer "
|
className="w-full my-4 py-4 text-center cursor-pointer "
|
||||||
>
|
>
|
||||||
{' '}
|
{' '}
|
||||||
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
{hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</LayoutBase>
|
</LayoutBase >
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,21 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
|
|
||||||
export const LayoutTagIndex = (props) => {
|
export const LayoutTagIndex = (props) => {
|
||||||
const { tags } = props
|
const { tags } = props
|
||||||
const { locale } = useGlobal()
|
|
||||||
return <LayoutBase {...props}>
|
return <LayoutBase {...props}>
|
||||||
<div className='p-10'>
|
<div className='p-10'>
|
||||||
<div className='dark:text-gray-200 mb-5'><i className='mr-4 fas fa-tag'/>{locale.COMMON.TAGS}:</div>
|
<div id='tags-list' className='duration-200 flex flex-wrap'>
|
||||||
<div id='tags-list' className='duration-200 flex flex-wrap'>
|
{tags.map(tag => {
|
||||||
{ tags.map(tag => {
|
return <div key={tag.name} className='p-2'>
|
||||||
return <div key={tag.name} className='p-2'>
|
<Link key={tag} href={`/tag/${encodeURIComponent(tag.name)}`} passHref>
|
||||||
<Link key={tag} href={`/tag/${encodeURIComponent(tag.name)}`} passHref>
|
<a className={`cursor-pointer inline-block rounded hover:bg-gray-500 hover:text-white duration-200
|
||||||
<a className={`cursor-pointer inline-block rounded hover:bg-gray-500 hover:text-white duration-200
|
|
||||||
mr-2 py-1 px-2 text-xs whitespace-nowrap dark:hover:text-white text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}>
|
mr-2 py-1 px-2 text-xs whitespace-nowrap dark:hover:text-white text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}>
|
||||||
<div className='font-light dark:text-gray-400'><i className='mr-1 fas fa-tag'/> {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
<div className='font-light dark:text-gray-400'><i className='mr-1 fas fa-tag' /> {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
}) }
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div> </LayoutBase>
|
</div> </LayoutBase>
|
||||||
}
|
}
|
||||||
|
|||||||
46
themes/example/components/ArticleInfo.js
Normal file
46
themes/example/components/ArticleInfo.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import Link from 'next/link'
|
||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import formatDate from '@/lib/formatDate'
|
||||||
|
|
||||||
|
export const ArticleInfo = (props) => {
|
||||||
|
const { post } = props
|
||||||
|
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
const date = formatDate(post?.date?.start_date || post?.createdTime, locale.LOCALE)
|
||||||
|
|
||||||
|
return <section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8">
|
||||||
|
<div>
|
||||||
|
<Link href={`/category/${post.category}`} passHref>
|
||||||
|
<a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
|
||||||
|
<i className="mr-1 fas fa-folder-open" />
|
||||||
|
{post.category}
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
<span className='mr-2'>|</span>
|
||||||
|
|
||||||
|
{post?.type[0] !== 'Page' && (<>
|
||||||
|
<Link
|
||||||
|
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
||||||
|
passHref
|
||||||
|
>
|
||||||
|
<a className="pl-1 mr-2 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 border-b dark:border-gray-500 border-dashed">
|
||||||
|
{date}
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
<span className='mr-2'>|</span>
|
||||||
|
<span className='mx-2 text-gray-400 dark:text-gray-500'>
|
||||||
|
{locale.COMMON.LAST_EDITED_TIME}: {post.lastEditedTime}
|
||||||
|
</span>
|
||||||
|
<span className='mr-2'>|</span>
|
||||||
|
|
||||||
|
</>)}
|
||||||
|
|
||||||
|
<span className="hidden busuanzi_container_page_pv font-light mr-2">
|
||||||
|
<i className='mr-1 fas fa-eye' />
|
||||||
|
|
||||||
|
<span className="mr-2 busuanzi_value_page_pv" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
}
|
||||||
55
themes/example/components/BlogList.js
Normal file
55
themes/example/components/BlogList.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
import BLOG from '@/blog.config'
|
||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export const BlogList = (props) => {
|
||||||
|
const { posts, postCount } = props
|
||||||
|
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
const router = useRouter()
|
||||||
|
const totalPage = Math.ceil(postCount / BLOG.POSTS_PER_PAGE)
|
||||||
|
|
||||||
|
const page = 1
|
||||||
|
const showNext =
|
||||||
|
page < totalPage &&
|
||||||
|
posts.length === BLOG.POSTS_PER_PAGE &&
|
||||||
|
posts.length < postCount
|
||||||
|
|
||||||
|
const currentPage = +page
|
||||||
|
|
||||||
|
return <div className="w-full md:pr-12 mb-12">
|
||||||
|
|
||||||
|
{posts.map(p => (
|
||||||
|
<article key={p.id} className="mb-12" >
|
||||||
|
<h2 className="mb-4">
|
||||||
|
<Link href={`/article/${p.slug}`}>
|
||||||
|
<a className="text-black text-xl md:text-2xl no-underline hover:underline"> {p.title}</a>
|
||||||
|
</Link>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className="mb-4 text-sm text-gray-700">
|
||||||
|
by <a href="#" className="text-gray-700">{BLOG.AUTHOR}</a> on {p.date?.start_date || p.createdTime}
|
||||||
|
<span className="font-bold mx-1"> | </span>
|
||||||
|
<a href="#" className="text-gray-700">{p.category}</a>
|
||||||
|
<span className="font-bold mx-1"> | </span>
|
||||||
|
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-gray-700 leading-normal">
|
||||||
|
{p.summary}
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="flex justify-between text-xs">
|
||||||
|
<Link href="/">
|
||||||
|
<a className={`${currentPage > 1 ? 'bg-black ' : 'bg-gray '} text-white no-underline py-2 px-3 rounded`}>{locale.PAGINATION.PREV}</a>
|
||||||
|
</Link>
|
||||||
|
<Link href={{ pathname: `/page/${currentPage + 1}`, query: router.query.s ? { s: router.query.s } : {} }}>
|
||||||
|
<a className={`${showNext ? 'bg-black ' : 'bg-gray '} text-white no-underline py-2 px-3 rounded`}>{locale.PAGINATION.NEXT}</a>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
49
themes/example/components/Footer.js
Normal file
49
themes/example/components/Footer.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import BLOG from '@/blog.config'
|
||||||
|
|
||||||
|
export const Footer = (props) => {
|
||||||
|
const d = new Date()
|
||||||
|
const currentYear = d.getFullYear()
|
||||||
|
const startYear = BLOG.SINCE && BLOG.SINCE !== currentYear && BLOG.SINCE + '-'
|
||||||
|
|
||||||
|
// {/* 页脚 */}
|
||||||
|
// <footer className="font-sans dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-sm p-6">
|
||||||
|
// <i className="fas fa-copyright" /> {`${startYear}${currentYear}`}{' '}
|
||||||
|
|
||||||
|
// <br />
|
||||||
|
// <span className="hidden busuanzi_container_site_pv">
|
||||||
|
// <i className="fas fa-eye" />
|
||||||
|
// <span className="px-1 busuanzi_value_site_pv"> </span>{' '}
|
||||||
|
// </span>
|
||||||
|
// <span className="pl-2 hidden busuanzi_container_site_uv">
|
||||||
|
// <i className="fas fa-users" />{' '}
|
||||||
|
// <span className="px-1 busuanzi_value_site_uv"> </span>{' '}
|
||||||
|
// </span>
|
||||||
|
// <br />
|
||||||
|
// <h1>{meta?.title || siteInfo.title}</h1>
|
||||||
|
// <span className='text-xs font-serif'>
|
||||||
|
// Powered by{' '}
|
||||||
|
// <a
|
||||||
|
// href="https://github.com/tangly1024/NotionNext"
|
||||||
|
// className="underline dark:text-gray-300"
|
||||||
|
// >
|
||||||
|
// NotionNext {BLOG.VERSION}
|
||||||
|
// </a>
|
||||||
|
// .
|
||||||
|
// </span>
|
||||||
|
// </footer>
|
||||||
|
|
||||||
|
return <footer className="w-full bg-white px-6 border-t">
|
||||||
|
<div className="container mx-auto max-w-4xl py-6 flex flex-wrap md:flex-no-wrap justify-between items-center text-sm">
|
||||||
|
©{`${startYear}${currentYear}`} {BLOG.AUTHOR}. All rights reserved.
|
||||||
|
<div className="pt-4 md:p-0 text-center md:text-right text-xs">
|
||||||
|
{/* 右侧链接 */}
|
||||||
|
{/* <a href="#" className="text-black no-underline hover:underline">Privacy Policy</a> */}
|
||||||
|
{BLOG.BEI_AN && (<a href="https://beian.miit.gov.cn/" className="text-black no-underline hover:underline ml-4">{BLOG.BEI_AN} </a>)}
|
||||||
|
<span className='text-black no-underline ml-4'>
|
||||||
|
Powered by
|
||||||
|
<a href="https://github.com/tangly1024/NotionNext" className=' hover:underline'> NotionNext {BLOG.VERSION} </a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
}
|
||||||
21
themes/example/components/Header.js
Normal file
21
themes/example/components/Header.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网站顶部
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const Header = (props) => {
|
||||||
|
const { siteInfo } = props
|
||||||
|
|
||||||
|
return <header className="w-full px-6 bg-white">
|
||||||
|
<div className="container mx-auto max-w-4xl md:flex justify-between items-center">
|
||||||
|
<Link href='/'>
|
||||||
|
<a className="py-6 w-full text-center md:text-left md:w-auto text-gray-dark no-underline flex justify-center items-center">
|
||||||
|
{siteInfo?.title}
|
||||||
|
</a></Link>
|
||||||
|
<div className="w-full md:w-auto text-center md:text-right">
|
||||||
|
{/* 右侧文字 */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
}
|
||||||
19
themes/example/components/JumpToTopButton.js
Normal file
19
themes/example/components/JumpToTopButton.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转到网页顶部
|
||||||
|
* 当屏幕下滑500像素后会出现该控件
|
||||||
|
* @param targetRef 关联高度的目标html标签
|
||||||
|
* @param showPercent 是否显示百分比
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const JumpToTopButton = () => {
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
return <div title={locale.POST.TOP} className='cursor-pointer p-2 text-center' onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
||||||
|
><i className='fas fa-angle-up text-2xl' />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JumpToTopButton
|
||||||
34
themes/example/components/Nav.js
Normal file
34
themes/example/components/Nav.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单导航
|
||||||
|
* @param {*} props
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const Nav = (props) => {
|
||||||
|
const { customNav } = props
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
let links = [
|
||||||
|
{ icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search' },
|
||||||
|
{ icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive' },
|
||||||
|
{ icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category' },
|
||||||
|
{ icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag' }
|
||||||
|
]
|
||||||
|
|
||||||
|
if (customNav) {
|
||||||
|
links = links.concat(customNav)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <nav className="w-full bg-white md:pt-0 px-6 relative z-20 border-t border-b border-gray-light">
|
||||||
|
<div className="container mx-auto max-w-4xl md:flex justify-between items-center text-sm md:text-md md:justify-start">
|
||||||
|
<div className="w-full md:w-2/3 text-center md:text-left py-4 flex flex-wrap justify-center items-stretch md:justify-start md:items-start">
|
||||||
|
{links.map(link => {
|
||||||
|
return link && <a href={link.to} className="px-2 md:pl-0 md:mr-3 md:pr-3 text-gray-700 no-underline md:border-r border-gray-light">{link.name}</a>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className="w-full md:w-1/3 text-center md:text-right">
|
||||||
|
{/* <!-- extra links --> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
44
themes/example/components/SideBar.js
Normal file
44
themes/example/components/SideBar.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import Live2D from '@/components/Live2D'
|
||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export const SideBar = (props) => {
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
const { latestPosts, categories } = props
|
||||||
|
return <div className="w-full md:w-64 sticky top-8">
|
||||||
|
|
||||||
|
<aside className="rounded shadow overflow-hidden mb-6">
|
||||||
|
<h3 className="text-sm bg-gray-100 text-gray-700 py-3 px-4 border-b">{locale.COMMON.CATEGORY}</h3>
|
||||||
|
|
||||||
|
<div className="p-4">
|
||||||
|
<ul className="list-reset leading-normal">
|
||||||
|
{categories?.map(category => {
|
||||||
|
return <Link key={category.name} href={`/category/${category.name}`} passHref>
|
||||||
|
<li> <a href="#" className="text-gray-darkest text-sm">{category.name}({category.count})</a></li>
|
||||||
|
</Link>
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<aside className="rounded shadow overflow-hidden mb-6">
|
||||||
|
<h3 className="text-sm bg-gray-100 text-gray-700 py-3 px-4 border-b">{locale.COMMON.LATEST_POSTS}</h3>
|
||||||
|
|
||||||
|
<div className="p-4">
|
||||||
|
<ul className="list-reset leading-normal">
|
||||||
|
{latestPosts?.map(p => {
|
||||||
|
return <Link key={p.id} href={`/article/${p.slug}`} passHref>
|
||||||
|
<li> <a href="#" className="text-gray-darkest text-sm">{p.title}</a></li>
|
||||||
|
</Link>
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<aside className="rounded overflow-hidden mb-6">
|
||||||
|
<Live2D />
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
19
themes/example/components/Title.js
Normal file
19
themes/example/components/Title.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import BLOG from '@/blog.config'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标题栏
|
||||||
|
* @param {*} props
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const Title = (props) => {
|
||||||
|
const { siteInfo, post } = props
|
||||||
|
const title = post?.title || siteInfo?.description
|
||||||
|
const description = post?.description || BLOG.AUTHOR
|
||||||
|
|
||||||
|
return <div className="text-center px-6 py-12 mb-6 bg-gray-100 border-b">
|
||||||
|
<h1 className=" text-xl md:text-4xl pb-4">{title}</h1>
|
||||||
|
<p className="leading-loose text-gray-dark">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user