heo主题微调优化

This commit is contained in:
tangly1024.com
2024-05-27 17:40:18 +08:00
parent 65ab188eca
commit 19de7e1ab8
12 changed files with 818 additions and 704 deletions

View File

@@ -1,10 +1,10 @@
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState, useRef, useLayoutEffect } from 'react'
import { useGlobal } from '@/lib/global'
import { saveDarkModeToLocalStorage, THEMES } from '@/themes/theme'
import useWindowSize from '@/hooks/useWindowSize'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { THEMES, saveDarkModeToLocalStorage } from '@/themes/theme'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
/**
* 自定义右键菜单
@@ -20,14 +20,14 @@ export default function CustomContextMenu(props) {
const [width, setWidth] = useState(0)
const [height, setHeight] = useState(0)
const { latestPosts } = props
const { allNavPages } = props
const router = useRouter()
/**
* 随机跳转文章
*/
function handleJumpToRandomPost() {
const randomIndex = Math.floor(Math.random() * latestPosts.length)
const randomPost = latestPosts[randomIndex]
const randomIndex = Math.floor(Math.random() * allNavPages.length)
const randomPost = allNavPages[randomIndex]
router.push(`${siteConfig('SUB_PATH', '')}/${randomPost?.slug}`)
}
@@ -37,16 +37,26 @@ export default function CustomContextMenu(props) {
}, [])
useEffect(() => {
const handleContextMenu = (event) => {
setShow(false)
}, [router])
useEffect(() => {
const handleContextMenu = event => {
event.preventDefault()
// 计算点击位置加菜单宽高是否超出屏幕,如果超出则贴边弹出
const x = (event.clientX < windowSize.width - width) ? event.clientX : windowSize.width - width
const y = (event.clientY < windowSize.height - height) ? event.clientY : windowSize.height - height
const x =
event.clientX < windowSize.width - width
? event.clientX
: windowSize.width - width
const y =
event.clientY < windowSize.height - height
? event.clientY
: windowSize.height - height
setPosition({ y: `${y}px`, x: `${x}px` })
setShow(true)
}
const handleClick = (event) => {
const handleClick = event => {
if (menuRef.current && !menuRef.current.contains(event.target)) {
setShow(false)
}
@@ -80,19 +90,20 @@ export default function CustomContextMenu(props) {
function handleCopyLink() {
const url = window.location.href
navigator.clipboard.writeText(url)
navigator.clipboard
.writeText(url)
.then(() => {
console.log('页面地址已复制')
})
.catch((error) => {
.catch(error => {
console.error('复制页面地址失败:', error)
})
setShow(false)
}
/**
* 切换主题
*/
* 切换主题
*/
function handleChangeTheme() {
const randomTheme = THEMES[Math.floor(Math.random() * THEMES.length)] // 从THEMES数组中 随机取一个主题
const query = router.query
@@ -104,14 +115,14 @@ export default function CustomContextMenu(props) {
* 复制内容
*/
function handleCopy() {
const selectedText = document.getSelection().toString();
const selectedText = document.getSelection().toString()
if (selectedText) {
const tempInput = document.createElement('input');
tempInput.value = selectedText;
document.body.appendChild(tempInput);
tempInput.select();
document.execCommand('copy');
document.body.removeChild(tempInput);
const tempInput = document.createElement('input')
tempInput.value = selectedText
document.body.appendChild(tempInput)
tempInput.select()
document.execCommand('copy')
document.body.removeChild(tempInput)
// alert("Text copied: " + selectedText);
} else {
// alert("Please select some text first.");
@@ -130,76 +141,119 @@ export default function CustomContextMenu(props) {
}
return (
<div
ref={menuRef}
style={{ top: position.y, left: position.x }}
className={`${show ? '' : 'invisible opacity-0'} select-none transition-opacity duration-200 fixed z-50`}
>
<div
ref={menuRef}
style={{ top: position.y, left: position.x }}
className={`${show ? '' : 'invisible opacity-0'} select-none transition-opacity duration-200 fixed z-50`}>
{/* 菜单内容 */}
<div className='rounded-xl w-52 dark:hover:border-yellow-600 bg-white dark:bg-[#040404] dark:text-gray-200 dark:border-gray-600 p-3 border drop-shadow-lg flex-col duration-300 transition-colors'>
{/* 顶部导航按钮 */}
<div className='flex justify-between'>
<i
onClick={handleBack}
className='hover:bg-blue-600 hover:text-white px-2 py-2 text-center w-8 rounded cursor-pointer fa-solid fa-arrow-left'></i>
<i
onClick={handleForward}
className='hover:bg-blue-600 hover:text-white px-2 py-2 text-center w-8 rounded cursor-pointer fa-solid fa-arrow-right'></i>
<i
onClick={handleRefresh}
className='hover:bg-blue-600 hover:text-white px-2 py-2 text-center w-8 rounded cursor-pointer fa-solid fa-rotate-right'></i>
<i
onClick={handleScrollTop}
className='hover:bg-blue-600 hover:text-white px-2 py-2 text-center w-8 rounded cursor-pointer fa-solid fa-arrow-up'></i>
</div>
{/* 菜单内容 */}
<div className='rounded-xl w-52 dark:hover:border-yellow-600 bg-white dark:bg-[#040404] dark:text-gray-200 dark:border-gray-600 p-3 border drop-shadow-lg flex-col duration-300 transition-colors'>
{/* 顶部导航按钮 */}
<div className='flex justify-between'>
<i onClick={handleBack} className="hover:bg-blue-600 hover:text-white px-2 py-2 text-center w-8 rounded cursor-pointer fa-solid fa-arrow-left"></i>
<i onClick={handleForward} className="hover:bg-blue-600 hover:text-white px-2 py-2 text-center w-8 rounded cursor-pointer fa-solid fa-arrow-right"></i>
<i onClick={handleRefresh} className="hover:bg-blue-600 hover:text-white px-2 py-2 text-center w-8 rounded cursor-pointer fa-solid fa-rotate-right"></i>
<i onClick={handleScrollTop} className="hover:bg-blue-600 hover:text-white px-2 py-2 text-center w-8 rounded cursor-pointer fa-solid fa-arrow-up"></i>
</div>
<hr className='my-2 border-dashed' />
{/* 跳转导航按钮 */}
<div className='w-full px-2'>
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST') && <div onClick={handleJumpToRandomPost} title={locale.MENU.WALK_AROUND} className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className="fa-solid fa-podcast mr-2" />
<div className='whitespace-nowrap'>{locale.MENU.WALK_AROUND}</div>
</div>}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY') && <Link href='/category' title={locale.MENU.CATEGORY} className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className="fa-solid fa-square-minus mr-2" />
<div className='whitespace-nowrap'>{locale.MENU.CATEGORY}</div>
</Link>}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_TAG') && <Link href='/tag' title={locale.MENU.TAGS} className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className="fa-solid fa-tag mr-2" />
<div className='whitespace-nowrap'>{locale.MENU.TAGS}</div>
</Link>}
</div>
<hr className='my-2 border-dashed' />
{/* 功能按钮 */}
<div className='w-full px-2'>
{siteConfig('CAN_COPY') && (
<div onClick={handleCopy} title={locale.MENU.COPY} className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className="fa-solid fa-copy mr-2" />
<div className='whitespace-nowrap'>{locale.MENU.COPY}</div>
</div>
)}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK') && <div onClick={handleCopyLink} title={locale.MENU.SHARE_URL} className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className="fa-solid fa-arrow-up-right-from-square mr-2" />
<div className='whitespace-nowrap'>{locale.MENU.SHARE_URL}</div>
</div>}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE') && <div onClick={handleChangeDarkMode} title={isDarkMode ? locale.MENU.LIGHT_MODE : locale.MENU.DARK_MODE} className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
{isDarkMode ? <i className="fa-regular fa-sun mr-2" /> : <i className="fa-regular fa-moon mr-2" />}
<div className='whitespace-nowrap'> {isDarkMode ? locale.MENU.LIGHT_MODE : locale.MENU.DARK_MODE}</div>
</div>}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH') && (
<div onClick={handleChangeTheme} title={locale.MENU.THEME_SWITCH} className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className="fa-solid fa-palette mr-2" />
<div className='whitespace-nowrap'>{locale.MENU.THEME_SWITCH}</div>
</div>
)}
</div>
<hr className='my-2 border-dashed' />
{/* 跳转导航按钮 */}
<div className='w-full px-2'>
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST') && (
<div
onClick={handleJumpToRandomPost}
title={locale.MENU.WALK_AROUND}
className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className='fa-solid fa-podcast mr-2' />
<div className='whitespace-nowrap'>{locale.MENU.WALK_AROUND}</div>
</div>
</div >
)}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY') && (
<Link
href='/category'
title={locale.MENU.CATEGORY}
className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className='fa-solid fa-square-minus mr-2' />
<div className='whitespace-nowrap'>{locale.MENU.CATEGORY}</div>
</Link>
)}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_TAG') && (
<Link
href='/tag'
title={locale.MENU.TAGS}
className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className='fa-solid fa-tag mr-2' />
<div className='whitespace-nowrap'>{locale.MENU.TAGS}</div>
</Link>
)}
</div>
<hr className='my-2 border-dashed' />
{/* 功能按钮 */}
<div className='w-full px-2'>
{siteConfig('CAN_COPY') && (
<div
onClick={handleCopy}
title={locale.MENU.COPY}
className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className='fa-solid fa-copy mr-2' />
<div className='whitespace-nowrap'>{locale.MENU.COPY}</div>
</div>
)}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK') && (
<div
onClick={handleCopyLink}
title={locale.MENU.SHARE_URL}
className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className='fa-solid fa-arrow-up-right-from-square mr-2' />
<div className='whitespace-nowrap'>{locale.MENU.SHARE_URL}</div>
</div>
)}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE') && (
<div
onClick={handleChangeDarkMode}
title={
isDarkMode ? locale.MENU.LIGHT_MODE : locale.MENU.DARK_MODE
}
className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
{isDarkMode ? (
<i className='fa-regular fa-sun mr-2' />
) : (
<i className='fa-regular fa-moon mr-2' />
)}
<div className='whitespace-nowrap'>
{' '}
{isDarkMode ? locale.MENU.LIGHT_MODE : locale.MENU.DARK_MODE}
</div>
</div>
)}
{siteConfig('CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH') && (
<div
onClick={handleChangeTheme}
title={locale.MENU.THEME_SWITCH}
className='w-full px-2 h-10 flex justify-start items-center flex-nowrap cursor-pointer hover:bg-blue-600 hover:text-white rounded-lg duration-200 transition-all'>
<i className='fa-solid fa-palette mr-2' />
<div className='whitespace-nowrap'>
{locale.MENU.THEME_SWITCH}
</div>
</div>
)}
</div>
</div>
</div>
)
}

