mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-13 23:16:47 +00:00
theme-heo-framework
This commit is contained in:
@@ -14,17 +14,16 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
|
||||
// const delay = (index % 2) * 200
|
||||
|
||||
return (
|
||||
|
||||
<div className={`${CONFIG.POST_LIST_COVER_HOVER_ENLARGE ? ' hover:scale-110 transition-all duration-150' : ''}`} >
|
||||
<div
|
||||
data-aos="fade-up"
|
||||
data-aos-easing="ease-in-out"
|
||||
data-aos-duration="800"
|
||||
data-aos-once="false"
|
||||
data-aos-anchor-placement="top-bottom"
|
||||
// data-aos="fade-up"
|
||||
// data-aos-easing="ease-in-out"
|
||||
// data-aos-duration="800"
|
||||
// data-aos-once="false"
|
||||
// data-aos-anchor-placement="top-bottom"
|
||||
id='blog-post-card'
|
||||
key={post.id}
|
||||
className={`md:h-56 w-full flex justify-between md:flex-row flex-col-reverse ${CONFIG.POST_LIST_IMG_CROSSOVER && index % 2 === 1 ? 'md:flex-row-reverse' : ''}
|
||||
className={`w-full justify-between flex flex-col-reverse lg:h-96 ${CONFIG.POST_LIST_IMG_CROSSOVER && index % 2 === 1 ? '' : ''}
|
||||
overflow-hidden border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray`}>
|
||||
|
||||
{/* 文字内容 */}
|
||||
@@ -32,7 +31,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
|
||||
|
||||
{/* 图片封面 */}
|
||||
{showPageCover && (
|
||||
<div className="md:w-5/12 overflow-hidden">
|
||||
<div className="md:w-5/12 lg:w-full overflow-hidden">
|
||||
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
|
||||
<div className='h-56 bg-center bg-cover hover:scale-110 duration-200' style={{ backgroundImage: `url('${post?.pageCoverThumbnail}')` }} />
|
||||
</Link>
|
||||
|
||||
@@ -20,7 +20,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
return (
|
||||
<div id="container" className='w-full'>
|
||||
{/* 文章列表 */}
|
||||
<div className="space-y-6 px-2">
|
||||
<div className="lg:grid lg:grid-cols-2">
|
||||
{posts?.map(post => (
|
||||
<BlogPostCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo}/>
|
||||
))}
|
||||
|
||||
9
themes/heo/components/CategoryBar.js
Normal file
9
themes/heo/components/CategoryBar.js
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
/**
|
||||
* 博客列表上方嵌入条
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
export default function CategoryBar(props) {
|
||||
return <div id='category-list' className="h-24 w-full bg-pink-100"></div>
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import React from 'react'
|
||||
import BLOG from '@/blog.config'
|
||||
import SocialButton from './SocialButton'
|
||||
// import DarkModeButton from '@/components/DarkModeButton'
|
||||
|
||||
const Footer = ({ title }) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function() {
|
||||
const copyrightDate = (function () {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
@@ -13,23 +14,36 @@ const Footer = ({ title }) => {
|
||||
})()
|
||||
|
||||
return (
|
||||
<footer
|
||||
className='relative z-10 dark:bg-black flex-shrink-0 bg-hexo-light-gray justify-center text-center m-auto w-full leading-6 text-gray-600 dark:text-gray-100 text-sm p-6'
|
||||
>
|
||||
{/* <DarkModeButton/> */}
|
||||
<footer
|
||||
className='relative z-10 flex-shrink-0 bg-white justify-center text-center m-auto w-full leading-6 text-gray-600 dark:text-gray-100 text-sm'
|
||||
>
|
||||
|
||||
<i className='fas fa-copyright' /> {`${copyrightDate}`} <span><i className='mx-1 animate-pulse fas fa-heart'/> <a href={BLOG.LINK} className='underline font-bold dark:text-gray-300 '>{BLOG.AUTHOR}</a>.<br/>
|
||||
<div id='color-transition' className='h-32 bg-gradient-to-b from-[#f7f9fe] to-white '>
|
||||
|
||||
{BLOG.BEI_AN && <><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
||||
</div>
|
||||
<div className='w-full h-24'>
|
||||
<SocialButton />
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<h1 className='text-xs pt-4 text-light-400 dark:text-gray-400'>{title} | {BLOG.BIO}</h1>
|
||||
<p className='text-xs pt-2 text-light-500 dark:text-gray-500'>Powered by <a href='https://github.com/tangly1024/NotionNext' className='dark:text-gray-300'>NotionNext {BLOG.VERSION}</a>.</p></span><br/>
|
||||
<br />
|
||||
|
||||
</footer>
|
||||
<div id='footer-bottom' className='w-full h-20 flex justify-between px-6 items-center bg-[#f1f3f7]'>
|
||||
<div id='footer-bottom-left'>
|
||||
<i className='fas fa-copyright' /> {`${copyrightDate}`} <i className='mx-1 animate-pulse fas fa-heart' /> <a href={BLOG.LINK} className='underline font-bold dark:text-gray-300 '>{BLOG.AUTHOR}</a>.
|
||||
</div>
|
||||
|
||||
<div id='footer-bottom-right'>
|
||||
{BLOG.BEI_AN && <><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a></>}
|
||||
|
||||
<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>
|
||||
<h1 className='text-xs text-light-400 dark:text-gray-400'>{title} | {BLOG.BIO}</h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,82 +1,82 @@
|
||||
// import Image from 'next/image'
|
||||
import { useEffect, useState } from 'react'
|
||||
import Typed from 'typed.js'
|
||||
import CONFIG from '../config'
|
||||
import NavButtonGroup from './NavButtonGroup'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import Logo from './Logo'
|
||||
import SearchDrawer from './SearchDrawer'
|
||||
|
||||
let wrapperTop = 0
|
||||
import { MenuListTop } from './MenuListTop'
|
||||
import throttle from 'lodash.throttle'
|
||||
import SideBar from './SideBar'
|
||||
import SideBarDrawer from './SideBarDrawer'
|
||||
|
||||
/**
|
||||
* 顶部全屏大图
|
||||
* 顶部导航
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
const Hero = props => {
|
||||
const [typed, changeType] = useState()
|
||||
const { siteInfo } = props
|
||||
const { locale } = useGlobal()
|
||||
const scrollToWrapper = () => {
|
||||
window.scrollTo({ top: wrapperTop, behavior: 'smooth' })
|
||||
const Header = props => {
|
||||
const searchDrawer = useRef()
|
||||
|
||||
const [isOpen, changeShow] = useState(false)
|
||||
const [headerBgShow, setHeaderBgShow] = useState(false)
|
||||
|
||||
const toggleMenuOpen = () => {
|
||||
changeShow(!isOpen)
|
||||
}
|
||||
|
||||
const toggleSideBarClose = () => {
|
||||
changeShow(false)
|
||||
}
|
||||
|
||||
// 监听滚动
|
||||
useEffect(() => {
|
||||
updateHeaderHeight()
|
||||
|
||||
if (!typed && window && document.getElementById('typed')) {
|
||||
changeType(
|
||||
new Typed('#typed', {
|
||||
strings: BLOG.GREETING_WORDS.split(','),
|
||||
typeSpeed: 200,
|
||||
backSpeed: 100,
|
||||
backDelay: 400,
|
||||
showCursor: true,
|
||||
smartBackspace: true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
window.addEventListener('resize', updateHeaderHeight)
|
||||
scrollTrigger()
|
||||
window.addEventListener('scroll', scrollTrigger)
|
||||
return () => {
|
||||
window.removeEventListener('resize', updateHeaderHeight)
|
||||
window.removeEventListener('scroll', scrollTrigger)
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
function updateHeaderHeight() {
|
||||
requestAnimationFrame(() => {
|
||||
const wrapperElement = document.getElementById('wrapper')
|
||||
wrapperTop = wrapperElement?.offsetTop
|
||||
})
|
||||
}
|
||||
const throttleMs = 200
|
||||
|
||||
return (
|
||||
<header
|
||||
id="header" style={{ zIndex: 1 }}
|
||||
className="w-full h-screen relative bg-black"
|
||||
>
|
||||
/**
|
||||
* 根据滚动条,切换导航栏样式
|
||||
*/
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY
|
||||
const header = document.querySelector('#header')
|
||||
|
||||
<div className="text-white absolute bottom-0 flex flex-col h-full items-center justify-center w-full ">
|
||||
{/* 站点标题 */}
|
||||
<div className='font-black text-4xl md:text-5xl shadow-text'>{siteInfo?.title}</div>
|
||||
{/* 站点欢迎语 */}
|
||||
<div className='mt-2 h-12 items-center text-center font-medium shadow-text text-lg'>
|
||||
<span id='typed' />
|
||||
// 导航栏设置 白色背景
|
||||
if (header && scrollS > 60) {
|
||||
setHeaderBgShow(true)
|
||||
} else {
|
||||
setHeaderBgShow(false)
|
||||
}
|
||||
}, throttleMs))
|
||||
|
||||
return (<div id='header' className='z-40'>
|
||||
<SearchDrawer cRef={searchDrawer} />
|
||||
|
||||
{/* 导航栏 */}
|
||||
<div id='sticky-nav' className={`${headerBgShow ? 'bg-white border-b' : 'bg-none'} top-0 duration-300 transition-all fixed text-black w-full z-20 transform`}>
|
||||
<div className='w-full max-w-7xl mx-auto flex justify-between items-center py-2 px-5'>
|
||||
<div className='flex'>
|
||||
<Logo {...props} />
|
||||
</div>
|
||||
|
||||
{/* 首页导航大按钮 */}
|
||||
{CONFIG.HOME_NAV_BUTTONS && <NavButtonGroup {...props} />}
|
||||
|
||||
{/* 滚动按钮 */}
|
||||
<div onClick={scrollToWrapper} className="z-10 cursor-pointer w-full text-center py-4 text-3xl absolute bottom-10 text-white">
|
||||
<div className="opacity-70 animate-bounce text-xs">{locale.COMMON.START_READING}</div>
|
||||
<i className='opacity-70 animate-bounce fas fa-angle-down' />
|
||||
{/* 右侧功能 */}
|
||||
<div className='mr-1 justify-end items-center '>
|
||||
<div className='hidden lg:flex'> <MenuListTop {...props} /></div>
|
||||
<div onClick={toggleMenuOpen} className='w-8 justify-center items-center h-8 cursor-pointer flex lg:hidden'>
|
||||
{isOpen ? <i className='fas fa-times' /> : <i className='fas fa-bars' />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='header-cover' style={{ backgroundImage: `url('${siteInfo?.pageCover}')` }}
|
||||
className={`header-cover bg-center w-full h-screen bg-cover ${CONFIG.HOME_NAV_BACKGROUND_IMG_FIXED ? 'bg-fixed' : ''}`} />
|
||||
|
||||
</header>
|
||||
)
|
||||
{/* 折叠侧边栏 */}
|
||||
<SideBarDrawer isOpen={isOpen} onClose={toggleSideBarClose}>
|
||||
<SideBar {...props} />
|
||||
</SideBarDrawer>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default Hero
|
||||
export default Header
|
||||
|
||||
29
themes/heo/components/Hero.js
Normal file
29
themes/heo/components/Hero.js
Normal file
@@ -0,0 +1,29 @@
|
||||
// import Image from 'next/image'
|
||||
|
||||
/**
|
||||
* 顶部全屏大图
|
||||
* @returns
|
||||
*/
|
||||
const Hero = props => {
|
||||
return (
|
||||
<div className="mt-16">
|
||||
|
||||
<notice className="max-w-7xl w-full mx-auto flex h-20 px-5">
|
||||
<div className="bg-indigo-100 w-full h-full"></div>
|
||||
</notice>
|
||||
|
||||
<hero id="hero" style={{ zIndex: 1 }} className="max-w-7xl w-full mx-auto flex relative px-5" >
|
||||
<div id='hero-left' className='flex flex-col flex-1 bg-red-200'>
|
||||
<div className="h-60 bg-blue-200"></div>
|
||||
<div className="h-24 bg-yellow-100"></div>
|
||||
</div>
|
||||
<div id='hero-right' className='flex flex-col flex-1 bg-green-200'>
|
||||
|
||||
</div>
|
||||
</hero>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Hero
|
||||
@@ -6,8 +6,10 @@ const Logo = props => {
|
||||
const { siteInfo } = props
|
||||
return (
|
||||
<Link href='/' passHref legacyBehavior>
|
||||
<div className='flex flex-col justify-center items-center cursor-pointer space-y-3'>
|
||||
<div className='font-medium text-lg p-1.5 rounded dark:border-white menu-link transform duration-200'> {siteInfo?.title || BLOG.TITLE}</div>
|
||||
<div className='flex justify-center items-center cursor-pointer'>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={siteInfo?.icon} width={24} height={24} alt={BLOG.AUTHOR} className='mr-2 hidden md:block' />
|
||||
<div className='font-medium text-lg my-auto rounded dark:border-white transform duration-200'> {siteInfo?.title || BLOG.TITLE}</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useGlobal } from '@/lib/global'
|
||||
import BLOG from '@/blog.config'
|
||||
import NotionIcon from '@/components/NotionIcon'
|
||||
|
||||
export default function HeaderArticle({ post, siteInfo }) {
|
||||
export default function PostHeader({ post, siteInfo }) {
|
||||
const { locale } = useGlobal()
|
||||
|
||||
if (!post) {
|
||||
@@ -1,18 +1,11 @@
|
||||
import Card from './Card'
|
||||
import CategoryGroup from './CategoryGroup'
|
||||
import LatestPostsGroup from './LatestPostsGroup'
|
||||
import TagGroups from './TagGroups'
|
||||
import Catalog from './Catalog'
|
||||
import { InfoCard } from './InfoCard'
|
||||
import { AnalyticsCard } from './AnalyticsCard'
|
||||
import CONFIG from '../config'
|
||||
import BLOG from '@/blog.config'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Announcement from './Announcement'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import Live2D from '@/components/Live2D'
|
||||
|
||||
const HexoRecentComments = dynamic(() => import('./HexoRecentComments'))
|
||||
const FaceBookPage = dynamic(
|
||||
() => {
|
||||
let facebook = <></>
|
||||
@@ -33,50 +26,36 @@ const FaceBookPage = dynamic(
|
||||
*/
|
||||
export default function SideRight(props) {
|
||||
const {
|
||||
post, currentCategory, categories, latestPosts, tags,
|
||||
currentTag, showCategory, showTag, rightAreaSlot, notice
|
||||
post, tagOptions,
|
||||
currentTag, rightAreaSlot, notice
|
||||
} = props
|
||||
|
||||
const { locale } = useGlobal()
|
||||
console.log('props', props)
|
||||
return (
|
||||
<div id='sideRight' className={'space-y-4 lg:w-80 lg:pt-0 px-2 pt-4'}>
|
||||
<InfoCard {...props} />
|
||||
{CONFIG.WIDGET_ANALYTICS && <AnalyticsCard {...props} />}
|
||||
<div id='sideRight' className='w-72'>
|
||||
|
||||
{showCategory && (
|
||||
<Card>
|
||||
<div className='ml-2 mb-1 '>
|
||||
<i className='fas fa-th' /> {locale.COMMON.CATEGORY}
|
||||
</div>
|
||||
<CategoryGroup
|
||||
currentCategory={currentCategory}
|
||||
categories={categories}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
{showTag && (
|
||||
<Card>
|
||||
<TagGroups tags={tags} currentTag={currentTag} />
|
||||
</Card>
|
||||
)}
|
||||
{CONFIG.WIDGET_LATEST_POSTS && latestPosts && latestPosts.length > 0 && <Card>
|
||||
<LatestPostsGroup {...props} />
|
||||
</Card>}
|
||||
<InfoCard {...props} className='w-72' />
|
||||
|
||||
<Announcement post={notice}/>
|
||||
<Card>
|
||||
<div>Join Us</div>
|
||||
</Card>
|
||||
|
||||
{BLOG.COMMENT_WALINE_SERVER_URL && BLOG.COMMENT_WALINE_RECENT && <HexoRecentComments/>}
|
||||
<Card>
|
||||
<TagGroups tags={tagOptions} currentTag={currentTag} />
|
||||
</Card>
|
||||
|
||||
<div className='sticky top-20'>
|
||||
{post && post.toc && post.toc.length > 1 && <Card>
|
||||
<Catalog toc={post.toc} />
|
||||
</Card>}
|
||||
<Announcement post={notice} />
|
||||
|
||||
{rightAreaSlot}
|
||||
<FaceBookPage/>
|
||||
<Live2D />
|
||||
</div>
|
||||
<div className='sticky top-20'>
|
||||
{post && post.toc && post.toc.length > 1 && <Card>
|
||||
<Catalog toc={post.toc} />
|
||||
</Card>}
|
||||
|
||||
</div>
|
||||
{rightAreaSlot}
|
||||
<FaceBookPage />
|
||||
<Live2D />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 博客列表上方嵌入条
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
export default function SlotBar(props) {
|
||||
const { tag, category } = props
|
||||
|
||||
if (tag) {
|
||||
return <div className="cursor-pointer px-3 py-2 mb-2 font-light hover:text-indigo-700 dark:hover:text-indigo-400 transform dark:text-white">
|
||||
<Link key={tag} href={`/tag/${encodeURIComponent(tag.name)}`} passHref
|
||||
className={'cursor-pointer inline-block rounded duration-200 mr-2 py-0.5 px-1 text-xl whitespace-nowrap '}>
|
||||
<div className='font-light dark:text-gray-400 dark:hover:text-white'> #{tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||
</Link>
|
||||
</div>
|
||||
} else if (category) {
|
||||
return <div className="cursor-pointer text-lg px-5 py-1 mb-2 font-light hover:text-indigo-700 dark:hover:text-indigo-400 transform dark:text-white">
|
||||
<i className="mr-1 far fa-folder-open" /> {category}
|
||||
</div>
|
||||
}
|
||||
return <></>
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import React from 'react'
|
||||
*/
|
||||
const SocialButton = () => {
|
||||
return <div className='w-full justify-center flex-wrap flex'>
|
||||
<div className='space-x-3 text-xl text-gray-600 dark:text-gray-300 '>
|
||||
<div className='space-x-12 text-3xl text-gray-600 dark:text-gray-300 '>
|
||||
{BLOG.CONTACT_GITHUB && <a target='_blank' rel='noreferrer' title={'github'} href={BLOG.CONTACT_GITHUB} >
|
||||
<i className='transform hover:scale-125 duration-150 fab fa-github dark:hover:text-indigo-400 hover:text-indigo-600'/>
|
||||
</a>}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import Link from 'next/link'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import CategoryGroup from './CategoryGroup'
|
||||
import Logo from './Logo'
|
||||
import SearchDrawer from './SearchDrawer'
|
||||
import TagGroups from './TagGroups'
|
||||
import { MenuListTop } from './MenuListTop'
|
||||
import { useRouter } from 'next/router'
|
||||
import throttle from 'lodash.throttle'
|
||||
import SideBar from './SideBar'
|
||||
import SideBarDrawer from './SideBarDrawer'
|
||||
|
||||
let windowTop = 0
|
||||
|
||||
/**
|
||||
* 顶部导航
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
const TopNav = props => {
|
||||
const searchDrawer = useRef()
|
||||
const { tags, currentTag, categories, currentCategory } = props
|
||||
const { locale } = useGlobal()
|
||||
const { isDarkMode } = useGlobal()
|
||||
const router = useRouter()
|
||||
|
||||
const [isOpen, changeShow] = useState(false)
|
||||
|
||||
const toggleMenuOpen = () => {
|
||||
changeShow(!isOpen)
|
||||
}
|
||||
|
||||
const toggleSideBarClose = () => {
|
||||
changeShow(false)
|
||||
}
|
||||
|
||||
// 监听滚动
|
||||
useEffect(() => {
|
||||
scrollTrigger()
|
||||
window.addEventListener('scroll', scrollTrigger)
|
||||
return () => {
|
||||
window.removeEventListener('scroll', scrollTrigger)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const throttleMs = 200
|
||||
|
||||
const scrollTrigger = useCallback(throttle(() => {
|
||||
const scrollS = window.scrollY
|
||||
const nav = document.querySelector('#sticky-nav')
|
||||
const header = document.querySelector('#header')
|
||||
// 是否将导航栏透明
|
||||
const navTransparent = (scrollS < document.documentElement.clientHeight - 12 && router.route === '/') || scrollS < 300 // 透明导航条的条件
|
||||
|
||||
if (header && navTransparent) {
|
||||
nav && nav.classList.replace('bg-white', 'bg-none')
|
||||
nav && nav.classList.replace('text-black', 'text-white')
|
||||
nav && nav.classList.replace('border', 'border-transparent')
|
||||
nav && nav.classList.replace('drop-shadow-md', 'shadow-none')
|
||||
nav && nav.classList.replace('dark:bg-hexo-black-gray', 'transparent')
|
||||
} else {
|
||||
nav && nav.classList.replace('bg-none', 'bg-white')
|
||||
nav && nav.classList.replace('text-white', 'text-black')
|
||||
nav && nav.classList.replace('border-transparent', 'border')
|
||||
nav && nav.classList.replace('shadow-none', 'drop-shadow-md')
|
||||
nav && nav.classList.replace('transparent', 'dark:bg-hexo-black-gray')
|
||||
}
|
||||
|
||||
const showNav = scrollS <= windowTop || scrollS < 5 || (header && scrollS <= header.clientHeight)// 非首页无大图时影藏顶部 滚动条置顶时隐藏
|
||||
if (!showNav) {
|
||||
nav && nav.classList.replace('top-0', '-top-20')
|
||||
windowTop = scrollS
|
||||
} else {
|
||||
nav && nav.classList.replace('-top-20', 'top-0')
|
||||
windowTop = scrollS
|
||||
}
|
||||
navDarkMode()
|
||||
}, throttleMs)
|
||||
)
|
||||
|
||||
const navDarkMode = () => {
|
||||
const nav = document.getElementById('sticky-nav')
|
||||
const header = document.querySelector('#header')
|
||||
if (!isDarkMode && nav && header) {
|
||||
if (window.scrollY < header.clientHeight) {
|
||||
nav?.classList?.add('dark')
|
||||
} else {
|
||||
nav?.classList?.remove('dark')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const searchDrawerSlot = <>
|
||||
{categories && (
|
||||
<section className='mt-8'>
|
||||
<div className='text-sm flex flex-nowrap justify-between font-light px-2'>
|
||||
<div className='text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-th-list' />{locale.COMMON.CATEGORY}</div>
|
||||
<Link
|
||||
href={'/category'}
|
||||
passHref
|
||||
className='mb-3 text-gray-400 hover:text-black dark:text-gray-400 dark:hover:text-white hover:underline cursor-pointer'>
|
||||
|
||||
{locale.COMMON.MORE} <i className='fas fa-angle-double-right' />
|
||||
|
||||
</Link>
|
||||
</div>
|
||||
<CategoryGroup currentCategory={currentCategory} categories={categories} />
|
||||
</section>
|
||||
)}
|
||||
|
||||
{tags && (
|
||||
<section className='mt-4'>
|
||||
<div className='text-sm py-2 px-2 flex flex-nowrap justify-between font-light dark:text-gray-200'>
|
||||
<div className='text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-tag' />{locale.COMMON.TAGS}</div>
|
||||
<Link
|
||||
href={'/tag'}
|
||||
passHref
|
||||
className='text-gray-400 hover:text-black dark:hover:text-white hover:underline cursor-pointer'>
|
||||
|
||||
{locale.COMMON.MORE} <i className='fas fa-angle-double-right' />
|
||||
|
||||
</Link>
|
||||
</div>
|
||||
<div className='p-2'>
|
||||
<TagGroups tags={tags} currentTag={currentTag} />
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</>
|
||||
|
||||
return (<div id='top-nav' className='z-40'>
|
||||
<SearchDrawer cRef={searchDrawer} slot={searchDrawerSlot} />
|
||||
|
||||
{/* 导航栏 */}
|
||||
<div id='sticky-nav' style={{ backdropFilter: 'blur(3px)' }} className={'top-0 duration-300 transition-all shadow-none fixed bg-none dark:bg-hexo-black-gray dark:text-gray-200 text-black w-full z-20 transform border-transparent dark:border-transparent'}>
|
||||
<div className='w-full flex justify-between items-center px-4 py-2'>
|
||||
<div className='flex'>
|
||||
<Logo {...props} />
|
||||
</div>
|
||||
|
||||
{/* 右侧功能 */}
|
||||
<div className='mr-1 justify-end items-center '>
|
||||
<div className='hidden lg:flex'> <MenuListTop {...props} /></div>
|
||||
<div onClick={toggleMenuOpen} className='w-8 justify-center items-center h-8 cursor-pointer flex lg:hidden'>
|
||||
{isOpen ? <i className='fas fa-times' /> : <i className='fas fa-bars' />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 折叠侧边栏 */}
|
||||
<SideBarDrawer isOpen={isOpen} onClose={toggleSideBarClose}>
|
||||
<SideBar {...props} />
|
||||
</SideBarDrawer>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default TopNav
|
||||
@@ -4,21 +4,20 @@ import CommonHead from '@/components/CommonHead'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import Footer from './components/Footer'
|
||||
import SideRight from './components/SideRight'
|
||||
import TopNav from './components/TopNav'
|
||||
import Header from './components/Header'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BLOG from '@/blog.config'
|
||||
import { isBrowser, loadExternalResource } from '@/lib/utils'
|
||||
import BlogPostListPage from './components/BlogPostListPage'
|
||||
import BlogPostListScroll from './components/BlogPostListScroll'
|
||||
import Hero from './components/Header'
|
||||
import Hero from './components/Hero'
|
||||
import { useRouter } from 'next/router'
|
||||
import Mark from 'mark.js'
|
||||
import Card from './components/Card'
|
||||
import RightFloatArea from './components/RightFloatArea'
|
||||
import SearchNav from './components/SearchNav'
|
||||
import BlogPostArchive from './components/BlogPostArchive'
|
||||
import { ArticleLock } from './components/ArticleLock'
|
||||
import HeaderArticle from './components/HeaderArticle'
|
||||
import PostHeader from './components/PostHeader'
|
||||
import JumpToCommentButton from './components/JumpToCommentButton'
|
||||
import TocDrawer from './components/TocDrawer'
|
||||
import TocDrawerButton from './components/TocDrawerButton'
|
||||
@@ -30,7 +29,7 @@ import ArticleRecommend from './components/ArticleRecommend'
|
||||
import ShareBar from '@/components/ShareBar'
|
||||
import TagItemMini from './components/TagItemMini'
|
||||
import Link from 'next/link'
|
||||
import SlotBar from './components/SlotBar'
|
||||
import CategoryBar from './components/CategoryBar'
|
||||
import { Transition } from '@headlessui/react'
|
||||
|
||||
/**
|
||||
@@ -40,7 +39,7 @@ import { Transition } from '@headlessui/react'
|
||||
* @constructor
|
||||
*/
|
||||
const LayoutBase = props => {
|
||||
const { children, headerSlot, floatSlot, slotTop, meta, siteInfo, className } = props
|
||||
const { children, headerSlot, slotTop, meta, siteInfo, className } = props
|
||||
const { onLoading } = useGlobal()
|
||||
|
||||
// 加载主题样式
|
||||
@@ -49,14 +48,14 @@ const LayoutBase = props => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div id='theme-hexo'>
|
||||
<div id='theme-heo' className='bg-[#f7f9fe]'>
|
||||
{/* 网页SEO */}
|
||||
<CommonHead meta={meta} siteInfo={siteInfo} />
|
||||
|
||||
{/* 顶部导航 */}
|
||||
<TopNav {...props} />
|
||||
<Header {...props} />
|
||||
|
||||
{/* 顶部嵌入 */}
|
||||
{/* 顶部嵌入 首页放hero,文章页放大图 */}
|
||||
<Transition
|
||||
show={!onLoading}
|
||||
appear={true}
|
||||
@@ -72,9 +71,9 @@ const LayoutBase = props => {
|
||||
</Transition>
|
||||
|
||||
{/* 主区块 */}
|
||||
<main id="wrapper" className={`${CONFIG.HOME_BANNER_ENABLE ? '' : 'pt-16'} bg-hexo-background-gray dark:bg-black w-full py-8 md:px-8 lg:px-24 min-h-screen relative`}>
|
||||
<main id="wrapper-outer" className={'w-full max-w-7xl mx-auto min-h-screen relative px-5'}>
|
||||
<div id="container-inner" className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'flex-row-reverse' : '') + ' w-full mx-auto lg:flex lg:space-x-4 justify-center relative z-10'} >
|
||||
<div className={`${className || ''} w-full max-w-4xl h-full `}>
|
||||
<div className={`${className || ''} w-full h-full`}>
|
||||
|
||||
<Transition
|
||||
show={!onLoading}
|
||||
@@ -99,9 +98,6 @@ const LayoutBase = props => {
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* 悬浮菜单 */}
|
||||
<RightFloatArea floatSlot={floatSlot} />
|
||||
|
||||
{/* 页脚 */}
|
||||
<Footer title={siteInfo?.title || BLOG.TITLE} />
|
||||
</div>
|
||||
@@ -116,7 +112,7 @@ const LayoutBase = props => {
|
||||
*/
|
||||
const LayoutIndex = (props) => {
|
||||
const headerSlot = CONFIG.HOME_BANNER_ENABLE && <Hero {...props} />
|
||||
return <LayoutPostList {...props} headerSlot={headerSlot} className='pt-8' />
|
||||
return <LayoutPostList {...props} headerSlot={headerSlot}/>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,8 +121,8 @@ const LayoutIndex = (props) => {
|
||||
* @returns
|
||||
*/
|
||||
const LayoutPostList = (props) => {
|
||||
return <LayoutBase {...props} className='pt-8'>
|
||||
<SlotBar {...props} />
|
||||
return <LayoutBase {...props}>
|
||||
<CategoryBar {...props} />
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
||||
</LayoutBase>
|
||||
}
|
||||
@@ -213,7 +209,7 @@ const LayoutSlug = props => {
|
||||
</>
|
||||
|
||||
return (
|
||||
<LayoutBase {...props} headerSlot={<HeaderArticle {...props} />} showCategory={false} showTag={false} floatSlot={floatSlot} >
|
||||
<LayoutBase {...props} headerSlot={<PostHeader {...props} />} showCategory={false} showTag={false} floatSlot={floatSlot} >
|
||||
<div className="w-full lg:hover:shadow lg:border rounded-t-xl lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black article">
|
||||
{lock && <ArticleLock validPassword={validPassword} />}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useGlobal } from '@/lib/global'
|
||||
import BLOG from '@/blog.config'
|
||||
import NotionIcon from '@/components/NotionIcon'
|
||||
|
||||
export default function HeaderArticle({ post, siteInfo }) {
|
||||
export default function PostHeader({ post, siteInfo }) {
|
||||
const { locale } = useGlobal()
|
||||
|
||||
if (!post) {
|
||||
@@ -10,7 +10,7 @@ import BLOG from '@/blog.config'
|
||||
import { isBrowser, loadExternalResource } from '@/lib/utils'
|
||||
import BlogPostListPage from './components/BlogPostListPage'
|
||||
import BlogPostListScroll from './components/BlogPostListScroll'
|
||||
import Hero from './components/Header'
|
||||
import Hero from './components/Hero'
|
||||
import { useRouter } from 'next/router'
|
||||
import Mark from 'mark.js'
|
||||
import Card from './components/Card'
|
||||
@@ -18,7 +18,7 @@ import RightFloatArea from './components/RightFloatArea'
|
||||
import SearchNav from './components/SearchNav'
|
||||
import BlogPostArchive from './components/BlogPostArchive'
|
||||
import { ArticleLock } from './components/ArticleLock'
|
||||
import HeaderArticle from './components/HeaderArticle'
|
||||
import PostHeader from './components/PostHeader'
|
||||
import JumpToCommentButton from './components/JumpToCommentButton'
|
||||
import TocDrawer from './components/TocDrawer'
|
||||
import TocDrawerButton from './components/TocDrawerButton'
|
||||
@@ -213,7 +213,7 @@ const LayoutSlug = props => {
|
||||
</>
|
||||
|
||||
return (
|
||||
<LayoutBase {...props} headerSlot={<HeaderArticle {...props} />} showCategory={false} showTag={false} floatSlot={floatSlot} >
|
||||
<LayoutBase {...props} headerSlot={<PostHeader {...props} />} showCategory={false} showTag={false} floatSlot={floatSlot} >
|
||||
<div className="w-full lg:hover:shadow lg:border rounded-t-xl lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black article">
|
||||
{lock && <ArticleLock validPassword={validPassword} />}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
export default function HeaderArticle({ post, siteInfo }) {
|
||||
/**
|
||||
* 文章背景图
|
||||
*/
|
||||
export default function PostHeader({ post, siteInfo }) {
|
||||
const headerImage = post?.pageCoverThumbnail ? post?.pageCoverThumbnail : siteInfo?.pageCover
|
||||
const title = post?.title
|
||||
return (
|
||||
@@ -17,7 +17,7 @@ import Hero from './components/Hero'
|
||||
import Announcement from './components/Announcement'
|
||||
import CatalogWrapper from './components/CatalogWrapper'
|
||||
import TagItemMiddle from './components/TagItemMiddle'
|
||||
import HeaderArticle from './components/HeaderArticle'
|
||||
import PostHeader from './components/PostHeader'
|
||||
import Link from 'next/link'
|
||||
import ArticleAdjacent from './components/ArticleAdjacent'
|
||||
import Comment from '@/components/Comment'
|
||||
@@ -177,7 +177,7 @@ const LayoutSearch = props => {
|
||||
*/
|
||||
const LayoutArchive = (props) => {
|
||||
const { archivePosts } = props
|
||||
return <LayoutBase {...props} headerSlot={<HeaderArticle {...props} />} >
|
||||
return <LayoutBase {...props} headerSlot={<PostHeader {...props} />} >
|
||||
<Card className='w-full -mt-32'>
|
||||
<div className="mb-10 pb-20 bg-white md:p-12 p-3 min-h-full dark:bg-hexo-black-gray">
|
||||
{Object.keys(archivePosts).map(archiveTitle => (
|
||||
@@ -200,7 +200,7 @@ const LayoutArchive = (props) => {
|
||||
const LayoutSlug = props => {
|
||||
const { post, lock, validPassword } = props
|
||||
|
||||
return (<LayoutBase {...props} headerSlot={<HeaderArticle {...props} />} showCategory={false} showTag={false} floatRightBottom={<JumpToCommentButton />}>
|
||||
return (<LayoutBase {...props} headerSlot={<PostHeader {...props} />} showCategory={false} showTag={false} floatRightBottom={<JumpToCommentButton />}>
|
||||
|
||||
<div id='inner-wrapper' className={'w-full lg:max-w-3xl 2xl:max-w-4xl'} >
|
||||
|
||||
@@ -310,7 +310,7 @@ const LayoutCategoryIndex = props => {
|
||||
const { categoryOptions } = props
|
||||
|
||||
return (
|
||||
<LayoutBase {...props} headerSlot={<HeaderArticle {...props} />} >
|
||||
<LayoutBase {...props} headerSlot={<PostHeader {...props} />} >
|
||||
|
||||
<div id='inner-wrapper' className='w-full'>
|
||||
<div className="drop-shadow-xl -mt-32 rounded-md mx-3 px-5 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black dark:text-gray-300">
|
||||
@@ -340,7 +340,7 @@ const LayoutTagIndex = props => {
|
||||
const { tagOptions } = props
|
||||
const { locale } = useGlobal()
|
||||
return (
|
||||
<LayoutBase {...props} headerSlot={<HeaderArticle {...props} />} >
|
||||
<LayoutBase {...props} headerSlot={<PostHeader {...props} />} >
|
||||
<div id='inner-wrapper' className='w-full drop-shadow-xl'>
|
||||
|
||||
<div className="-mt-32 rounded-md mx-3 px-5 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
|
||||
|
||||
@@ -23,7 +23,7 @@ const BlogPost = ({ post }) => {
|
||||
</article>
|
||||
|
||||
</Link>)
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
export default BlogPost
|
||||
|
||||
Reference in New Issue
Block a user