mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 15:09:22 +00:00
feature:
目录组件百分比进度
This commit is contained in:
@@ -165,10 +165,13 @@ export default function ArticleDetail ({ post, blockMap, recommendPosts, prev, n
|
||||
{/* 悬浮目录按钮 */}
|
||||
<div className="block lg:hidden">
|
||||
<TocDrawerButton onClick={() => { drawerRight.current.handleSwitchVisible() }} />
|
||||
<TocDrawer post={post} cRef={drawerRight} />
|
||||
<TocDrawer post={post} cRef={drawerRight} targetRef={targetRef} />
|
||||
</div>
|
||||
|
||||
<Progress targetRef={targetRef} />
|
||||
{/* 移动端顶部进度条 */}
|
||||
{/* <div className='fixed left-0 top-0 w-full z-40 block md:hidden'>
|
||||
<Progress targetRef={targetRef} />
|
||||
</div> */}
|
||||
</>)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import smoothscroll from 'smoothscroll-polyfill'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const JumpToBottomButton = ({ targetRef, showPercent = true }) => {
|
||||
const JumpToBottomButton = ({ targetRef, showPercent = false }) => {
|
||||
const { locale } = useGlobal()
|
||||
const [show, switchShow] = useState(false)
|
||||
const [percent, changePercent] = useState(0)
|
||||
|
||||
@@ -12,7 +12,7 @@ import smoothscroll from 'smoothscroll-polyfill'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const JumpToTopButton = ({ targetRef, showPercent = true }) => {
|
||||
const JumpToTopButton = ({ targetRef, showPercent = false }) => {
|
||||
const { locale } = useGlobal()
|
||||
const [show, switchShow] = useState(false)
|
||||
const [percent, changePercent] = useState(0)
|
||||
@@ -39,7 +39,7 @@ const JumpToTopButton = ({ targetRef, showPercent = true }) => {
|
||||
|
||||
return (<div id='jump-to-top' className='right-3 fixed flex bottom-48 duration-500 z-20'>
|
||||
<div onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
||||
className={(show ? '' : 'hidden') + ' animate__fadeInRight animate__animated animate__faster shadow-card rounded-xl glassmorphism py-1 cursor-pointer '}>
|
||||
className={(show ? '' : 'hidden') + ' animate__fadeInRight animate__animated animate__faster shadow-card rounded-xl glassmorphism py-3 cursor-pointer '}>
|
||||
<div className='text-center'>
|
||||
<div className='w-10 dark:text-gray-200 transform hover:scale-150 duration-200 text-xs' title={locale.POST.TOP} >
|
||||
<FontAwesomeIcon icon={faArrowUp} />
|
||||
|
||||
@@ -8,7 +8,7 @@ import React, { useEffect, useState } from 'react'
|
||||
const Progress = ({ targetRef }) => {
|
||||
const [percent, changePercent] = useState(0)
|
||||
const scrollListener = () => {
|
||||
if (targetRef.current) {
|
||||
if (targetRef?.current) {
|
||||
const clientHeight = targetRef ? (targetRef.current.clientHeight) : 0
|
||||
const scrollY = window.pageYOffset
|
||||
const fullHeight = clientHeight - window.outerHeight
|
||||
@@ -23,8 +23,9 @@ const Progress = ({ targetRef }) => {
|
||||
return () => document.removeEventListener('scroll', scrollListener)
|
||||
}, [percent])
|
||||
|
||||
return (<div className='h-1 fixed left-0 top-0 w-full shadow-2xl z-40 bg-blue-200'>
|
||||
<div className='h-1 bg-blue-600 fixed left-0 top-0 duration-200 rounded' style={{ width: `${percent}%` }}/>
|
||||
return (<div className='h-4 w-full shadow-2xl bg-purple-400'>
|
||||
<div className='text-center w-full absolute text-white text-xs'>{percent}%</div>
|
||||
<div className='h-4 bg-purple-700 duration-200 rounded-r' style={{ width: `${percent}%` }}/>
|
||||
</div>)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { faAngleDoubleRight, faChartBar, faThList } from '@fortawesome/free-soli
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import Progress from './Progress'
|
||||
|
||||
/**
|
||||
* 侧边平铺
|
||||
@@ -21,7 +22,7 @@ import React from 'react'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const SideAreaLeft = ({ title, tags, currentTag, post, posts, categories, currentCategory, currentSearch }) => {
|
||||
const SideAreaLeft = ({ title, tags, currentTag, post, posts, categories, currentCategory, currentSearch, targetRef }) => {
|
||||
const { locale } = useGlobal()
|
||||
const showToc = post && post.toc && post.toc.length > 1
|
||||
const postCount = posts?.length || 0
|
||||
@@ -71,10 +72,10 @@ const SideAreaLeft = ({ title, tags, currentTag, post, posts, categories, curren
|
||||
|
||||
{showToc && (
|
||||
<section className='sticky top-8 pb-20 rounded-xl shadow-md bg-white dark:bg-gray-800 hover:shadow-2xl duration-200'>
|
||||
<div className='border-b text-2xl bg-white text-black rounded-t-xl dark:border-gray-700 dark:bg-gray-700 dark:text-white py-6 px-6'>
|
||||
<div className='border-b text-center text-2xl bg-white text-black rounded-t-xl dark:border-gray-700 dark:bg-gray-700 dark:text-white py-6 px-6'>
|
||||
{locale.COMMON.TABLE_OF_CONTENTS}
|
||||
</div>
|
||||
<Toc toc={post.toc} />
|
||||
<Toc toc={post.toc} targetRef={targetRef} />
|
||||
</section>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useCallback } from 'react'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { uuidToId } from 'notion-utils'
|
||||
import Progress from './Progress'
|
||||
// import { cs } from 'react-notion-x'
|
||||
|
||||
/**
|
||||
@@ -9,7 +10,7 @@ import { uuidToId } from 'notion-utils'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const Toc = ({ toc }) => {
|
||||
const Toc = ({ toc, targetRef }) => {
|
||||
// 无目录就直接返回空
|
||||
if (!toc || toc.length < 1) return <></>
|
||||
|
||||
@@ -51,6 +52,9 @@ const Toc = ({ toc }) => {
|
||||
}, throttleMs))
|
||||
|
||||
return <>
|
||||
<div className='w-full'>
|
||||
<Progress targetRef={targetRef}/>
|
||||
</div>
|
||||
<nav className=' dark:text-gray-100 bg-white dark:bg-gray-800 overflow-y-auto scroll-hidden p-6'>
|
||||
{toc.map((tocItem) => {
|
||||
const id = uuidToId(tocItem.id)
|
||||
@@ -58,9 +62,9 @@ const Toc = ({ toc }) => {
|
||||
<a
|
||||
key={id}
|
||||
href={`#${id}`}
|
||||
className={`notion-table-of-contents-item duration-300 transform font-light
|
||||
className={`notion-table-of-contents-item duration-300 transform font-mono
|
||||
notion-table-of-contents-item-indent-level-${tocItem.indentLevel}
|
||||
${activeSection === id && ' font-bold text-blue-400 dark:text-white'}`}
|
||||
${activeSection === id && ' font-bold text-purple-500 dark:text-purple-400'}`}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useGlobal } from '@/lib/global'
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const TocDrawer = ({ post, cRef }) => {
|
||||
const TocDrawer = ({ post, cRef, targetRef }) => {
|
||||
// 暴露给父组件 通过cRef.current.handleMenuClick 调用
|
||||
useImperativeHandle(cRef, () => {
|
||||
return {
|
||||
@@ -26,13 +26,13 @@ const TocDrawer = ({ post, cRef }) => {
|
||||
{/* 侧边菜单 */}
|
||||
<div
|
||||
className={(showDrawer ? 'animate__slideInRight ' : ' -mr-72 animate__slideOutRight') +
|
||||
' shadow-xl animate__animated animate__faster max-h-96 ' +
|
||||
' shadow-card animate__animated animate__faster max-h-96 ' +
|
||||
' w-60 duration-200 fixed right-4 top-16 rounded overflow-y-auto'}>
|
||||
{post && <>
|
||||
<div className='text-xl font-bold text-black dark:text-white bg-gray-200 dark:bg-gray-600 py-2 px-6'>
|
||||
<div className='text-xl font-bold text-center text-black dark:text-white bg-white dark:bg-gray-600 py-2 px-6'>
|
||||
{locale.COMMON.TABLE_OF_CONTENTS}
|
||||
</div>
|
||||
<Toc toc={post.toc}/>
|
||||
<Toc toc={post.toc} targetRef={targetRef}/>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -75,7 +75,7 @@ const BaseLayout = ({
|
||||
<div className='flex justify-center flex-1 mx-auto md:pt-8 pb-12'>
|
||||
|
||||
<div id='left' className='hidden lg:block flex-col w-72'>
|
||||
<SideAreaLeft title={meta.title} post={post} posts={totalPosts} tags={tags} currentSearch={currentSearch} currentTag={currentTag} categories={categories} currentCategory={currentCategory} />
|
||||
<SideAreaLeft targetRef={targetRef} title={meta.title} post={post} posts={totalPosts} tags={tags} currentSearch={currentSearch} currentTag={currentTag} categories={categories} currentCategory={currentCategory} />
|
||||
</div>
|
||||
|
||||
<div id='center' className='flex-grow max-w-4xl min-h-screen md:mx-10' ref={targetRef}>
|
||||
@@ -94,7 +94,7 @@ const BaseLayout = ({
|
||||
</div>
|
||||
|
||||
<Footer title={meta.title}/>
|
||||
<JumpToTopButton targetRef={targetRef} showPercent={true} />
|
||||
<JumpToTopButton targetRef={targetRef} showPercent={false} />
|
||||
<JumpToBottomButton targetRef={targetRef} showPercent={false}/>
|
||||
<FloatDarkModeButton/>
|
||||
</div>
|
||||
|
||||
7
lib/cache/cache_manager.js
vendored
7
lib/cache/cache_manager.js
vendored
@@ -1,4 +1,5 @@
|
||||
import { getCacheFromMemory, setCacheToMemory } from '@/lib/cache/memory_cache'
|
||||
// import { getCacheFromMemory, setCacheToMemory } from '@/lib/cache/memory_cache'
|
||||
import { getCacheFromFile, setCacheToFile } from './local_file_cache'
|
||||
const enableCache = true // 生产环境禁用
|
||||
|
||||
/**
|
||||
@@ -10,7 +11,7 @@ export async function getDataFromCache (key) {
|
||||
if (!enableCache) {
|
||||
return null
|
||||
}
|
||||
const dataFromCache = await getCacheFromMemory(key)
|
||||
const dataFromCache = await getCacheFromFile(key)
|
||||
if (JSON.stringify(dataFromCache) === '[]') {
|
||||
return null
|
||||
}
|
||||
@@ -21,5 +22,5 @@ export async function setDataToCache (key, data) {
|
||||
if (!enableCache || !data) {
|
||||
return
|
||||
}
|
||||
await setCacheToMemory(key, data)
|
||||
await setCacheToFile(key, data)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user