View File

@@ -523,6 +523,8 @@ summary > .notion-h {
.notion-page {
/* width: var(--notion-max-width); */
width: 100% !important;
padding-left: 0px !important;
padding-right: 0px !important;
/* padding-left: calc(min(12px, 8vw)); */
/* padding-right: calc(min(12px, 8vw)); */
}

View File

@@ -1,87 +0,0 @@
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import CONFIG from '../config'
import { siteConfig } from '@/lib/config'
/**
* 上一篇,下一篇文章
* @param {prev,next} param0
* @returns
*/
export default function ArticleAdjacent({ prev, next }) {
const [isScrollEnd, setIsScrollEnd] = useState(false)
const router = useRouter()
useEffect(() => {
setIsScrollEnd(false)
}, [router])
useEffect(() => {
// 文章是否已经到了底部
const targetElement = document.getElementById('article-end')
const handleIntersect = (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setIsScrollEnd(true)
}
})
}
const options = {
root: null,
rootMargin: '0px',
threshold: 0.1
}
const observer = new IntersectionObserver(handleIntersect, options)
observer.observe(targetElement)
return () => {
observer.disconnect()
}
}, [])
if (!prev || !next || !siteConfig('HEO_ARTICLE_ADJACENT', null, CONFIG)) {
return <></>
}
return (
<div id='article-end'>
{/* 移动端 */}
<section className='lg:hidden pt-8 text-gray-800 items-center text-xs md:text-sm flex flex-col m-1 '>
<Link
href={`/${prev.slug}`}
passHref
className='cursor-pointer justify-between space-y-1 px-5 py-6 rounded-t-xl dark:bg-[#1e1e1e] border dark:border-gray-600 border-b-0 items-center dark:text-white flex flex-col w-full h-18 duration-200'
>
<div className='flex justify-start items-center w-full'>上一篇</div>
<div className='flex justify-center items-center text-lg font-bold'>{prev.title}</div>
</Link>
<Link
href={`/${next.slug}`}
passHref
className='cursor-pointer justify-between space-y-1 px-5 py-6 rounded-b-xl dark:bg-[#1e1e1e] border dark:border-gray-600 items-center dark:text-white flex flex-col w-full h-18 duration-200'
>
<div className='flex justify-start items-center w-full'>下一篇</div>
<div className='flex justify-center items-center text-lg font-bold'>{next.title}</div>
</Link>
</section>
{/* 桌面端 */}
<div id='pc-next-post' className={`hidden md:block fixed z-40 right-24 bottom-4 duration-200 transition-all ${isScrollEnd ? 'mb-0 opacity-100' : '-mb-24 opacity-0'}`}>
<Link
href={`/${next.slug}`}
className='cursor-pointer drop-shadow-xl duration transition-all h-24 dark:bg-[#1e1e1e] border dark:border-gray-600 p-3 bg-white dark:text-gray-300 dark:hover:text-yellow-600 hover:text-white hover:font-bold hover:bg-blue-600 rounded-lg flex flex-col justify-between'
>
<div className='text-xs'>下一篇</div>
<hr />
<div>{next?.title}</div>
</Link>
</div>
</div>
)
}

View File

