OpenWrite适配所有主题

This commit is contained in:
tangly1024.com
2024-09-05 12:13:07 +08:00
parent 218d1fa37e
commit c351b76c13
15 changed files with 953 additions and 757 deletions

View File

@@ -1,7 +1,7 @@
import { siteConfig } from '@/lib/config' import { siteConfig } from '@/lib/config'
import { isBrowser, loadExternalResource } from '@/lib/utils' import { isBrowser, loadExternalResource } from '@/lib/utils'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { useEffect, useRef } from 'react' import { useEffect } from 'react'
/** /**
* OpenWrite公众号导流插件 * OpenWrite公众号导流插件
* 使用介绍https://openwrite.cn/guide/readmore/readmore.html#%E4%BA%8C%E3%80%81%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8 * 使用介绍https://openwrite.cn/guide/readmore/readmore.html#%E4%BA%8C%E3%80%81%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8
@@ -20,8 +20,6 @@ const OpenWrite = () => {
'原创不易,完成人机检测,阅读全文' '原创不易,完成人机检测,阅读全文'
) )
const hasLoaded = useRef(false)
const loadOpenWrite = async () => { const loadOpenWrite = async () => {
try { try {
await loadExternalResource( await loadExternalResource(
@@ -48,11 +46,10 @@ const OpenWrite = () => {
} }
useEffect(() => { useEffect(() => {
if (isBrowser && blogId && !hasLoaded.current) { if (isBrowser && blogId) {
loadOpenWrite() loadOpenWrite()
hasLoaded.current = true
} }
}, [router]) })
return <></> return <></>
} }

View File

@@ -179,10 +179,12 @@ const LayoutSlug = props => {
{lock ? ( {lock ? (
<PostLock validPassword={validPassword} /> <PostLock validPassword={validPassword} />
) : ( ) : (
<div id='article-wrapper'> <div>
<PostMeta post={post} /> <PostMeta post={post} />
<NotionPage post={post} /> <div id='article-wrapper'>
<ShareBar post={post} /> <NotionPage post={post} />
<ShareBar post={post} />
</div>
<Comment frontMatter={post} /> <Comment frontMatter={post} />
</div> </div>
)} )}

View File

@@ -341,8 +341,10 @@ const LayoutSlug = props => {
{/* Notion文章主体 */} {/* Notion文章主体 */}
{post && ( {post && (
<section id='article-wrapper' className='px-1'> <section className='px-1'>
<NotionPage post={post} /> <div id='article-wrapper'>
<NotionPage post={post} />
</div>
{/* 分享 */} {/* 分享 */}
<ShareBar post={post} /> <ShareBar post={post} />

View File

@@ -288,14 +288,17 @@ const LayoutSlug = props => {
return ( return (
<> <>
<div <div
className={`article h-full w-full ${fullWidth ? '' : 'xl:max-w-5xl'} ${hasCode ? 'xl:w-[73.15vw]' : ''} lg:hover:shadow lg:border rounded-2xl lg:px-2 lg:py-4 bg-white dark:bg-[#18171d] dark:border-gray-600`}> className={`article h-full w-full ${fullWidth ? '' : 'xl:max-w-5xl'} ${hasCode ? 'xl:w-[73.15vw]' : ''} bg-white dark:bg-[#18171d] dark:border-gray-600 lg:hover:shadow lg:border rounded-2xl lg:px-2 lg:py-4 `}>
{/* 文章锁 */} {/* 文章锁 */}
{lock && <PostLock validPassword={validPassword} />} {lock && <PostLock validPassword={validPassword} />}
{!lock && ( {!lock && (
<div id='article-wrapper' className='mx-auto md:w-full md:px-5'> <div className='mx-auto md:w-full md:px-5'>
{/* 文章主体 */} {/* 文章主体 */}
<article itemScope itemType='https://schema.org/Movie'> <article
id='article-wrapper'
itemScope
itemType='https://schema.org/Movie'>
{/* Notion文章主体 */} {/* Notion文章主体 */}
<section <section
className='wow fadeInUp p-5 justify-center mx-auto' className='wow fadeInUp p-5 justify-center mx-auto'

View File

@@ -287,10 +287,9 @@ const LayoutSlug = props => {
{lock && <ArticleLock validPassword={validPassword} />} {lock && <ArticleLock validPassword={validPassword} />}
{!lock && ( {!lock && (
<div <div className='overflow-x-auto flex-grow mx-auto md:w-full md:px-5 '>
id='article-wrapper'
className='overflow-x-auto flex-grow mx-auto md:w-full md:px-5 '>
<article <article
id='article-wrapper'
itemScope itemScope
itemType='https://schema.org/Movie' itemType='https://schema.org/Movie'
className='subpixel-antialiased overflow-y-hidden'> className='subpixel-antialiased overflow-y-hidden'>

View File

@@ -1,4 +1,3 @@
'use client' 'use client'
/** /**
@@ -7,21 +6,21 @@
* 2. 内容大部分是在此文件中写死notion数据从props参数中传进来 * 2. 内容大部分是在此文件中写死notion数据从props参数中传进来
* 3. 您可在此网站找到更多喜欢的组件 https://www.tailwind-kit.com/ * 3. 您可在此网站找到更多喜欢的组件 https://www.tailwind-kit.com/
*/ */
import Loading from '@/components/Loading'
import NotionPage from '@/components/NotionPage' import NotionPage from '@/components/NotionPage'
import Header from './components/Header' import { siteConfig } from '@/lib/config'
import Footer from './components/Footer' import { isBrowser } from '@/lib/utils'
import Hero from './components/Hero' import { useRouter } from 'next/router'
import { useEffect } from 'react'
import Features from './components/Features' import Features from './components/Features'
import FeaturesBlocks from './components/FeaturesBlocks' import FeaturesBlocks from './components/FeaturesBlocks'
import Testimonials from './components/Testimonials' import Footer from './components/Footer'
import Header from './components/Header'
import Hero from './components/Hero'
import Newsletter from './components/Newsletter' import Newsletter from './components/Newsletter'
import { useRouter } from 'next/router'
import CONFIG from './config'
import Loading from '@/components/Loading'
import { isBrowser } from '@/lib/utils'
import { siteConfig } from '@/lib/config'
import { Pricing } from './components/Pricing' import { Pricing } from './components/Pricing'
import { useEffect } from 'react' import Testimonials from './components/Testimonials'
import CONFIG from './config'
/** /**
* 布局框架 * 布局框架
@@ -30,22 +29,23 @@ import { useEffect } from 'react'
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutBase = (props) => { const LayoutBase = props => {
const { children } = props const { children } = props
return <div id='theme-landing' className={`${siteConfig('FONT_STYLE')} scroll-smooth overflow-hidden flex flex-col justify-between bg-white dark:bg-black`}> return (
<div
id='theme-landing'
className={`${siteConfig('FONT_STYLE')} scroll-smooth overflow-hidden flex flex-col justify-between bg-white dark:bg-black`}>
{/* 顶部导航栏 */}
<Header />
{/* 顶部导航栏 */} {/* 内容 */}
<Header /> <div id='content-wrapper'>{children}</div>
{/* 内容 */} {/* 底部页脚 */}
<div id='content-wrapper'> <Footer />
{children}
</div>
{/* 底部页脚 */}
<Footer />
</div> </div>
)
} }
/** /**
@@ -53,16 +53,16 @@ const LayoutBase = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutIndex = (props) => { const LayoutIndex = props => {
return ( return (
<> <>
<Hero /> <Hero />
<Features /> <Features />
<FeaturesBlocks /> <FeaturesBlocks />
<Testimonials /> <Testimonials />
<Pricing/> <Pricing />
<Newsletter /> <Newsletter />
</> </>
) )
} }
@@ -71,7 +71,7 @@ const LayoutIndex = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutSlug = (props) => { const LayoutSlug = props => {
const { post } = props const { post } = props
// 如果 是 /article/[slug] 的文章路径则进行重定向到另一个域名 // 如果 是 /article/[slug] 的文章路径则进行重定向到另一个域名
@@ -79,49 +79,90 @@ const LayoutSlug = (props) => {
useEffect(() => { useEffect(() => {
// 404 // 404
if (!post) { if (!post) {
setTimeout(() => { setTimeout(
if (isBrowser) { () => {
const article = document.getElementById('notion-article') if (isBrowser) {
if (!article) { const article = document.getElementById('notion-article')
router.push('/404').then(() => { if (!article) {
console.warn('找不到页面', router.asPath) router.push('/404').then(() => {
}) console.warn('找不到页面', router.asPath)
})
}
} }
} },
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000) siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
} }
}, [post]) }, [post])
if (JSON.parse(siteConfig('LANDING_POST_REDIRECT_ENABLE', null, CONFIG)) && isBrowser && router.route === '/[prefix]/[slug]') { if (
const redirectUrl = siteConfig('LANDING_POST_REDIRECT_URL', null, CONFIG) + router.asPath.replace('?theme=landing', '') JSON.parse(siteConfig('LANDING_POST_REDIRECT_ENABLE', null, CONFIG)) &&
isBrowser &&
router.route === '/[prefix]/[slug]'
) {
const redirectUrl =
siteConfig('LANDING_POST_REDIRECT_URL', null, CONFIG) +
router.asPath.replace('?theme=landing', '')
router.push(redirectUrl) router.push(redirectUrl)
return <div id='theme-landing'><Loading /></div> return (
<div id='theme-landing'>
<Loading />
</div>
)
} }
return <> return (
<div id='container-inner' className='mx-auto max-w-screen-lg p-12'> <>
<NotionPage {...props} /> <div id='container-inner' className='mx-auto max-w-screen-lg p-12'>
<div id='article-wrapper'>
<NotionPage {...props} />
</div> </div>
</div>
</> </>
)
} }
// 其他布局暂时留空 // 其他布局暂时留空
const LayoutSearch = (props) => <><Hero /></> const LayoutSearch = props => (
const LayoutArchive = (props) => <><Hero /></> <>
const Layout404 = (props) => <><Hero /></> <Hero />
const LayoutCategoryIndex = (props) => <><Hero /></> </>
const LayoutPostList = (props) => <><Hero /></> )
const LayoutTagIndex = (props) => <><Hero /></> const LayoutArchive = props => (
<>
<Hero />
</>
)
const Layout404 = props => (
<>
<Hero />
</>
)
const LayoutCategoryIndex = props => (
<>
<Hero />
</>
)
const LayoutPostList = props => (
<>
<Hero />
</>
)
const LayoutTagIndex = props => (
<>
<Hero />
</>
)
export { export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404, Layout404,
LayoutPostList, LayoutArchive,
LayoutBase,
LayoutCategoryIndex, LayoutCategoryIndex,
LayoutTagIndex LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
} }

View File

@@ -254,9 +254,7 @@ const LayoutSlug = props => {
{lock && <ArticleLock validPassword={validPassword} />} {lock && <ArticleLock validPassword={validPassword} />}
{!lock && ( {!lock && (
<div <div className='overflow-x-auto md:w-full px-3 '>
id='article-wrapper'
className='overflow-x-auto md:w-full px-3 '>
{/* 文章信息 */} {/* 文章信息 */}
{post?.type && post?.type === 'Post' && ( {post?.type && post?.type === 'Post' && (
<> <>
@@ -268,7 +266,7 @@ const LayoutSlug = props => {
)} )}
<div className='lg:px-10 subpixel-antialiased'> <div className='lg:px-10 subpixel-antialiased'>
<article itemScope> <article id='article-wrapper' itemScope>
{/* Notion文章主体 */} {/* Notion文章主体 */}
<section <section
data-wow-delay='.1s' data-wow-delay='.1s'

View File

@@ -1,39 +1,39 @@
import CONFIG from './config' import Comment from '@/components/Comment'
import { useState, createContext, useContext, useEffect } from 'react'
import Footer from './components/Footer'
import InfoCard from './components/InfoCard'
import RevolverMaps from './components/RevolverMaps'
import Tabs from '@/components/Tabs'
import TopNavBar from './components/TopNavBar'
import SearchInput from './components/SearchInput'
import BottomMenuBar from './components/BottomMenuBar'
import { useGlobal } from '@/lib/global'
import { useRouter } from 'next/router'
import Live2D from '@/components/Live2D' import Live2D from '@/components/Live2D'
import Announcement from './components/Announcement' import replaceSearchResult from '@/components/Mark'
import JumpToTopButton from './components/JumpToTopButton' import NotionPage from '@/components/NotionPage'
import BlogPostListPage from './components/BlogPostListPage' import ShareBar from '@/components/ShareBar'
import BlogPostListScroll from './components/BlogPostListScroll' import Tabs from '@/components/Tabs'
import Catalog from './components/Catalog' import { siteConfig } from '@/lib/config'
import { ArticleLock } from './components/ArticleLock' import { useGlobal } from '@/lib/global'
import TagGroups from './components/TagGroups'
import CategoryGroup from './components/CategoryGroup'
import { isBrowser } from '@/lib/utils' import { isBrowser } from '@/lib/utils'
import { Transition } from '@headlessui/react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useState } from 'react'
import Announcement from './components/Announcement'
import ArticleAround from './components/ArticleAround'
import ArticleInfo from './components/ArticleInfo'
import { ArticleLock } from './components/ArticleLock'
import BlogArchiveItem from './components/BlogArchiveItem' import BlogArchiveItem from './components/BlogArchiveItem'
import BlogPostBar from './components/BlogPostBar' import BlogPostBar from './components/BlogPostBar'
import NotionPage from '@/components/NotionPage' import BlogPostListPage from './components/BlogPostListPage'
import Comment from '@/components/Comment' import BlogPostListScroll from './components/BlogPostListScroll'
import ArticleAround from './components/ArticleAround' import BottomMenuBar from './components/BottomMenuBar'
import TocDrawer from './components/TocDrawer' import Catalog from './components/Catalog'
import CategoryGroup from './components/CategoryGroup'
import CategoryItem from './components/CategoryItem' import CategoryItem from './components/CategoryItem'
import Footer from './components/Footer'
import InfoCard from './components/InfoCard'
import JumpToTopButton from './components/JumpToTopButton'
import RevolverMaps from './components/RevolverMaps'
import SearchInput from './components/SearchInput'
import TagGroups from './components/TagGroups'
import TagItemMini from './components/TagItemMini' import TagItemMini from './components/TagItemMini'
import ShareBar from '@/components/ShareBar' import TocDrawer from './components/TocDrawer'
import Link from 'next/link' import TopNavBar from './components/TopNavBar'
import { Transition } from '@headlessui/react' import CONFIG from './config'
import { Style } from './style' import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import ArticleInfo from './components/ArticleInfo'
import { siteConfig } from '@/lib/config'
// 主题全局状态 // 主题全局状态
const ThemeGlobalMedium = createContext() const ThemeGlobalMedium = createContext()
@@ -51,86 +51,96 @@ const LayoutBase = props => {
const router = useRouter() const router = useRouter()
const [tocVisible, changeTocVisible] = useState(false) const [tocVisible, changeTocVisible] = useState(false)
const { onLoading, fullWidth } = useGlobal() const { onLoading, fullWidth } = useGlobal()
const [slotRight, setSlotRight] = useState(null); const [slotRight, setSlotRight] = useState(null)
useEffect(()=> { useEffect(() => {
if (post?.toc?.length > 0) { if (post?.toc?.length > 0) {
setSlotRight( setSlotRight(
<div key={locale.COMMON.TABLE_OF_CONTENTS}> <div key={locale.COMMON.TABLE_OF_CONTENTS}>
<Catalog toc={post?.toc} /> <Catalog toc={post?.toc} />
</div> </div>
); )
} else { } else {
setSlotRight(null); setSlotRight(null)
} }
},[post]) }, [post])
const slotTop = <BlogPostBar {...props} /> const slotTop = <BlogPostBar {...props} />
return ( return (
<ThemeGlobalMedium.Provider value={{ tocVisible, changeTocVisible }}> <ThemeGlobalMedium.Provider value={{ tocVisible, changeTocVisible }}>
{/* CSS样式 */} {/* CSS样式 */}
<Style /> <Style />
<div id='theme-medium' className={`${siteConfig('FONT_STYLE')} bg-white dark:bg-hexo-black-gray w-full h-full min-h-screen justify-center dark:text-gray-300 scroll-smooth`}> <div
id='theme-medium'
className={`${siteConfig('FONT_STYLE')} bg-white dark:bg-hexo-black-gray w-full h-full min-h-screen justify-center dark:text-gray-300 scroll-smooth`}>
<main
id='wrapper'
className={
(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE'))
? 'flex-row-reverse'
: '') + 'relative flex justify-between w-full h-full mx-auto'
}>
{/* 桌面端左侧菜单 */}
{/* <LeftMenuBar/> */}
<main id='wrapper' className={(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE')) ? 'flex-row-reverse' : '') + 'relative flex justify-between w-full h-full mx-auto'}> {/* 主区 */}
{/* 桌面端左侧菜单 */} <div id='container-wrapper' className='w-full relative z-10'>
{/* <LeftMenuBar/> */} {/* 顶部导航栏 */}
<TopNavBar {...props} />
{/* 主区 */} <div
<div id='container-wrapper' className='w-full relative z-10'> id='container-inner'
className={`px-7 ${fullWidth ? '' : 'max-w-5xl'} justify-center mx-auto min-h-screen`}>
<Transition
show={!onLoading}
appear={true}
enter='transition ease-in-out duration-700 transform order-first'
enterFrom='opacity-0 translate-y-16'
enterTo='opacity-100'
leave='transition ease-in-out duration-300 transform'
leaveFrom='opacity-100'
leaveTo='opacity-0 -translate-y-16'
unmount={false}>
{slotTop}
{children}
</Transition>
{/* 顶部导航栏 */} <JumpToTopButton />
<TopNavBar {...props} />
<div id='container-inner' className={`px-7 ${fullWidth ? '' : 'max-w-5xl'} justify-center mx-auto min-h-screen`}>
<Transition
show={!onLoading}
appear={true}
enter="transition ease-in-out duration-700 transform order-first"
enterFrom="opacity-0 translate-y-16"
enterTo="opacity-100"
leave="transition ease-in-out duration-300 transform"
leaveFrom="opacity-100"
leaveTo="opacity-0 -translate-y-16"
unmount={false}
>
{slotTop}
{children}
</Transition>
<JumpToTopButton />
</div>
{/* 底部 */}
<Footer title={siteConfig('TITLE')} />
</div>
{/* 桌面端右侧 */}
{fullWidth
? null
: <div className={`hidden xl:block border-l dark:border-transparent w-80 flex-shrink-0 relative z-10 ${siteConfig('MEDIUM_RIGHT_PANEL_DARK', null, CONFIG) ? 'bg-hexo-black-gray dark' : ''}`}>
<div className='py-14 px-6 sticky top-0'>
<Tabs>
{slotRight}
<div key={locale.NAV.ABOUT}>
{router.pathname !== '/search' && <SearchInput className='mt-6 mb-12' />}
{showInfoCard && <InfoCard {...props} />}
{siteConfig('MEDIUM_WIDGET_REVOLVER_MAPS', null, CONFIG) === 'true' && <RevolverMaps />}
</div>
</Tabs>
<Announcement post={notice} />
<Live2D />
</div>
</div>}
</main>
{/* 移动端底部导航栏 */}
<BottomMenuBar {...props} className='block md:hidden' />
</div> </div>
</ThemeGlobalMedium.Provider>
{/* 底部 */}
<Footer title={siteConfig('TITLE')} />
</div>
{/* 桌面端右侧 */}
{fullWidth ? null : (
<div
className={`hidden xl:block border-l dark:border-transparent w-80 flex-shrink-0 relative z-10 ${siteConfig('MEDIUM_RIGHT_PANEL_DARK', null, CONFIG) ? 'bg-hexo-black-gray dark' : ''}`}>
<div className='py-14 px-6 sticky top-0'>
<Tabs>
{slotRight}
<div key={locale.NAV.ABOUT}>
{router.pathname !== '/search' && (
<SearchInput className='mt-6 mb-12' />
)}
{showInfoCard && <InfoCard {...props} />}
{siteConfig('MEDIUM_WIDGET_REVOLVER_MAPS', null, CONFIG) ===
'true' && <RevolverMaps />}
</div>
</Tabs>
<Announcement post={notice} />
<Live2D />
</div>
</div>
)}
</main>
{/* 移动端底部导航栏 */}
<BottomMenuBar {...props} className='block md:hidden' />
</div>
</ThemeGlobalMedium.Provider>
) )
} }
@@ -140,7 +150,7 @@ const LayoutBase = props => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutIndex = (props) => { const LayoutIndex = props => {
return <LayoutPostList {...props} /> return <LayoutPostList {...props} />
} }
@@ -148,10 +158,16 @@ const LayoutIndex = (props) => {
* 博客列表 * 博客列表
* @returns * @returns
*/ */
const LayoutPostList = (props) => { const LayoutPostList = props => {
return <> return (
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />} <>
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogPostListPage {...props} />
) : (
<BlogPostListScroll {...props} />
)}
</> </>
)
} }
/** /**
@@ -163,64 +179,72 @@ const LayoutSlug = props => {
const { post, prev, next, lock, validPassword } = props const { post, prev, next, lock, validPassword } = props
const { locale } = useGlobal() const { locale } = useGlobal()
const slotRight = post?.toc && post?.toc?.length >= 3 && ( const slotRight = post?.toc && post?.toc?.length >= 3 && (
<div key={locale.COMMON.TABLE_OF_CONTENTS} > <div key={locale.COMMON.TABLE_OF_CONTENTS}>
<Catalog toc={post?.toc} /> <Catalog toc={post?.toc} />
</div> </div>
) )
const router = useRouter() const router = useRouter()
useEffect(() => { useEffect(() => {
// 404 // 404
if (!post) { if (!post) {
setTimeout(() => { setTimeout(
if (isBrowser) { () => {
const article = document.getElementById('notion-article') if (isBrowser) {
if (!article) { const article = document.getElementById('notion-article')
router.push('/404').then(() => { if (!article) {
console.warn('找不到页面', router.asPath) router.push('/404').then(() => {
}) console.warn('找不到页面', router.asPath)
})
}
} }
} },
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000) siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
} }
}, [post]) }, [post])
return ( return (
<div {...props} > <div {...props}>
{/* 文章锁 */} {/* 文章锁 */}
{lock && <ArticleLock validPassword={validPassword} />} {lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id='article-wrapper'> {!lock && (
<div>
{/* 文章信息 */}
<ArticleInfo {...props} />
{/* 文章信息 */} {/* Notion文章主体 */}
<ArticleInfo {...props} /> <article id='article-wrapper' className='px-1 max-w-4xl'>
{post && <NotionPage post={post} />}
</article>
{/* Notion文章主体 */} {/* 文章底部区域 */}
<section className="px-1 max-w-4xl"> <section>
{post && (<NotionPage post={post} />)} {/* 分享 */}
</section> <ShareBar post={post} />
{/* 文章分类和标签信息 */}
<div className='flex justify-between'>
{siteConfig('MEDIUM_POST_DETAIL_CATEGORY', null, CONFIG) &&
post?.category && <CategoryItem category={post?.category} />}
<div>
{siteConfig('MEDIUM_POST_DETAIL_TAG', null, CONFIG) &&
post?.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>
</div>
{/* 上一篇下一篇文章 */}
{post?.type === 'Post' && <ArticleAround prev={prev} next={next} />}
{/* 评论区 */}
<Comment frontMatter={post} />
</section>
{/* 文章底部区域 */} {/* 移动端目录 */}
<section> <TocDrawer {...props} />
{/* 分享 */}
<ShareBar post={post} />
{/* 文章分类和标签信息 */}
<div className='flex justify-between'>
{siteConfig('MEDIUM_POST_DETAIL_CATEGORY', null, CONFIG) && post?.category && <CategoryItem category={post?.category} />}
<div>
{siteConfig('MEDIUM_POST_DETAIL_TAG', null, CONFIG) && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
</div>
</div>
{/* 上一篇下一篇文章 */}
{post?.type === 'Post' && <ArticleAround prev={prev} next={next} />}
{/* 评论区 */}
<Comment frontMatter={post} />
</section>
{/* 移动端目录 */}
<TocDrawer {...props} />
</div>}
</div> </div>
)}
</div>
) )
} }
@@ -229,7 +253,7 @@ const LayoutSlug = props => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutSearch = (props) => { const LayoutSearch = props => {
const { locale } = useGlobal() const { locale } = useGlobal()
const { keyword } = props const { keyword } = props
const router = useRouter() const router = useRouter()
@@ -248,23 +272,32 @@ const LayoutSearch = (props) => {
} }
}, []) }, [])
return <> return (
<>
{/* 搜索导航栏 */}
<div className='py-12'>
<div className='pb-4 w-full'>{locale.NAV.SEARCH}</div>
<SearchInput currentSearch={currentSearch} {...props} />
{!currentSearch && (
<>
<TagGroups {...props} />
<CategoryGroup {...props} />
</>
)}
</div>
{/* 搜索导航栏 */} {/* 文章列表 */}
<div className='py-12'> {currentSearch && (
<div className='pb-4 w-full'>{locale.NAV.SEARCH}</div> <div>
<SearchInput currentSearch={currentSearch} {...props} /> {siteConfig('POST_LIST_STYLE') === 'page' ? (
{!currentSearch && <> <BlogPostListPage {...props} />
<TagGroups {...props} /> ) : (
<CategoryGroup {...props} /> <BlogPostListScroll {...props} />
</>} )}
</div> </div>
)}
{/* 文章列表 */}
{currentSearch && <div>
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
</div>}
</> </>
)
} }
/** /**
@@ -275,12 +308,17 @@ const LayoutSearch = (props) => {
const LayoutArchive = props => { const LayoutArchive = props => {
const { archivePosts } = props const { archivePosts } = props
return ( return (
<> <>
<div className="mb-10 pb-20 md:py-12 py-3 min-h-full"> <div className='mb-10 pb-20 md:py-12 py-3 min-h-full'>
{Object.keys(archivePosts)?.map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} /> {Object.keys(archivePosts)?.map(archiveTitle => (
)} <BlogArchiveItem
</div> key={archiveTitle}
</> archiveTitle={archiveTitle}
archivePosts={archivePosts}
/>
))}
</div>
</>
) )
} }
@@ -290,9 +328,13 @@ const LayoutArchive = props => {
* @returns * @returns
*/ */
const Layout404 = props => { const Layout404 = props => {
return <> return (
<div className='w-full h-96 py-80 flex justify-center items-center'>404 Not found.</div> <>
<div className='w-full h-96 py-80 flex justify-center items-center'>
404 Not found.
</div>
</> </>
)
} }
/** /**
@@ -300,33 +342,37 @@ const Layout404 = props => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutCategoryIndex = (props) => { const LayoutCategoryIndex = props => {
const { categoryOptions } = props const { categoryOptions } = props
const { locale } = useGlobal() const { locale } = useGlobal()
return ( return (
<> <>
<div className='bg-white dark:bg-gray-700 py-10'> <div className='bg-white dark:bg-gray-700 py-10'>
<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 id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={
'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'
}>
<i className='mr-4 fas fa-folder' />
{category.name}({category.count})
</div> </div>
<div id='category-list' className='duration-200 flex flex-wrap'> </Link>
{categoryOptions?.map(category => { )
return ( })}
<Link </div>
key={category.name} </div>
href={`/category/${category.name}`} </>
passHref
legacyBehavior>
<div
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
<i className='mr-4 fas fa-folder' />{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</div>
</>
) )
} }
@@ -339,35 +385,35 @@ const LayoutTagIndex = props => {
const { tagOptions } = props const { tagOptions } = props
const { locale } = useGlobal() const { locale } = useGlobal()
return ( return (
<> <>
<div className="bg-white dark:bg-gray-700 py-10"> <div className='bg-white dark:bg-gray-700 py-10'>
<div className="dark:text-gray-200 mb-5"> <div className='dark:text-gray-200 mb-5'>
<i className="mr-4 fas fa-tag" /> <i className='mr-4 fas fa-tag' />
{locale.COMMON.TAGS}: {locale.COMMON.TAGS}:
</div> </div>
<div id="tags-list" className="duration-200 flex flex-wrap"> <div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions?.map(tag => { {tagOptions?.map(tag => {
return ( return (
<div key={tag.name} className="p-2"> <div key={tag.name} className='p-2'>
<TagItemMini key={tag.name} tag={tag} /> <TagItemMini key={tag.name} tag={tag} />
</div> </div>
) )
})} })}
</div> </div>
</div> </div>
</> </>
) )
} }
export { export {
CONFIG as THEME_CONFIG, Layout404,
LayoutArchive,
LayoutBase, LayoutBase,
LayoutCategoryIndex,
LayoutIndex, LayoutIndex,
LayoutPostList, LayoutPostList,
LayoutSearch, LayoutSearch,
LayoutArchive,
LayoutSlug, LayoutSlug,
Layout404, LayoutTagIndex,
LayoutCategoryIndex, CONFIG as THEME_CONFIG
LayoutTagIndex
} }

View File

@@ -290,8 +290,10 @@ const LayoutSlug = props => {
{/* Notion文章主体 */} {/* Notion文章主体 */}
{post && ( {post && (
<section id='article-wrapper' className='px-1'> <section className='px-1'>
<NotionPage post={post} /> <div id='article-wrapper'>
<NotionPage post={post} />
</div>
{/* 分享 */} {/* 分享 */}
{/* <ShareBar post={post} /> */} {/* <ShareBar post={post} /> */}

View File

@@ -35,9 +35,7 @@ export default function ArticleDetail(props) {
} }
return ( return (
<div <div className='shadow md:hover:shadow-2xl overflow-x-auto flex-grow mx-auto w-screen md:w-full '>
id='article-wrapper'
className='shadow md:hover:shadow-2xl overflow-x-auto flex-grow mx-auto w-screen md:w-full '>
<div <div
itemScope itemScope
itemType='https://schema.org/Movie' itemType='https://schema.org/Movie'
@@ -100,7 +98,7 @@ export default function ArticleDetail(props) {
)} )}
{/* Notion内容主体 */} {/* Notion内容主体 */}
<article className='mx-auto'> <article id='article-wrapper' className='mx-auto'>
<WWAds className='w-full' orientation='horizontal' /> <WWAds className='w-full' orientation='horizontal' />
{post && <NotionPage post={post} />} {post && <NotionPage post={post} />}
<WWAds className='w-full' orientation='horizontal' /> <WWAds className='w-full' orientation='horizontal' />

View File

@@ -1,34 +1,37 @@
import CONFIG from './config' import replaceSearchResult from '@/components/Mark'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { isBrowser } from '@/lib/utils'
import dynamic from 'next/dynamic'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useRef, useState } from 'react'
import Announcement from './components/Announcement'
import ArticleDetail from './components/ArticleDetail'
import { ArticleLock } from './components/ArticleLock'
import BlogListBar from './components/BlogListBar'
import BlogPostArchive from './components/BlogPostArchive'
import BlogPostListPage from './components/BlogPostListPage'
import BlogPostListScroll from './components/BlogPostListScroll'
import Card from './components/Card'
import FloatDarkModeButton from './components/FloatDarkModeButton' import FloatDarkModeButton from './components/FloatDarkModeButton'
import Footer from './components/Footer' import Footer from './components/Footer'
import JumpToBottomButton from './components/JumpToBottomButton' import JumpToBottomButton from './components/JumpToBottomButton'
import JumpToTopButton from './components/JumpToTopButton' import JumpToTopButton from './components/JumpToTopButton'
import SideAreaLeft from './components/SideAreaLeft' import SideAreaLeft from './components/SideAreaLeft'
import SideAreaRight from './components/SideAreaRight' import SideAreaRight from './components/SideAreaRight'
import TopNav from './components/TopNav'
import { useGlobal } from '@/lib/global'
import { createContext, useContext, useEffect, useRef, useState } from 'react'
import BlogPostListScroll from './components/BlogPostListScroll'
import BlogPostListPage from './components/BlogPostListPage'
import StickyBar from './components/StickyBar' import StickyBar from './components/StickyBar'
import { isBrowser } from '@/lib/utils'
import TocDrawerButton from './components/TocDrawerButton'
import TocDrawer from './components/TocDrawer'
import { ArticleLock } from './components/ArticleLock'
import BlogPostArchive from './components/BlogPostArchive'
import TagItem from './components/TagItem' import TagItem from './components/TagItem'
import { useRouter } from 'next/router' import TocDrawer from './components/TocDrawer'
import ArticleDetail from './components/ArticleDetail' import TocDrawerButton from './components/TocDrawerButton'
import Link from 'next/link' import TopNav from './components/TopNav'
import BlogListBar from './components/BlogListBar' import CONFIG from './config'
import { Style } from './style' import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import { siteConfig } from '@/lib/config'
import Announcement from './components/Announcement'
import Card from './components/Card'
import dynamic from 'next/dynamic'
const AlgoliaSearchModal = dynamic(() => import('@/components/AlgoliaSearchModal'), { ssr: false }) const AlgoliaSearchModal = dynamic(
() => import('@/components/AlgoliaSearchModal'),
{ ssr: false }
)
// 主题全局状态 // 主题全局状态
const ThemeGlobalNext = createContext() const ThemeGlobalNext = createContext()
@@ -39,7 +42,7 @@ export const useNextGlobal = () => useContext(ThemeGlobalNext)
* @returns {JSX.Element} * @returns {JSX.Element}
* @constructor * @constructor
*/ */
const LayoutBase = (props) => { const LayoutBase = props => {
const { children, headerSlot, rightAreaSlot, post } = props const { children, headerSlot, rightAreaSlot, post } = props
const targetRef = useRef(null) const targetRef = useRef(null)
const floatButtonGroup = useRef(null) const floatButtonGroup = useRef(null)
@@ -50,7 +53,7 @@ const LayoutBase = (props) => {
const clientHeight = targetRef?.clientHeight const clientHeight = targetRef?.clientHeight
const scrollY = window.pageYOffset const scrollY = window.pageYOffset
const fullHeight = clientHeight - window.outerHeight const fullHeight = clientHeight - window.outerHeight
let per = parseFloat(((scrollY / fullHeight * 100)).toFixed(0)) let per = parseFloat(((scrollY / fullHeight) * 100).toFixed(0))
if (per > 100) per = 100 if (per > 100) per = 100
const shouldShow = scrollY > 100 && per > 0 const shouldShow = scrollY > 100 && per > 0
@@ -75,11 +78,15 @@ const LayoutBase = (props) => {
// 悬浮抽屉 // 悬浮抽屉
const drawerRight = useRef(null) const drawerRight = useRef(null)
const floatSlot = <div className='block lg:hidden'> const floatSlot = (
<TocDrawerButton onClick={() => { <div className='block lg:hidden'>
drawerRight?.current?.handleSwitchVisible() <TocDrawerButton
}} /> onClick={() => {
</div> drawerRight?.current?.handleSwitchVisible()
}}
/>
</div>
)
const tocRef = isBrowser ? document.getElementById('article-wrapper') : null const tocRef = isBrowser ? document.getElementById('article-wrapper') : null
@@ -87,53 +94,77 @@ const LayoutBase = (props) => {
return ( return (
<ThemeGlobalNext.Provider value={{ searchModal }}> <ThemeGlobalNext.Provider value={{ searchModal }}>
<div id='theme-next' className={`${siteConfig('FONT_STYLE')} dark:bg-black scroll-smooth`}> <div
<Style/> id='theme-next'
className={`${siteConfig('FONT_STYLE')} dark:bg-black scroll-smooth`}>
<Style />
{/* 移动端顶部导航栏 */} {/* 移动端顶部导航栏 */}
<TopNav {...props} /> <TopNav {...props} />
<AlgoliaSearchModal cRef={searchModal} {...props}/> <AlgoliaSearchModal cRef={searchModal} {...props} />
<>{headerSlot}</> <>{headerSlot}</>
{/* 顶部黑线装饰 */} {/* 顶部黑线装饰 */}
<div className='h-0.5 w-full bg-gray-700 dark:bg-gray-600 hidden lg:block' /> <div className='h-0.5 w-full bg-gray-700 dark:bg-gray-600 hidden lg:block' />
{/* 主区 */} {/* 主区 */}
<main id='wrapper' className={(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE')) ? 'flex-row-reverse' : '') + ' next relative flex justify-center flex-1 pb-12'}> <main
{/* 左侧栏样式 */} id='wrapper'
<SideAreaLeft targetRef={targetRef} {...props} /> className={
(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE'))
? 'flex-row-reverse'
: '') + ' next relative flex justify-center flex-1 pb-12'
}>
{/* 左侧栏样式 */}
<SideAreaLeft targetRef={targetRef} {...props} />
{/* 中央内容 */} {/* 中央内容 */}
<section id='container-inner' className={`${siteConfig('NEXT_NAV_TYPE', null, CONFIG) !== 'normal' ? 'mt-24' : ''} lg:max-w-3xl xl:max-w-4xl flex-grow md:mt-0 min-h-screen w-full relative z-10`} ref={targetRef}> <section
{children} id='container-inner'
</section> className={`${siteConfig('NEXT_NAV_TYPE', null, CONFIG) !== 'normal' ? 'mt-24' : ''} lg:max-w-3xl xl:max-w-4xl flex-grow md:mt-0 min-h-screen w-full relative z-10`}
ref={targetRef}>
{children}
</section>
{/* 右侧栏样式 */} {/* 右侧栏样式 */}
{siteConfig('NEXT_RIGHT_BAR', null, CONFIG) && <SideAreaRight targetRef={targetRef} slot={rightAreaSlot} {...props} />} {siteConfig('NEXT_RIGHT_BAR', null, CONFIG) && (
<SideAreaRight
targetRef={targetRef}
slot={rightAreaSlot}
{...props}
/>
)}
</main>
</main> {/* 悬浮目录按钮 */}
{post && (
<div className='block lg:hidden'>
<TocDrawer post={post} cRef={drawerRight} targetRef={tocRef} />
</div>
)}
{/* 悬浮目录按钮 */} {/* 右下角悬浮 */}
{post && <div className='block lg:hidden'> <div
<TocDrawer post={post} cRef={drawerRight} targetRef={tocRef} /> ref={floatButtonGroup}
</div>} className='right-8 bottom-12 lg:right-2 fixed justify-end z-20 '>
<div
{/* 右下角悬浮 */} className={
<div ref={floatButtonGroup} className='right-8 bottom-12 lg:right-2 fixed justify-end z-20 '> (showRightFloat ? 'animate__animated ' : 'hidden') +
<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 '}> ' animate__fadeInUp rounded-md glassmorphism justify-center duration-500 animate__faster flex space-x-2 items-center cursor-pointer '
<JumpToTopButton percent={percent} /> }>
<JumpToBottomButton /> <JumpToTopButton percent={percent} />
<FloatDarkModeButton /> <JumpToBottomButton />
{floatSlot} <FloatDarkModeButton />
</div> {floatSlot}
</div> </div>
{/* 页脚 */}
<Footer title={siteConfig('TITLE')} />
</div> </div>
</ThemeGlobalNext.Provider>
{/* 页脚 */}
<Footer title={siteConfig('TITLE')} />
</div>
</ThemeGlobalNext.Provider>
) )
} }
@@ -143,21 +174,24 @@ const LayoutBase = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutIndex = (props) => { const LayoutIndex = props => {
const { notice } = props const { notice } = props
return <> return (
{/* 首页移动端顶部显示公告 */} <>
<Card className='my-2 lg:hidden'> {/* 首页移动端顶部显示公告 */}
<Announcement post={notice} /> <Card className='my-2 lg:hidden'>
</Card> <Announcement post={notice} />
</Card>
<BlogListBar {...props} /> <BlogListBar {...props} />
{siteConfig('POST_LIST_STYLE') !== 'page' {siteConfig('POST_LIST_STYLE') !== 'page' ? (
? <BlogPostListScroll {...props} showSummary={true} /> <BlogPostListScroll {...props} showSummary={true} />
: <BlogPostListPage {...props} /> ) : (
} <BlogPostListPage {...props} />
)}
</> </>
)
} }
/** /**
@@ -165,16 +199,18 @@ const LayoutIndex = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutPostList = (props) => { const LayoutPostList = props => {
return <> return (
<>
<BlogListBar {...props} />
<BlogListBar {...props} /> {siteConfig('POST_LIST_STYLE') !== 'page' ? (
<BlogPostListScroll {...props} showSummary={true} />
{siteConfig('POST_LIST_STYLE') !== 'page' ) : (
? <BlogPostListScroll {...props} showSummary={true} /> <BlogPostListPage {...props} />
: <BlogPostListPage {...props} /> )}
}
</> </>
)
} }
/** /**
@@ -182,7 +218,7 @@ const LayoutPostList = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutSearch = (props) => { const LayoutSearch = props => {
const { locale } = useGlobal() const { locale } = useGlobal()
const { posts, keyword } = props const { posts, keyword } = props
@@ -200,20 +236,21 @@ const LayoutSearch = (props) => {
}, []) }, [])
return ( return (
<> <>
<StickyBar> <StickyBar>
<div className="p-4 dark:text-gray-200"> <div className='p-4 dark:text-gray-200'>
<i className="mr-1 fas fa-search" />{' '} <i className='mr-1 fas fa-search' /> {posts?.length}{' '}
{posts?.length} {locale.COMMON.RESULT_OF_SEARCH} {locale.COMMON.RESULT_OF_SEARCH}
</div> </div>
</StickyBar> </StickyBar>
<div className="md:mt-5"> <div className='md:mt-5'>
{siteConfig('POST_LIST_STYLE') !== 'page' {siteConfig('POST_LIST_STYLE') !== 'page' ? (
? <BlogPostListScroll {...props} showSummary={true} /> <BlogPostListScroll {...props} showSummary={true} />
: <BlogPostListPage {...props} /> ) : (
} <BlogPostListPage {...props} />
</div> )}
</> </div>
</>
) )
} }
@@ -236,16 +273,21 @@ const Layout404 = props => {
}, 3000) }, 3000)
}, []) }, [])
return <> return (
<div className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'> <>
<div className='dark:text-gray-200'> <div className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'>
<h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'><i className='mr-2 fas fa-spinner animate-spin' />404</h2> <div className='dark:text-gray-200'>
<div className='inline-block text-left h-32 leading-10 items-center'> <h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'>
<h2 className='m-0 p-0'>页面无法加载即将返回首页</h2> <i className='mr-2 fas fa-spinner animate-spin' />
</div> 404
</div> </h2>
<div className='inline-block text-left h-32 leading-10 items-center'>
<h2 className='m-0 p-0'>页面无法加载即将返回首页</h2>
</div>
</div> </div>
</div>
</> </>
)
} }
/** /**
@@ -253,21 +295,21 @@ const Layout404 = props => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutArchive = (props) => { const LayoutArchive = props => {
const { archivePosts } = props const { archivePosts } = props
return ( return (
<> <>
<div className="mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-hexo-black-gray shadow-md min-h-full"> <div className='mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-hexo-black-gray shadow-md min-h-full'>
{Object.keys(archivePosts).map(archiveTitle => ( {Object.keys(archivePosts).map(archiveTitle => (
<BlogPostArchive <BlogPostArchive
key={archiveTitle} key={archiveTitle}
posts={archivePosts[archiveTitle]} posts={archivePosts[archiveTitle]}
archiveTitle={archiveTitle} archiveTitle={archiveTitle}
/> />
))} ))}
</div> </div>
</> </>
) )
} }
@@ -276,33 +318,34 @@ const LayoutArchive = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutSlug = (props) => { const LayoutSlug = props => {
const { post, lock, validPassword } = props const { post, lock, validPassword } = props
const router = useRouter() const router = useRouter()
useEffect(() => { useEffect(() => {
// 404 // 404
if (!post) { if (!post) {
setTimeout(() => { setTimeout(
if (isBrowser) { () => {
const article = document.getElementById('notion-article') if (isBrowser) {
if (!article) { const article = document.getElementById('notion-article')
router.push('/404').then(() => { if (!article) {
console.warn('找不到页面', router.asPath) router.push('/404').then(() => {
}) console.warn('找不到页面', router.asPath)
})
}
} }
} },
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000) siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
} }
}, [post]) }, [post])
return ( return (
<> <>
{post && !lock && <ArticleDetail {...props} />}
{post && !lock && <ArticleDetail {...props} />} {post && lock && <ArticleLock validPassword={validPassword} />}
</>
{post && lock && <ArticleLock validPassword={validPassword} />}
</>
) )
} }
@@ -311,33 +354,37 @@ const LayoutSlug = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutCategoryIndex = (props) => { const LayoutCategoryIndex = props => {
const { allPosts, categoryOptions } = props const { allPosts, categoryOptions } = props
const { locale } = useGlobal() const { locale } = useGlobal()
return ( return (
<div totalPosts={allPosts} {...props}> <div totalPosts={allPosts} {...props}>
<div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'> <div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'>
<div className='dark:text-gray-200 mb-5'> <div className='dark:text-gray-200 mb-5'>
<i className='mr-4 fas faTh' />{locale.COMMON.CATEGORY}: <i className='mr-4 fas faTh' />
</div> {locale.COMMON.CATEGORY}:
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
<i className='mr-4 fas fa-folder' />{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</div>
</div> </div>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={
'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'
}>
<i className='mr-4 fas fa-folder' />
{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</div>
</div>
) )
} }
@@ -346,30 +393,39 @@ const LayoutCategoryIndex = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutTagIndex = (props) => { const LayoutTagIndex = props => {
const { tagOptions } = props const { tagOptions } = props
const { locale } = useGlobal() const { locale } = useGlobal()
return <> return (
<div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'> <>
<div className='dark:text-gray-200 mb-5'><i className='fas fa-tags mr-4' />{locale.COMMON.TAGS}:</div> <div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'>
<div id='tags-list' className='duration-200 flex flex-wrap'> <div className='dark:text-gray-200 mb-5'>
{tagOptions.map(tag => { <i className='fas fa-tags mr-4' />
return <div key={tag.name} className='p-2'><TagItem key={tag.name} tag={tag} /></div> {locale.COMMON.TAGS}:
})}
</div>
</div> </div>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => {
return (
<div key={tag.name} className='p-2'>
<TagItem key={tag.name} tag={tag} />
</div>
)
})}
</div>
</div>
</> </>
)
} }
export { export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404, Layout404,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex, LayoutCategoryIndex,
LayoutIndex,
LayoutPostList, LayoutPostList,
LayoutTagIndex LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
} }

View File

@@ -1,32 +1,35 @@
import CONFIG from './config' import Comment from '@/components/Comment'
import { createContext, useEffect, useState, useContext, useRef } from 'react'
import Nav from './components/Nav'
import { Footer } from './components/Footer'
import JumpToTopButton from './components/JumpToTopButton'
import Live2D from '@/components/Live2D' import Live2D from '@/components/Live2D'
import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global' import { useGlobal } from '@/lib/global'
import { deepClone, isBrowser } from '@/lib/utils'
import { Transition } from '@headlessui/react'
import dynamic from 'next/dynamic'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useRef, useState } from 'react'
import Announcement from './components/Announcement' import Announcement from './components/Announcement'
import { ArticleFooter } from './components/ArticleFooter'
import { ArticleInfo } from './components/ArticleInfo'
import { ArticleLock } from './components/ArticleLock'
import BlogArchiveItem from './components/BlogArchiveItem'
import BlogListBar from './components/BlogListBar'
import { BlogListPage } from './components/BlogListPage' import { BlogListPage } from './components/BlogListPage'
import { BlogListScroll } from './components/BlogListScroll' import { BlogListScroll } from './components/BlogListScroll'
import { deepClone, isBrowser } from '@/lib/utils' import { Footer } from './components/Footer'
import JumpToTopButton from './components/JumpToTopButton'
import Nav from './components/Nav'
import SearchNavBar from './components/SearchNavBar' import SearchNavBar from './components/SearchNavBar'
import BlogArchiveItem from './components/BlogArchiveItem' import CONFIG from './config'
import { ArticleLock } from './components/ArticleLock'
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'
import Link from 'next/link'
import BlogListBar from './components/BlogListBar'
import { Transition } from '@headlessui/react'
import { Style } from './style' import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import { siteConfig } from '@/lib/config'
import { useRouter } from 'next/router'
import dynamic from 'next/dynamic'
const AlgoliaSearchModal = dynamic(() => import('@/components/AlgoliaSearchModal'), { ssr: false }) const AlgoliaSearchModal = dynamic(
() => import('@/components/AlgoliaSearchModal'),
{ ssr: false }
)
// 主题全局状态 // 主题全局状态
const ThemeGlobalNobelium = createContext() const ThemeGlobalNobelium = createContext()
@@ -45,56 +48,56 @@ const LayoutBase = props => {
const searchModal = useRef(null) const searchModal = useRef(null)
// 在列表中进行实时过滤 // 在列表中进行实时过滤
const [filterKey, setFilterKey] = useState('') const [filterKey, setFilterKey] = useState('')
const topSlot = <BlogListBar {...props}/> const topSlot = <BlogListBar {...props} />
return ( return (
<ThemeGlobalNobelium.Provider value={{ searchModal, filterKey, setFilterKey }}> <ThemeGlobalNobelium.Provider
<div id='theme-nobelium' className={`${siteConfig('FONT_STYLE')} nobelium relative dark:text-gray-300 w-full bg-white dark:bg-black min-h-screen flex flex-col scroll-smooth`}> value={{ searchModal, filterKey, setFilterKey }}>
<div
id='theme-nobelium'
className={`${siteConfig('FONT_STYLE')} nobelium relative dark:text-gray-300 w-full bg-white dark:bg-black min-h-screen flex flex-col scroll-smooth`}>
<Style />
<Style /> {/* 顶部导航栏 */}
<Nav {...props} />
{/* 顶部导航栏 */} {/* 主区 */}
<Nav {...props} /> <main
id='out-wrapper'
className={`relative m-auto flex-grow w-full transition-all ${!fullWidth ? 'max-w-2xl px-4' : 'px-4 md:px-24'}`}>
<Transition
show={!onLoading}
appear={true}
enter='transition ease-in-out duration-700 transform order-first'
enterFrom='opacity-0 translate-y-16'
enterTo='opacity-100'
leave='transition ease-in-out duration-300 transform'
leaveFrom='opacity-100 translate-y-0'
leaveTo='opacity-0 -translate-y-16'
unmount={false}>
{/* 顶部插槽 */}
{topSlot}
{children}
</Transition>
</main>
{/* 主区 */} {/* 页脚 */}
<main id='out-wrapper' className={`relative m-auto flex-grow w-full transition-all ${!fullWidth ? 'max-w-2xl px-4' : 'px-4 md:px-24'}`}> <Footer {...props} />
<Transition {/* 右下悬浮 */}
show={!onLoading} <div className='fixed right-4 bottom-4'>
appear={true} <JumpToTopButton />
enter="transition ease-in-out duration-700 transform order-first" </div>
enterFrom="opacity-0 translate-y-16"
enterTo="opacity-100"
leave="transition ease-in-out duration-300 transform"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 -translate-y-16"
unmount={false}
>
{/* 顶部插槽 */}
{topSlot}
{children}
</Transition>
</main> {/* 左下悬浮 */}
<div className='bottom-4 -left-14 fixed justify-end z-40'>
<Live2D />
</div>
{/* 页脚 */} {/* 搜索框 */}
<Footer {...props} /> <AlgoliaSearchModal cRef={searchModal} {...props} />
</div>
{/* 右下悬浮 */} </ThemeGlobalNobelium.Provider>
<div className='fixed right-4 bottom-4'>
<JumpToTopButton />
</div>
{/* 左下悬浮 */}
<div className="bottom-4 -left-14 fixed justify-end z-40">
<Live2D />
</div>
{/* 搜索框 */}
<AlgoliaSearchModal cRef={searchModal} {...props}/>
</div>
</ThemeGlobalNobelium.Provider>
) )
} }
@@ -105,9 +108,7 @@ const LayoutBase = props => {
* @returns * @returns
*/ */
const LayoutIndex = props => { const LayoutIndex = props => {
return ( return <LayoutPostList {...props} topSlot={<Announcement {...props} />} />
<LayoutPostList {...props} topSlot={<Announcement {...props} />} />
)
} }
/** /**
@@ -130,11 +131,15 @@ const LayoutPostList = props => {
} }
return ( return (
<> <>
{topSlot} {topSlot}
{tag && <SearchNavBar {...props} />} {tag && <SearchNavBar {...props} />}
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} posts={filteredBlogPosts} /> : <BlogListScroll {...props} posts={filteredBlogPosts} />} {siteConfig('POST_LIST_STYLE') === 'page' ? (
</> <BlogListPage {...props} posts={filteredBlogPosts} />
) : (
<BlogListScroll {...props} posts={filteredBlogPosts} />
)}
</>
) )
} }
@@ -172,10 +177,16 @@ const LayoutSearch = props => {
filteredBlogPosts = deepClone(posts) filteredBlogPosts = deepClone(posts)
} }
return <> return (
<SearchNavBar {...props} /> <>
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} posts={filteredBlogPosts} /> : <BlogListScroll {...props} posts={filteredBlogPosts} />} <SearchNavBar {...props} />
</> {siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogListPage {...props} posts={filteredBlogPosts} />
) : (
<BlogListScroll {...props} posts={filteredBlogPosts} />
)}
</>
)
} }
/** /**
@@ -186,11 +197,17 @@ const LayoutSearch = props => {
const LayoutArchive = props => { const LayoutArchive = props => {
const { archivePosts } = props const { archivePosts } = props
return ( return (
<> <>
<div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> <div className='mb-10 pb-20 md:py-12 p-3 min-h-screen w-full'>
{Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} {Object.keys(archivePosts).map(archiveTitle => (
</div> <BlogArchiveItem
</> key={archiveTitle}
archiveTitle={archiveTitle}
archivePosts={archivePosts}
/>
))}
</div>
</>
) )
} }
@@ -205,34 +222,39 @@ const LayoutSlug = props => {
useEffect(() => { useEffect(() => {
// 404 // 404
if (!post) { if (!post) {
setTimeout(() => { setTimeout(
if (isBrowser) { () => {
const article = document.getElementById('notion-article') if (isBrowser) {
if (!article) { const article = document.getElementById('notion-article')
router.push('/404').then(() => { if (!article) {
console.warn('找不到页面', router.asPath) router.push('/404').then(() => {
}) console.warn('找不到页面', router.asPath)
})
}
} }
} },
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000) siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
} }
}, [post]) }, [post])
return ( return (
<> <>
{lock && <ArticleLock validPassword={validPassword} />}
{lock && <ArticleLock validPassword={validPassword} />} {!lock && (
<div className='px-2'>
{!lock && <div id="article-wrapper" className="px-2"> <>
<> <ArticleInfo post={post} />
<ArticleInfo post={post} /> <div id='article-wrapper'>
<NotionPage post={post} /> <NotionPage post={post} />
<ShareBar post={post} /> </div>
<Comment frontMatter={post} /> <ShareBar post={post} />
<ArticleFooter /> <Comment frontMatter={post} />
</> <ArticleFooter />
</div>} </>
</div>
</> )}
</>
) )
} }
@@ -241,10 +263,8 @@ const LayoutSlug = props => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const Layout404 = (props) => { const Layout404 = props => {
return <> return <>404 Not found.</>
404 Not found.
</>
} }
/** /**
@@ -252,28 +272,31 @@ const Layout404 = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutCategoryIndex = (props) => { const LayoutCategoryIndex = props => {
const { categoryOptions } = props const { categoryOptions } = props
return ( return (
<> <>
<div id='category-list' className='duration-200 flex flex-wrap'> <div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => { {categoryOptions?.map(category => {
return ( return (
<Link <Link
key={category.name} key={category.name}
href={`/category/${category.name}`} href={`/category/${category.name}`}
passHref passHref
legacyBehavior> legacyBehavior>
<div <div
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}> className={
<i className='mr-4 fas fa-folder' />{category.name}({category.count}) 'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'
</div> }>
</Link> <i className='mr-4 fas fa-folder' />
) {category.name}({category.count})
})} </div>
</div> </Link>
</> )
})}
</div>
</>
) )
} }
@@ -282,37 +305,43 @@ const LayoutCategoryIndex = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutTagIndex = (props) => { const LayoutTagIndex = props => {
const { tagOptions } = props const { tagOptions } = props
return ( return (
<> <>
<div> <div>
<div id='tags-list' className='duration-200 flex flex-wrap'> <div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => { {tagOptions.map(tag => {
return ( return (
<div key={tag.name} className='p-2'> <div key={tag.name} className='p-2'>
<Link key={tag} href={`/tag/${encodeURIComponent(tag.name)}`} passHref <Link
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`}> key={tag}
<div className='font-light dark:text-gray-400'><i className='mr-1 fas fa-tag' /> {tag.name + (tag.count ? `(${tag.count})` : '')} </div> href={`/tag/${encodeURIComponent(tag.name)}`}
</Link> passHref
</div> 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`}>
) <div className='font-light dark:text-gray-400'>
})} <i className='mr-1 fas fa-tag' />{' '}
</div> {tag.name + (tag.count ? `(${tag.count})` : '')}{' '}
</div> </div>
</> </Link>
</div>
)
})}
</div>
</div>
</>
) )
} }
export { export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404, Layout404,
LayoutPostList, LayoutArchive,
LayoutBase,
LayoutCategoryIndex, LayoutCategoryIndex,
LayoutTagIndex LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
} }

View File

@@ -1,26 +1,26 @@
import CONFIG from './config' import Comment from '@/components/Comment'
import { createContext, useContext, useEffect, useState } from 'react' import replaceSearchResult from '@/components/Mark'
import Header from './components/Nav' import NotionPage from '@/components/NotionPage'
import { useGlobal } from '@/lib/global' import ShareBar from '@/components/ShareBar'
import { siteConfig } from '@/lib/config' import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { isBrowser } from '@/lib/utils'
import { Transition } from '@headlessui/react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useState } from 'react'
import { ArticleFooter } from './components/ArticleFooter'
import { ArticleInfo } from './components/ArticleInfo'
import { ArticleLock } from './components/ArticleLock'
import BlogArchiveItem from './components/BlogArchiveItem'
import { BlogListPage } from './components/BlogListPage' import { BlogListPage } from './components/BlogListPage'
import { BlogListScroll } from './components/BlogListScroll' import { BlogListScroll } from './components/BlogListScroll'
import { isBrowser } from '@/lib/utils'
import SearchNavBar from './components/SearchNavBar'
import BlogArchiveItem from './components/BlogArchiveItem'
import { ArticleLock } from './components/ArticleLock'
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'
import Link from 'next/link'
import { Transition } from '@headlessui/react'
import BottomNav from './components/BottomNav' import BottomNav from './components/BottomNav'
import Modal from './components/Modal' import Modal from './components/Modal'
import Header from './components/Nav'
import SearchNavBar from './components/SearchNavBar'
import CONFIG from './config'
import { Style } from './style' import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import { useRouter } from 'next/router'
// 主题全局状态 // 主题全局状态
const ThemeGlobalPlog = createContext() const ThemeGlobalPlog = createContext()
@@ -52,42 +52,45 @@ const LayoutBase = props => {
}, [router.events]) }, [router.events])
return ( return (
<ThemeGlobalPlog.Provider value={{ showModal, setShowModal, modalContent, setModalContent }}> <ThemeGlobalPlog.Provider
<div id='theme-plog' className={`${siteConfig('FONT_STYLE')} plog relative dark:text-gray-300 w-full dark:bg-black min-h-screen scroll-smooth`} > value={{ showModal, setShowModal, modalContent, setModalContent }}>
<div
id='theme-plog'
className={`${siteConfig('FONT_STYLE')} plog relative dark:text-gray-300 w-full dark:bg-black min-h-screen scroll-smooth`}>
<Style />
<Style/> {/* 移动端顶部导航栏 */}
<Header {...props} />
{/* 移动端顶部导航栏 */} {/* 主区 */}
<Header {...props} /> <main
id='out-wrapper'
className={
'relative m-auto flex-grow w-full transition-all pb-16 pt-16 md:pt-0'
}>
<Transition
show={!onLoading}
appear={true}
enter='transition ease-in-out duration-700 transform order-first'
enterFrom='opacity-0 translate-y-16'
enterTo='opacity-100'
leave='transition ease-in-out duration-300 transform'
leaveFrom='opacity-100 translate-y-0'
leaveTo='opacity-0 -translate-y-16'
unmount={false}>
{/* 顶部插槽 */}
{topSlot}
{children}
</Transition>
</main>
{/* 主区 */} {/* 弹出框 - 用于放大显示首页图片等作用 */}
<main id='out-wrapper' className={'relative m-auto flex-grow w-full transition-all pb-16 pt-16 md:pt-0'}> <Modal {...props} />
<Transition {/* 桌面端底部导航栏 */}
show={!onLoading} <BottomNav {...props} />
appear={true} </div>
enter="transition ease-in-out duration-700 transform order-first" </ThemeGlobalPlog.Provider>
enterFrom="opacity-0 translate-y-16"
enterTo="opacity-100"
leave="transition ease-in-out duration-300 transform"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 -translate-y-16"
unmount={false}
>
{/* 顶部插槽 */}
{topSlot}
{children}
</Transition>
</main>
{/* 弹出框 - 用于放大显示首页图片等作用 */}
<Modal {...props}/>
{/* 桌面端底部导航栏 */}
<BottomNav {...props} />
</div>
</ThemeGlobalPlog.Provider >
) )
} }
@@ -98,9 +101,7 @@ const LayoutBase = props => {
* @returns * @returns
*/ */
const LayoutIndex = props => { const LayoutIndex = props => {
return ( return <LayoutPostList {...props} />
<LayoutPostList {...props} />
)
} }
/** /**
@@ -110,9 +111,13 @@ const LayoutIndex = props => {
*/ */
const LayoutPostList = props => { const LayoutPostList = props => {
return ( return (
<> <>
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />} {siteConfig('POST_LIST_STYLE') === 'page' ? (
</> <BlogListPage {...props} />
) : (
<BlogListScroll {...props} />
)}
</>
) )
} }
@@ -149,11 +154,17 @@ const LayoutSearch = props => {
const LayoutArchive = props => { const LayoutArchive = props => {
const { archivePosts } = props const { archivePosts } = props
return ( return (
<> <>
<div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full"> <div className='mb-10 pb-20 md:py-12 p-3 min-h-screen w-full'>
{Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)} {Object.keys(archivePosts).map(archiveTitle => (
</div> <BlogArchiveItem
</> key={archiveTitle}
archiveTitle={archiveTitle}
archivePosts={archivePosts}
/>
))}
</div>
</>
) )
} }
@@ -168,34 +179,39 @@ const LayoutSlug = props => {
useEffect(() => { useEffect(() => {
// 404 // 404
if (!post) { if (!post) {
setTimeout(() => { setTimeout(
if (isBrowser) { () => {
const article = document.getElementById('notion-article') if (isBrowser) {
if (!article) { const article = document.getElementById('notion-article')
router.push('/404').then(() => { if (!article) {
console.warn('找不到页面', router.asPath) router.push('/404').then(() => {
}) console.warn('找不到页面', router.asPath)
})
}
} }
} },
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000) siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
} }
}, [post]) }, [post])
return ( return (
<> <>
{lock && <ArticleLock validPassword={validPassword} />}
{lock && <ArticleLock validPassword={validPassword} />} {!lock && (
<div className='px-2 my-16 max-w-6xl mx-auto'>
{!lock && <div id="article-wrapper" className="px-2 my-16 max-w-6xl mx-auto"> <>
<> <ArticleInfo post={post} />
<ArticleInfo post={post} /> <div id='article-wrapper'>
<NotionPage post={post} /> <NotionPage post={post} />
<ShareBar post={post} /> </div>
<Comment frontMatter={post} /> <ShareBar post={post} />
<ArticleFooter /> <Comment frontMatter={post} />
</> <ArticleFooter />
</div>} </>
</div>
</> )}
</>
) )
} }
@@ -204,10 +220,8 @@ const LayoutSlug = props => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const Layout404 = (props) => { const Layout404 = props => {
return <> return <>404 Not found.</>
404 Not found.
</>
} }
/** /**
@@ -215,28 +229,31 @@ const Layout404 = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutCategoryIndex = (props) => { const LayoutCategoryIndex = props => {
const { categoryOptions } = props const { categoryOptions } = props
return ( return (
<> <>
<div id='category-list' className='duration-200 flex flex-wrap'> <div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => { {categoryOptions?.map(category => {
return ( return (
<Link <Link
key={category.name} key={category.name}
href={`/category/${category.name}`} href={`/category/${category.name}`}
passHref passHref
legacyBehavior> legacyBehavior>
<div <div
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}> className={
<i className='mr-4 fas fa-folder' />{category.name}({category.count}) 'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'
</div> }>
</Link> <i className='mr-4 fas fa-folder' />
) {category.name}({category.count})
})} </div>
</div> </Link>
</> )
})}
</div>
</>
) )
} }
@@ -245,37 +262,43 @@ const LayoutCategoryIndex = (props) => {
* @param {*} props * @param {*} props
* @returns * @returns
*/ */
const LayoutTagIndex = (props) => { const LayoutTagIndex = props => {
const { tagOptions } = props const { tagOptions } = props
return ( return (
<> <>
<div> <div>
<div id='tags-list' className='duration-200 flex flex-wrap'> <div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => { {tagOptions.map(tag => {
return ( return (
<div key={tag.name} className='p-2'> <div key={tag.name} className='p-2'>
<Link key={tag} href={`/tag/${encodeURIComponent(tag.name)}`} passHref <Link
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`}> key={tag}
<div className='font-light dark:text-gray-400'><i className='mr-1 fas fa-tag' /> {tag.name + (tag.count ? `(${tag.count})` : '')} </div> href={`/tag/${encodeURIComponent(tag.name)}`}
</Link> passHref
</div> 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`}>
) <div className='font-light dark:text-gray-400'>
})} <i className='mr-1 fas fa-tag' />{' '}
</div> {tag.name + (tag.count ? `(${tag.count})` : '')}{' '}
</div> </div>
</> </Link>
</div>
)
})}
</div>
</div>
</>
) )
} }
export { export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404, Layout404,
LayoutPostList, LayoutArchive,
LayoutBase,
LayoutCategoryIndex, LayoutCategoryIndex,
LayoutTagIndex LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
} }

