mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
组件调整、排版调整、新增右侧目录抽屉
This commit is contained in:
@@ -69,7 +69,7 @@
|
||||
- **页面渲染**: [React-notion-x](https://github.com/NotionX/react-notion-x)
|
||||
- **样式**: Tailwind CSS 和 `@tailwindcss/jit` compiler
|
||||
- **评论**: Gitalk,Cusdis,Utterances
|
||||
- **图标**:[fontawesome](https://fontawesome.com/v5.15/icons?d=gallery)
|
||||
- **图标**:[fontawesome](https://fontawesome.com/v4.7/icons/?d=gallery)
|
||||
|
||||
## 页面样式主题
|
||||
- 仿照 [fukasawa](https://andersnoren.se/themes/fukasawa)
|
||||
|
||||
@@ -34,7 +34,6 @@ const Container = ({ children, layout, fullWidth, tags, meta, ...customMeta }) =
|
||||
return (
|
||||
<div className={[BLOG.font, theme].join(' ')}>
|
||||
<CommonHead meta={meta} />
|
||||
<TopNav tags={tags}/>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -3,14 +3,16 @@ import BLOG from '@/blog.config'
|
||||
import SearchInput from '@/components/SearchInput'
|
||||
import MenuButtonGroup from '@/components/MenuButtonGroup'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import React, { forwardRef, useImperativeHandle, useState } from 'react'
|
||||
import React, { useImperativeHandle, useState } from 'react'
|
||||
import InfoCard from '@/components/InfoCard'
|
||||
import TagList from '@/components/TagList'
|
||||
|
||||
/**
|
||||
* 抽屉面板,可以从侧面拉出
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const Drawer = ({ post, currentTag, cRef }) => {
|
||||
const Drawer = ({ post, currentTag, cRef, tags }) => {
|
||||
// 暴露给父组件 通过cRef.current.handleMenuClick 调用
|
||||
useImperativeHandle(cRef, () => {
|
||||
return {
|
||||
@@ -22,6 +24,7 @@ const Drawer = ({ post, currentTag, cRef }) => {
|
||||
const handleMenuClick = () => {
|
||||
switchShowDrawer(!showDrawer)
|
||||
}
|
||||
console.log(post)
|
||||
return <div>
|
||||
<div className='fixed top-0 left-0 z-30 h-full'>
|
||||
<div
|
||||
@@ -49,11 +52,16 @@ const Drawer = ({ post, currentTag, cRef }) => {
|
||||
<div className='px-5 my-3 block md:hidden'>
|
||||
<SearchInput currentTag={currentTag} />
|
||||
</div>
|
||||
<InfoCard/>
|
||||
{/* 菜单 */}
|
||||
<MenuButtonGroup allowCollapse={false} />
|
||||
{post && (
|
||||
<div className='sticky top-24'>
|
||||
<TocBar toc={post.toc} />
|
||||
{tags && (
|
||||
<div className='p-4'>
|
||||
{/* 标签云 */}
|
||||
<section>
|
||||
<strong className='text-xl text-gray-600 dark:text-gray-400'>标签</strong>
|
||||
<TagList tags={tags} currentTag={currentTag} />
|
||||
</section>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
52
components/DrawerRight.js
Normal file
52
components/DrawerRight.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import TocBar from '@/components/TocBar'
|
||||
import React, { useImperativeHandle, useState } from 'react'
|
||||
|
||||
/**
|
||||
* 右侧边栏
|
||||
* @param toc
|
||||
* @param post
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const DrawerRight = ({ post, cRef }) => {
|
||||
// 暴露给父组件 通过cRef.current.handleMenuClick 调用
|
||||
useImperativeHandle(cRef, () => {
|
||||
return {
|
||||
handleMenuClick: () => handleMenuClick()
|
||||
}
|
||||
})
|
||||
const [showDrawer, switchShowDrawer] = useState(false)
|
||||
const handleMenuClick = () => {
|
||||
switchShowDrawer(!showDrawer)
|
||||
}
|
||||
|
||||
console.log(post)
|
||||
return <div>
|
||||
<div className='fixed top-0 right-0 z-30 h-full'>
|
||||
<div
|
||||
className={(showDrawer ? 'shadow-2xl' : '-mr-72') + ' overflow-y-auto duration-200 w-72 h-full bg-white dark:bg-gray-700 border-r dark:border-gray-600'}>
|
||||
{/* LOGO */}
|
||||
<div className='sticky top-0 z-20 bg-white w-72 flex space-x-4 px-5 py-3.5 dark:border-gray-500 border-b dark:bg-gray-900 '>
|
||||
<div className='flex text-lg justify-center font-bold font-semibold px-2 py-1 duration-200 dark:text-gray-300'>文章目录
|
||||
</div>
|
||||
<div
|
||||
className='z-10 p-1 duration-200 mr-2 absolute right-6 text-gray-600 text-xl cursor-pointer dark:text-gray-300'>
|
||||
<i className='fa hover:scale-125 transform duration-200 fa-bookmark-o ' onClick={handleMenuClick} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 侧边菜单 */}
|
||||
<div
|
||||
className={(showDrawer ? 'shadow-2xl ' : ' -mr-72 ') + ' w-72 duration-200 h-full fixed right-0 top-16 overflow-y-auto'}>
|
||||
<div className='z-20'>
|
||||
<TocBar toc={post.toc}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 背景蒙版 */}
|
||||
<div className={(showDrawer ? 'block' : 'hidden') + ' fixed top-0 left-0 z-20 w-full h-full bg-black bg-opacity-50'}
|
||||
onClick={handleMenuClick} />
|
||||
</div>
|
||||
}
|
||||
export default DrawerRight
|
||||
27
components/InfoCard.js
Normal file
27
components/InfoCard.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import Image from 'next/image'
|
||||
import React from 'react'
|
||||
import Router from 'next/router'
|
||||
|
||||
const InfoCard = () => {
|
||||
return <>
|
||||
<div className='flex justify-center text-center'>
|
||||
<div className='mx-auto py-4 leading-8'>
|
||||
<div className='hover:rotate-45 hover:scale-125 transform duration-200 cursor-pointer' onClick={ () => { Router.push('/') }}>
|
||||
<Image
|
||||
alt={BLOG.author}
|
||||
width={100}
|
||||
height={100}
|
||||
src='/avatar.svg'
|
||||
className='rounded-full border-black'
|
||||
/>
|
||||
</div>
|
||||
<h1 className='text-2xl dark:text-white py-2'>{BLOG.author}</h1>
|
||||
<h2 className='text-sm text-gray-500 dark:text-gray-400'>{BLOG.description}</h2>
|
||||
<h2 className='text-sm fa fa-map-marker text-gray-500 dark:text-gray-400'> Fuzhou,China</h2>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default InfoCard
|
||||
@@ -33,7 +33,7 @@ const JumpToTop = ({ targetRef, showPercent = true }) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={(show ? 'animate__fade InUp' : 'animate__fadeOutUp') + ' animate__animated animate__faster'}>
|
||||
className={(show ? 'animate__fade InUp' : 'animate__fadeOutUp') + ' animate__animated animate__faster shadow-lg'}>
|
||||
<div
|
||||
className='border dark:border-gray-500 dark:bg-gray-600 bg-white cursor-pointer hover:shadow-2xl'
|
||||
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}>
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import React from 'react'
|
||||
import { useLocale } from '@/lib/locale'
|
||||
import Link from 'next/link'
|
||||
|
||||
const MenuButtonGroup = ({ allowCollapse = false }) => {
|
||||
const locale = useLocale()
|
||||
const links = [
|
||||
{ id: 0, icon: 'fa-home', name: locale.NAV.INDEX, to: '/' || '/', show: true },
|
||||
// { id: 0, icon: 'fa-home', name: locale.NAV.INDEX, to: '/' || '/', show: true },
|
||||
{ id: 1, icon: 'fa-info-circle', name: locale.NAV.ABOUT, to: '/article/about', show: true },
|
||||
{ id: 2, icon: 'fa-rss-square', name: locale.NAV.RSS, to: '/feed', show: true },
|
||||
{ id: 3, icon: 'fa-compass', name: '发现', to: 'https://search.tangly1024.com/', show: true },
|
||||
{ id: 4, icon: 'fa-envelope', name: locale.NAV.MAIL, to: 'mailto:tlyong1992@hotmail.com', show: true },
|
||||
{ id: 5, icon: 'fa-weibo', name: '微博', to: 'https://weibo.com/tangly1024', show: true },
|
||||
{ id: 6, icon: 'fa-map-marker', name: 'Fuzhou', to: '#', show: true },
|
||||
{ id: 7, icon: 'fa-github', name: 'Github', to: 'https://github.com/tangly1024', show: true },
|
||||
{ id: 8, icon: 'fa-twitter', name: 'Twitter', to: 'https://twitter.com/troy1024_1', show: true },
|
||||
{ id: 9, icon: 'fa-telegram', name: 'Telegram', to: 'https://t.me/tangly_1024', show: true }
|
||||
{ id: 5, icon: 'fa-weibo', name: '微博', to: 'https://weibo.com/tangly1024', show: true },
|
||||
{ id: 4, icon: 'fa-envelope', name: locale.NAV.MAIL, to: 'mailto:tlyong1992@hotmail.com', show: true },
|
||||
{ id: 2, icon: 'fa-rss-square', name: locale.NAV.RSS, to: '/feed', show: true },
|
||||
{ id: 3, icon: 'fa-compass', name: '发现', to: 'https://search.tangly1024.com/', show: true }
|
||||
// { id: 6, icon: 'fa-map-marker', name: 'Fuzhou', to: '#', show: true },
|
||||
// { id: 8, icon: 'fa-twitter', name: 'Twitter', to: 'https://twitter.com/troy1024_1', show: true },
|
||||
// { id: 9, icon: 'fa-telegram', name: 'Telegram', to: 'https://t.me/tangly_1024', show: true }
|
||||
]
|
||||
return <nav id='nav'>
|
||||
<div className='leading-8 text-gray-700 dark:text-gray-400'>
|
||||
@@ -25,7 +24,7 @@ const MenuButtonGroup = ({ allowCollapse = false }) => {
|
||||
key={link.id + link.icon}
|
||||
title={link.to}
|
||||
href={link.to}
|
||||
className='py-3 px-5 hover:bg-gray-100 cursor-pointer dark:hover:bg-black duration-100 flex flex-nowrap align-middle'
|
||||
className='py-2 px-5 hover:bg-gray-100 cursor-pointer dark:hover:bg-black duration-100 flex flex-nowrap align-middle'
|
||||
>
|
||||
<div className='my-auto w-5 text-2xl justify-center flex'>
|
||||
<i className={'fa ' + link.icon} />
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import React, { useRef, useState } from 'react'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import throttle from 'lodash.throttle'
|
||||
import ShareButton from '@/components/ShareButton'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
|
||||
/**
|
||||
* 右侧边栏
|
||||
* @param toc
|
||||
* @param post
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const RightAside = ({ toc, post }) => {
|
||||
// 无目录就直接返回空
|
||||
if (toc.length < 1) return <></>
|
||||
// 监听滚动事件
|
||||
React.useEffect(() => {
|
||||
window.addEventListener('resize', resizeWindowHideToc)
|
||||
return () => {
|
||||
window.removeEventListener('resize', resizeWindowHideToc)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const resizeWindowHideToc = throttle(() => {
|
||||
if (window.innerWidth > 1300) {
|
||||
changeHideAside(false)
|
||||
} else {
|
||||
changeHideAside(true)
|
||||
}
|
||||
}, 500)
|
||||
const [hideAside, changeHideAside] = useState(true)
|
||||
const targetRef = useRef()
|
||||
return <aside className='dark:bg-gray-800' ref={targetRef}>
|
||||
{/* 上方菜单组 */}
|
||||
<div
|
||||
className={(hideAside ? 'right-0' : 'right-48') + ' z-20 space-x-2 fixed flex top-0 px-3 py-1 duration-500'}>
|
||||
{/* 目录按钮 */}
|
||||
<div
|
||||
className='border dark:border-gray-500 my-2 bg-white dark:bg-gray-600 bg-opacity-70 dark:hover:bg-gray-100 text-xl cursor-pointer dark:text-gray-300 dark:hover:text-black p-1'>
|
||||
<i className='fa fa-book p-2.5 hover:scale-125 transform duration-200'
|
||||
onClick={() => changeHideAside(!hideAside)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 下方菜单组 */}
|
||||
<div
|
||||
className={(hideAside ? 'right-0' : 'right-48') + ' space-x-2 fixed flex bottom-24 px-4 py-1 duration-500'}>
|
||||
<div className='flex-wrap'>
|
||||
{/* 分享按钮 */}
|
||||
<ShareButton post={post} />
|
||||
{/* 跳回顶部 */}
|
||||
<JumpToTop targetRef={targetRef} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 目录 */}
|
||||
<section
|
||||
className={(hideAside ? '-mr-48' : 'mr-0 shadow-xl xl:shadow-none') + ' md:static top-0 fixed h-full w-48 right-0 dark:bg-gray-800 duration-500 top-0'}>
|
||||
<div className='sticky top-0'>
|
||||
<TocBar toc={toc} />
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</aside>
|
||||
}
|
||||
export default RightAside
|
||||
@@ -24,7 +24,7 @@ const ShareButton = ({ post }) => {
|
||||
<ShareBar post={post}/>
|
||||
</div>
|
||||
<div ref={btnRef}
|
||||
className='z-20 border dark:border-gray-500 dark:bg-gray-600 bg-white cursor-pointer text-md hover:shadow-2xl'>
|
||||
className='z-20 border dark:border-gray-500 dark:bg-gray-600 bg-white cursor-pointer text-md hover:shadow-2xl shadow-lg'>
|
||||
<i className='transform duration-200 hover:scale-150 dark:text-gray-200 p-4 fa fa-share-alt' title='share' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
import React from 'react'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import MenuButtonGroup from '@/components/MenuButtonGroup'
|
||||
import InfoCard from '@/components/InfoCard'
|
||||
import TagList from '@/components/TagList'
|
||||
|
||||
const SideBar = ({ tags, currentTag, post }) => {
|
||||
return <aside className='z-10 bg-white dark:border-gray-500 border-gray-200 hidden md:block'>
|
||||
return <aside className='z-10 dark:border-gray-500 border-gray-200 bg-white 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'>
|
||||
<div className='hidden md:block sticky top-16'>
|
||||
|
||||
<InfoCard/>
|
||||
<div className={post ? 'hidden xl:block' : 'block'}>
|
||||
<MenuButtonGroup allowCollapse={true}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{post && (
|
||||
<div className='sticky top-12'>
|
||||
<TocBar toc={post.toc} />
|
||||
</div>
|
||||
)}
|
||||
{tags && (
|
||||
<div className='p-4'>
|
||||
{/* 标签云 */}
|
||||
<section>
|
||||
<strong className='text-xl text-gray-600 dark:text-gray-400'>标签</strong>
|
||||
<TagList tags={tags} currentTag={currentTag} />
|
||||
</section>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
}
|
||||
|
||||
34
components/TagList.js
Normal file
34
components/TagList.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 标签组
|
||||
* @param tags
|
||||
* @param currentTag
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const TagList = ({ tags, currentTag }) => {
|
||||
if (!tags) return <></>
|
||||
return (
|
||||
<div id='tags-list' className='duration-500 dark:border-gray-600 dark:bg-gray-800 w-52 pt-2'>
|
||||
{Object.keys(tags).map(key => {
|
||||
const selected = key === currentTag
|
||||
return (
|
||||
<Link key={key} href={selected ? '/' : `/tag/${encodeURIComponent(key)}`}>
|
||||
<span
|
||||
className={`cursor-pointer inline-block border hover:bg-gray-300 duration-200 mr-1 my-1 p-1 font-medium font-light text-xs 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-200 text-gray-600 dark:bg-gray-600 dark:border-gray-600'
|
||||
}`}
|
||||
>
|
||||
<a>
|
||||
{`${key} (${tags[key]})`}
|
||||
</a>
|
||||
</span>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TagList
|
||||
@@ -7,9 +7,11 @@ import Link from 'next/link'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const Tags = ({ tags, currentTag }) => {
|
||||
const TagsBar = ({ tags, currentTag }) => {
|
||||
if (!tags) return <></>
|
||||
return (<div className='bg-white dark:bg-gray-800 flex overflow-x-auto'>
|
||||
return (
|
||||
<div id='tags-bar' className='fixed xl:mt-0 top-16 duration-500 z-10 w-full border-b dark:border-gray-600'>
|
||||
<div className='bg-white dark:bg-gray-800 flex overflow-x-auto'>
|
||||
<div className='z-30 sticky left-0 flex'>
|
||||
<div className='px-2 bg-white dark:bg-gray-800'/>
|
||||
<div className='px-5 -line-x-opacity bg-black'/>
|
||||
@@ -38,7 +40,8 @@ const Tags = ({ tags, currentTag }) => {
|
||||
<div className='px-2 bg-white dark:bg-gray-800'/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Tags
|
||||
export default TagsBar
|
||||
@@ -51,10 +51,7 @@ const TocBar = ({ toc }) => {
|
||||
}, throttleMs))
|
||||
|
||||
return <div className='bg-white dark:bg-gray-800 pb-10 min-h-screen'>
|
||||
<div className='w-52 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-auto'>
|
||||
<nav className='text-gray-500 dark:text-gray-400 underline overflow-auto scroll-hidden py-2'>
|
||||
{toc.map((tocItem) => {
|
||||
const id = uuidToId(tocItem.id)
|
||||
return (
|
||||
|
||||
@@ -2,23 +2,22 @@ import Link from 'next/link'
|
||||
import BLOG from '@/blog.config'
|
||||
import React, { useRef } from 'react'
|
||||
import DarkModeButton from '@/components/DarkModeButton'
|
||||
import Image from 'next/image'
|
||||
import SearchInput from '@/components/SearchInput'
|
||||
import Drawer from '@/components/Drawer'
|
||||
import DrawerRight from '@/components/DrawerRight'
|
||||
|
||||
const TopNav = ({ tags, currentTag, post }) => {
|
||||
const drawer = useRef()
|
||||
const drawerRight = useRef()
|
||||
|
||||
return (<div className='fixed w-full top-0 z-20'>
|
||||
{/* 侧面抽屉 */}
|
||||
<Drawer post={post} currentTag={currentTag} cRef={drawer} />
|
||||
<Drawer post={post} currentTag={currentTag} cRef={drawer} tags={tags} />
|
||||
<DrawerRight post={post} cRef={drawerRight}/>
|
||||
|
||||
<div id='sticky-nav'
|
||||
className='transform 2xl:mt-0 duration-500 bg-white dark:bg-gray-800 border-b dark:border-gray-700'>
|
||||
{/* 导航栏 */}
|
||||
<div
|
||||
className=' text-sm m-auto w-full flex flex-row justify-between items-center px-4 py-2 shadow-md '
|
||||
>
|
||||
{/* 导航栏 */}
|
||||
<div id='sticky-nav' className='xl:mt-0 transform 2xl:mt-0 duration-500 bg-white dark:bg-gray-800 border-b dark:border-gray-700'>
|
||||
<div className='text-sm m-auto w-full flex flex-row justify-between items-center px-4 py-2 shadow-md'>
|
||||
{/* 左侧LOGO */}
|
||||
<div className='flex ml-12'>
|
||||
<div onClick={() => { drawer.current.handleMenuClick() }}
|
||||
@@ -42,16 +41,8 @@ const TopNav = ({ tags, currentTag, post }) => {
|
||||
{/* 右侧功能 */}
|
||||
<div className='flex flex-nowrap space-x-1'>
|
||||
<DarkModeButton />
|
||||
<div className='flex align-middle cursor-pointer'>
|
||||
<Link href='/article/about'>
|
||||
<Image
|
||||
alt={BLOG.author}
|
||||
width={28}
|
||||
height={28}
|
||||
src='/avatar.svg'
|
||||
className='rounded-full border-black'
|
||||
/>
|
||||
</Link>
|
||||
<div className='z-10 p-1 duration-200 mr-2 h-12 text-xl cursor-pointer dark:text-gray-300 '>
|
||||
<i className='fa p-2.5 hover:scale-125 transform duration-200 fa-bookmark' onClick={() => { drawerRight.current.handleMenuClick() }}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import formatDate from '@/lib/formatDate'
|
||||
import 'gitalk/dist/gitalk.css'
|
||||
import Comment from '@/components/Comment'
|
||||
import Progress from '@/components/Progress'
|
||||
import { useRef } from 'react'
|
||||
import React, { useRef } from 'react'
|
||||
import Image from 'next/image'
|
||||
import RewardButton from '@/components/RewardButton'
|
||||
import BlogPostMini from '@/components/BlogPostMini'
|
||||
@@ -15,6 +15,8 @@ import JumpToTop from '@/components/JumpToTop'
|
||||
import SideBar from '@/components/SideBar'
|
||||
import Footer from '@/components/Footer'
|
||||
import Container from '@/components/Container'
|
||||
import TocBar from '@/components/TocBar'
|
||||
import TopNav from '@/components/TopNav'
|
||||
|
||||
const mapPageUrl = id => {
|
||||
return 'https://www.notion.so/' + id.replace(/-/g, '')
|
||||
@@ -23,7 +25,7 @@ const mapPageUrl = id => {
|
||||
const ArticleLayout = ({
|
||||
children,
|
||||
blockMap,
|
||||
frontMatter,
|
||||
post,
|
||||
emailHash,
|
||||
fullWidth = true,
|
||||
tags,
|
||||
@@ -31,7 +33,7 @@ const ArticleLayout = ({
|
||||
next
|
||||
}) => {
|
||||
const meta = {
|
||||
title: frontMatter.title,
|
||||
title: post.title,
|
||||
type: 'article'
|
||||
}
|
||||
const targetRef = useRef(null)
|
||||
@@ -41,14 +43,16 @@ const ArticleLayout = ({
|
||||
<Container meta={meta} tags={tags}>
|
||||
|
||||
{/* live2d 看板娘 */}
|
||||
<script async src='https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js' />
|
||||
<script async src='https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js' />
|
||||
|
||||
<Progress targetRef={targetRef} />
|
||||
|
||||
<TopNav tags={tags} post={post} />
|
||||
|
||||
{/* Wrapper */}
|
||||
<div className='flex justify-between bg-gray-100'>
|
||||
|
||||
<SideBar tags={tags} post={frontMatter} />
|
||||
<SideBar tags={tags} post={post} />
|
||||
|
||||
{/* 主体区块 */}
|
||||
<main className='bg-gray-100 w-full dark:bg-gray-800' ref={targetRef} >
|
||||
@@ -56,23 +60,23 @@ const ArticleLayout = ({
|
||||
<header
|
||||
className='hover:scale-105 hover:shadow-2xl duration-200 transform mx-auto max-w-5xl mt-16 lg:mt-20 md:flex-shrink-0 animate__fadeIn animate__animated'>
|
||||
{/* 封面图 */}
|
||||
{frontMatter.page_cover && frontMatter.page_cover.length > 1 && (
|
||||
{post.page_cover && post.page_cover.length > 1 && (
|
||||
<img className='bg-center object-cover w-full' style={{ maxHeight: '40rem' }}
|
||||
src={frontMatter.page_cover} alt={frontMatter.title} />
|
||||
src={post.page_cover} alt={post.title} />
|
||||
)}
|
||||
</header>
|
||||
|
||||
<article className='mb-10 overflow-x-auto md:px-10 px-5 py-10 max-w-5xl mx-auto bg-white dark:border-gray-700 dark:bg-gray-700'>
|
||||
{/* 文章标题 */}
|
||||
<h1 className='font-bold text-4xl text-black my-5 dark:text-white animate__animated animate__fadeIn'>
|
||||
{frontMatter.title}
|
||||
{post.title}
|
||||
</h1>
|
||||
|
||||
{/* 文章信息 */}
|
||||
<div className='justify-between flex flex-wrap bg-gray-50 p-2 dark:bg-gray-700 dark:text-white'>
|
||||
<div className='flex-nowrap flex'>
|
||||
|
||||
{frontMatter.slug !== 'about' && (<>
|
||||
{post.slug !== 'about' && (<>
|
||||
<a
|
||||
className='hidden md:block duration-200 px-1' href='/article/about'
|
||||
>
|
||||
@@ -80,18 +84,18 @@ const ArticleLayout = ({
|
||||
className='rounded-full cursor-pointer transform hover:scale-125 duration-200' />
|
||||
</a>
|
||||
</>)}
|
||||
{frontMatter.tags && (
|
||||
{post.tags && (
|
||||
<div className='flex flex-nowrap leading-8 p-1'>
|
||||
{frontMatter.tags.map(tag => (
|
||||
{post.tags.map(tag => (
|
||||
<TagItem key={tag} tag={tag} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{frontMatter.type[0] !== 'Page' && (
|
||||
{post.type[0] !== 'Page' && (
|
||||
<div className='flex items-start text-gray-500 dark:text-gray-400 leading-10'>
|
||||
{formatDate(
|
||||
frontMatter?.date?.start_date || frontMatter.createdTime,
|
||||
post?.date?.start_date || post.createdTime,
|
||||
BLOG.lang
|
||||
)}
|
||||
</div>
|
||||
@@ -131,7 +135,7 @@ const ArticleLayout = ({
|
||||
className='overflow-auto dark:bg-gray-700 dark:text-gray-300 bg-gray-100 p-5 leading-8 border-l-4 border-red-500'>
|
||||
<ul>
|
||||
<li><strong>本文作者:</strong>{BLOG.author}</li>
|
||||
<li><strong>本文链接:</strong> <a href={url}>{url}</a> 《{frontMatter.title}》</li>
|
||||
<li><strong>本文链接:</strong> <a href={url}>{url}</a> 《{post.title}》</li>
|
||||
<li><strong>版权声明:</strong> 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!</li>
|
||||
</ul>
|
||||
</section>
|
||||
@@ -144,7 +148,7 @@ const ArticleLayout = ({
|
||||
</div>
|
||||
</div>
|
||||
{/* 评论互动 */}
|
||||
<Comment frontMatter={frontMatter} />
|
||||
<Comment frontMatter={post} />
|
||||
</article>
|
||||
|
||||
<div className='w-full border-t px-10 max-w-5xl mx-auto'>
|
||||
@@ -153,12 +157,24 @@ const ArticleLayout = ({
|
||||
|
||||
</main>
|
||||
|
||||
{/* 目录 */}
|
||||
<aside className='dark:bg-gray-800'>
|
||||
<section className='xl:static xl:block hidden top-0 right-0 fixed h-full w-52 dark:bg-gray-800 duration-500'>
|
||||
<div className='sticky top-16'>
|
||||
<div className='border-t dark:border-gray-600 border-b text-2xl bg-white font-bold text-black dark:bg-black dark:text-white py-6 px-6'>
|
||||
文章目录
|
||||
</div>
|
||||
<TocBar toc={post.toc} />
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
{/* 下方菜单组 */}
|
||||
<div
|
||||
className='right-0 space-x-2 fixed flex bottom-24 px-5 py-1 duration-500'>
|
||||
<div className='flex-wrap'>
|
||||
{/* 分享按钮 */}
|
||||
<ShareButton post={frontMatter} />
|
||||
<ShareButton post={post} />
|
||||
{/* 跳回顶部 */}
|
||||
<JumpToTop targetRef={targetRef}/>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useRouter } from 'next/router'
|
||||
import Tags from '@/components/Tags'
|
||||
import TagsBar from '@/components/TagsBar'
|
||||
import Footer from '@/components/Footer'
|
||||
import React, { useRef } from 'react'
|
||||
import Container from '@/components/Container'
|
||||
@@ -54,11 +54,7 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
|
||||
{/* 侧边菜单 */}
|
||||
<SideBar />
|
||||
<div className='flex-grow'>
|
||||
|
||||
<div id='tags-bar' className='fixed 2xl:mt-0 top-16 duration-500 z-10 w-full border-b dark:border-gray-600'>
|
||||
<Tags tags={tags} currentTag={currentTag} />
|
||||
</div>
|
||||
|
||||
<TagsBar tags={tags} currentTag={currentTag} />
|
||||
<main id='post-list-wrapper' className='pt-16 md:pt-28 px-2 md:px-20'>
|
||||
{(!page || page === 1) && (<div className='py-5' />)}
|
||||
|
||||
@@ -88,13 +84,11 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
|
||||
<Footer/>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 下方菜单组 */}
|
||||
<div
|
||||
className='right-0 space-x-2 fixed flex bottom-24 px-5 py-1 duration-500'>
|
||||
<div className='right-0 space-x-2 fixed flex bottom-24 px-5 py-1 duration-500'>
|
||||
<div className='flex-wrap'>
|
||||
<JumpToTop targetRef={targetRef} showPercent={false}/>
|
||||
</div>
|
||||
|
||||
@@ -3,11 +3,12 @@ import PropTypes from 'prop-types'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useRouter } from 'next/router'
|
||||
import Tags from '@/components/Tags'
|
||||
import TagsBar from '@/components/TagsBar'
|
||||
import Footer from '@/components/Footer'
|
||||
import React, { useRef } from 'react'
|
||||
import Container from '@/components/Container'
|
||||
import JumpToTop from '@/components/JumpToTop'
|
||||
import SideBar from '@/components/SideBar'
|
||||
|
||||
const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
|
||||
const meta = {
|
||||
@@ -50,12 +51,10 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
|
||||
|
||||
<div ref={targetRef} className={`${BLOG.font} flex justify-between bg-gray-100 dark:bg-black min-h-screen`}>
|
||||
{/* 侧边菜单 */}
|
||||
{/* <SideBar /> */}
|
||||
<SideBar />
|
||||
<div className='flex-grow'>
|
||||
|
||||
<div id='tags-bar' className='fixed top-16 duration-500 z-10 w-full border-b dark:border-gray-600'>
|
||||
<Tags tags={tags} currentTag={currentTag} />
|
||||
</div>
|
||||
<TagsBar tags={tags} currentTag={currentTag} />
|
||||
|
||||
<main id='post-list-wrapper' className='pt-16 md:pt-28 px-2 md:px-20'>
|
||||
{(!page || page === 1) && (<div className='py-5' />)}
|
||||
@@ -83,7 +82,7 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
|
||||
<Pagination page={page} showNext={showNext} />
|
||||
</div>
|
||||
<div className='w-full border-t '>
|
||||
<Footer/>
|
||||
<Footer />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -94,7 +93,7 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
|
||||
<div
|
||||
className='right-0 space-x-2 fixed flex bottom-24 px-5 py-1 duration-500'>
|
||||
<div className='flex-wrap'>
|
||||
<JumpToTop targetRef={targetRef} showPercent={false}/>
|
||||
<JumpToTop targetRef={targetRef} showPercent={false} />
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -12,7 +12,7 @@ const BlogPost = ({ post, blockMap, emailHash, tags, prev, next }) => {
|
||||
return (
|
||||
<ArticleLayout
|
||||
blockMap={blockMap}
|
||||
frontMatter={post}
|
||||
post={post}
|
||||
emailHash={emailHash}
|
||||
tags={tags}
|
||||
prev={prev}
|
||||
|
||||
Reference in New Issue
Block a user