@@ -0,0 +1,187 @@
import { siteConfig } from '@/lib/config'
import { isBrowser } from '@/lib/utils'
import throttle from 'lodash.throttle'
import { useCallback, useEffect, useRef, useState } from 'react'
import DarkModeButton from './DarkModeButton'
import Logo from './Logo'
import { MenuListTop } from './MenuListTop'
import RandomPostButton from './RandomPostButton'
import ReadingProgress from './ReadingProgress'
import SearchButton from './SearchButton'
import SlideOver from './SlideOver'
/**
* 页头:顶部导航
* @param {*} param0
* @returns
*/
const Header = props => {
const [fixedNav, setFixedNav] = useState(false)
const [textWhite, setTextWhite] = useState(false)
const [navBgWhite, setBgWhite] = useState(false)
const [activeIndex, setActiveIndex] = useState(0)
const slideOverRef = useRef()
const toggleMenuOpen = () => {
slideOverRef?.current?.toggleSlideOvers()
}
/**
* 根据滚动条,切换导航栏样式
*/
const scrollTrigger = useCallback(
throttle(() => {
const scrollS = window.scrollY
// 导航栏设置 白色背景
if (scrollS <= 0) {
setFixedNav(false)
setBgWhite(false)
// 文章详情页特殊处理
if (document.querySelector('#post-bg')) {
setFixedNav(true)
setTextWhite(true)
setBgWhite(false)
}
} else {
// 向下滚动后的导航样式
setFixedNav(true)
setTextWhite(false)
setBgWhite(true)
}
}, 200)
)
// 监听滚动
useEffect(() => {
scrollTrigger()
window.addEventListener('scroll', scrollTrigger)
return () => {
window.removeEventListener('scroll', scrollTrigger)
}
}, [])
// 监听导航栏显示文字
useEffect(() => {
let prevScrollY = 0
let ticking = false
const handleScroll = () => {
if (!ticking) {
window.requestAnimationFrame(() => {
const currentScrollY = window.scrollY
if (currentScrollY > prevScrollY) {
setActiveIndex(1) // 向下滚动时设置activeIndex为1
} else {
setActiveIndex(0) // 向上滚动时设置activeIndex为0
}
prevScrollY = currentScrollY
ticking = false
})
ticking = true
}
}
if (isBrowser) {
window.addEventListener('scroll', handleScroll)
}
return () => {
if (isBrowser) {
window.removeEventListener('scroll', handleScroll)
}
}
}, [])
return (
<>
<style jsx>{`
@keyframes fade-in-down {
0% {
opacity: 0.5;
transform: translateY(-30%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fade-in-up {
0% {
opacity: 0.5;
transform: translateY(30%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.fade-in-down {
animation: fade-in-down 0.3s ease-in-out;
}
.fade-in-up {
animation: fade-in-up 0.3s ease-in-out;
}
`}</style>
{/* 顶部导航菜单栏 */}
<nav
id='nav'
className={`z-20 h-16 top-0 w-full
${fixedNav ? 'fixed' : 'relative bg-transparent'}
${textWhite ? 'text-white ' : 'text-black dark:text-white'}
${navBgWhite ? 'bg-white dark:bg-[#18171d] shadow' : 'bg-transparent'}`}>
<div className='flex h-full mx-auto justify-between items-center max-w-[86rem] px-8'>
{/* 左侧logo */}
<div className='flex'>
<Logo {...props} />
</div>
{/* 中间菜单 */}
<div
id='nav-bar-swipe'
className={`hidden lg:flex flex-grow flex-col items-center justify-center h-full relative w-full ${activeIndex === 0 ? 'fade-in-down' : 'fade-in-up'}`}>
{activeIndex === 0 && <MenuListTop {...props} />}
{activeIndex === 1 && (
<h1 className='font-bold text-center text-light-400 dark:text-gray-400'>
{siteConfig('AUTHOR') || siteConfig('TITLE')}{' '}
{siteConfig('BIO') && <>|</>} {siteConfig('BIO')}
</h1>
)}
</div>
{/* 右侧固定 */}
<div className='flex flex-shrink-0 justify-center items-center'>
<RandomPostButton {...props} />
<SearchButton {...props} />
{!JSON.parse(siteConfig('THEME_SWITCH')) && (
<div className='hidden md:block'>
<DarkModeButton {...props} />
</div>
)}
<ReadingProgress />
{/* 移动端菜单按钮 */}
<div
onClick={toggleMenuOpen}
className='flex lg:hidden w-8 justify-center items-center h-8 cursor-pointer'>
<i className='fas fa-bars' />
</div>
</div>
{/* 右边侧拉抽屉 */}
<SlideOver cRef={slideOverRef} {...props} />
</div>
</nav>
</>
)
}
export default Header

View File