View File

@@ -224,9 +224,7 @@ const LayoutSlug = props => {
<> <>
{lock && <ArticleLock validPassword={validPassword} />} {lock && <ArticleLock validPassword={validPassword} />}
<div <div className={`px-2 ${fullWidth ? '' : 'xl:max-w-4xl 2xl:max-w-6xl'}`}>
id='article-wrapper'
className={`px-2 ${fullWidth ? '' : 'xl:max-w-4xl 2xl:max-w-6xl'}`}>
{/* 文章信息 */} {/* 文章信息 */}
<ArticleInfo post={post} /> <ArticleInfo post={post} />
@@ -234,8 +232,10 @@ const LayoutSlug = props => {
{/* <AdSlot type={'in-article'} /> */} {/* <AdSlot type={'in-article'} /> */}
<WWAds orientation='horizontal' className='w-full' /> <WWAds orientation='horizontal' className='w-full' />
{/* Notion文章主体 */} <div id='article-wrapper'>
{!lock && <NotionPage post={post} />} {/* Notion文章主体 */}
{!lock && <NotionPage post={post} />}
</div>
{/* 分享 */} {/* 分享 */}
<ShareBar post={post} /> <ShareBar post={post} />

View File

@@ -143,8 +143,8 @@ const LayoutSlug = props => {
<Banner title={post?.title} description={post?.summary} /> <Banner title={post?.title} description={post?.summary} />
<div className='container grow'> <div className='container grow'>
<div className='flex flex-wrap justify-center -mx-4'> <div className='flex flex-wrap justify-center -mx-4'>
<div className='w-full p-4'> <div id='container-inner' className='w-full p-4'>
<div id='container-inner' className='mx-auto'> <div id='article-wrapper' className='mx-auto'>
<NotionPage {...props} /> <NotionPage {...props} />
</div> </div>
</div> </div>