mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-16 15:09:28 +00:00
medium toc mobile
This commit is contained in:
@@ -10,10 +10,10 @@ import CONFIG_HEXO from '../config_hexo'
|
||||
* @constructor
|
||||
*/
|
||||
const TocDrawerButton = (props) => {
|
||||
const { locale } = useGlobal()
|
||||
if (!CONFIG_HEXO.WIDGET_TOC) {
|
||||
return <></>
|
||||
}
|
||||
const { locale } = useGlobal()
|
||||
return (<div onClick={props.onClick} className='py-2 px-3 cursor-pointer transform duration-200 flex justify-center items-center w-7 h-7 text-center' title={locale.POST.TOP} >
|
||||
<i className='fas fa-list-ol text-xs'/>
|
||||
</div>)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
import React from 'react'
|
||||
import { useState, createContext, useContext } from 'react'
|
||||
import Footer from './components/Footer'
|
||||
import InfoCard from './components/InfoCard'
|
||||
import RevolverMaps from './components/RevolverMaps'
|
||||
@@ -12,6 +12,7 @@ import { useGlobal } from '@/lib/global'
|
||||
import { useRouter } from 'next/router'
|
||||
import Live2D from '@/components/Live2D'
|
||||
import BLOG from '@/blog.config'
|
||||
const ThemeGlobalMedium = createContext()
|
||||
|
||||
/**
|
||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||
@@ -23,9 +24,10 @@ const LayoutBase = props => {
|
||||
const { children, meta, showInfoCard = true, slotRight, slotTop, siteInfo } = props
|
||||
const { locale } = useGlobal()
|
||||
const router = useRouter()
|
||||
const [tocVisible, changeTocVisible] = useState(false)
|
||||
|
||||
return (
|
||||
<div className='bg-white dark:bg-hexo-black-gray w-full h-full min-h-screen justify-center dark:text-gray-300'>
|
||||
<ThemeGlobalMedium.Provider value={{ tocVisible, changeTocVisible }} className='bg-white dark:bg-hexo-black-gray w-full h-full min-h-screen justify-center dark:text-gray-300'>
|
||||
<CommonHead meta={meta} />
|
||||
<main id='wrapper' className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'flex-row-reverse' : '') + 'relative flex justify-between w-full h-full mx-auto'}>
|
||||
{/* 桌面端左侧菜单 */}
|
||||
@@ -62,9 +64,10 @@ const LayoutBase = props => {
|
||||
|
||||
{/* 移动端底部 */}
|
||||
<Footer title={siteInfo?.title}/>
|
||||
<BottomMenuBar className='block md:hidden' />
|
||||
</div>
|
||||
<BottomMenuBar {...props} className='block md:hidden' />
|
||||
</ThemeGlobalMedium.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutBase
|
||||
export const useMediumGlobal = () => useContext(ThemeGlobalMedium)
|
||||
|
||||
@@ -2,27 +2,102 @@ import LayoutBase from './LayoutBase'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import React from 'react'
|
||||
import Catalog from './components/Catalog'
|
||||
import { ArticleDetail } from './components/ArticleDetail'
|
||||
import { ArticleLock } from './components/ArticleLock'
|
||||
import JumpToTopButton from './components/JumpToTopButton'
|
||||
import formatDate from '@/lib/formatDate'
|
||||
import BLOG from '@/blog.config'
|
||||
import Link from 'next/link'
|
||||
import NotionPage from '@/components/NotionPage'
|
||||
import CONFIG_MEDIUM from './config_medium'
|
||||
import Comment from '@/components/Comment'
|
||||
import ArticleAround from './components/ArticleAround'
|
||||
import TocDrawer from './components/TocDrawer'
|
||||
import CategoryItem from './components/CategoryItem'
|
||||
import TagItemMini from './components/TagItemMini'
|
||||
|
||||
export const LayoutSlug = props => {
|
||||
const { post, lock, validPassword } = props
|
||||
const { post, prev, next, siteInfo, lock, validPassword } = props
|
||||
const { locale } = useGlobal()
|
||||
|
||||
const date = formatDate(
|
||||
post?.date?.start_date || post?.createdTime,
|
||||
locale.LOCALE
|
||||
)
|
||||
if (!post) {
|
||||
return <LayoutBase {...props} showInfoCard={true}
|
||||
/>
|
||||
/>
|
||||
}
|
||||
|
||||
const slotRight = post?.toc && post?.toc?.length > 3 && (
|
||||
<div key={locale.COMMON.TABLE_OF_CONTENTS} >
|
||||
<Catalog toc={post.toc} />
|
||||
</div>
|
||||
<div key={locale.COMMON.TABLE_OF_CONTENTS} >
|
||||
<Catalog toc={post.toc} />
|
||||
<JumpToTopButton className='text-gray-400 hover:text-green-500 hover:bg-gray-100 py-1 duration-200' />
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<LayoutBase showInfoCard={true} slotRight={slotRight} {...props} >
|
||||
{!lock ? <ArticleDetail {...props} /> : <ArticleLock validPassword={validPassword} />}
|
||||
</LayoutBase>
|
||||
<LayoutBase showInfoCard={true} slotRight={slotRight} {...props} >
|
||||
{/* 文章锁 */}
|
||||
{lock && <ArticleLock validPassword={validPassword} />}
|
||||
|
||||
{!lock && <div id='container'>
|
||||
|
||||
{/* title */}
|
||||
<h1 className="text-3xl pt-12 font-sans dark:text-gray-300">{post?.title}</h1>
|
||||
|
||||
{/* meta */}
|
||||
<section className="py-2 items-center text-sm font-sans px-1">
|
||||
<div className='flex flex-wrap text-gray-500 py-1 dark:text-gray-600'>
|
||||
<span className='whitespace-nowrap'> <i className='far fa-calendar mr-2' />{date}</span>
|
||||
<span className='mx-1'>|</span>
|
||||
<span className='whitespace-nowrap mr-2'><i className='far fa-calendar-check mr-2' />{post.lastEditedTime}</span>
|
||||
<div className="hidden busuanzi_container_page_pv font-light mr-2 whitespace-nowrap">
|
||||
<i className="mr-1 fas fa-eye" /><span className="busuanzi_value_page_pv" />
|
||||
</div>
|
||||
</div>
|
||||
<Link href="/about" passHref legacyBehavior>
|
||||
<div className='flex pt-2'>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={siteInfo?.icon} className='rounded-full cursor-pointer' width={22} alt={BLOG.AUTHOR} />
|
||||
|
||||
<div className="mr-3 ml-2 my-auto text-green-500 cursor-pointer">
|
||||
{BLOG.AUTHOR}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
{/* Notion文章主体 */}
|
||||
<section id="notion-article" className="px-1 max-w-5xl">
|
||||
{post && (<NotionPage post={post} />)}
|
||||
</section>
|
||||
|
||||
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
|
||||
{/* 文章内嵌广告 */}
|
||||
<ins
|
||||
className="adsbygoogle"
|
||||
style={{ display: 'block', textAlign: 'center' }}
|
||||
data-adtest="on"
|
||||
data-ad-layout="in-article"
|
||||
data-ad-format="fluid"
|
||||
data-ad-client="ca-pub-2708419466378217"
|
||||
data-ad-slot="3806269138"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className='flex justify-between'>
|
||||
{CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category && <CategoryItem category={post.category} />}
|
||||
<div>
|
||||
{CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
|
||||
</div>
|
||||
</div>
|
||||
{post.type === 'Post' && <ArticleAround prev={prev} next={next} />}
|
||||
<Comment frontMatter={post} />
|
||||
</section>
|
||||
|
||||
<TocDrawer {...props} />
|
||||
</div>}
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import Comment from '@/components/Comment'
|
||||
import Link from 'next/link'
|
||||
import ArticleAround from './ArticleAround'
|
||||
import CategoryItem from './CategoryItem'
|
||||
import TagItemMini from './TagItemMini'
|
||||
import CONFIG_MEDIUM from '../config_medium'
|
||||
import formatDate from '@/lib/formatDate'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import BLOG from '@/blog.config'
|
||||
import NotionPage from '@/components/NotionPage'
|
||||
import React from 'react'
|
||||
|
||||
export const ArticleDetail = props => {
|
||||
const { post, prev, next, siteInfo } = props
|
||||
const { locale } = useGlobal()
|
||||
|
||||
const date = formatDate(
|
||||
post?.date?.start_date || post?.createdTime,
|
||||
locale.LOCALE
|
||||
)
|
||||
return (
|
||||
<div id='container'>
|
||||
|
||||
{/* title */}
|
||||
<h1 className="text-3xl pt-12 font-sans dark:text-gray-300">{post?.title}</h1>
|
||||
|
||||
{/* meta */}
|
||||
<section className="py-2 items-center text-sm font-sans px-1">
|
||||
<div className='flex flex-wrap text-gray-500 py-1 dark:text-gray-600'>
|
||||
<span className='whitespace-nowrap'> <i className='far fa-calendar mr-2' />{date}</span>
|
||||
<span className='mx-1'>|</span>
|
||||
<span className='whitespace-nowrap mr-2'><i className='far fa-calendar-check mr-2'/>{post.lastEditedTime}</span>
|
||||
<div className="hidden busuanzi_container_page_pv font-light mr-2 whitespace-nowrap">
|
||||
<i className="mr-1 fas fa-eye" /><span className="busuanzi_value_page_pv" />
|
||||
</div>
|
||||
</div>
|
||||
<Link href="/about" passHref legacyBehavior>
|
||||
<div className='flex pt-2'>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={siteInfo?.icon} className='rounded-full cursor-pointer' width={22} alt={BLOG.AUTHOR} />
|
||||
|
||||
<div className="mr-3 ml-2 my-auto text-green-500 cursor-pointer">
|
||||
{BLOG.AUTHOR}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</section>
|
||||
{/* Notion文章主体 */}
|
||||
<section id="notion-article" className="px-1 max-w-5xl">
|
||||
{post && (<NotionPage post={post} />)}
|
||||
</section>
|
||||
|
||||
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
|
||||
{/* 文章内嵌广告 */}
|
||||
<ins
|
||||
className="adsbygoogle"
|
||||
style={{ display: 'block', textAlign: 'center' }}
|
||||
data-adtest="on"
|
||||
data-ad-layout="in-article"
|
||||
data-ad-format="fluid"
|
||||
data-ad-client="ca-pub-2708419466378217"
|
||||
data-ad-slot="3806269138"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className='flex justify-between'>
|
||||
{CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category && <CategoryItem category={post.category} />}
|
||||
<div>
|
||||
{CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
|
||||
</div>
|
||||
</div>
|
||||
{post.type === 'Post' && <ArticleAround prev={prev} next={next} />}
|
||||
<Comment frontMatter={post} />
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,19 @@
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import { useMediumGlobal } from '../LayoutBase'
|
||||
import JumpToTopButton from './JumpToTopButton'
|
||||
|
||||
export default function BottomMenuBar ({ className }) {
|
||||
export default function BottomMenuBar ({ post, className }) {
|
||||
const { tocVisible, changeTocVisible } = useMediumGlobal()
|
||||
const showTocBotton = post?.toc?.length > 0
|
||||
|
||||
const toggleToc = () => {
|
||||
changeTocVisible(!tocVisible)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'sticky z-10 bottom-0 w-full h-12 bg-white dark:bg-hexo-black-gray ' + className}>
|
||||
<div className='flex justify-between h-full shadow-card'>
|
||||
<Link href='/' passHref legacyBehavior>
|
||||
<div className='flex w-full items-center justify-center cursor-pointer'>
|
||||
<i className='fas fa-home' />
|
||||
</div>
|
||||
</Link>
|
||||
<Link href='/search' passHref legacyBehavior>
|
||||
<div className='flex w-full items-center justify-center cursor-pointer'>
|
||||
<i className='fas fa-search'/>
|
||||
@@ -19,6 +22,14 @@ export default function BottomMenuBar ({ className }) {
|
||||
<div className='flex w-full items-center justify-center cursor-pointer'>
|
||||
<JumpToTopButton/>
|
||||
</div>
|
||||
{showTocBotton && <div onClick={toggleToc} className='flex w-full items-center justify-center cursor-pointer'>
|
||||
<i className='fas fa-list-ol ' />
|
||||
</div>}
|
||||
{ !showTocBotton && <Link href='/' passHref legacyBehavior>
|
||||
<div className='flex w-full items-center justify-center cursor-pointer'>
|
||||
<i className='fas fa-home' />
|
||||
</div>
|
||||
</Link>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useRef } from 'react'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { uuidToId } from 'notion-utils'
|
||||
import Progress from './Progress'
|
||||
import JumpToTopButton from './JumpToTopButton'
|
||||
|
||||
/**
|
||||
* 目录导航组件
|
||||
* @param toc
|
||||
@@ -85,7 +85,6 @@ const Catalog = ({ toc }) => {
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
<JumpToTopButton className='text-gray-400 hover:text-green-500 hover:bg-gray-100 py-1 duration-200' />
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ import CONFIG_MEDIUM from '../config_medium'
|
||||
* @constructor
|
||||
*/
|
||||
const JumpToTopButton = ({ showPercent = false, percent, className }) => {
|
||||
const { locale } = useGlobal()
|
||||
if (!CONFIG_MEDIUM.WIDGET_TO_TOP) {
|
||||
return <></>
|
||||
}
|
||||
const { locale } = useGlobal()
|
||||
return (<div className={'flex space-x-1 items-center cursor-pointer w-full justify-center ' + className } onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
|
||||
<div title={locale.POST.TOP} >
|
||||
<i className='fas fa-arrow-up'/>
|
||||
|
||||
35
themes/medium/components/TocDrawer.js
Normal file
35
themes/medium/components/TocDrawer.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import Catalog from './Catalog'
|
||||
import { useMediumGlobal } from '../LayoutBase'
|
||||
|
||||
/**
|
||||
* 悬浮抽屉目录
|
||||
* @param toc
|
||||
* @param post
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const TocDrawer = ({ post, cRef }) => {
|
||||
const { tocVisible, changeTocVisible } = useMediumGlobal()
|
||||
const switchVisible = () => {
|
||||
changeTocVisible(!tocVisible)
|
||||
}
|
||||
return <>
|
||||
<div id='medium-toc-float' className='fixed top-0 right-0 z-40'>
|
||||
{/* 侧边菜单 */}
|
||||
<div
|
||||
className={(tocVisible ? 'animate__slideInRight ' : ' -mr-72 animate__slideOutRight') +
|
||||
' shadow-card h-56 overflow-y-hidden' +
|
||||
' w-60 duration-200 fixed right-1 bottom-16 rounded py-2 bg-white dark:bg-gray-600'}>
|
||||
{post && <>
|
||||
<div className='dark:text-gray-400 text-gray-600'>
|
||||
<Catalog toc={post.toc}/>
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
</div>
|
||||
{/* 背景蒙版 */}
|
||||
<div id='right-drawer-background' className={(tocVisible ? 'block' : 'hidden') + ' fixed top-0 left-0 z-30 w-full h-full'}
|
||||
onClick={switchVisible} />
|
||||
</>
|
||||
}
|
||||
export default TocDrawer
|
||||
Reference in New Issue
Block a user