@@ -62,13 +62,13 @@ function BannerGroup(props) {
*/
function Banner(props) {
const router = useRouter()
const { latestPosts } = props
const { allNavPages } = props
/**
* 随机跳转文章
*/
function handleClickBanner() {
const randomIndex = Math.floor(Math.random() * latestPosts.length)
const randomPost = latestPosts[randomIndex]
const randomIndex = Math.floor(Math.random() * allNavPages.length)
const randomPost = allNavPages[randomIndex]
router.push(`${siteConfig('SUB_PATH', '')}/${randomPost?.slug}`)
}

View File

@@ -1,170 +0,0 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import Logo from './Logo'
import throttle from 'lodash.throttle'
import RandomPostButton from './RandomPostButton'
import SearchButton from './SearchButton'
import DarkModeButton from './DarkModeButton'
import SlideOver from './SlideOver'
import ReadingProgress from './ReadingProgress'
import { MenuListTop } from './MenuListTop'
import { isBrowser } from '@/lib/utils'
import { siteConfig } from '@/lib/config'
/**
* 顶部导航
* @param {*} param0
* @returns
*/
const NavBar = props => {
const [fixedNav, setFixedNav] = useState(false)
const [textWhite, setTextWhite] = useState(false)
const [navBgWhite, setBgWhite] = useState(false)
const [activeIndex, setActiveIndex] = useState(0)
const slideOverRef = useRef()
const toggleMenuOpen = () => {
slideOverRef?.current?.toggleSlideOvers()
}
/**
* 根据滚动条,切换导航栏样式
*/
const scrollTrigger = useCallback(throttle(() => {
const scrollS = window.scrollY
// 导航栏设置 白色背景
if (scrollS <= 0) {
setFixedNav(false)
setBgWhite(false)
// 文章详情页特殊处理
if (document.querySelector('#post-bg')) {
setFixedNav(true)
setTextWhite(true)
setBgWhite(false)
}
} else {
// 向下滚动后的导航样式
setFixedNav(true)
setTextWhite(false)
setBgWhite(true)
}
}, 200))
// 监听滚动
useEffect(() => {
scrollTrigger()
window.addEventListener('scroll', scrollTrigger)
return () => {
window.removeEventListener('scroll', scrollTrigger)
}
}, [])
// 监听导航栏显示文字
useEffect(() => {
let prevScrollY = 0
let ticking = false
const handleScroll = () => {
if (!ticking) {
window.requestAnimationFrame(() => {
const currentScrollY = window.scrollY
if (currentScrollY > prevScrollY) {
setActiveIndex(1) // 向下滚动时设置activeIndex为1
} else {
setActiveIndex(0) // 向上滚动时设置activeIndex为0
}
prevScrollY = currentScrollY
ticking = false
})
ticking = true
}
}
if (isBrowser) {
window.addEventListener('scroll', handleScroll)
}
return () => {
if (isBrowser) {
window.removeEventListener('scroll', handleScroll)
}
}
}, [])
return (<>
<style jsx>{`
@keyframes fade-in-down {
0% {
opacity: 0.5;
transform: translateY(-30%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fade-in-up {
0% {
opacity: 0.5;
transform: translateY(30%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.fade-in-down {
animation: fade-in-down 0.3s ease-in-out;
}
.fade-in-up {
animation: fade-in-up 0.3s ease-in-out;
}
`}</style>
{/* 顶部导航菜单栏 */}
<nav id='nav' className={`z-20 h-16 top-0 w-full
${fixedNav ? 'fixed' : 'relative bg-transparent'}
${textWhite ? 'text-white ' : 'text-black dark:text-white'}
${navBgWhite ? 'bg-white dark:bg-[#18171d]' : 'bg-transparent'}`}>
<div className='flex h-full mx-auto justify-between items-center max-w-[86rem] px-8'>
{/* 左侧logo */}
<div className='flex'>
<Logo {...props} />
</div>
{/* 中间菜单 */}
<div id='nav-bar-swipe' className={`hidden lg:flex flex-grow flex-col items-center justify-center h-full relative w-full ${activeIndex === 0 ? 'fade-in-down' : 'fade-in-up'}`}>
{activeIndex === 0 && <MenuListTop {...props} />}
{activeIndex === 1 && <h1 className='font-bold text-center text-light-400 dark:text-gray-400'>{siteConfig('AUTHOR') || siteConfig('TITLE')} {siteConfig('BIO') && <>|</>} {siteConfig('BIO')}</h1>}
</div>
{/* 右侧固定 */}
<div className='flex flex-shrink-0 justify-center items-center'>
<RandomPostButton {...props} />
<SearchButton {...props}/>
{!JSON.parse(siteConfig('THEME_SWITCH')) && <div className='hidden md:block'><DarkModeButton {...props} /></div>}
<ReadingProgress />
{/* 移动端菜单按钮 */}
<div onClick={toggleMenuOpen} className='flex lg:hidden w-8 justify-center items-center h-8 cursor-pointer'>
<i className='fas fa-bars' />
</div>
</div>
{/* 右边侧拉抽屉 */}
<SlideOver cRef={slideOverRef} {...props} />
</div>
</nav>
</>)
}
export default NavBar

View File

@@ -0,0 +1,89 @@
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import CONFIG from '../config'
/**
* 上一篇,下一篇文章
* @param {prev,next} param0
* @returns
*/
export default function PostAdjacent({ prev, next }) {
const [isScrollEnd, setIsScrollEnd] = useState(false)
const router = useRouter()
useEffect(() => {
setIsScrollEnd(false)
}, [router])
useEffect(() => {
// 文章是否已经到了底部
const targetElement = document.getElementById('article-end')
const handleIntersect = entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setIsScrollEnd(true)
}
})
}
const options = {
root: null,
rootMargin: '0px',
threshold: 0.1
}
const observer = new IntersectionObserver(handleIntersect, options)
observer.observe(targetElement)
return () => {
observer.disconnect()
}
}, [])
if (!prev || !next || !siteConfig('HEO_ARTICLE_ADJACENT', null, CONFIG)) {
return <></>
}
return (
<div id='article-end'>
{/* 移动端 */}
<section className='lg:hidden pt-8 text-gray-800 items-center text-xs md:text-sm flex flex-col m-1 '>
<Link
href={`/${prev.slug}`}
passHref
className='cursor-pointer justify-between space-y-1 px-5 py-6 rounded-t-xl dark:bg-[#1e1e1e] border dark:border-gray-600 border-b-0 items-center dark:text-white flex flex-col w-full h-18 duration-200'>
<div className='flex justify-start items-center w-full'>上一篇</div>
<div className='flex justify-center items-center text-lg font-bold'>
{prev.title}
</div>
</Link>
<Link
href={`/${next.slug}`}
passHref
className='cursor-pointer justify-between space-y-1 px-5 py-6 rounded-b-xl dark:bg-[#1e1e1e] border dark:border-gray-600 items-center dark:text-white flex flex-col w-full h-18 duration-200'>
<div className='flex justify-start items-center w-full'>下一篇</div>
<div className='flex justify-center items-center text-lg font-bold'>
{next.title}
</div>
</Link>
</section>
{/* 桌面端 */}
<div
id='pc-next-post'
className={`hidden md:block fixed z-40 right-24 bottom-4 duration-200 transition-all ${isScrollEnd ? 'mb-0 opacity-100' : '-mb-24 opacity-0'}`}>
<Link
href={`/${next.slug}`}
className='cursor-pointer drop-shadow-xl duration transition-all h-24 dark:bg-[#1e1e1e] border dark:border-gray-600 p-3 bg-white dark:text-gray-300 dark:hover:text-yellow-600 hover:font-bold hover:text-blue-600 rounded-lg flex flex-col justify-between'>
<div className='text-xs'>下一篇</div>
<hr />
<div>{next?.title}</div>
</Link>
</div>
</div>
)
}

View File

