Files
NotionNext/themes/typography/index.js
Blackberry009 a8192e0179 feat: 优化css
2025-06-09 17:46:08 +08:00

375 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { AdSlot } from '@/components/GoogleAdsense'
import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { 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 } from 'react'
import BlogPostBar from './components/BlogPostBar'
import CONFIG from './config'
import { Style } from './style'
import Catalog from './components/Catalog'
const AlgoliaSearchModal = dynamic(
() => import('@/components/AlgoliaSearchModal'),
{ ssr: false }
)
// 主题组件
const BlogArchiveItem = dynamic(() => import('./components/BlogArchiveItem'), {
ssr: false
})
const ArticleLock = dynamic(() => import('./components/ArticleLock'), {
ssr: false
})
const ArticleInfo = dynamic(() => import('./components/ArticleInfo'), {
ssr: false
})
const Comment = dynamic(() => import('@/components/Comment'), { ssr: false })
const ArticleAround = dynamic(() => import('./components/ArticleAround'), {
ssr: false
})
const TopBar = dynamic(() => import('./components/TopBar'), { ssr: false })
const NavBar = dynamic(() => import('./components/NavBar'), { ssr: false })
const JumpToTopButton = dynamic(() => import('./components/JumpToTopButton'), {
ssr: false
})
const Footer = dynamic(() => import('./components/Footer'), { ssr: false })
const SearchInput = dynamic(() => import('./components/SearchInput'), {
ssr: false
})
const WWAds = dynamic(() => import('@/components/WWAds'), { ssr: false })
const BlogListPage = dynamic(() => import('./components/BlogListPage'), {
ssr: false
})
const RecommendPosts = dynamic(() => import('./components/RecommendPosts'), {
ssr: false
})
// 主题全局状态
const ThemeGlobalSimple = createContext()
export const useSimpleGlobal = () => useContext(ThemeGlobalSimple)
/**
* 基础布局
*
* @param {*} props
* @returns
*/
const LayoutBase = props => {
const { children, slotTop } = props
// const { onLoading, fullWidth } = useGlobal()
const onLoading = true
const searchModal = useRef(null)
console.log('aa', props)
return (
<ThemeGlobalSimple.Provider value={{ searchModal }}>
<div
id='theme-typography'
className={`${siteConfig('FONT_STYLE')} font-typography h-screen flex flex-col dark:text-gray-300 bg-white dark:bg-black overflow-hidden`}>
<Style />
{siteConfig('SIMPLE_TOP_BAR', null, CONFIG) && <TopBar {...props} />}
<div className='flex flex-1 mx-auto overflow-hidden p-8 md:p-0 md:max-w-7xl md:w-8/12 w-screen'>
{/* 主体 - 使用 flex 布局 */}
{/* 文章详情才显示 */}
{props.post && (
<div className='mt-20 hidden md:block'>
<Catalog {...props} />
</div>
)}
<div className='overflow-hidden mt-20'>
{/* 左侧内容区域 - 可滚动 */}
<div
id='container-inner'
className='flex-1 h-full w-full px-24 overflow-y-auto scroll-hidden'>
{/* 移动端导航 - 显示在顶部 */}
<div className='md:hidden'>
<NavBar {...props} />
</div>
<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}>
{slotTop}
{children}
</Transition>
{onLoading && (
<div className="flex flex-col justify-center items-center min-h-[50vh]">
<div className="flex space-x-2">
<div className="w-2 h-2 bg-gray-500 dark:bg-gray-300 rounded-full animate-bounce [animation-delay:-0.3s]"></div>
<div className="w-2 h-2 bg-gray-500 dark:bg-gray-300 rounded-full animate-bounce [animation-delay:-0.15s]"></div>
<div className="w-2 h-2 bg-gray-500 dark:bg-gray-300 rounded-full animate-bounce"></div>
</div>
<div className="text-xl font-medium text-gray-600 dark:text-gray-300">别着急坐和放宽</div>
</div>
)}
<AdSlot type='native' />
{/* 移动端页脚 - 显示在底部 */}
<div className='md:hidden z-30 dark:bg-black'>
<Footer {...props} />
</div>
</div>
</div>
{/* 右侧导航和页脚 - 固定不滚动 */}
<div className='hidden md:flex md:flex-col md:flex-shrink-0 md:h-[100vh] sticky top-20'>
<NavBar {...props} />
<Footer {...props} />
</div>
</div>
<div className='fixed right-4 bottom-4 z-20'>
<JumpToTopButton />
</div>
{/* 搜索框 */}
<AlgoliaSearchModal cRef={searchModal} {...props} />
</div>
</ThemeGlobalSimple.Provider>
)
}
/**
* 博客首页
* 首页就是列表
* @param {*} props
* @returns
*/
const LayoutIndex = props => {
return <LayoutPostList {...props} />
}
/**
* 博客列表
* @param {*} props
* @returns
*/
const LayoutPostList = props => {
return (
<>
<BlogPostBar {...props} />
<BlogListPage {...props} />
</>
)
}
/**
* 搜索页
* 也是博客列表
* @param {*} props
* @returns
*/
const LayoutSearch = props => {
const { keyword } = props
useEffect(() => {
if (isBrowser) {
replaceSearchResult({
doms: document.getElementById('posts-wrapper'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
}
})
}
}, [])
const slotTop = siteConfig('ALGOLIA_APP_ID') ? null : (
<SearchInput {...props} />
)
return <LayoutPostList {...props} slotTop={slotTop} />
}
/**
* 归档页
* @param {*} props
* @returns
*/
const LayoutArchive = props => {
const { archivePosts } = props
return (
<>
<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}
/>
))}
</div>
</>
)
}
/**
* 文章详情
* @param {*} props
* @returns
*/
const LayoutSlug = props => {
const { post, lock, validPassword, prev, next, recommendPosts } = props
const { fullWidth } = useGlobal()
return (
<>
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && post && (
<div
className={`px-2 pt-3 ${fullWidth ? '' : 'xl:max-w-4xl 2xl:max-w-6xl'}`}>
{/* 文章信息 */}
<ArticleInfo post={post} />
{/* 广告嵌入 */}
{/* <AdSlot type={'in-article'} /> */}
<WWAds orientation='horizontal' className='w-full' />
<div id='article-wrapper'>
{/* Notion 文章主体 */}
{!lock && <NotionPage post={post} />}
</div>
{/* 分享 */}
{/* <ShareBar post={post} /> */}
{/* 广告嵌入 */}
<AdSlot type={'in-article'} />
{post?.type === 'Post' && (
<>
<ArticleAround prev={prev} next={next} />
<RecommendPosts recommendPosts={recommendPosts} />
</>
)}
{/* 评论区 */}
<Comment frontMatter={post} />
</div>
)}
</>
)
}
/**
* 404
* @param {*} props
* @returns
*/
const Layout404 = props => {
const { post } = props
const router = useRouter()
const waiting404 = siteConfig('POST_WAITING_TIME_FOR_404') * 1000
useEffect(() => {
// 404
if (!post) {
setTimeout(() => {
if (isBrowser) {
const article = document.querySelector(
'#article-wrapper #notion-article'
)
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
}
}
}, waiting404)
}
}, [post])
return <>404 Not found.</>
}
/**
* 分类列表
* @param {*} props
* @returns
*/
const LayoutCategoryIndex = props => {
const { categoryOptions } = props
return (
<>
<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>
</>
)
}
/**
* 标签列表
* @param {*} props
* @returns
*/
const LayoutTagIndex = props => {
const { tagOptions } = props
return (
<>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => {
return (
<div key={tag.name} className='p-2'>
<Link
key={tag}
href={`/tag/${encodeURIComponent(tag.name)}`}
passHref
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' />{' '}
{tag.name + (tag.count ? `(${tag.count})` : '')}{' '}
</div>
</Link>
</div>
)
})}
</div>
</>
)
}
export {
Layout404,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
}