mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
4.0 仿Youtube界面样式
This commit is contained in:
@@ -8,7 +8,7 @@ const DarkModeButton = () => {
|
||||
changeTheme(newTheme)
|
||||
localStorage.setItem('theme', newTheme)
|
||||
}
|
||||
return <div className='z-10 p-1 border hover:shadow-xl duration-200 dark:border-gray-500 mr-2 h-12 my-2 bg-white dark:bg-gray-600 dark:bg-opacity-70 bg-opacity-70 dark:hover:bg-gray-100 text-xl cursor-pointer dark:text-gray-300 dark:hover:text-black'>
|
||||
return <div className='z-10 p-1 duration-200 mr-2 h-12 bg-white dark:bg-gray-600 dark:bg-opacity-70 bg-opacity-70 text-xl cursor-pointer dark:text-gray-300 '>
|
||||
<i className={'fa p-2.5 hover:scale-125 transform duration-200 ' + (theme === 'dark' ? ' fa-sun-o' : ' fa-moon-o') } onClick={handleChangeDarkMode} />
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -4,15 +4,13 @@ import React from 'react'
|
||||
const Footer = ({ fullWidth = true }) => {
|
||||
const d = new Date()
|
||||
const y = d.getFullYear()
|
||||
const from = +BLOG.since
|
||||
return (
|
||||
<footer
|
||||
className='flex-shrink-0 m-auto w-full text-gray-500 dark:text-gray-400 text-sm text-gray-400'
|
||||
className='flex-shrink-0 m-auto w-full text-gray-500 dark:text-gray-400 text-xs text-gray-400 p-6'
|
||||
>
|
||||
<hr className='py-2'/>
|
||||
<span className='fa fa-shield leading-6'> <a href='https://beian.miit.gov.cn/' className='ml-1'>闽ICP备20010331号</a></span>
|
||||
<br />
|
||||
<span className='fa fa-copyright leading-6'> {from === y || !from ? y : `${from} - ${y}`} {BLOG.author} </span>
|
||||
<span className='fa fa-copyright leading-6'> {` ${y}`} {BLOG.author} </span>
|
||||
<br />
|
||||
<span id='busuanzi_container_site_pv' className='hidden'>
|
||||
<a id='busuanzi_container_site_pv' href='https://www.cnzz.com/stat/website.php?web_id=1279970751' target='_blank'
|
||||
|
||||
@@ -26,7 +26,7 @@ const NavBar = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const Header = ({ navBarTitle, fullWidth }) => {
|
||||
const Header = ({ navBarTitle, fullWidth = true }) => {
|
||||
const navRef = useRef(null)
|
||||
const sentinelRef = useRef([])
|
||||
// 当Header移出屏幕时改变的样式
|
||||
@@ -49,7 +49,7 @@ const Header = ({ navBarTitle, fullWidth }) => {
|
||||
}, [sentinelRef])
|
||||
return (
|
||||
<>
|
||||
{ BLOG.autoCollapsedNavBar === true && (
|
||||
{BLOG.autoCollapsedNavBar === true && (
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
@@ -70,38 +70,41 @@ const Header = ({ navBarTitle, fullWidth }) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className='observer-element h-0.5' ref={sentinelRef}/>
|
||||
<div className='observer-element h-0.5 ' ref={sentinelRef} />
|
||||
|
||||
<div
|
||||
className={`sticky-nav m-auto w-full h-6 flex flex-row justify-between items-center mb-2 py-8 bg-opacity-60 ${
|
||||
!fullWidth ? 'max-w-5xl px-4' : 'px-4 md:px-24'
|
||||
}`}
|
||||
className='z-30 px-4 sticky-nav m-auto w-full h-6 flex flex-row justify-between items-center py-6 bg-white bg-opacity-80 '
|
||||
id='sticky-nav'
|
||||
ref={navRef}
|
||||
>
|
||||
<div className='flex items-center'>
|
||||
<Link href='/'>
|
||||
<a>
|
||||
<div className='h-6'>
|
||||
<Image
|
||||
alt={BLOG.author}
|
||||
width={24}
|
||||
height={24}
|
||||
src='/favicon.svg'
|
||||
className='rounded-full'
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<div className='flex cursor-pointer'>
|
||||
<div className='px-2 text-xl'>
|
||||
<i className='fa fa-bars hover:scale-125 transform duration-200' />
|
||||
</div>
|
||||
<Image
|
||||
alt={BLOG.author}
|
||||
width={28}
|
||||
height={28}
|
||||
src='/avatar.svg'
|
||||
className='rounded-full'
|
||||
/>
|
||||
<div
|
||||
className='mx-1 text-center cursor-pointer text-xl p-1
|
||||
dark:bg-gray-900 dark:text-gray-300 font-semibold
|
||||
dark:hover:bg-gray-600 text-black hover:scale-105
|
||||
hover:shadow-2xl duration-200 transform'>{BLOG.title}</div>
|
||||
|
||||
</div>
|
||||
{navBarTitle
|
||||
? (
|
||||
<p className='ml-2 font-medium text-gray-500 dark:text-night header-name'>
|
||||
<p className='ml-1 font-medium text-gray-500 dark:text-night header-name'>
|
||||
{navBarTitle}
|
||||
</p>
|
||||
)
|
||||
: (
|
||||
<p className='ml-2 font-medium text-500 dark:text-night header-name'>
|
||||
{BLOG.title} {' '}
|
||||
{BLOG.title},{' '}
|
||||
<p className='ml-1 font-medium dark:text-night header-name'>
|
||||
<span className='font-normal'>{BLOG.description}</span>
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -3,11 +3,12 @@ import throttle from 'lodash.throttle'
|
||||
import { useLocale } from '@/lib/locale'
|
||||
|
||||
/**
|
||||
* 跳转到网页顶部;当屏幕下滑500像素后会出现该控件
|
||||
* 跳转到网页顶部
|
||||
* 当屏幕下滑500像素后会出现该控件
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const TopJumper = () => {
|
||||
const JumpToTop = () => {
|
||||
const locale = useLocale()
|
||||
|
||||
const [show, switchShow] = useState(false)
|
||||
@@ -36,4 +37,4 @@ const TopJumper = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default TopJumper
|
||||
export default JumpToTop
|
||||
42
components/LeftFloatButton.js
Normal file
42
components/LeftFloatButton.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import throttle from 'lodash.throttle'
|
||||
import DarkModeButton from '@/components/DarkModeButton'
|
||||
|
||||
/**
|
||||
* 左上角悬浮菜单栏
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const LeftFloatButton = () => {
|
||||
// 监听resize事件
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', collapseSideBar)
|
||||
collapseSideBar()
|
||||
return () => {
|
||||
window.removeEventListener('resize', collapseSideBar)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const collapseSideBar = throttle(() => {
|
||||
if (window.innerWidth > 1300) {
|
||||
changeCollapse(false)
|
||||
} else {
|
||||
changeCollapse(true)
|
||||
}
|
||||
}, 500)
|
||||
const [collapse, changeCollapse] = useState(true)
|
||||
console.log(collapse)
|
||||
return <div
|
||||
className={(collapse ? 'left-0' : 'left-72') + ' z-30 fixed flex flex-nowrap md:flex-col top-0 pl-4 py-1 duration-500 ease-in-out'}>
|
||||
{/* 菜单折叠 */}
|
||||
<div className='p-1 border hover:shadow-xl duration-200 dark:border-gray-500 h-12 bg-white dark:bg-gray-600 dark:bg-opacity-70 bg-opacity-70
|
||||
dark:hover:bg-gray-100 text-xl cursor-pointer mr-2 my-2 dark:text-gray-300 dark:hover:text-black'>
|
||||
<i className='fa fa-bars p-2.5 hover:scale-125 transform duration-200'
|
||||
onClick={() => changeCollapse(!collapse)} />
|
||||
</div>
|
||||
{/* 夜间模式 */}
|
||||
<DarkModeButton />
|
||||
</div>
|
||||
}
|
||||
|
||||
export default LeftFloatButton
|
||||
11
components/Logo.js
Normal file
11
components/Logo.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import Link from 'next/link'
|
||||
import BLOG from '@/blog.config'
|
||||
import React from 'react'
|
||||
|
||||
const Logo = () => {
|
||||
return <Link href='/'>
|
||||
<div
|
||||
className='mx-auto text-center cursor-pointer text-3xl dark:bg-gray-900 dark:text-gray-300 font-semibold dark:hover:bg-gray-600 bg-gray-700 text-white p-2 hover:scale-105 hover:shadow-2xl duration-200 transform'>{BLOG.title}</div>
|
||||
</Link>
|
||||
}
|
||||
export default Logo
|
||||
@@ -3,6 +3,13 @@ import { useLocale } from '@/lib/locale'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
/**
|
||||
* 翻页插件
|
||||
* @param page 当前页码
|
||||
* @param showNext 是否有下一页
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const Pagination = ({ page, showNext }) => {
|
||||
const locale = useLocale()
|
||||
const router = useRouter()
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'
|
||||
import throttle from 'lodash.throttle'
|
||||
|
||||
/**
|
||||
* 跳转到网页顶部;当屏幕下滑500像素后会出现该控件
|
||||
* 顶部页面阅读进度条
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react'
|
||||
import { createPopper } from '@popperjs/core'
|
||||
|
||||
/**
|
||||
* 赞赏模块
|
||||
* 赞赏按钮
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
@@ -2,8 +2,15 @@ import React, { useState } from 'react'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import throttle from 'lodash.throttle'
|
||||
import ShareButton from '@/components/ShareButton'
|
||||
import TopJumper from '@/components/TopJumper'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
|
||||
/**
|
||||
* 右侧边栏
|
||||
* @param toc
|
||||
* @param post
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const RightAside = ({ toc, post }) => {
|
||||
// 无目录就直接返回空
|
||||
if (toc.length < 1) return <></>
|
||||
@@ -43,7 +50,7 @@ const RightAside = ({ toc, post }) => {
|
||||
{/* 分享按钮 */}
|
||||
<ShareButton post={post} />
|
||||
{/* 跳回顶部 */}
|
||||
<TopJumper />
|
||||
<JumpToTop />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from 'react'
|
||||
import TopJumper from '@/components/TopJumper'
|
||||
import ShareButton from '@/components/ShareButton'
|
||||
|
||||
const RightWidget = ({ post }) => {
|
||||
return <div className='flex-wrap'>
|
||||
<ShareButton post={post} />
|
||||
<TopJumper />
|
||||
</div>
|
||||
}
|
||||
export default RightWidget
|
||||
@@ -1,134 +0,0 @@
|
||||
import Tags from '@/components/Tags'
|
||||
import { useLocale } from '@/lib/locale'
|
||||
import Link from 'next/link'
|
||||
import BLOG from '@/blog.config'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import Router, { useRouter } from 'next/router'
|
||||
import DarkModeButton from '@/components/DarkModeButton'
|
||||
import Footer from '@/components/Footer'
|
||||
import throttle from 'lodash.throttle'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import SocialButton from '@/components/SocialButton'
|
||||
|
||||
const SideBar = ({ tags, currentTag, post }) => {
|
||||
const locale = useLocale()
|
||||
const router = useRouter()
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
|
||||
const handleKeyUp = (e) => {
|
||||
if (e.keyCode === 13) {
|
||||
Router.push({ pathname: '/', query: { s: searchValue } })
|
||||
}
|
||||
}
|
||||
|
||||
// 监听resize事件
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', collapseSideBar)
|
||||
collapseSideBar()
|
||||
return () => {
|
||||
window.removeEventListener('resize', collapseSideBar)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const collapseSideBar = throttle(() => {
|
||||
if (window.innerWidth > 1300) {
|
||||
changeCollapse(false)
|
||||
} else {
|
||||
changeCollapse(true)
|
||||
}
|
||||
}, 500)
|
||||
const [collapse, changeCollapse] = useState(true)
|
||||
|
||||
return <aside className='z-10'>
|
||||
|
||||
<div
|
||||
className={(collapse ? '-ml-80 ' : 'shadow-2xl xl:shadow-none ') + ' dark:bg-gray-800 bg-white sidebar h-full w-72 duration-500 ease-in-out'}>
|
||||
|
||||
{/* Logo */}
|
||||
<section className='flex border-b px-5 pt-8 pb-6 flex-col sticky top-0 bg-white dark:bg-gray-800 z-10'>
|
||||
<Link href='/'>
|
||||
<div
|
||||
className='mx-auto text-center cursor-pointer text-3xl dark:bg-gray-900 dark:text-gray-300 font-semibold dark:hover:bg-gray-600 bg-gray-700 text-white p-2 hover:scale-105 hover:shadow-2xl duration-200 transform'>{BLOG.title}</div>
|
||||
</Link>
|
||||
|
||||
<i className='mx-auto fa fa-map-marker pl-1 dark:text-gray-300 mt-5' > Fuzhou, China</i>
|
||||
</section>
|
||||
|
||||
{/* 搜索框 */}
|
||||
<section className={ (post ? ' ' : ' sticky top-36 ') + ' z-20 border-t border-b flex justify-center items-center py-5 pr-5 pl-2 bg-gray-100 dark:bg-black'}>
|
||||
<input
|
||||
type='text'
|
||||
placeholder={
|
||||
currentTag ? `${locale.SEARCH.TAGS} #${currentTag}` : `${locale.SEARCH.ARTICLES}`
|
||||
}
|
||||
className='shadow-inner duration-200 pl-2 rounded w-full py-2 border dark:border-gray-600 bg-white text-black dark:bg-gray-700 dark:text-white'
|
||||
onKeyUp={handleKeyUp}
|
||||
onChange={e => setSearchValue(e.target.value)}
|
||||
defaultValue={router.query.s ?? ''}
|
||||
/>
|
||||
<i className='fa fa-search text-gray-400 -ml-8' />
|
||||
</section>
|
||||
|
||||
{/* wrapper */}
|
||||
<div className={ (post ? ' ' : ' ') + 'px-6'}>
|
||||
|
||||
{/* 菜单 */}
|
||||
<nav className='mt-6'>
|
||||
<strong className='text-2xl text-gray-600 dark:text-gray-400'>菜单</strong>
|
||||
<ul className='mt-4 leading-8 text-gray-500 dark:text-gray-400'>
|
||||
<li><a className='fa fa-info hover:underline' href='/article/about' id='about'><span
|
||||
className='ml-2'>关于本站</span></a></li>
|
||||
<li><a className='fa fa-rss hover:underline' href='/feed' target='_blank' id='feed'><span
|
||||
className='ml-2'>RSS订阅</span></a></li>
|
||||
<li></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{/* 标签云 */}
|
||||
<section className='mt-6'>
|
||||
<strong className='text-2xl text-gray-600 dark:text-gray-400'>标签</strong>
|
||||
<div className='mt-4'>
|
||||
<Tags tags={tags} currentTag={currentTag} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 联系 */}
|
||||
<section>
|
||||
<div className='mt-6'>
|
||||
<strong className='text-2xl text-gray-600 dark:text-gray-400'>联系我</strong>
|
||||
<div className='mt-2 py-2'>
|
||||
<SocialButton />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 站点信息 */}
|
||||
<section className='my-3'>
|
||||
<Footer />
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
{post && (
|
||||
<div className='sticky top-36'>
|
||||
<TocBar toc={post.toc} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
{/* 顶部菜单按钮 */}
|
||||
<div
|
||||
className={(collapse ? 'left-0' : 'left-72') + ' z-30 fixed flex flex-nowrap md:flex-col top-0 pl-4 py-1 duration-500 ease-in-out'}>
|
||||
{/* 菜单折叠 */}
|
||||
<div className='p-1 border hover:shadow-xl duration-200 dark:border-gray-500 h-12 bg-white dark:bg-gray-600 dark:bg-opacity-70 bg-opacity-70
|
||||
dark:hover:bg-gray-100 text-xl cursor-pointer mr-2 my-2 dark:text-gray-300 dark:hover:text-black'>
|
||||
<i className='fa fa-bars p-2.5 hover:scale-125 transform duration-200'
|
||||
onClick={() => changeCollapse(!collapse)} />
|
||||
</div>
|
||||
{/* 夜间模式 */}
|
||||
<DarkModeButton />
|
||||
</div>
|
||||
</aside>
|
||||
}
|
||||
export default SideBar
|
||||
67
components/SideBarEmbed.js
Normal file
67
components/SideBarEmbed.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import React from 'react'
|
||||
import Footer from '@/components/Footer'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import SocialButton from '@/components/SocialButton'
|
||||
|
||||
const SideBarEmbed = ({ tags, currentTag, post }) => {
|
||||
return <aside className='z-30 bg-white dark:border-gray-500 border-gray-200'>
|
||||
|
||||
<div
|
||||
className='dark:bg-gray-800 scroll-hidden left-0 duration-500 ease-in-out '>
|
||||
|
||||
{/* wrapper */}
|
||||
<div className='sticky top-12'>
|
||||
|
||||
{/* 菜单 */}
|
||||
<nav>
|
||||
<ul className='leading-8 text-gray-700 dark:text-gray-400'>
|
||||
<li className='hover:bg-gray-100 dark:hover:bg-black duration-100 p-2'>
|
||||
<a className='fa fa-home w-full px-4' href='/' id='home'>
|
||||
<span className='ml-2'>主页</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className='hover:bg-gray-100 dark:hover:bg-black duration-100 p-2'>
|
||||
<a className='fa fa-info-circle w-full px-4' href='/article/about' id='about'>
|
||||
<span className='ml-2'>关于本站</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className='hover:bg-gray-100 dark:hover:bg-black duration-100 p-2'>
|
||||
<a className='fa fa-rss-square w-full px-4' href='/feed' target='_blank' id='feed'>
|
||||
<span className='ml-2'>RSS订阅</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<hr className='dark:border-gray-600'/>
|
||||
|
||||
{/* 联系 */}
|
||||
<section className='mt-6 mb-6 '>
|
||||
<strong className='text-gray-600 dark:text-gray-400 px-6'>联系我</strong>
|
||||
<div>
|
||||
<i className='fa fa-map-marker text-sm dark:text-gray-300 px-6 mt-3' > Fuzhou, China</i>
|
||||
</div>
|
||||
<div>
|
||||
<SocialButton />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 站点信息 */}
|
||||
<section className='my-3 xl:block'>
|
||||
<hr className='dark:border-gray-600'/>
|
||||
<Footer />
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
{post && (
|
||||
<div className='sticky top-12'>
|
||||
<TocBar toc={post.toc} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
}
|
||||
export default SideBarEmbed
|
||||
67
components/SideBarResponsive.js
Normal file
67
components/SideBarResponsive.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import React from 'react'
|
||||
import Footer from '@/components/Footer'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import SocialButton from '@/components/SocialButton'
|
||||
|
||||
const SideBarResponsive = ({ tags, currentTag, post }) => {
|
||||
return <aside className='z-10 bg-white dark:border-gray-500 border-gray-200 mt-12 hidden md:block'>
|
||||
|
||||
<div
|
||||
className='dark:bg-gray-800 border-r dark:border-gray-700 h-full scroll-hidden left-0 duration-500 ease-in-out min-h-screen'>
|
||||
|
||||
{/* wrapper */}
|
||||
<div className='hidden md:block sticky top-12'>
|
||||
|
||||
{/* 菜单 */}
|
||||
<nav>
|
||||
<ul className='leading-8 text-gray-700 dark:text-gray-400'>
|
||||
<li className='hover:bg-gray-100 dark:hover:bg-black duration-100 p-2'>
|
||||
<a className='fa fa-home w-full px-4' href='/' id='home'>
|
||||
<span className='ml-2 hidden xl:inline-block'>主页</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className='hover:bg-gray-100 dark:hover:bg-black duration-100 p-2'>
|
||||
<a className='fa fa-info-circle w-full px-4' href='/article/about' id='about'>
|
||||
<span className='ml-2 hidden xl:inline-block'>关于本站</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className='hover:bg-gray-100 dark:hover:bg-black duration-100 p-2'>
|
||||
<a className='fa fa-rss-square w-full px-4' href='/feed' target='_blank' id='feed'>
|
||||
<span className='ml-2 hidden xl:inline-block'>RSS订阅</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<hr className='dark:border-gray-600'/>
|
||||
|
||||
{/* 联系 */}
|
||||
<section className='mt-6 mb-6 hidden xl:inline-block'>
|
||||
<strong className='text-gray-600 dark:text-gray-400 px-6'>联系我</strong>
|
||||
<div>
|
||||
<i className='fa fa-map-marker text-sm dark:text-gray-300 px-6 mt-3' > Fuzhou, China</i>
|
||||
</div>
|
||||
<div>
|
||||
<SocialButton />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 站点信息 */}
|
||||
<section className='my-3 hidden xl:block'>
|
||||
<hr className='dark:border-gray-600'/>
|
||||
<Footer />
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
{post && (
|
||||
<div className='sticky top-12'>
|
||||
<TocBar toc={post.toc} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
}
|
||||
export default SideBarResponsive
|
||||
@@ -1,8 +1,13 @@
|
||||
import React from 'react'
|
||||
|
||||
/**
|
||||
* 社交联系方式按钮组
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const SocialButton = () => {
|
||||
return <>
|
||||
<div className='space-x-3 text-2xl text-gray-500 dark:text-gray-400'>
|
||||
return <div className='w-52'>
|
||||
<div className='space-x-3 text-2xl text-black dark:text-gray-400 px-6'>
|
||||
<a target='_blank' rel='noreferrer' title={'github'}
|
||||
href={'https://github.com/tangly1024'} >
|
||||
<div className='fa fa-github transform hover:scale-125 duration-150'/>
|
||||
@@ -18,7 +23,8 @@ const SocialButton = () => {
|
||||
href={'https://weibo.com/tangly1024'} >
|
||||
<div className='fa fa-weibo transform hover:scale-125 duration-150'/>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
}
|
||||
export default SocialButton
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 标签组
|
||||
* @param tags
|
||||
* @param currentTag
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const Tags = ({ tags, currentTag }) => {
|
||||
if (!tags) return <></>
|
||||
return (
|
||||
<ul className='flex flex-wrap py-1 max-w-full overflow-x-auto'>
|
||||
return (<div className='bg-white dark:bg-gray-800 flex overflow-x-auto'>
|
||||
<ul id='tag-container' className='px-20 flex py-1 space-x-3'>
|
||||
{Object.keys(tags).map(key => {
|
||||
const selected = key === currentTag
|
||||
return (
|
||||
<Link key={key} href={`/tag/${encodeURIComponent(key)}`}>
|
||||
<Link key={key} href={selected ? '/' : `/tag/${encodeURIComponent(key)}`}>
|
||||
<li
|
||||
className={`cursor-pointer hover:bg-gray-600 rounded-sm hover:text-white duration-200 mr-1 my-1 px-2 py-1 font-medium text-xs whitespace-nowrap
|
||||
dark:text-gray-300 dark:hover:bg-gray-600 ${selected ? 'text-white bg-black dark:border-gray-600' : 'bg-gray-200 text-gray-600 dark:bg-gray-900 dark:border-gray-600'
|
||||
className={`cursor-pointer border hover:bg-gray-300 rounded-xl duration-200 mr-1 my-1 px-2 py-1 font-medium font-light text-sm whitespace-nowrap
|
||||
dark:text-gray-300 dark:hover:bg-gray-800 ${selected ? 'text-white bg-black dark:hover:bg-gray-900 dark:bg-black dark:border-gray-800' : 'bg-gray-100 text-gray-600 dark:bg-gray-600 dark:border-gray-600'
|
||||
}`}
|
||||
>
|
||||
<a>
|
||||
@@ -21,6 +28,7 @@ const Tags = ({ tags, currentTag }) => {
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ import { uuidToId } from 'notion-utils'
|
||||
import { cs } from 'react-notion-x'
|
||||
|
||||
/**
|
||||
* 目录组件
|
||||
* 目录导航组件
|
||||
* @param toc
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const TocBar = ({ toc }) => {
|
||||
// 无目录就直接返回空
|
||||
@@ -47,8 +50,8 @@ const TocBar = ({ toc }) => {
|
||||
setActiveSection(currentSectionId)
|
||||
}, throttleMs)
|
||||
|
||||
return <div className='bg-white dark:bg-gray-800 pb-10'>
|
||||
<div className='border-t border-b text-2xl bg-gray-100 font-bold text-black dark:bg-black dark:text-white py-6 px-6'>
|
||||
return <div className='bg-white dark:bg-gray-800 pb-10 w-52 hidden md:block min-h-screen'>
|
||||
<div className='border-t dark:border-gray-600 border-b text-2xl bg-gray-100 font-bold text-black dark:bg-black dark:text-white py-6 px-6'>
|
||||
文章目录
|
||||
</div>
|
||||
<nav className='text-gray-500 dark:text-gray-400 underline overflow-y-auto overflow-x-hidden'>
|
||||
|
||||
@@ -1,72 +1,105 @@
|
||||
import Link from 'next/link'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useState } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { useLocale } from '@/lib/locale'
|
||||
import Router, { useRouter } from 'next/router'
|
||||
import DarkModeButton from '@/components/DarkModeButton'
|
||||
import SocialButton from '@/components/SocialButton'
|
||||
import Image from 'next/image'
|
||||
import SideBarEmbed from '@/components/SideBarEmbed'
|
||||
|
||||
const TopNav = ({ tags, currentTag }) => {
|
||||
const TopNav = ({ tags, currentTag, post }) => {
|
||||
const locale = useLocale()
|
||||
const [hiddenMenu, switchHiddenMenu] = useState(!currentTag)
|
||||
// 点击按钮更改菜单状态
|
||||
const [showDrawer, switchShowDrawer] = useState(false)
|
||||
// 点击按钮更改侧边抽屉状态
|
||||
const handleMenuClick = () => {
|
||||
switchHiddenMenu(!hiddenMenu)
|
||||
switchShowDrawer(!showDrawer)
|
||||
}
|
||||
const router = useRouter()
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
const handleSearch = () => {
|
||||
if (searchValue && searchValue !== '') {
|
||||
Router.push({ pathname: '/', query: { s: searchValue } }).then(r => {
|
||||
console.log(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleKeyUp = (e) => {
|
||||
if (e.keyCode === 13) {
|
||||
Router.push({ pathname: '/', query: { s: searchValue } })
|
||||
handleSearch()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='bg-white dark:bg-gray-600'>
|
||||
{/* 隐藏的顶部菜单 */}
|
||||
<nav
|
||||
className={(hiddenMenu ? '-mt-10' : ' ') + ' py-1 overflow-hidden bg-gray-800 text-xl text-gray-200 w-full ease-in-out duration-500'}>
|
||||
<ul className='mx-5 duration-300'>
|
||||
<li>
|
||||
<SocialButton/>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div className='bg-white dark:bg-gray-600 border-b dark:border-gray-700'>
|
||||
|
||||
<div className='fixed top-0 left-0 z-30 h-full'>
|
||||
<div className={(showDrawer ? 'shadow-2xl' : '-ml-52') + ' duration-200 w-52 h-full bg-white dark:bg-gray-800 border-r dark:border-gray-600'}>
|
||||
<div className='flex space-x-4 px-5 dark:bg-gray-600'>
|
||||
<div
|
||||
className='z-10 p-1 duration-200 mr-2 bg-white dark:bg-gray-600 text-gray-600 text-xl cursor-pointer dark:text-gray-300'>
|
||||
<i className='fa hover:scale-125 transform duration-200 fa-bars ' onClick={handleMenuClick}/>
|
||||
</div>
|
||||
<Link href='/'>
|
||||
<a
|
||||
className='flex justify-center font-bold font-semibold hover:bg-gray-800 hover:text-white p-2 duration-200
|
||||
dark:text-gray-300
|
||||
'>{BLOG.title}</a>
|
||||
</Link>
|
||||
</div>
|
||||
<SideBarEmbed post={post}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={(showDrawer ? 'block' : 'hidden') + ' fixed top-0 left-0 z-20 w-full h-full bg-black bg-opacity-40' } onClick={handleMenuClick}/>
|
||||
|
||||
{/* 导航栏 */}
|
||||
<div
|
||||
id='sticky-nav'
|
||||
className='text-sm ticky-nav m-auto w-full flex flex-row justify-between items-center px-5 '
|
||||
className='text-sm m-auto w-full flex flex-row justify-between items-center px-5'
|
||||
>
|
||||
<div>
|
||||
<div className='flex space-x-4'>
|
||||
<div
|
||||
className='z-10 p-1 duration-200 mr-2 bg-white dark:bg-gray-600 text-gray-600 text-xl cursor-pointer dark:text-gray-300'>
|
||||
<i className='fa hover:scale-125 transform duration-200 fa-bars '
|
||||
onClick={handleMenuClick} />
|
||||
</div>
|
||||
<Link href='/'>
|
||||
<a
|
||||
className='flex justify-center border-black border-2 bg-whitefont-semibold hover:bg-gray-800 hover:text-white p-2 duration-200
|
||||
dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-100 dark:hover:text-black
|
||||
className='flex justify-center font-bold font-semibold hover:bg-gray-800 hover:text-white p-2 duration-200
|
||||
dark:text-gray-300
|
||||
'>{BLOG.title}</a>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{/* 搜索框 */}
|
||||
<div className='px-4 flex w-20'>
|
||||
<i className='py-3 fa fa-search text-gray-400 absolute cursor-pointer px-2' />
|
||||
<div className='flex border dark:border-gray-600'>
|
||||
<input
|
||||
type='text'
|
||||
placeholder={currentTag ? `${locale.SEARCH.TAGS} #${currentTag}` : `${locale.SEARCH.ARTICLES}`}
|
||||
className={'transition duration-200 leading-10 pl-8 block border-gray-300 dark:border-gray-600 bg-white text-black dark:bg-gray-800 dark:text-white'}
|
||||
className={'md:w-80 transition border-r dark:border-gray-700 duration-200 leading-10 pl-2 block border-gray-300 bg-white text-black dark:bg-gray-800 dark:text-white'}
|
||||
onKeyUp={handleKeyUp}
|
||||
onChange={e => setSearchValue(e.target.value)}
|
||||
defaultValue={router.query.s ?? ''}
|
||||
/>
|
||||
<div className='py-3 px-5 bg-gray-50 flex dark:bg-gray-500 justify-center align-middle cursor-pointer'
|
||||
onClick={handleSearch}>
|
||||
<i className='fa fa-search text-black absolute cursor-pointer' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-nowrap space-x-1'>
|
||||
<div className='z-10 p-1 border hover:shadow-xl duration-200 dark:border-gray-500 mr-2 h-12 my-2 bg-white dark:bg-gray-600 dark:bg-opacity-70 bg-opacity-70 dark:hover:bg-gray-100 text-xl cursor-pointer dark:text-gray-300 dark:hover:text-black'>
|
||||
<i className={'fa p-2.5 hover:scale-125 transform duration-200 ' + (hiddenMenu ? ' fa-bars ' : ' fa-times') } onClick={handleMenuClick} />
|
||||
</div>
|
||||
<DarkModeButton/>
|
||||
|
||||
<DarkModeButton />
|
||||
<a className='flex align-middle cursor-pointer' href='/article/about'>
|
||||
<Image
|
||||
alt={BLOG.author}
|
||||
width={28}
|
||||
height={28}
|
||||
src='/avatar.svg'
|
||||
className='rounded-full border-black'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* 评论插件
|
||||
* @param issueTerm
|
||||
* @param layout
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const Utterances = ({ issueTerm, layout }) => {
|
||||
useEffect(() => {
|
||||
const theme =
|
||||
BLOG.appearance === 'auto'
|
||||
? 'preferred-color-scheme'
|
||||
: BLOG.appearance === 'light'
|
||||
? 'github-light'
|
||||
: 'github-dark'
|
||||
? 'github-light'
|
||||
: 'github-dark'
|
||||
const script = document.createElement('script')
|
||||
const anchor = document.getElementById('comments')
|
||||
script.setAttribute('src', 'https://utteranc.es/client.js')
|
||||
|
||||
@@ -9,12 +9,13 @@ import { useRef } from 'react'
|
||||
import Image from 'next/image'
|
||||
import RewardButton from '@/components/RewardButton'
|
||||
import { useTheme } from '@/lib/theme'
|
||||
import SideBar from '@/components/SideBar'
|
||||
import BlogPostMini from '@/components/BlogPostMini'
|
||||
import { useRouter } from 'next/router'
|
||||
import ShareButton from '@/components/ShareButton'
|
||||
import TopJumper from '@/components/TopJumper'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
import TopNav from '@/components/TopNav'
|
||||
import SideBarResponsive from '@/components/SideBarResponsive'
|
||||
|
||||
const mapPageUrl = id => {
|
||||
return 'https://www.notion.so/' + id.replace(/-/g, '')
|
||||
@@ -47,10 +48,14 @@ const ArticleLayout = ({
|
||||
|
||||
<Progress targetRef={targetRef} />
|
||||
|
||||
<div className=' fixed w-full top-0 z-20'>
|
||||
<TopNav post={frontMatter}/>
|
||||
</div>
|
||||
|
||||
{/* Wrapper */}
|
||||
<div className='flex justify-between bg-gray-100 dark:bg-black'>
|
||||
|
||||
<SideBar tags={tags} post={frontMatter} />
|
||||
<SideBarResponsive tags={tags} post={frontMatter} />
|
||||
|
||||
{/* 主体区块 */}
|
||||
<main className='bg-gray-100 dark:bg-black w-full'>
|
||||
@@ -163,7 +168,7 @@ const ArticleLayout = ({
|
||||
{/* 分享按钮 */}
|
||||
<ShareButton post={frontMatter} />
|
||||
{/* 跳回顶部 */}
|
||||
<TopJumper />
|
||||
<JumpToTop />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,10 +4,10 @@ import Pagination from '@/components/Pagination'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTheme } from '@/lib/theme'
|
||||
import { useEffect, useState } from 'react'
|
||||
import SideBar from '@/components/SideBar'
|
||||
import throttle from 'lodash.throttle'
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
import TopNav from '@/components/TopNav'
|
||||
import Tags from '@/components/Tags'
|
||||
import SideBarResponsive from '@/components/SideBarResponsive'
|
||||
|
||||
const DefaultLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
|
||||
const meta = {
|
||||
@@ -44,80 +44,53 @@ const DefaultLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
|
||||
showNext = page * BLOG.postsPerPage < totalPosts
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// 首页隐藏看板娘
|
||||
// const ref = document.getElementById('waifu')
|
||||
// if (ref) {
|
||||
// ref.remove()
|
||||
// }
|
||||
window.addEventListener('resize', changeColumnCount)
|
||||
changeColumnCount()
|
||||
return () => {
|
||||
window.removeEventListener('resize', changeColumnCount)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const changeColumnCount = throttle(() => {
|
||||
if (window.innerWidth > 2500) {
|
||||
changeColumn(5)
|
||||
} else if (window.innerWidth > 1800) {
|
||||
changeColumn(4)
|
||||
} else if (window.innerWidth > 1300) {
|
||||
changeColumn(3)
|
||||
} else if (window.innerWidth > 900) {
|
||||
changeColumn(2)
|
||||
} else if (window.innerWidth <= 900) {
|
||||
changeColumn(1)
|
||||
}
|
||||
}, 500)
|
||||
|
||||
const [column, changeColumn] = useState(3)
|
||||
|
||||
const { theme } = useTheme()
|
||||
|
||||
return (
|
||||
<div id='wrapper' className={theme}>
|
||||
<CommonHead meta={meta} />
|
||||
<div className={`${BLOG.font} flex bg-gray-100 dark:bg-black min-h-screen`}>
|
||||
<div className=' fixed w-full top-0 z-20'>
|
||||
<TopNav />
|
||||
</div>
|
||||
|
||||
<div className={`${BLOG.font} flex justify-between bg-gray-100 dark:bg-black min-h-screen`}>
|
||||
{/* 侧边菜单 */}
|
||||
<SideBar tags={tags} currentTag={currentTag} />
|
||||
<main className='md:px-24 p-5 flex-grow'>
|
||||
{(!page || page === 1) && (<div className='py-5' />)}
|
||||
<SideBarResponsive />
|
||||
|
||||
{/* 标签 */}
|
||||
{currentTag && (
|
||||
<div className='pb-5 dark:text-gray-200'>
|
||||
<div className='py-1'>标签: {currentTag}</div>
|
||||
<hr />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 当前搜索 */}
|
||||
{(currentSearch || (page && page !== 1)) && (
|
||||
<div className='pb-5'>
|
||||
<div className='dark:text-gray-200 flex justify-between py-1'>
|
||||
{currentSearch && (<span>搜索关键词: {currentSearch}</span>)}
|
||||
{page && page !== 1 && (<span>页 {page} / {totalPages}</span>)}
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='mx-auto'>
|
||||
{/* 文章列表 */}
|
||||
<div style={{ columnCount: column }}>
|
||||
{!postsToShow.length && (
|
||||
<p className='text-gray-500 dark:text-gray-300'>No posts found.</p>
|
||||
)}
|
||||
{postsToShow.map(post => (
|
||||
<BlogPost key={post.id} post={post} tags={tags} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Pagination page={page} showNext={showNext} />
|
||||
<div className='flex-grow'>
|
||||
<div className='fixed top-12 z-10 w-full border-b dark:border-gray-600'>
|
||||
<Tags tags={tags} currentTag={currentTag} />
|
||||
</div>
|
||||
|
||||
</main>
|
||||
<main id='post-list-wrapper' className='py-24 px-8 md:px-20'>
|
||||
{(!page || page === 1) && (<div className='py-5' />)}
|
||||
|
||||
{/* 当前搜索 */}
|
||||
{(currentSearch || (page && page !== 1)) && (
|
||||
<div className='pb-5'>
|
||||
<div className='dark:text-gray-200 flex justify-between py-1'>
|
||||
{page && page !== 1 && (<span>页 {page} / {totalPages}</span>)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className=''>
|
||||
{/* 文章列表 */}
|
||||
<div className='grid xl:grid-cols-3 lg:grid-cols-2 grid-cols-1 gap-3'>
|
||||
{!postsToShow.length && (
|
||||
<p className='text-gray-500 dark:text-gray-300'>No posts found.</p>
|
||||
)}
|
||||
{postsToShow.map(post => (
|
||||
<BlogPost key={post.id} post={post} tags={tags} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Pagination page={page} showNext={showNext} />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -109,12 +109,9 @@ nav {
|
||||
@apply right-auto left-0 hidden lg:block z-10 !important
|
||||
}
|
||||
|
||||
@media (max-width: 1300px){
|
||||
.sidebar{
|
||||
-ms-overflow-style: none;
|
||||
overflow: -moz-scrollbars-none;
|
||||
@apply border-r border-gray-200 h-screen overflow-y-scroll fixed left-0
|
||||
}
|
||||
.sidebar::-webkit-scrollbar { width: 0 !important }
|
||||
.scroll-hidden{
|
||||
-ms-overflow-style: none;
|
||||
overflow: -moz-scrollbars-none;
|
||||
}
|
||||
|
||||
.scroll-hidden::-webkit-scrollbar { width: 0 !important }
|
||||
|
||||
Reference in New Issue
Block a user