@@ -1,11 +1,15 @@
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import CONFIG from '../config'
import { siteConfig } from '@/lib/config'
export default function ArticleCopyright () {
/**
* 版权声明
* @returns
*/
export default function PostCopyright() {
const router = useRouter()
const [path, setPath] = useState(siteConfig('LINK') + router.asPath)
useEffect(() => {
@@ -19,17 +23,19 @@ export default function ArticleCopyright () {
}
return (
<section className="dark:text-gray-300 mt-6 mx-1 ">
<ul className="overflow-x-auto whitespace-nowrap text-sm dark:bg-gray-900 bg-gray-100 p-5 leading-8 border-l-2 border-indigo-500">
<section className='dark:text-gray-300 mt-6 mx-1 '>
<ul className='overflow-x-auto whitespace-nowrap text-sm dark:bg-gray-900 bg-gray-100 p-5 leading-8 border-l-2 border-indigo-500'>
<li>
<strong className='mr-2'>{locale.COMMON.AUTHOR}:</strong>
<Link href={'/about'} className="hover:underline">
<Link href={'/about'} className='hover:underline'>
{siteConfig('AUTHOR')}
</Link>
</li>
<li>
<strong className='mr-2'>{locale.COMMON.URL}:</strong>
<a className="whitespace-normal break-words hover:underline" href={path}>
<strong className='mr-2'>{locale.COMMON.URL}:</strong>
<a
className='whitespace-normal break-words hover:underline'
href={path}>
{path}
</a>
</li>

View File

@@ -1,12 +1,17 @@
import Link from 'next/link'
import { siteConfig } from '@/lib/config'
import NotionIcon from '@/components/NotionIcon'
import WavesArea from './WavesArea'
import { HashTag } from '@/components/HeroIcons'
import WordCount from '@/components/WordCount'
import LazyImage from '@/components/LazyImage'
import NotionIcon from '@/components/NotionIcon'
import WordCount from '@/components/WordCount'
import { siteConfig } from '@/lib/config'
import { formatDateFmt } from '@/lib/utils/formatDate'
import Link from 'next/link'
import WavesArea from './WavesArea'
/**
* 文章页头
* @param {*} param0
* @returns
*/
export default function PostHeader({ post, siteInfo }) {
if (!post) {
return <></>
@@ -15,91 +20,121 @@ export default function PostHeader({ post, siteInfo }) {
const headerImage = post?.pageCover ? post.pageCover : siteInfo?.pageCover
return (
<div id='post-bg' className="w-full h-[30rem] relative md:flex-shrink-0 overflow-hidden bg-cover bg-center bg-no-repeat z-10 mb-5">
<style jsx>{`
.coverdiv:after {
position: absolute;
content: '';
width: 100%;
height: 100%;
top: 0;
left: 0;
box-shadow: 110px -130px 300px 60px #0060e0 inset;
}
`}</style>
<div
id='post-bg'
className='w-full h-[30rem] relative md:flex-shrink-0 overflow-hidden bg-cover bg-center bg-no-repeat z-10 mb-5'>
<style jsx>{`
.coverdiv:after {
position: absolute;
content: '';
width: 100%;
height: 100%;
top: 0;
left: 0;
box-shadow: 110px -130px 300px 60px #0060e0 inset;
}
`}</style>
<div style={{ backdropFilter: 'blur(15px)' }} className={'bg-[#0060e0] absolute top-0 w-full h-full py-10 flex justify-center items-center'}>
{/* 文章背景图 */}
<div id='post-cover-wrapper' style={{ filter: 'blur(15px)' }} className='coverdiv lg:translate-x-96 opacity-50 lg:rotate-12'>
<LazyImage id='post-cover' className='w-full h-full object-cover opacity-80 max-h-[50rem] min-w-[50vw] min-h-[20rem]' src={headerImage} />
</div>
{/* 文章文字描述 */}
<div id='post-info' className='absolute top-48 z-10 flex flex-col space-y-4 lg:-mt-12 w-full max-w-[86rem] px-5'>
{/* 分类+标签 */}
<div className='flex justify-center md:justify-start items-center'>
{post.category && <>
<Link href={`/category/${post.category}`} className='mr-4' passHref legacyBehavior>
<div className="cursor-pointer font-sm font-bold px-3 py-1 rounded-lg bg-blue-500 hover:bg-white text-white hover:text-blue-500 duration-200 ">
{post.category}
</div>
</Link>
</>}
{post.tagItems && (
<div className="hidden md:flex justify-center flex-nowrap overflow-x-auto">
{post.tagItems.map((tag, index) => (
<Link
key={index}
href={`/tag/${encodeURIComponent(tag.name)}`}
passHref
className={'cursor-pointer inline-block text-gray-50 hover:text-white duration-200 py-0.5 px-1 whitespace-nowrap '}>
<div className='font-light flex items-center'><HashTag className='text-gray-200 stroke-2 mr-0.5 w-3 h-3' /> {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
</Link>
))}
</div>
)}
</div>
{/* 文章Title */}
<div className="max-w-5xl font-bold text-3xl lg:text-5xl md:leading-snug shadow-text-md flex justify-center md:justify-start text-white">
{siteConfig('POST_TITLE_ICON') && <NotionIcon icon={post.pageIcon} />}{post.title}
</div>
{/* 标题底部补充信息 */}
<section className="flex-wrap shadow-text-md flex text-sm justify-center md:justify-start mt-4 text-white dark:text-gray-400 font-light leading-8">
<div className='flex justify-center dark:text-gray-200 text-opacity-70'>
<div className='mr-2'><WordCount /></div>
{post?.type !== 'Page' && (
<>
<Link
href={`/archive#${formatDateFmt(post?.publishDate, 'yyyy-MM')}`}
passHref
className="pl-1 mr-2 cursor-pointer hover:underline">
<i className="fa-regular fa-calendar"></i> {post?.publishDay}
</Link>
</>
)}
<div className="pl-1 mr-2">
<i className="fa-regular fa-calendar-check"></i> {post.lastEditedDay}
</div>
</div>
{JSON.parse(siteConfig('ANALYTICS_BUSUANZI_ENABLE')) && <div className="busuanzi_container_page_pv font-light mr-2">
<i className="fa-solid fa-fire-flame-curved"></i> <span className="mr-2 busuanzi_value_page_pv" />
</div>}
</section>
</div>
<WavesArea />
</div>
<div
style={{ backdropFilter: 'blur(15px)' }}
className={
'bg-[#0060e0] absolute top-0 w-full h-full py-10 flex justify-center items-center'
}>
{/* 文章背景图 */}
<div
id='post-cover-wrapper'
style={{ filter: 'blur(15px)' }}
className='coverdiv lg:translate-x-96 opacity-50 lg:rotate-12'>
<LazyImage
id='post-cover'
className='w-full h-full object-cover opacity-80 max-h-[50rem] min-w-[50vw] min-h-[20rem]'
src={headerImage}
/>
</div>
{/* 文章文字描述 */}
<div
id='post-info'
className='absolute top-48 z-10 flex flex-col space-y-4 lg:-mt-12 w-full max-w-[86rem] px-5'>
{/* 分类+标签 */}
<div className='flex justify-center md:justify-start items-center'>
{post.category && (
<>
<Link
href={`/category/${post.category}`}
className='mr-4'
passHref
legacyBehavior>
<div className='cursor-pointer font-sm font-bold px-3 py-1 rounded-lg bg-blue-500 hover:bg-white text-white hover:text-blue-500 duration-200 '>
{post.category}
</div>
</Link>
</>
)}
{post.tagItems && (
<div className='hidden md:flex justify-center flex-nowrap overflow-x-auto'>
{post.tagItems.map((tag, index) => (
<Link
key={index}
href={`/tag/${encodeURIComponent(tag.name)}`}
passHref
className={
'cursor-pointer inline-block text-gray-50 hover:text-white duration-200 py-0.5 px-1 whitespace-nowrap '
}>
<div className='font-light flex items-center'>
<HashTag className='text-gray-200 stroke-2 mr-0.5 w-3 h-3' />{' '}
{tag.name + (tag.count ? `(${tag.count})` : '')}{' '}
</div>
</Link>
))}
</div>
)}
</div>
{/* 文章Title */}
<div className='max-w-5xl font-bold text-3xl lg:text-5xl md:leading-snug shadow-text-md flex justify-center md:justify-start text-white'>
{siteConfig('POST_TITLE_ICON') && (
<NotionIcon icon={post.pageIcon} />
)}
{post.title}
</div>
{/* 标题底部补充信息 */}
<section className='flex-wrap shadow-text-md flex text-sm justify-center md:justify-start mt-4 text-white dark:text-gray-400 font-light leading-8'>
<div className='flex justify-center dark:text-gray-200 text-opacity-70'>
<div className='mr-2'>
<WordCount />
</div>
{post?.type !== 'Page' && (
<>
<Link
href={`/archive#${formatDateFmt(post?.publishDate, 'yyyy-MM')}`}
passHref
className='pl-1 mr-2 cursor-pointer hover:underline'>
<i className='fa-regular fa-calendar'></i>{' '}
{post?.publishDay}
</Link>
</>
)}
<div className='pl-1 mr-2'>
<i className='fa-regular fa-calendar-check'></i>{' '}
{post.lastEditedDay}
</div>
</div>
{JSON.parse(siteConfig('ANALYTICS_BUSUANZI_ENABLE')) && (
<div className='busuanzi_container_page_pv font-light mr-2'>
<i className='fa-solid fa-fire-flame-curved'></i>{' '}
<span className='mr-2 busuanzi_value_page_pv' />
</div>
)}
</section>
</div>
<WavesArea />
</div>
</div>
)
}

View File

@@ -8,7 +8,7 @@ import { useEffect, useRef } from 'react'
* @param validPassword(bool) 回调函数校验正确回调入参为true
* @returns
*/
export const ArticleLock = props => {
export const PostLock = props => {
const { validPassword } = props
const { locale } = useGlobal()
const submitPassword = () => {
@@ -27,25 +27,35 @@ export const ArticleLock = props => {
passwordInputRef.current.focus()
}, [])
return <div id='container' className='w-full flex justify-center items-center h-96 '>
<div className='text-center space-y-3'>
<div className='font-bold dark:text-gray-300 text-black'>{locale.COMMON.ARTICLE_LOCK_TIPS}</div>
<div className='flex mx-4'>
<input id="password" type='password'
onKeyDown={(e) => {
return (
<div
id='container'
className='w-full flex justify-center items-center h-96 '>
<div className='text-center space-y-3'>
<div className='font-bold dark:text-gray-300 text-black'>
{locale.COMMON.ARTICLE_LOCK_TIPS}
</div>
<div className='flex mx-4'>
<input
id='password'
type='password'
onKeyDown={e => {
if (e.key === 'Enter') {
submitPassword()
}
}}
ref={passwordInputRef} // 绑定ref到passwordInputRef变量
className='outline-none w-full text-sm pl-5 rounded-l transition focus:shadow-lg font-light leading-10 bg-gray-100 dark:bg-gray-500'>
</input>
<div onClick={submitPassword} className="px-3 whitespace-nowrap cursor-pointer items-center justify-center py-2 bg-indigo-500 hover:bg-indigo-400 text-white rounded-r duration-300" >
<i className={'duration-200 cursor-pointer fas fa-key'} >&nbsp;{locale.COMMON.SUBMIT}</i>
className='outline-none w-full text-sm pl-5 rounded-l transition focus:shadow-lg font-light leading-10 bg-gray-100 dark:bg-gray-500'></input>
<div
onClick={submitPassword}
className='px-3 whitespace-nowrap cursor-pointer items-center justify-center py-2 bg-indigo-500 hover:bg-indigo-400 text-white rounded-r duration-300'>
<i className={'duration-200 cursor-pointer fas fa-key'}>
&nbsp;{locale.COMMON.SUBMIT}
</i>
</div>
</div>
</div>
<div id='tips'>
<div id='tips'></div>
</div>
</div>
</div>
)
}

View File

@@ -9,7 +9,7 @@ import CONFIG from '../config'
* @param {prev,next} param0
* @returns
*/
export default function ArticleRecommend({ recommendPosts, siteInfo }) {
export default function PostRecommend({ recommendPosts, siteInfo }) {
const { locale } = useGlobal()
if (
@@ -55,6 +55,10 @@ export default function ArticleRecommend({ recommendPosts, siteInfo }) {
src={headerImage}
className='absolute top-0 w-full h-full object-cover object-center group-hover:scale-110 group-hover:brightness-50 transform duration-200'
/>
{/* 卡片的阴影遮罩,为了凸显图片上的文字 */}
<div className='h-3/4 w-full absolute left-0 bottom-0'>
<div className='h-full w-full absolute opacity-80 group-hover:opacity-100 transition-all duration-1000 bg-gradient-to-b from-transparent to-black'></div>
</div>
</div>
</Link>
)

View File

@@ -6,41 +6,41 @@
* 2. 更多说明参考此[文档](https://docs.tangly1024.com/article/notionnext-heo)
*/
import CONFIG from './config'
import { useEffect, useState } from 'react'
import Footer from './components/Footer'
import SideRight from './components/SideRight'
import NavBar from './components/NavBar'
import Comment from '@/components/Comment'
import { AdSlot } from '@/components/GoogleAdsense'
import { HashTag } from '@/components/HeroIcons'
import LazyImage from '@/components/LazyImage'
import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import WWAds from '@/components/WWAds'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { loadWowJS } from '@/lib/plugins/wow'
import { isBrowser } from '@/lib/utils'
import { Transition } from '@headlessui/react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import BlogPostArchive from './components/BlogPostArchive'
import BlogPostListPage from './components/BlogPostListPage'
import BlogPostListScroll from './components/BlogPostListScroll'
import Hero from './components/Hero'
import { useRouter } from 'next/router'
import SearchNav from './components/SearchNav'
import BlogPostArchive from './components/BlogPostArchive'
import { ArticleLock } from './components/ArticleLock'
import PostHeader from './components/PostHeader'
import Comment from '@/components/Comment'
import NotionPage from '@/components/NotionPage'
import ArticleAdjacent from './components/ArticleAdjacent'
import ArticleCopyright from './components/ArticleCopyright'
import ArticleRecommend from './components/ArticleRecommend'
import ShareBar from '@/components/ShareBar'
import Link from 'next/link'
import CategoryBar from './components/CategoryBar'
import { Transition } from '@headlessui/react'
import { Style } from './style'
import { NoticeBar } from './components/NoticeBar'
import { HashTag } from '@/components/HeroIcons'
import LatestPostsGroup from './components/LatestPostsGroup'
import FloatTocButton from './components/FloatTocButton'
import replaceSearchResult from '@/components/Mark'
import LazyImage from '@/components/LazyImage'
import WWAds from '@/components/WWAds'
import { AdSlot } from '@/components/GoogleAdsense'
import { siteConfig } from '@/lib/config'
import { isBrowser } from '@/lib/utils'
import { loadWowJS } from '@/lib/plugins/wow'
import Footer from './components/Footer'
import Header from './components/Header'
import Hero from './components/Hero'
import LatestPostsGroup from './components/LatestPostsGroup'
import { NoticeBar } from './components/NoticeBar'
import PostAdjacent from './components/PostAdjacent'
import PostCopyright from './components/PostCopyright'
import PostHeader from './components/PostHeader'
import { PostLock } from './components/PostLock'
import PostRecommend from './components/PostRecommend'
import SearchNav from './components/SearchNav'
import SideRight from './components/SideRight'
import CONFIG from './config'
import { Style } from './style'
/**
* 基础布局 采用上中下布局,移动端使用顶部侧边导航栏
@@ -49,38 +49,39 @@ import { loadWowJS } from '@/lib/plugins/wow'
* @constructor
*/
const LayoutBase = props => {
const {
children,
slotTop,
className
} = props
const { children, slotTop, className } = props
// 全屏模式下的最大宽度
const { fullWidth } = useGlobal()
const router = useRouter()
const headerSlot = (
<header>
<header className='shadow'>
{/* 顶部导航 */}
<NavBar {...props} />
<Header {...props} />
{/* 通知横幅 */}
{router.route === '/'
? <>
<NoticeBar />
<Hero {...props} />
{router.route === '/' ? (
<>
<NoticeBar />
<Hero {...props} />
</>
: null}
) : null}
{fullWidth ? null : <PostHeader {...props} />}
</header>
)
// 右侧栏 用户信息+标签列表
const slotRight = (router.route === '/404' || fullWidth) ? null : <SideRight {...props} />
const slotRight =
router.route === '/404' || fullWidth ? null : <SideRight {...props} />
const maxWidth = fullWidth ? 'max-w-[96rem] mx-auto' : 'max-w-[86rem]' // 普通最大宽度是86rem和顶部菜单栏对齐留空则与窗口对齐
const HEO_HERO_BODY_REVERSE = siteConfig('HEO_HERO_BODY_REVERSE', false, CONFIG)
const HEO_HERO_BODY_REVERSE = siteConfig(
'HEO_HERO_BODY_REVERSE',
false,
CONFIG
)
// 加载wow动画
useEffect(() => {
@@ -89,10 +90,8 @@ const LayoutBase = props => {
return (
<div
id="theme-heo"
className={`${siteConfig('FONT_STYLE')} bg-[#f7f9fe] dark:bg-[#18171d] h-full min-h-screen flex flex-col scroll-smooth`}
>
id='theme-heo'
className={`${siteConfig('FONT_STYLE')} bg-[#f7f9fe] dark:bg-[#18171d] h-full min-h-screen flex flex-col scroll-smooth`}>
<Style />
{/* 顶部嵌入 导航栏首页放hero文章页放文章详情 */}
@@ -100,15 +99,11 @@ const LayoutBase = props => {
{/* 主区块 */}
<main
id="wrapper-outer"
className={`flex-grow w-full ${maxWidth} mx-auto relative md:px-5`}
>
id='wrapper-outer'
className={`flex-grow w-full ${maxWidth} mx-auto relative md:px-5`}>
<div
id="container-inner"
className={
`${HEO_HERO_BODY_REVERSE ? 'flex-row-reverse' : ''} w-full mx-auto lg:flex justify-center relative z-10`
}
>
id='container-inner'
className={`${HEO_HERO_BODY_REVERSE ? 'flex-row-reverse' : ''} w-full mx-auto lg:flex justify-center relative z-10`}>
<div className={`w-full h-auto ${className || ''}`}>
{/* 主区上部嵌入 */}
{slotTop}
@@ -117,12 +112,11 @@ const LayoutBase = props => {
<div className='lg:px-2'></div>
<div className="hidden xl:block">
<div className='hidden xl:block'>
{/* 主区快右侧 */}
{slotRight}
</div>
</div>
</main>
{/* 页脚 */}
@@ -139,17 +133,15 @@ const LayoutBase = props => {
*/
const LayoutIndex = props => {
return (
<div id="post-outer-wrapper" className="px-5 md:px-0">
{/* 文章分类条 */}
<CategoryBar {...props} />
{siteConfig('POST_LIST_STYLE') === 'page'
? (
<BlogPostListPage {...props} />
)
: (
<BlogPostListScroll {...props} />
)}
</div>
<div id='post-outer-wrapper' className='px-5 md:px-0'>
{/* 文章分类条 */}
<CategoryBar {...props} />
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogPostListPage {...props} />
) : (
<BlogPostListScroll {...props} />
)}
</div>
)
}
@@ -160,17 +152,15 @@ const LayoutIndex = props => {
*/
const LayoutPostList = props => {
return (
<div id="post-outer-wrapper" className="px-5 md:px-0">
{/* 文章分类条 */}
<CategoryBar {...props} />
{siteConfig('POST_LIST_STYLE') === 'page'
? (
<BlogPostListPage {...props} />
)
: (
<BlogPostListScroll {...props} />
)}
</div>
<div id='post-outer-wrapper' className='px-5 md:px-0'>
{/* 文章分类条 */}
<CategoryBar {...props} />
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogPostListPage {...props} />
) : (
<BlogPostListScroll {...props} />
)}
</div>
)
}
@@ -200,26 +190,19 @@ const LayoutSearch = props => {
}
}, [])
return (
<div
{...props}
currentSearch={currentSearch}
>
<div id="post-outer-wrapper" className="px-5 md:px-0">
{!currentSearch
? (
<SearchNav {...props} />
)
: (
<div id="posts-wrapper">
{siteConfig('POST_LIST_STYLE') === 'page'
? (
<BlogPostListPage {...props} />
)
: (
<BlogPostListScroll {...props} />
)}
</div>
<div {...props} currentSearch={currentSearch}>
<div id='post-outer-wrapper' className='px-5 md:px-0'>
{!currentSearch ? (
<SearchNav {...props} />
) : (
<div id='posts-wrapper'>
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogPostListPage {...props} />
) : (
<BlogPostListScroll {...props} />
)}
</div>
)}
</div>
</div>
)
@@ -236,20 +219,20 @@ const LayoutArchive = props => {
// 归档页顶部显示条,如果是默认归档则不显示。分类详情页显示分类列表,标签详情页显示当前标签
return (
<div className="p-5 rounded-xl border dark:border-gray-600 max-w-6xl w-full bg-white dark:bg-[#1e1e1e]">
{/* 文章分类条 */}
<CategoryBar {...props} border={false} />
<div className='p-5 rounded-xl border dark:border-gray-600 max-w-6xl w-full bg-white dark:bg-[#1e1e1e]'>
{/* 文章分类条 */}
<CategoryBar {...props} border={false} />
<div className="px-3">
{Object.keys(archivePosts).map(archiveTitle => (
<BlogPostArchive
key={archiveTitle}
posts={archivePosts[archiveTitle]}
archiveTitle={archiveTitle}
/>
))}
</div>
<div className='px-3'>
{Object.keys(archivePosts).map(archiveTitle => (
<BlogPostArchive
key={archiveTitle}
posts={archivePosts[archiveTitle]}
archiveTitle={archiveTitle}
/>
))}
</div>
</div>
)
}
@@ -269,80 +252,88 @@ const LayoutSlug = props => {
setHasCode(hasCode)
}, [])
const commentEnable = siteConfig('COMMENT_TWIKOO_ENV_ID') || siteConfig('COMMENT_WALINE_SERVER_URL') || siteConfig('COMMENT_VALINE_APP_ID') ||
siteConfig('COMMENT_GISCUS_REPO') || siteConfig('COMMENT_CUSDIS_APP_ID') || siteConfig('COMMENT_UTTERRANCES_REPO') ||
siteConfig('COMMENT_GITALK_CLIENT_ID') || siteConfig('COMMENT_WEBMENTION_ENABLE')
const commentEnable =
siteConfig('COMMENT_TWIKOO_ENV_ID') ||
siteConfig('COMMENT_WALINE_SERVER_URL') ||
siteConfig('COMMENT_VALINE_APP_ID') ||
siteConfig('COMMENT_GISCUS_REPO') ||
siteConfig('COMMENT_CUSDIS_APP_ID') ||
siteConfig('COMMENT_UTTERRANCES_REPO') ||
siteConfig('COMMENT_GITALK_CLIENT_ID') ||
siteConfig('COMMENT_WEBMENTION_ENABLE')
const router = useRouter()
useEffect(() => {
// 404
if (!post) {
setTimeout(() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
setTimeout(
() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
}
}
}
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000)
},
siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
}
}, [post])
return (
<>
<div className={`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 article`}>
{lock && <ArticleLock validPassword={validPassword} />}
<div
className={`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 article`}>
{lock && <PostLock validPassword={validPassword} />}
{!lock && (
<div
id="article-wrapper"
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
itemScope
itemType="https://schema.org/Movie"
data-wow-delay=".2s"
className="wow fadeInUp subpixel-antialiased overflow-y-hidden"
>
itemType='https://schema.org/Movie'
data-wow-delay='.2s'
className='wow fadeInUp subpixel-antialiased overflow-y-hidden'>
{/* Notion文章主体 */}
<section className="px-5 justify-center mx-auto">
<WWAds orientation="horizontal" className="w-full" />
<section className='px-5 justify-center mx-auto'>
<WWAds orientation='horizontal' className='w-full' />
{post && <NotionPage post={post} />}
<WWAds orientation="horizontal" className="w-full" />
<WWAds orientation='horizontal' className='w-full' />
</section>
{/* 分享 */}
<ShareBar post={post} />
{post?.type === 'Post' && (
<div className="px-5">
<div className='px-5'>
{/* 版权 */}
<ArticleCopyright {...props} />
<PostCopyright {...props} />
{/* 文章推荐 */}
<ArticleRecommend {...props} />
<PostRecommend {...props} />
{/* 上一篇\下一篇文章 */}
<ArticleAdjacent {...props} />
<PostAdjacent {...props} />
</div>
)}
</article>
{fullWidth
? null
: <div className={`${commentEnable && post ? '' : 'hidden'}`}>
<hr className="my-4 border-dashed" />
{fullWidth ? null : (
<div className={`${commentEnable && post ? '' : 'hidden'}`}>
<hr className='my-4 border-dashed' />
{/* 评论区上方广告 */}
<div className="py-2">
<AdSlot />
<div className='py-2'>
<AdSlot />
</div>
{/* 评论互动 */}
<div className="duration-200 overflow-x-auto px-5">
<div className="text-2xl dark:text-white">
<i className="fas fa-comment mr-1" />
<div className='duration-200 overflow-x-auto px-5'>
<div className='text-2xl dark:text-white'>
<i className='fas fa-comment mr-1' />
{locale.COMMON.COMMENTS}
</div>
<Comment frontMatter={post} className="" />
<Comment frontMatter={post} className='' />
</div>
</div>}
</div>
)}
</div>
)}
</div>
@@ -361,39 +352,38 @@ const Layout404 = props => {
const { onLoading, fullWidth } = useGlobal()
return (
<>
{/* 主区块 */}
{/* 主区块 */}
<main
id="wrapper-outer"
className={`flex-grow ${fullWidth ? '' : 'max-w-4xl'} w-screen mx-auto px-5`}
>
<div id="error-wrapper" className={'w-full mx-auto justify-center'}>
id='wrapper-outer'
className={`flex-grow ${fullWidth ? '' : 'max-w-4xl'} w-screen mx-auto px-5`}>
<div id='error-wrapper' className={'w-full mx-auto justify-center'}>
<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}
>
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}>
{/* 404卡牌 */}
<div className="error-content flex flex-col md:flex-row w-full mt-12 h-[30rem] md:h-96 justify-center items-center bg-white dark:bg-[#1B1C20] border dark:border-gray-800 rounded-3xl">
<div className='error-content flex flex-col md:flex-row w-full mt-12 h-[30rem] md:h-96 justify-center items-center bg-white dark:bg-[#1B1C20] border dark:border-gray-800 rounded-3xl'>
{/* 左侧动图 */}
<LazyImage
className="error-img h-60 md:h-full p-4"
src={'https://bu.dusays.com/2023/03/03/6401a7906aa4a.gif'}
></LazyImage>
className='error-img h-60 md:h-full p-4'
src={
'https://bu.dusays.com/2023/03/03/6401a7906aa4a.gif'
}></LazyImage>
{/* 右侧文字 */}
<div className="error-info flex-1 flex flex-col justify-center items-center space-y-4">
<h1 className="error-title font-extrabold md:text-9xl text-7xl dark:text-white">
<div className='error-info flex-1 flex flex-col justify-center items-center space-y-4'>
<h1 className='error-title font-extrabold md:text-9xl text-7xl dark:text-white'>
404
</h1>
<div className='dark:text-white'>请尝试站内搜索寻找文章</div>
<Link href="/">
<button className="bg-blue-500 py-2 px-4 text-white shadow rounded-lg hover:bg-blue-600 hover:shadow-md duration-200 transition-all">
<Link href='/'>
<button className='bg-blue-500 py-2 px-4 text-white shadow rounded-lg hover:bg-blue-600 hover:shadow-md duration-200 transition-all'>
回到主页
</button>
</Link>
@@ -401,7 +391,7 @@ const Layout404 = props => {
</div>
{/* 404页面底部显示最新文章 */}
<div className="mt-12">
<div className='mt-12'>
<LatestPostsGroup {...props} />
</div>
</Transition>
@@ -421,38 +411,35 @@ const LayoutCategoryIndex = props => {
const { locale } = useGlobal()
return (
<div id="category-outer-wrapper" className="mt-8 px-5 md:px-0">
<div className="text-4xl font-extrabold dark:text-gray-200 mb-5">
{locale.COMMON.CATEGORY}
</div>
<div
id="category-list"
className="duration-200 flex flex-wrap m-10 justify-center"
>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior
>
<div
className={
'group mr-5 mb-5 flex flex-nowrap items-center border bg-white text-2xl rounded-xl dark:hover:text-white px-4 cursor-pointer py-3 hover:text-white hover:bg-indigo-600 transition-all hover:scale-110 duration-150'
}
>
<HashTag className={'w-5 h-5 stroke-gray-500 stroke-2'} />
{category.name}
<div className="bg-[#f1f3f8] ml-1 px-2 rounded-lg group-hover:text-indigo-600 ">
{category.count}
</div>
</div>
</Link>
)
})}
</div>
<div id='category-outer-wrapper' className='mt-8 px-5 md:px-0'>
<div className='text-4xl font-extrabold dark:text-gray-200 mb-5'>
{locale.COMMON.CATEGORY}
</div>
<div
id='category-list'
className='duration-200 flex flex-wrap m-10 justify-center'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={
'group mr-5 mb-5 flex flex-nowrap items-center border bg-white text-2xl rounded-xl dark:hover:text-white px-4 cursor-pointer py-3 hover:text-white hover:bg-indigo-600 transition-all hover:scale-110 duration-150'
}>
<HashTag className={'w-5 h-5 stroke-gray-500 stroke-2'} />
{category.name}
<div className='bg-[#f1f3f8] ml-1 px-2 rounded-lg group-hover:text-indigo-600 '>
{category.count}
</div>
</div>
</Link>
)
})}
</div>
</div>
)
}
@@ -466,50 +453,47 @@ const LayoutTagIndex = props => {
const { locale } = useGlobal()
return (
<div id="tag-outer-wrapper" className="px-5 mt-8 md:px-0">
<div className="text-4xl font-extrabold dark:text-gray-200 mb-5">
{locale.COMMON.TAGS}
</div>
<div
id="tag-list"
className="duration-200 flex flex-wrap space-x-5 space-y-5 m-10 justify-center"
>
{tagOptions.map(tag => {
return (
<Link
key={tag.name}
href={`/tag/${tag.name}`}
passHref
legacyBehavior
>
<div
className={
'group flex flex-nowrap items-center border bg-white text-2xl rounded-xl dark:hover:text-white px-4 cursor-pointer py-3 hover:text-white hover:bg-indigo-600 transition-all hover:scale-110 duration-150'
}
>
<HashTag className={'w-5 h-5 stroke-gray-500 stroke-2'} />
{tag.name}
<div className="bg-[#f1f3f8] ml-1 px-2 rounded-lg group-hover:text-indigo-600 ">
{tag.count}
</div>
</div>
</Link>
)
})}
</div>
<div id='tag-outer-wrapper' className='px-5 mt-8 md:px-0'>
<div className='text-4xl font-extrabold dark:text-gray-200 mb-5'>
{locale.COMMON.TAGS}
</div>
<div
id='tag-list'
className='duration-200 flex flex-wrap space-x-5 space-y-5 m-10 justify-center'>
{tagOptions.map(tag => {
return (
<Link
key={tag.name}
href={`/tag/${tag.name}`}
passHref
legacyBehavior>
<div
className={
'group flex flex-nowrap items-center border bg-white text-2xl rounded-xl dark:hover:text-white px-4 cursor-pointer py-3 hover:text-white hover:bg-indigo-600 transition-all hover:scale-110 duration-150'
}>
<HashTag className={'w-5 h-5 stroke-gray-500 stroke-2'} />
{tag.name}
<div className='bg-[#f1f3f8] ml-1 px-2 rounded-lg group-hover:text-indigo-600 '>
{tag.count}
</div>
</div>
</Link>
)
})}
</div>
</div>
)
}
export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404,
LayoutPostList,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
LayoutTagIndex
LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
}